[Add] Secondary weapons.

[Add] Preliminary seeker missile.
This commit is contained in:
Allanis 2013-02-15 07:31:59 +00:00
parent 627240c5a4
commit 36f1936667
13 changed files with 397 additions and 128 deletions

View File

@ -18,10 +18,8 @@
<ai>merchant</ai>
<faction>Merchant</faction>
<pilots>
<pilot chance='100'>Merchant Ship</pilot>
<pilot chance='80'>Merchant Ship</pilot>
<pilot chance='80'>Merchant Ship</pilot>
<pilot chance='60'>Merchant Ship</pilot>
<pilot chance='60'>Merchant Ship</pilot>
</pilots>
</fleet>
<fleet name="Pirate">

View File

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<Outfits>
<outfit name="laser">
<outfit name="Laser">
<general>
<max>5</max>
<tech>2</tech>
<mass>1</mass>
<mass>5</mass>
</general>
<specific type = "1">
<sound>laser</sound>
<specific type="1">
<gfx>lasergreen</gfx>
<delay>500</delay>
<speed>550</speed>
@ -19,4 +18,33 @@
</damage>
</specific>
</outfit>
<outfit name="Missile Launcher">
<general>
<max>2</max>
<tech>4</tech>
<mass>10</mass>
</general>
<specific type="5" secondary="1">
<ammo>Missile</ammo>
<delay>1200</delay>
</specific>
</outfit>
<outfit name="Missile">
<general>
<max>60</max>
<tech>2</tech>
<mass>1</mass>
</general>
<specific type="6">
<gfx>missile</gfx>
<duration>5</duration>
<thrust>1200</thrust>
<turn>200</turn>
<speed>600</speed>
<damage>
<armour>25</armour>
<shield>20</shield>
</damage>
</specific>
</outfit>
</Outfits>

View File

@ -24,7 +24,7 @@
<cap_cargo>25</cap_cargo>
</characteristics>
<outfits>
<outfit quantity='1'>laser</outfit>
<outfit quantity='1'>Laser</outfit>
</outfits>
</ship>
<ship name = "Leapard">
@ -51,7 +51,7 @@
<cap_cargo>10</cap_cargo>
</characteristics>
<outfits>
<outfit quantity ='2'>laser</outfit>
<outfit quantity ='2'>Laser</outfit>
</outfits>
</ship>
<ship name="Lancer">
@ -78,7 +78,9 @@
<cap_cargo>40</cap_cargo>
</characteristics>
<outfits>
<outfit quantity='4'>laser</outfit>
<outfit quantity='3'>Laser</outfit>
<outfit quantity='2'>Missile Launcher</outfit>
<outfit quantity='20'>Missile</outfit>
</outfits>
</ship>
</Ships>

BIN
gfx/outfit/missile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

107
src/ai.c
View File

