From 8aaba0be4c933d43654accfa9d73b20296d0a129 Mon Sep 17 00:00:00 2001 From: Allanis Date: Mon, 30 Dec 2013 21:51:59 +0000 Subject: [PATCH] [Add] Added a ton more escort stuff. --- src/escort.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/escort.h | 13 ++++ src/input.c | 27 +++++++- src/outfit.c | 93 +++++++++++++++------------ src/outfit.h | 28 +++++++- src/pilot.c | 8 +++ src/pilot.h | 38 +++++------ 7 files changed, 322 insertions(+), 61 deletions(-) create mode 100644 src/escort.c create mode 100644 src/escort.h diff --git a/src/escort.c b/src/escort.c new file mode 100644 index 0000000..f35e230 --- /dev/null +++ b/src/escort.c @@ -0,0 +1,176 @@ +/** + * @file escorts.c + * + * @brief Handles the players escorts. + */ + +#include "lephisto.h" +#include "log.h" +#include "player.h" +#include "llua.h" +#include "lluadef.h" +#include "llua_space.h" +#include "escort.h" + +#define ESCORT_PREALLOC 8 /**< Number of escorts to automatically allocate first. */ + +#define ESCORT_ATTACK 1 /**< Attack order. */ +#define ESCORT_HOLD 2 /**< Hold order. */ +#define ESCORT_RETURN 3 /**< Return to ship order. */ +#define ESCORT_CLEAR 4 /**< Clear orders. */ + +/* Static. */ +static int escort_command(Pilot* parent, int cmd, int param); +/* Extern. */ +extern void ai_setPilot(Pilot* p); + +/** + * @fn int escort_create(unsigned int parent, char* ship, + * Vec2* pos, Vec2* vel, int carried) + * + * @brief Create an escort. + * @param parent Parent of the escort (who she's guarding). + * @param ship Name of the ship escort should have. + * @param pos Position to create escort at. + * @param vel Velocity to create escort with. + * @param carried Does escort come out of the parent? + */ +int escort_create(unsigned int parent, char* ship, + Vec2* pos, Vec2* vel, int carried) { + + Ship* s; + Pilot* p, *pe; + char buf[16]; + unsigned int e, f; + + /* Get important stuff. */ + p = pilot_get(parent); + s = ship_get(ship); + snprintf(buf, 16, "tpl/escort*%u", parent); + + /* Set flags. */ + f = PILOT_ESCORT; + if(carried) f |= PILOT_CARRIED; + + /* Create the pilot. */ + e = pilot_create(s, NULL, p->faction, buf, 0., pos, vel, f); + pe = pilot_get(e); + pe->parent = parent; + + /* Add to escort list. */ + p->nescorts++; + if(p->nescorts == 1) + p->escorts = malloc(sizeof(unsigned int) * ESCORT_PREALLOC); + else if(p->nescorts > ESCORT_PREALLOC) + p->escorts = realloc(p->escorts, sizeof(unsigned int) * p->nescorts); + p->escorts[p->nescorts-1] = e; + + return 0; +} + +/** + * @fn static int escort_command(Pilot* parent, int cmd, int param) + * + * @brief Run an escort command on all of a pilots escorts. + * @param parent Pilot who is giving orders. + * @param cmd Order to give. + * @param param Parameter for order. + * @return 0 on success, 1 if no orders given. + */ +static int escort_command(Pilot* parent, int cmd, int param) { + int i, n; + lua_State* L; + Pilot* e; + char* buf; + + if(parent->nescorts == 0) + return 1; + + n = 0; + for(i = 0; i < parent->nescorts; i++) { + e = pilot_get(parent->escorts[i]); + if(e == NULL) /* Most likely died. */ + continue; + + /* Check if command makes sense. */ + if((cmd == ESCORT_RETURN) && !pilot_isFlag(parent, PILOT_CARRIED)) + continue; + + n++; /* Amount of escorts left. */ + + /* Prepare ai. */ + ai_setPilot(e); + + /* Set up stack. */ + L = e->ai->L; + switch(cmd) { + case ESCORT_ATTACK: + buf = "e_attack"; + break; + case ESCORT_HOLD: + buf = "e_hold"; + break; + case ESCORT_RETURN: + buf = "e_return"; + break; + case ESCORT_CLEAR: + buf = "e_clear"; + break; + } + lua_getglobal(L, buf); + if(param >= 0) + lua_pushnumber(L, param); + + /* Run command. */ + if(lua_pcall(L, (param >= 0) ? 1 : 0, 0, 0)) + WARN("Pilot '%s' ai -> '%s' : %s", e->name, + buf, lua_tostring(L, -1)); + } + return !n; +} + +/** + * @fn void escorts_attack(Pilot* parent) + * + * @brief HAve a pilot order it's escorts to attack its target. + * @param parent Pilot giving the order. + */ +void escorts_attack(Pilot* parent) { + if(parent->target != parent->id) + if(escort_command(parent, ESCORT_ATTACK, parent->target)==0) + player_message("Escorts: Attacking %s.", pilot_get(parent->target)->name); +} + +/** + * @fn void escorts_hold(Pilot* parent) + * + * @brief Have a pilot order its escorts to hold position. + * @param parent Pilot giving the order. + */ +void escorts_hold(Pilot* parent) { + if(escort_command(parent, ESCORT_HOLD, -1)==0) + player_message("Escorts: Holding position."); +} + +/** + * @fn void escorts_return(Pilot* parent) + * + * @brief Have a pilot order its escorts to dock. + * @param parent Pilot giving the order. + */ +void escorts_return(Pilot* parent) { + if(escort_command(parent, ESCORT_RETURN, -1)==0) + player_message("Escorts: Returning to ship."); +} + +/** + * @fn void escorts_clear(Pilot* parent) + * + * @brief Have a pilot order its escorts to clear orders. + * @param parent Pilot giving the order. + */ +void escorts_clear(Pilot* parent) { + if(escort_command(parent, ESCORT_CLEAR, -1)==0) + player_message("Escorts: Clearing orders."); +} + diff --git a/src/escort.h b/src/escort.h new file mode 100644 index 0000000..94ebbc6 --- /dev/null +++ b/src/escort.h @@ -0,0 +1,13 @@ +#pragma once +#include "physics.h" +#include "pilot.h" + +int escort_create(unsigned int parent, char* ship, + Vec2* pos, Vec2* vel, int carried); + +/* Keybind commands. */ +void escorts_attack(Pilot* parent); +void escorts_hold(Pilot* parent); +void escorts_return(Pilot* parent); +void escorts_clear(Pilot* parent); + diff --git a/src/input.c b/src/input.c index 568595d..e8fa178 100644 --- a/src/input.c +++ b/src/input.c @@ -12,6 +12,7 @@ #include "menu.h" #include "board.h" #include "map.h" +#include "escort.h" #include "input.h" #define KEY_PRESS ( 1.) /**< Key is pressed. */ @@ -37,6 +38,8 @@ const char* keybindNames[] = { "target", "target_nearest", "target_hostile", /* Fighting. */ "primary", "face", "board", + /* Escorts. */ + "e_attack", "e_hold", "e_return", "e_clear", /* Secondary weapons. */ "secondary", "secondary_next", /* Space Navigation. */ @@ -52,8 +55,6 @@ unsigned int input_afterburnSensibility = 200; /**< ms between taps to afterbur /* From player.c */ extern double player_turn; -extern unsigned int player_target; - /** * @fn void input_setDefault(void) @@ -75,8 +76,15 @@ void input_setDefault(void) { input_setKeybind("primary", KEYBIND_KEYBOARD, SDLK_SPACE, KMOD_NONE, 0); input_setKeybind("face", KEYBIND_KEYBOARD, SDLK_f, KMOD_NONE, 0); input_setKeybind("board", KEYBIND_KEYBOARD, SDLK_b, KMOD_NONE, 0); + /* Escorts. */ + input_setKeybind("e_attack", KEYBIND_KEYBOARD, SDLK_f, KMOD_NONE, 0); + input_setKeybind("e_hold", KEYBIND_KEYBOARD, SDLK_g, KMOD_NONE, 0); + input_setKeybind("e_return", KEYBIND_KEYBOARD, SDLK_r, KMOD_NONE, 0); + input_setKeybind("e_cleark", KEYBIND_KEYBOARD, SDLK_c, KMOD_NONE, 0); + + /* Secondary weapon. */ - input_setKeybind("secondary", KEYBIND_KEYBOARD, SDLK_LSHIFT, KMOD_ALL, 0); + input_setKeybind("secondary", KEYBIND_KEYBOARD, SDLK_LSHIFT, KMOD_ALL, 0); input_setKeybind("secondary_next", KEYBIND_KEYBOARD, SDLK_e, KMOD_NONE, 0); /* Space */ input_setKeybind("autonav", KEYBIND_KEYBOARD, SDLK_j, KMOD_LCTRL, 0); @@ -299,6 +307,19 @@ static void input_key(int keynum, double value, int kabs) { player_board(); } } + /* Escorts. */ + else if(INGAME() && KEY("e_attack")) { + if(value == KEY_PRESS) escorts_attack(player); + } + else if(INGAME() && KEY("e_hold")) { + if(value == KEY_PRESS) escorts_hold(player); + } + else if(INGAME() && KEY("e_return")) { + if(value == KEY_PRESS) escorts_return(player); + } + else if(INGAME() && KEY("e_clear")) { + if(value == KEY_PRESS) escorts_clear(player); + } /* Shooting secondary weapon. */ else if(KEY("secondary") && NOHYP()) { if(value == KEY_PRESS) { player_setFlag(PLAYER_SECONDARY); } diff --git a/src/outfit.c b/src/outfit.c index e040ef8..e75e367 100644 --- a/src/outfit.c +++ b/src/outfit.c @@ -265,6 +265,28 @@ int outfit_isJammer(const Outfit* o) { return(o->type == OUTFIT_TYPE_JAMMER); } +/** + * @fn int outfit_isFighterBay(const Outfit* o) + * + * @brief Check if outfit is a fighter bay. + * @param o Outfit to check. + * @param 1 if o is a jammer. + */ +int outfit_isFighterBay(const Outfit* o) { + return (o->type == OUTFIT_TYPE_FIGHTER_BAY); +} + +/** + * @fn int outfit_isFighter(const Outfit* o) + * + * @brief Check if outfit is a fighter. + * @param o Outfit to check. + * @param 1 if o is a jammer. + */ +int outfit_isFighter(const Outfit* o) { + return (o->type == OUTFIT_TYPE_FIGHTER); +} + /** * @fn int outfit_isMap(const Outfit* o) * @@ -336,9 +358,10 @@ DamageType outfit_damageType(const Outfit* o) { * @param o Outfit to get information from. */ int outfit_delay(const Outfit* o) { - if(outfit_isBolt(o)) return o->u.blt.delay; - else if(outfit_isBeam(o)) return o->u.bem.delay; - else if(outfit_isLauncher(o)) return o->u.lau.delay; + if(outfit_isBolt(o)) return o->u.blt.delay; + else if(outfit_isBeam(o)) return o->u.bem.delay; + else if(outfit_isLauncher(o)) return o->u.lau.delay; + else if(outfit_isFighterBay(o)) return o->u.bay.delay; return -1; } @@ -407,6 +430,8 @@ const char* outfit_getType(const Outfit* o) { "Ship Modification", "Afterburner", "Jammer", + "Fighter Bay", + "Fighter", "Map" }; @@ -421,32 +446,18 @@ const char* outfit_getType(const Outfit* o) { * @return the outfits broad type in human readable form. */ const char* outfit_getTypeBroad(const Outfit* o) { - int i = 0; - - const char* outfit_typenamebroad[] = { - "NULL", - "Bolt Weapon", - "Beam Weapon", - "Launcher", - "Ammo", - "Turret", - "Modification", - "Afterburner", - "Jammer", - "Map" - }; - - if(outfit_isBolt(o)) i = 1; - else if(outfit_isBeam(o)) i = 2; - else if(outfit_isLauncher(o)) i = 3; - else if(outfit_isAmmo(o)) i = 4; - else if(outfit_isTurret(o)) i = 5; - else if(outfit_isMod(o)) i = 6; - else if(outfit_isAfterburner(o)) i = 7; - else if(outfit_isJammer(o)) i = 8; - else if(outfit_isMap(o)) i = 9; - - return outfit_typenamebroad[i]; + if(outfit_isBolt(o)) return "Bolt Weapon"; + else if(outfit_isBeam(o)) return "Beam Weapon"; + else if(outfit_isLauncher(o)) return "Launcher"; + else if(outfit_isAmmo(o)) return "Ammo"; + else if(outfit_isTurret(o)) return "Turret"; + else if(outfit_isMod(o)) return "Modification"; + else if(outfit_isAfterburner(o)) return "Afterburner"; + else if(outfit_isJammer(o)) return "Jammer"; + else if(outfit_isFighterBay(o)) return "Fighter Bay"; + else if(outfit_isFighter(o)) return "Fighter"; + else if(outfit_isMap(o)) return "Map"; + else return "Unknown"; } /* Return the damage type from a str. */ @@ -904,22 +915,26 @@ int outfit_load(void) { /* Frees the outfit stack. */ void outfit_free(void) { int i; + Outfit* o; for(i = 0; i < outfit_nstack; i++) { + o = &outfit_stack[i]; + /* Free graphics. */ if(outfit_gfx(&outfit_stack[i])) gl_freeTexture(outfit_gfx(&outfit_stack[i])); + /* Type specification. */ + if(outfit_isLauncher(o) && o->u.lau.ammo) + free(o->u.lau.ammo); + if(outfit_isFighterBay(o) && o->u.bay.ammo) + free(o->u.bay.ammo); + /* Strings. */ - if(outfit_isLauncher(&outfit_stack[i]) && outfit_stack[i].u.lau.ammo) - free(outfit_stack[i].u.lau.ammo); - - if(outfit_stack[i].description) - free(outfit_stack[i].description); - - if(outfit_stack[i].gfx_store) - gl_freeTexture(outfit_stack[i].gfx_store); - - free(outfit_stack[i].name); + if(o->description) + free(o->description); + if(o->gfx_store) + gl_freeTexture(o->gfx_store); + free(o->name); } free(outfit_stack); } diff --git a/src/outfit.h b/src/outfit.h index b830a19..164718a 100644 --- a/src/outfit.h +++ b/src/outfit.h @@ -32,6 +32,8 @@ typedef enum OutfitType_ { OUTFIT_TYPE_MODIFICATION, /**< Modifies the ship afterburn capability. */ OUTFIT_TYPE_AFTERBURNER, /**< Gives the ship afterburn capability. */ OUTFIT_TYPE_JAMMER, /**< Used to nullify seeker missiles. */ + OUTFIT_TYPE_FIGHTER_BAY, /**< Contains other ships. */ + OUTFIT_TYPE_FIGHTER, /**< Ship contained in FIGHTER BAY. */ OUTFIT_TYPE_MAP, /**< Give the player more knowledge about systems. */ OUTFIT_TYPE_SENTINEL /**< Indicates last type. */ } OutfitType; @@ -171,6 +173,26 @@ typedef struct OutfitAfterburnerData_ { double energy; /**< Energy used while active. */ } OutfitAfterburnerData; +/** + * @struct OutfitFighterBayData + * + * @brief Represents a fighter bay. + */ +typedef struct OutfitFighterBayData_ { + char* ammo; /**< Ships to use as ammo. */ + double delay; /**< Delay between launches. */ +} OutfitFighterBayData; + +/** + * @struct OutfitFighterData + * + * @brief Represents a fighter for a fighter bay. + */ +typedef struct OutfitFighterData_ { + char* ship; /**< Ship to use for fighter. */ + int sound; /**< Sound to make when launching. */ +} OutfitFighterData; + /** * @struct OutfitMapData * @@ -225,6 +247,8 @@ typedef struct Outfit_ { OutfitModificationData mod; /**< MODIFICATION. */ OutfitAfterburnerData afb; /**< AFTERBURNER. */ OutfitJammerData jam; /**< JAMMER. */ + OutfitFighterBayData bay; /**< FIGHTER_BAY. */ + OutfitFighterData fig; /**< FIGHTER. */ OutfitMapData map; /**< MAP. */ } u; } Outfit; @@ -245,8 +269,10 @@ int outfit_isAmmo(const Outfit* o); int outfit_isTurret(const Outfit* o); int outfit_isMod(const Outfit* o); int outfit_isAfterburner(const Outfit* o); -int outfit_isMap(const Outfit* o); int outfit_isJammer(const Outfit* o); +int outfit_isFighterBay(const Outfit* o); +int outfit_isFighter(const Outfit* o); +int outfit_isMap(const Outfit* o); const char* outfit_getType(const Outfit* o); const char* outfit_getTypeBroad(const Outfit* o); diff --git a/src/pilot.c b/src/pilot.c index 2f2139c..2c92b1b 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -1260,6 +1260,13 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, int faction, /* All update the same way. */ pilot->update = pilot_update; + /* Escort stuff. */ + if(flags & PILOT_ESCORT) { + pilot->flags |= PILOT_ESCORT; + if(flags & PILOT_CARRIED) + pilot->flags |= PILOT_CARRIED; + } + /* AI. */ pilot->target = pilot->id; /* Self = no target. */ if(ai != NULL) @@ -1378,6 +1385,7 @@ void pilot_free(Pilot* p) { if(p->outfits) free(p->outfits); free(p->name); if(p->commodities) free(p->commodities); + if(p->escorts) free(p->escorts); free(p); } diff --git a/src/pilot.h b/src/pilot.h index b2a8604..d62cff9 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -33,24 +33,26 @@ #define pilot_setFlag(p,f) (p->flags |= (f)) /**< Set flag f on pilot p. */ #define pilot_rmFlag(p,f) (p->flags ^= (f)) /**< Remove flag f on pilot p. */ /* Creation. */ -#define PILOT_PLAYER (1<<0) /**< Pilot is a player. */ -#define PILOT_HASTURRET (1<<20) /**< Pilot has turrets. */ -#define PILOT_HASBEAMS (1<<23) /**< Pilot has beam weapons. */ -#define PILOT_NO_OUTFITS (1<<21) /**< Do not create the pilot with outfits. */ -#define PILOT_EMPTY (1<<22) /**< Do not add pilot to stack. */ +#define PILOT_PLAYER (1<<0) /**< Pilot is a player. */ +#define PILOT_ESCORT (1<<1) /**< Pilot is an escort. */ +#define PILOT_CARRIED (1<<2) /**< Pilot usually resides in a fighter bay. */ +#define PILOT_EMPTY (1<<5) /**< Do not add pilot to stack. */ +#define PILOT_NO_OUTFITS (1<<6) /**< Do not create the pilot with outfits. */ +#define PILOT_HASTURRET (1<<9) /**< Pilot has turrets. */ +#define PILOT_HASBEAMS (1<<10) /**< Pilot has beam weapons. */ /* Dynamic. */ -#define PILOT_HOSTILE (1<<1) /**< Pilot is hostile to the player. */ -#define PILOT_COMBAT (1<<2) /**< Pilot is engaged in combat. */ -#define PILOT_AFTERBURNER (1<<3) /**< Pilot has her afterburner activated. */ -#define PILOT_HYP_PREP (1<<5) /**< Pilot is getting ready for hyperspace. */ -#define PILOT_HYP_BEGIN (1<<6) /**< Pilot is starting engines. */ -#define PILOT_HYPERSPACE (1<<7) /**< Pilot is in hyperspace. */ -#define PILOT_BOARDED (1<<8) /**< Pilot has been boarded already! */ -#define PILOT_DISABLED (1<<9) /**< Pilot is disabled. */ -#define PILOT_DEAD (1<<10) /**< Pilot is on it's death bed. */ -#define PILOT_DEATH_SOUND (1<<11) /**< Pilot just did death explosion. */ -#define PILOT_EXPLODED (1<<12) /**< Pilot did final death explosion. */ -#define PILOT_DELETE (1<<15) /**< Pilot will get delete asap. */ +#define PILOT_HOSTILE (1<<11) /**< Pilot is hostile to the player. */ +#define PILOT_COMBAT (1<<12) /**< Pilot is engaged in combat. */ +#define PILOT_AFTERBURNER (1<<13) /**< Pilot has her afterburner activated. */ +#define PILOT_HYP_PREP (1<<15) /**< Pilot is getting ready for hyperspace. */ +#define PILOT_HYP_BEGIN (1<<16) /**< Pilot is starting engines. */ +#define PILOT_HYPERSPACE (1<<17) /**< Pilot is in hyperspace. */ +#define PILOT_BOARDED (1<<18) /**< Pilot has been boarded already! */ +#define PILOT_DISABLED (1<<19) /**< Pilot is disabled. */ +#define PILOT_DEAD (1<<20) /**< Pilot is on it's death bed. */ +#define PILOT_DEATH_SOUND (1<<21) /**< Pilot just did death explosion. */ +#define PILOT_EXPLODED (1<<22) /**< Pilot did final death explosion. */ +#define PILOT_DELETE (1<<25) /**< Pilot will get delete asap. */ /* Just makes life simpler. */ #define pilot_isPlayer(p) ((p)->flags & PILOT_PLAYER) /**< Check if pilot is a player. */ @@ -164,7 +166,7 @@ typedef struct Pilot_ { /* Escort stuff. */ unsigned int parent; /**< Pilots parent. */ - unsigned int* escort; /**< Pilots escorts. */ + unsigned int* escorts; /**< Pilots escorts. */ int nescorts; /**< Number of pilot escorts. */ /* AI. */