@ -48,8 +48,10 @@
// Call the AI function with name f.
#define AI_LCALL(f) (lua_getglobal(L, f), lua_pcall(L, 0, 0, 0))
// Register a number constant n to name s (syntax is just like lua_register).
// Register a number constant n to name s (syntax is just like lua_regfunc).
#define lua_regnumber(l,s,n) (lua_pushnumber(l,n), lua_setglobal(l,s))
// Registers a C function.
#define lua_regfunc(l,s,f) (lua_pushcfunction(l,f), lua_setglobal(L,s))
// L state, void* buf, int n size, char* s identifier.
#define luaL_dobuffer(L,b,n,s) (luaL_loadbuffer(L,b,n,s) || lua_pcall(L, 0, LUA_MULTRET, 0))
@ -60,6 +62,13 @@
#define MAX_DIR_ERR 0.1*M_PI/180.
#define MIN_VEL_ERR 0.5
// Ai flags.
#define ai_setFlag(f) (pilot_flags |= f)
#define ai_isFlag(f) (pilot_flags & f)
// Flags.
#define AI_PRIMARY (1<<0) // Firing primary weapon.
#define AI_SECONDARY (1<<1) // Firing secondary weapon.
// file info.
#define AI_PREFIX "../scripts/ai/"
#define AI_SUFFIX ".lua"
@ -114,6 +123,7 @@ static int ai_getrndplanet(lua_State* L); // pointer getrndplanet()
static int ai_hyperspace(lua_State* L); // [number] hyperspace()
// Combat.
static int ai_combat(lua_State* L); // combat(number)
static int ai_settarget(lua_State* L); // settarget(number)
static int ai_shoot(lua_State* L); // shoot(number) number = 1,2,3.
static int ai_getenemy(lua_State* L); // number getenemy().
static int ai_hostile(lua_State* L); // hostile(number).
@ -130,7 +140,8 @@ static int ai_rng(lua_State* L); // rng(number, number)
static Pilot* cur_pilot = NULL;
static double pilot_acc = 0.;
static double pilot_turn = 0.;
static int pilot_primary = 0;
static int pilot_flags = 0;
static int pilot_target = 0;
// Destroy the AI part of the pilot.
void ai_destroy(Pilot* p) {
@ -190,47 +201,48 @@ static int ai_loadProfile(char* filename) {
// Register C funstions in Lua.
// Tasks.
lua_register(L, "pushtask", ai_pushtask);
lua_register(L, "poptask", ai_poptask);
lua_register(L, "taskname", ai_taskname);
lua_regfunc(L, "pushtask", ai_pushtask);
lua_regfunc(L, "poptask", ai_poptask);
lua_regfunc(L, "taskname", ai_taskname);
// Consult.
lua_register(L, "gettarget", ai_gettarget);
lua_register(L, "gettargetid", ai_gettargetid);
lua_register(L, "armour", ai_armour);
lua_register(L, "shield", ai_shield);
lua_register(L, "parmour", ai_parmour);
lua_register(L, "pshield", ai_pshield);
lua_register(L, "getdist", ai_getdistance);
lua_register(L, "getpos", ai_getpos);
lua_register(L, "minbrakedist", ai_minbrakedist);
lua_regfunc(L, "gettarget", ai_gettarget);
lua_regfunc(L, "gettargetid", ai_gettargetid);
lua_regfunc(L, "armour", ai_armour);
lua_regfunc(L, "shield", ai_shield);
lua_regfunc(L, "parmour", ai_parmour);
lua_regfunc(L, "pshield", ai_pshield);
lua_regfunc(L, "getdist", ai_getdistance);
lua_regfunc(L, "getpos", ai_getpos);
lua_regfunc(L, "minbrakedist", ai_minbrakedist);
// Boolean.
lua_register(L, "exists", ai_exists);
lua_register(L, "ismaxvel", ai_ismaxvel);
lua_register(L, "isstopped", ai_isstopped);
lua_register(L, "isenemy", ai_isenemy);
lua_register(L, "isally", ai_isally);
lua_register(L, "incombat", ai_incombat);
lua_regfunc(L, "exists", ai_exists);
lua_regfunc(L, "ismaxvel", ai_ismaxvel);
lua_regfunc(L, "isstopped", ai_isstopped);
lua_regfunc(L, "isenemy", ai_isenemy);
lua_regfunc(L, "isally", ai_isally);
lua_regfunc(L, "incombat", ai_incombat);
// Movement.
lua_register(L, "accel", ai_accel);
lua_register(L, "turn", ai_turn);
lua_register(L, "face", ai_face);
lua_register(L, "brake", ai_brake);
lua_register(L, "getnearestplanet", ai_getnearestplanet);
lua_register(L, "getrndplanet", ai_getrndplanet);
lua_register(L, "hyperspace", ai_hyperspace);
lua_regfunc(L, "accel", ai_accel);
lua_regfunc(L, "turn", ai_turn);
lua_regfunc(L, "face", ai_face);
lua_regfunc(L, "brake", ai_brake);
lua_regfunc(L, "getnearestplanet", ai_getnearestplanet);
lua_regfunc(L, "getrndplanet", ai_getrndplanet);
lua_regfunc(L, "hyperspace", ai_hyperspace);
// Combat.
lua_register(L, "combat", ai_combat);
lua_register(L, "shoot", ai_shoot);
lua_register(L, "getenemy", ai_getenemy);
lua_register(L, "hostile", ai_hostile);
lua_regfunc(L, "combat", ai_combat);
lua_regfunc(L, "settarget", ai_settarget);
lua_regfunc(L, "shoot", ai_shoot);
lua_regfunc(L, "getenemy", ai_getenemy);
lua_regfunc(L, "hostile", ai_hostile);
// Timers.
lua_register(L, "settimer", ai_settimer);
lua_register(L, "timeup", ai_timeup);
lua_regfunc(L, "settimer", ai_settimer);
lua_regfunc(L, "timeup", ai_timeup);
// Misc.
lua_register(L, "createvect", ai_createvect);
lua_register(L, "comm", ai_comm);
lua_register(L, "broadcast", ai_broadcast);
lua_register(L, "rng", ai_rng);
lua_regfunc(L, "createvect", ai_createvect);
lua_regfunc(L, "comm", ai_comm);
lua_regfunc(L, "broadcast", ai_broadcast);
lua_regfunc(L, "rng", ai_rng);
// Now load the file, since all the functions have been previously loaded.
@ -277,7 +289,8 @@ void ai_think(Pilot* pilot) {
// Clean up some variables.
pilot_acc = pilot_turn = 0.;
pilot_primary = 0;
pilot_flags = 0;
pilot_target = 0;
// Control function if pilot is idle or tick is up.
if((cur_pilot->tcontrol < SDL_GetTicks()) || (cur_pilot->task == NULL)) {
@ -299,7 +312,9 @@ void ai_think(Pilot* pilot) {
cur_pilot->solid->dir_vel -= cur_pilot->ship->turn * pilot_turn;
vect_pset(&cur_pilot->solid->force, cur_pilot->ship->thrust * pilot_acc, cur_pilot->solid->dir);
if(pilot_primary) pilot_shoot(pilot, 0); // AMG, he's gunna shoot!
// Fire weapons if needs be.
if(ai_isFlag(AI_PRIMARY)) pilot_shoot(pilot, pilot_target, 0); // Primary.
if(ai_isFlag(AI_SECONDARY)) pilot_shoot(pilot, pilot_target, 1); // Secondary.
}
// Pilot is attacked.
@ -676,14 +691,22 @@ static int ai_combat(lua_State* L) {
return 0;
}
// Set the pilots target.
static int ai_settarget(lua_State* L) {
MIN_ARGS(1);
if(lua_isnumber(L,1)) pilot_target = (int)lua_tonumber(L,1);
return 0;
}
// Pew pew.. Says the pilot.
static int ai_shoot(lua_State* L) {
int n = 1;
if(lua_isnumber(L, 1)) n = (int)lua_tonumber(L,1);
if(n == 1) pilot_primary = 1;
//else if(n == 2) pilot_secondary = 1;
//else if(n == 3) pilot_primary = pilot_secondary = 1;
if(n == 1) ai_setFlag(AI_PRIMARY);
else if(n == 2) ai_setFlag(AI_SECONDARY);
else if(n == 3) ai_setFlag(AI_PRIMARY | AI_SECONDARY);
return 0;
}

View File

@ -7,6 +7,8 @@
#include "xml.h"
#include "outfit.h"
#define outfit_setProp(o,p) ((o)->properties |= p)
#define XML_OUTFIT_ID "Outfits"
#define XML_OUTFIT_TAG "outfit"
@ -18,6 +20,8 @@ static int outfits = 0;
static Outfit* outfit_parse(const xmlNodePtr parent);
static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent);
static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent);
static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent);
// Return an outfit.
Outfit* outfit_get(const char* name) {
@ -98,7 +102,8 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
}
} while((node = node->next));
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
MELEMENT(tmp->accuracy, "tech");
if(tmp->gfx_space == NULL)
WARN("Outfit '%s' missing 'gfx' element", tmp->name);
MELEMENT(tmp->delay, "delay");
MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->range, "range");
@ -108,6 +113,60 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
#undef MELEMENT
}
// Parse the specific area for a launcher and loads it into Outfit.
static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node;
node = parent->xmlChildrenNode;
do {
// Load the dataz.
if(xml_isNode(node, "delay")) tmp->delay = xml_getInt(node);
else if(xml_isNode(node, "ammo")) tmp->ammo = strdup(xml_get(node));
} while((node = node->next));
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
if(tmp->ammo == NULL) WARN("Outfit '%s' missing 'ammo' element", tmp->name);
MELEMENT(tmp->delay, "delay");
#undef MELEMENT
}
// Parse the specific area for a weapon and load it into Outfit.
static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr cur, node;
node = parent->xmlChildrenNode;
char str[PATH_MAX] = "\0";
do {
if(xml_isNode(node, "thrust")) tmp->thrust = xml_getFloat(node);
else if(xml_isNode(node, "turn")) tmp->turn = xml_getFloat(node);
else if(xml_isNode(node, "speed")) tmp->speed = xml_getFloat(node);
else if(xml_isNode(node, "duration")) tmp->duration = 1000*(unsigned int)xml_getFloat(node);
else if(xml_isNode(node, "gfx")) {
snprintf(str, strlen(xml_get(node))+sizeof(OUTFIT_GFX)+4,
OUTFIT_GFX"%s.png", xml_get(node));
tmp->gfx_space = gl_newSprite(str, 6, 6);
}
else if(xml_isNode(node, "damage")) {
cur = node->children;
do {
if(xml_isNode(cur, "armour")) tmp->damage_armour = xml_getFloat(cur);
else if(xml_isNode(cur, "shield")) tmp->damage_shield = xml_getFloat(cur);
} while((cur = cur->next));
}
} while((node = node->next));
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
if(tmp->gfx_space == NULL)
WARN("Outfit '%s' missing 'gfx' element", tmp->name);
MELEMENT(tmp->thrust, " thrust");
MELEMENT(tmp->turn, "turn");
MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->range, "duration");
MELEMENT(tmp->damage_armour, "armour' from element 'damage");
MELEMENT(tmp->damage_shield, "shield' from element 'damage");
#undef MELEMENT
}
// Parse and return Outfits from parent node.
static Outfit* outfit_parse(const xmlNodePtr parent) {
Outfit* tmp = CALLOC_L(Outfit);
@ -130,26 +189,33 @@ static Outfit* outfit_parse(const xmlNodePtr parent) {
}
else if(xml_isNode(node, "specific")) {
// Has to be processed seperately.
// Get the type.
prop = xml_nodeProp(node, "type");
if(prop == NULL)
ERR("Outfit '%s' element 'specific' missing property 'type'", tmp->name);
tmp->type = atoi(prop);
free(prop);
switch(tmp->type) {
case OUTFIT_TYPE_NULL:
WARN("Outfit '%s' is of type NONE", tmp->name);
break;
case OUTFIT_TYPE_BOLT:
outfit_parseSWeapon(tmp, node);
break;
default:
break;
// Is this the secondary weapon?
prop = xml_nodeProp(node, "secondary");
if(prop != NULL) {
if((int)atoi(prop)) outfit_setProp(tmp, OUTFIT_PROP_WEAP_SECONDARY);
free(prop);
}
if(tmp->type == OUTFIT_TYPE_NULL)
WARN("Outfit '%s' is of type NONE", tmp->name);
else if(outfit_isWeapon(tmp))
outfit_parseSWeapon(tmp, node);
else if(outfit_isLauncher(tmp))
outfit_parseSLauncher(tmp, node);
else if(outfit_isAmmo(tmp))
outfit_parseSAmmo(tmp, node);
}
} while((node = node->next));
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
MELEMENT(tmp->max, "max");
MELEMENT(tmp->tech, "tech");
MELEMENT(tmp->tech, "tech");
MELEMENT(tmp->mass, "mass");
MELEMENT(tmp->type, "type");
#undef MELEMENT
@ -202,6 +268,10 @@ void outfit_free(void) {
for(i = 0; i < outfits; i++) {
if(outfit_isWeapon(&outfit_stack[i]) && outfit_stack[i].gfx_space)
gl_freeTexture(outfit_stack[i].gfx_space);
if(outfit_isLauncher(&outfit_stack[i]) && outfit_stack[i].ammo)
free(outfit_stack[i].ammo);
free(outfit_stack[i].name);
}
free(outfit_stack);

View File

@ -1,8 +1,9 @@
#pragma once
#include "opengl.h"
#define OUTFIT_PROP_WEAP_PRIMARY (1<<0)
#define OUTFIT_PROP_WEAP_SECONDARY (1<<1)
#define outfit_isProp(o,p) ((o)->properties & p)
// Property flags.
#define OUTFIT_PROP_WEAP_SECONDARY (1<<0)
// Outfit types.
typedef enum {
@ -48,12 +49,14 @@ typedef struct {
};
struct { // Launcher.
//unsigned int delay; // Delay between shots.
char* ammo;
};
struct { // Ammo.
//double speed; // Max speed.
//double turn; // Turn vel.
//double thrust; // Acceleration.
//double damage_armour, damage_shield;
double turn; // Turn vel.
double thrust; // Acceleration.
unsigned int duration; // Duration.
//double damage_armour, damage_shield; // Damage.
//gl_texture* gfx_space;
};

View File

@ -64,7 +64,7 @@ unsigned int pilot_getNearest(const Pilot* p) {
for(tp = 0, d = 0., i = 0; i < pilots; i++)
if(areEnemies(p->faction, pilot_stack[i]->faction)) {
td = vect_dist(&pilot_stack[i]->solid->pos, &p->solid->pos);
if((!tp) || (td < d)) {
if(!pilot_isDisabled(pilot_stack[i]) && ((!tp) || (td < d))) {
d = td;
tp = pilot_stack[i]->id;
}
@ -106,27 +106,40 @@ Pilot* pilot_get(const unsigned int id) {
}
// Mkay, this is how we shoot. Listen up.
void pilot_shoot(Pilot* p, const int secondary) {
void pilot_shoot(Pilot* p, const unsigned int target, const int secondary) {
int i;
if(!secondary) {
// Primary weapons.
if(!p->outfits) return; // No outfits.
for(i = 0; i < p->noutfits; i++) // Cycle through outfits to find weapons.
if(outfit_isWeapon(p->outfits[i].outfit) || // Is a weapon or launch?
outfit_isLauncher(p->outfits[i].outfit))
if(outfit_isWeapon(p->outfits[i].outfit)) // Are we a weapon?
// Ready to shoot again.
if((SDL_GetTicks()-p->outfits[i].timer) > (p->outfits[i].outfit->delay/p->outfits[i].quantity))
// Different weapons have different behaviours.
switch(p->outfits[i].outfit->type) {
case OUTFIT_TYPE_BOLT:
weapon_add(p->outfits[i].outfit, p->solid->dir, &p->solid->pos,
&p->solid->vel, p->id, (p==player) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG);
p->outfits[i].timer = SDL_GetTicks();
&p->solid->vel, p->id, target, (p==player) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG);
p->outfits[i].timer = SDL_GetTicks(); // Let's not try this again for a while.
break;
default:
break;
}
} else {
if(!p->secondary) return; // No secondary weapon.
if(outfit_isLauncher(p->secondary->outfit)) {
if(((SDL_GetTicks()-p->secondary->timer) >
(p->secondary->outfit->delay/p->secondary->quantity)) &&
p->ammo && (p->ammo->quantity > 0)) {
weapon_add(p->ammo->outfit, p->solid->dir, &p->solid->pos, &p->solid->vel,
p->id, target, (p==player) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG);
p->secondary->timer = SDL_GetTicks(); // Let's not try this again for a while.
p->ammo->quantity -= 1; // No getting this one back.
}
}
}
}
@ -145,6 +158,27 @@ void pilot_hit(Pilot* p, const double damage_shield, const double damage_armour)
p->armour = 0.;
}
// Set the pilot's ammo based on their secondary weapon.
void pilot_setAmmo(Pilot* p) {
int i;
char* name;
if((p->secondary == NULL) || !outfit_isLauncher(p->secondary->outfit)) {
p->ammo = NULL;
return;
}
name = p->secondary->outfit->ammo;
for(i = 0; i < p->noutfits; i++)
if(strcmp(p->outfits[i].outfit->name, name)==0) {
p->ammo = p->outfits + i;
return;
}
p->ammo = NULL;
}
// Render the pilot.
void pilot_render(Pilot* p) {
int sx, sy;
@ -231,6 +265,8 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profi
// Outfits.
pilot->outfits = NULL;
pilot->secondary = NULL;
pilot->ammo = NULL;
ShipOutfit* so;
if(ship->outfit) {
pilot->noutfits = 0;
@ -316,7 +352,7 @@ void pilots_free(void) {
void pilots_update(double dt) {
int i;
for(i = 0; i < pilots; i++) {
if(pilot_stack[i]->think && !pilot_isFlag(pilot_stack[i], PILOT_DISABLED))
if(pilot_stack[i]->think && !pilot_isDisabled(pilot_stack[i]))
pilot_stack[i]->think(pilot_stack[i]);
if(pilot_stack[i]->update)
pilot_stack[i]->update(pilot_stack[i], dt);

View File

@ -25,6 +25,7 @@
#define PILOT_DISABLED (1<<4) // Pilot is disabled.
// Just makes life simpler.
#define pilot_isPlayer(p) ((p)->flags & PILOT_PLAYER)
#define pilot_isDisabled(p) ((p)->flags & PILOT_DISABLED)
typedef struct {
Outfit* outfit; // Associated outfit.
@ -54,6 +55,8 @@ typedef struct Pilot {
// Outfit management.
PilotOutfit* outfits;
int noutfits;
PilotOutfit* secondary; // Secondary weapon.
PilotOutfit* ammo; // Secondary ammo (if needed).
unsigned int flags; // Used for AI etc.
@ -90,8 +93,9 @@ unsigned int pilot_getHostile(void); // Only for the player.
Fleet* fleet_get(const char* name);
// MISC.
void pilot_shoot(Pilot* p, const int secondary);
void pilot_shoot(Pilot* p, const unsigned int target, const int secondary);
void pilot_hit(Pilot* p, const double damage_shield, const double damage_armour);
void pilot_setAmmo(Pilot* p);
// Creation.
void pilot_init(Pilot* dest, Ship* ship, char* name, Faction* faction, AI_Profile* ai,

View File

@ -26,6 +26,8 @@
#define PLAYER_TURN_LEFT (1<<0) // Player is turning left.
#define PLAYER_TURN_RIGHT (1<<1) // Player is turning right.
#define PLAYER_FACE (1<<2) // Player is facing target.
#define PLAYER_PRIMARY (1<<3) // Player is shooting primary weapon.
#define PLAYER_SECONDARY (1<<4) // Player is shooting secondary weapon.
// Flag functions.
#define player_isFlag(f) (player_flags & f)
@ -46,19 +48,17 @@ static Keybind** player_input; // Contains the players keybindings.
// Name of each keybinding.
const char* keybindNames[] = { "accel", "left", "right", // Movement.
"primary", "target", "target_nearest", "face", "board", // Combat.
"secondary", "secondary_next", // Secondary weapons.
"mapzoomin", "mapzoomout", "screenshot", "end" }; // Misc.
// Player stuff.
Pilot* player = NULL; // extern in pilot.h
unsigned int credits = 0;
static int player_flags = 0; // Player flags.
static unsigned int player_flags = 0; // Player flags.
static double player_turn = 0.; // Turn velocity from input.
static double player_acc = 0.; // Accel velocity from input.
static int player_primary = 0; // Player is shooting primary weapon.
//static int player_secondary = 0; // layer is shooting secondary weapon.
static unsigned int player_target = PLAYER_ID; // Targetted pilot.
static int planet_target = -1; // Targetted planet.
static int weapon = -1; // Secondary weapon is in use.
// Pilot stuff for GUI.
extern Pilot** pilot_stack;
@ -148,6 +148,7 @@ static void gui_renderBar(const glColour* c, const Vec2* p, const Rect* r, const
// Keybinds.
static void player_board(void);
static void player_secondaryNext(void);
static void player_screenshot(void);
// Create a new player.
@ -254,7 +255,7 @@ void player_render(void) {
if(player_target != PLAYER_ID) {
p = pilot_get(player_target);
if(pilot_isFlag(p, PILOT_DISABLED)) c = &cInert;
if(pilot_isDisabled(p)) c = &cInert;
else if(pilot_isFlag(p, PILOT_HOSTILE)) c = &cHostile;
else c = &cNeutral;
@ -340,7 +341,7 @@ void player_render(void) {
gui_renderBar(&cEnergy, &gui.pos_energy, &gui.energy, player->energy / player->energy_max);
// Weapon.
if(weapon == -1) {
if(player->secondary == NULL) {
i = gl_printWidth(NULL, "Secondary");
vect_csetmin(&v, VX(gui.pos_weapon) + (gui.weapon.w - i)/2., VY(gui.pos_weapon) - 5);
gl_print(NULL, &v, &cConsole, "Secondary");
@ -348,7 +349,21 @@ void player_render(void) {
vect_csetmin(&v, VX(gui.pos_weapon) + (gui.weapon.w - i)/2., VY(gui.pos_weapon) - 10 - gl_defFont.h);
gl_print(&gui.smallFont, &v, &cGrey, "None");
} else {
if(player->ammo == NULL) {
i = gl_printWidth(&gui.smallFont, "%s", player->secondary->outfit->name);
vect_csetmin(&v, VX(gui.pos_weapon) + (gui.weapon.w - i)/2.,
VY(gui.pos_weapon) - (gui.weapon.h - gui.smallFont.h)/2.);
gl_print(&gui.smallFont, &v, &cConsole, "%s", player->secondary->outfit->name);
} else {
i = gl_printWidth(&gui.smallFont, "%s", player->secondary->outfit->name);
vect_csetmin(&v, VX(gui.pos_weapon) + (gui.weapon.w - i)/2.,
VY(gui.pos_weapon) - 5);
gl_print(&gui.smallFont, &v, NULL, "%s", player->ammo->outfit->name);
i = gl_printWidth(NULL, "%d", player->ammo->quantity);
vect_csetmin(&v, VX(gui.pos_weapon) + (gui.weapon.w - i)/2.,
VY(gui.pos_weapon) - 10 - gl_defFont.h);
gl_print(NULL, &v, &cConsole, "%d", player->ammo->quantity);
}
}
// Target.
@ -362,7 +377,7 @@ void player_render(void) {
gl_print(&gui.smallFont, &gui.pos_target_faction, NULL, "%s", p->faction->name);
// Target status.
if(pilot_isFlag(p, PILOT_DISABLED))
if(pilot_isDisabled(p))
// Disable the pilot.
gl_print(&gui.smallFont, &gui.pos_target_health, NULL, "Disabled");
else if(p->shield > p->shield_max / 100.)
@ -433,7 +448,7 @@ static void gui_renderPilot(const Pilot* p) {
glBegin(GL_QUADS);
// Colours.
if(p->id == player_target) COLOUR(cRadar_targ);
else if(pilot_isFlag(p, PILOT_DISABLED)) COLOUR(cInert);
else if(pilot_isDisabled(p)) COLOUR(cInert);
else if(pilot_isFlag(p, PILOT_HOSTILE)) COLOUR(cHostile);
else COLOUR(cNeutral);
@ -750,7 +765,9 @@ void player_think(Pilot* player) {
if(player_turn)
player->solid->dir_vel -= player->ship->turn * player_turn;
if(player_primary) pilot_shoot(player, 0);
if(player_isFlag(PLAYER_PRIMARY)) pilot_shoot(player, 0, 0);
if(player_isFlag(PLAYER_SECONDARY) && (player_target != PLAYER_ID)) // Needs a target.
pilot_shoot(player, player_target, 1);
vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir);
}
@ -764,7 +781,7 @@ void player_board(void) {
}
p = pilot_get(player_target);
if(!pilot_isFlag(p, PILOT_DISABLED)) {
if(!pilot_isDisabled(p)) {
player_message("You cannot board a ship that isn't disabled!");
return;
}
@ -778,7 +795,32 @@ void player_board(void) {
player_message("You are going too fact to board the ship");
return;
}
player_message("Ship boarding isn't implemented yet! HAHA");
player_message("It's a shame Allanis hasn't added boarding yet, right?!");
}
// Get the next secondary weapon.
static void player_secondaryNext(void) {
int i = 0;
// Get the current secondary weapon pos.
if(player->secondary != NULL)
for(i = 0; i < player->noutfits; i++)
if(&player->outfits[i] == player->secondary) {
i++;
break;
}
// Get the next secondary weapon.
for(; i < player->noutfits; i++)
if(outfit_isProp(player->outfits[i].outfit, OUTFIT_PROP_WEAP_SECONDARY)) {
player->secondary = player->outfits + i;
break;
}
// We didn't find an outfit.
if(i >= player->noutfits)
player->secondary = NULL;
// Set ammo.
pilot_setAmmo(player);
}
// Take a screenshot.
@ -795,17 +837,19 @@ static void player_screenshot(void) {
// Set the default input keys.
void input_setDefault(void) {
input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0);
input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_a, 0);
input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_d, 0);
input_setKeybind("primary", KEYBIND_KEYBOARD, SDLK_SPACE, 0);
input_setKeybind("target", KEYBIND_KEYBOARD, SDLK_TAB, 0);
input_setKeybind("target_nearest", KEYBIND_KEYBOARD, SDLK_r, 0);
input_setKeybind("face", KEYBIND_KEYBOARD, SDLK_f, 0);
input_setKeybind("board", KEYBIND_KEYBOARD, SDLK_b, 0);
input_setKeybind("mapzoomin", KEYBIND_KEYBOARD, SDLK_UP, 0);
input_setKeybind("mapzoomout", KEYBIND_KEYBOARD, SDLK_DOWN, 0);
input_setKeybind("screenshot", KEYBIND_KEYBOARD, SDLK_F12, 0);
input_setKeybind("accel", KEYBIND_KEYBOARD, SDLK_w, 0);
input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_a, 0);
input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_d, 0);
input_setKeybind("primary", KEYBIND_KEYBOARD, SDLK_SPACE, 0);
input_setKeybind("target", KEYBIND_KEYBOARD, SDLK_TAB, 0);
input_setKeybind("target_nearest", KEYBIND_KEYBOARD, SDLK_r, 0);
input_setKeybind("face", KEYBIND_KEYBOARD, SDLK_f, 0);
input_setKeybind("board", KEYBIND_KEYBOARD, SDLK_b, 0);
input_setKeybind("secondary", KEYBIND_KEYBOARD, SDLK_LSHIFT, 0);
input_setKeybind("secondary_next", KEYBIND_KEYBOARD, SDLK_q, 0);
input_setKeybind("mapzoomin", KEYBIND_KEYBOARD, SDLK_UP, 0);
input_setKeybind("mapzoomout", KEYBIND_KEYBOARD, SDLK_DOWN, 0);
input_setKeybind("screenshot", KEYBIND_KEYBOARD, SDLK_F12, 0);
}
// Initialization/exit functions (does not assign keys).
@ -881,8 +925,8 @@ static void input_key(int keynum, double value, int abs) {
}
// Shoot primary weapon. BOOM BOOM.
else if(strcmp(player_input[keynum]->name, "primary")==0) {
if(value == KEY_PRESS) player_primary = 1;
else if(value == KEY_RELEASE) player_primary = 0;
if(value == KEY_PRESS) player_setFlag(PLAYER_PRIMARY);
else if(value == KEY_RELEASE) player_rmFlag(PLAYER_PRIMARY);
}
// Targetting.
else if(strcmp(player_input[keynum]->name, "target")==0) {
@ -907,16 +951,26 @@ static void input_key(int keynum, double value, int abs) {
else if(strcmp(player_input[keynum]->name, "board")==0) {
if(value == KEY_PRESS) player_board();
}
// Shooting secondary weapon.
else if(strcmp(player_input[keynum]->name, "secondary")==0) {
if(value == KEY_PRESS) player_setFlag(PLAYER_SECONDARY);
else if(value == KEY_RELEASE) player_rmFlag(PLAYER_SECONDARY);
}
// Selecting secondary weapon.
else if(strcmp(player_input[keynum]->name, "secondary_next")==0) {
if(value == KEY_PRESS) player_secondaryNext();
}
// Zoom in.
else if(strcmp(player_input[keynum]->name, "mapzoomin")==0) {
if(value == KEY_PRESS && gui.radar.res < RADAR_RES_MAX)
if((value == KEY_PRESS) && (gui.radar.res < RADAR_RES_MAX))
gui.radar.res += RADAR_RES_INTERVAL;
}
// Zoom out.
else if(strcmp(player_input[keynum]->name, "mapzoomout")==0) {
if(value == KEY_PRESS && gui.radar.res > RADAR_RES_MIN)
if((value == KEY_PRESS) && (gui.radar.res > RADAR_RES_MIN))
gui.radar.res -= RADAR_RES_INTERVAL;
}
// Take a screenshot.
else if(strcmp(player_input[keynum]->name, "screenshot")==0) {
if(value == KEY_PRESS) player_screenshot();
}

View File

@ -117,7 +117,7 @@ static Ship* ship_parse(xmlNodePtr parent) {
if((ocur = tmp->outfit) == NULL) tmp->outfit = otmp;
else {
while(ocur->next);
while(ocur->next) ocur = ocur->next;
ocur->next = otmp;
}
}

View File

@ -12,6 +12,8 @@
#include "player.h"
#include "weapon.h"
#define weapon_isSmart(w) (w->think)
// Some stuff from pilot.
extern Pilot** pilot_stack;
extern int pilots;
@ -23,6 +25,7 @@ typedef struct Weapon {
Solid* solid; // Actually has its own solid. :D
unsigned int parent; // The pilot that just shot at you!
unsigned int target; // Target to hit. Only used by seeking stuff.
const Outfit* outfit; // Related outfit that fired.
unsigned int timer; // Mainly used to see when the weapon was fired.
@ -42,12 +45,16 @@ static int mwfrontLayer = 0; // Allocated memory size.
static Weapon* weapon_create(const Outfit* outfit, const double dir,
const Vec2* pos, const Vec2* vel, unsigned int parent);
const Vec2* pos, const Vec2* vel, const unsigned int parent,
const unsigned int target);
static void weapon_render(const Weapon* w);
static void weapon_update(Weapon* w, const double dt, WeaponLayer layer);
static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer);
static void weapon_destroy(Weapon* w, WeaponLayer layer);
static void weapon_free(Weapon* w);
// Think.
static void think_seeker(Weapon* w);
// Draw the minimap weapons (player.c).
#define PIXEL(x,y) if((shape == RADAR_RECT && ABS(x) < w/2. && ABS(y)<h/2.) || \
@ -72,6 +79,25 @@ void weapon_minimap(const double res, const double w, const double h, const Rada
}
#undef PIXEL
static void think_seeker(Weapon* w) {
if(w->target == w->parent) return; // HEY! Self harm is not allowed.
Pilot* p = pilot_get(w->target);
if(p == NULL) return; // Can't do anything with no pilots.
double diff = angle_diff(w->solid->dir, vect_angle(&w->solid->pos, &p->solid->pos));
w->solid->dir_vel = 10 * diff * w->outfit->turn;
// Face the target.
if(w->solid->dir_vel > w->outfit->turn) w->solid->dir_vel = w->outfit->turn;
else if(w->solid->dir_vel < -w->outfit->turn) w->solid->dir_vel = -w->outfit->turn;
vect_pset(&w->solid->force, w->outfit->thrust, w->solid->dir);
if(VMOD(w->solid->vel) > w->outfit->speed)
// We should not go any faster.
vect_pset(&w->solid->vel, w->outfit->speed, VANGLE(w->solid->vel));
}
// Update all weapons in the layer.
void weapons_update(const double dt, WeaponLayer layer) {
Weapon** wlayer;
@ -92,15 +118,20 @@ void weapons_update(const double dt, WeaponLayer layer) {
for(i = 0; i < (*nlayer); i++) {
w = wlayer[i];
switch(wlayer[i]->outfit->type) {
case OUTFIT_TYPE_BOLT:
case OUTFIT_TYPE_MISSILE_SEEK_AMMO:
if(SDL_GetTicks() > (wlayer[i]->timer + wlayer[i]->outfit->duration)) {
weapon_destroy(wlayer[i], layer);
continue;
}
break;
default:
// Check see if it exceeds distance.
if(SDL_GetTicks() > (wlayer[i]->timer + 1000*(unsigned int)
wlayer[i]->outfit->range/wlayer[i]->outfit->speed)) {
weapon_destroy(wlayer[i],layer);
continue;
}
break;
default:
break;
}
weapon_update(wlayer[i], dt, layer);
// If the weapon has been deleted we are going to have to hold back one.
@ -126,38 +157,51 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
for(i = 0; i < pilots; i++) {
gl_getSpriteFromDir(&psx, &psy, pilot_stack[i]->ship->gfx_space,
pilot_stack[i]->solid->dir);
if(w->parent == pilot_stack[i]->id) continue; // Hey! That's you.
if((w->parent != pilot_stack[i]->id) && // The pilot hasn't shoot it.
if((weapon_isSmart(w)) && (pilot_stack[i]->id == w->target) &&
CollideSprite(w->outfit->gfx_space, wsx, wsy, &w->solid->pos,
pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos)) {
weapon_hit(w, pilot_stack[i], layer);
return;
}
else if(!weapon_isSmart(w) &&
!areAllies(pilot_get(w->parent)->faction, pilot_stack[i]->faction) &&
CollideSprite(w->outfit->gfx_space, wsx, wsy, &w->solid->pos,
pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos)) {
if(!pilot_isPlayer(pilot_stack[i]))
// Inform the ai it has been attacked. Useless if we are player.
ai_attacked(pilot_stack[i], w->parent);
if(w->parent == PLAYER_ID) // Make hostile to player.
pilot_setFlag(pilot_stack[i], PILOT_HOSTILE);
// Inform the ship that it should take some damage.
pilot_hit(pilot_stack[i], w->outfit->damage_shield, w->outfit->damage_armour);
// No need for the weapon particle anymore.
weapon_destroy(w, layer);
pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos)) {
weapon_hit(w, pilot_stack[i], layer);
return;
}
}
if(w->think) (*w->think)(w);
if(weapon_isSmart(w)) (*w->think)(w);
(*w->solid->update)(w->solid, dt);
weapon_render(w);
}
// Good shot.
static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer) {
// Someone should let the ai know it's been attacked.
if(!pilot_isPlayer(p))
ai_attacked(p, w->parent);
if(w->parent == PLAYER_ID)
// Make hostile to player.
pilot_setFlag(p, PILOT_HOSTILE);
// Let the ship know that is should take some kind of damage.
pilot_hit(p, w->outfit->damage_shield, w->outfit->damage_armour);
// We don't need the weapon particle any longer.
weapon_destroy(w, layer);
}
static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* pos,
const Vec2* vel, unsigned int parent) {
const Vec2* vel, unsigned int parent, const unsigned int target) {
Vec2 v;
double mass = 1; // Presumer lasers have a mass of 1.
double rdir = dir; // Real direction (accuracy).
Weapon* w = MALLOC_L(Weapon);
w->parent = parent; // Non-Changeable.
w->target = target; // Non-Changeable.
w->outfit = outfit; // Non-Changeable.
w->update = weapon_update;
w->timer = SDL_GetTicks();
@ -172,6 +216,11 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
vect_cadd(&v, outfit->speed*cos(rdir), outfit->speed*sin(rdir));
w->solid = solid_create(mass, rdir, pos, &v);
break;
case OUTFIT_TYPE_MISSILE_SEEK_AMMO:
mass = w->outfit->mass;
w->solid = solid_create(mass, dir, pos, vel);
w->think = think_seeker; // Eeek!!!
break;
default:
// Just dump it where the player is.
w->solid = solid_create(mass, dir, pos, vel);
@ -182,13 +231,14 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
// Add a new weapon.
void weapon_add(const Outfit* outfit, const double dir, const Vec2* pos, const Vec2* vel,
unsigned int parent, WeaponLayer layer) {
if(!outfit_isWeapon(outfit)) {
unsigned int parent, unsigned int target, WeaponLayer layer) {
if(!outfit_isWeapon(outfit) && !outfit_isAmmo(outfit)) {
ERR("Trying to create a weapon from a non-Weapon type Outfit");
return;
}
Weapon* w = weapon_create(outfit, dir, pos, vel, parent);
Weapon* w = weapon_create(outfit, dir, pos, vel, parent, target);
// Set the propper layer.
Weapon** curLayer = NULL;

View File

@ -5,7 +5,8 @@
typedef enum { WEAPON_LAYER_BG, WEAPON_LAYER_FG } WeaponLayer;
void weapon_add(const Outfit* outfit, const double dir,
const Vec2* pos, const Vec2* vel, unsigned int parent, WeaponLayer layer);
const Vec2* pos, const Vec2* vel, unsigned int parent,
const unsigned int target, WeaponLayer layer);
void weapons_update(const double dt, WeaponLayer layer);