[Fix] Huge fix of outfits, missiles now work, compiles in C99, no seg fault on exit.

This commit is contained in:
Allanis 2013-02-27 01:17:46 +00:00
parent 1578278f00
commit 1d89d4e7c6
7 changed files with 142 additions and 80 deletions

View File

@ -24,9 +24,9 @@ CVORBIS =
CGL =
CFLAGS = $(CLUA) $(CSDL) $(CXML) $(CTTF) $(CGL) $(CAL) $(CVORBIS) $(VERSION)
ifdef DEBUG
CFLAGS += -W -Wall -g3 -DDEBUG -DLUA_USE_APICHECK
CFLAGS += -W -Wall -g3 -DDEBUG -DLUA_USE_APICHECK -std=c99
else
CFLAGS += -O2 -funroll-loops -pipe
CFLAGS += -O2 -funroll-loops -pipe -std=c99
endif
# LDFLAGS.

View File

@ -40,8 +40,9 @@
<specific type="6">
<gfx>missile</gfx>
<sound>missile</sound>
<spfx>ExmM</spfx>
<spfx>ExpM</spfx>
<duration>5</duration>
<lockon>1</lockon>
<thrust>1200</thrust>
<turn>200</turn>
<speed>600</speed>

View File

@ -82,6 +82,8 @@
</characteristics>
<outfits>
<outfit quantity='3'>Laser</outfit>
<outfit quantity='2'>Missile Launcher</outfit>
<outfit quantity='20'>Missile</outfit>
</outfits>
</ship>
</Ships>

View File

@ -74,6 +74,32 @@ int outfit_isAmmo(const Outfit* o) {
}
// Get the outfit graphics.
glTexture* outfit_gfx(const Outfit* o) {
if(outfit_isWeapon(o)) return o->u.wpn.gfx_space;
else if(outfit_isAmmo(o)) return o->u.amm.gfx_space;
return NULL;
}
// Get the outfit spfx if applicable.
int outfit_spfx(const Outfit* o) {
if(outfit_isWeapon(o)) return o->u.wpn.spfx;
else if(outfit_isAmmo(o)) return o->u.amm.spfx;
return -1;
}
double outfit_dmgShield(const Outfit* o) {
if(outfit_isWeapon(o)) return o->u.wpn.damage_armour;
else if (outfit_isAmmo(o)) return o->u.amm.damage_armour;
return -1;
}
double outfit_dmgArmour(const Outfit* o) {
if(outfit_isWeapon(o)) return o->u.wpn.damage_shield;
else if(outfit_isAmmo(o)) return o->u.amm.damage_shield;
return -1;
}
const char* outfit_typename[] = {
"NULL",
"Bolt Cannon",
@ -103,36 +129,38 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
do {
// Load all the things.
if(xml_isNode(node, "speed")) tmp->speed = xml_getFloat(node);
else if(xml_isNode(node, "delay")) tmp->delay = xml_getInt(node);
else if(xml_isNode(node, "range")) tmp->range = xml_getFloat(node);
else if(xml_isNode(node, "accuracy")) tmp->accuracy = xml_getFloat(node);
if(xml_isNode(node, "speed")) tmp->u.wpn.speed = xml_getFloat(node);
else if(xml_isNode(node, "delay")) tmp->u.wpn.delay = xml_getInt(node);
else if(xml_isNode(node, "range")) tmp->u.wpn.range = xml_getFloat(node);
else if(xml_isNode(node, "accuracy")) tmp->u.wpn.accuracy = 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);
tmp->u.wpn.gfx_space = gl_newSprite(str, 6, 6);
}
else if(xml_isNode(node, "spfx"))
tmp->spfx = spfx_get(xml_get(node));
tmp->u.wpn.spfx = spfx_get(xml_get(node));
else if(xml_isNode(node, "sound"))
tmp->sound = sound_get(xml_get(node));
tmp->u.wpn.sound = sound_get(xml_get(node));
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);
if(xml_isNode(cur, "armour"))
tmp->u.wpn.damage_armour = xml_getFloat(cur);
else if(xml_isNode(cur, "shield"))
tmp->u.wpn.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)
if(tmp->u.wpn.gfx_space == NULL)
WARN("Outfit '%s' missing 'gfx' element", tmp->name);
MELEMENT(tmp->sound, "sound");
MELEMENT(tmp->delay, "delay");
MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->range, "range");
MELEMENT(tmp->accuracy, "accuracy");
MELEMENT(tmp->damage_armour, "armour' from element 'damage");
MELEMENT(tmp->damage_shield, "shield' from element 'damage");
MELEMENT(tmp->u.wpn.sound, "sound");
MELEMENT(tmp->u.wpn.delay, "delay");
MELEMENT(tmp->u.wpn.speed, "speed");
MELEMENT(tmp->u.wpn.range, "range");
MELEMENT(tmp->u.wpn.accuracy, "accuracy");
MELEMENT(tmp->u.wpn.damage_armour, "armour' from element 'damage");
MELEMENT(tmp->u.wpn.damage_shield, "shield' from element 'damage");
#undef MELEMENT
}
@ -143,13 +171,13 @@ static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent) {
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));
if(xml_isNode(node, "delay")) tmp->u.lau.delay = xml_getInt(node);
else if(xml_isNode(node, "ammo")) tmp->u.lau.ammo = strdup(xml_get(node));
} while((node = node->next));
#define MELEMENT(o,s) if(o) WARN("Outfit '%s' missing '"s"' element", tmp->name)
MELEMENT(tmp->ammo == NULL, "ammo");
MELEMENT(tmp->delay==0, "delay");
MELEMENT(tmp->u.lau.ammo == NULL, "ammo");
MELEMENT(tmp->u.lau.delay==0, "delay");
#undef MELEMENT
}
@ -161,36 +189,40 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
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);
if(xml_isNode(node, "thrust")) tmp->u.amm.thrust = xml_getFloat(node);
else if(xml_isNode(node, "turn")) tmp->u.amm.turn = xml_getFloat(node);
else if(xml_isNode(node, "speed")) tmp->u.amm.speed = xml_getFloat(node);
else if(xml_isNode(node, "duration"))
tmp->u.amm.duration = (unsigned int)1000.*xml_getFloat(node);
else if(xml_isNode(node, "lockon"))
tmp->u.amm.lockon = (unsigned int)1000.*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);
tmp->u.amm.gfx_space = gl_newSprite(str, 6, 6);
}
else if(xml_isNode(node, "spfx"))
tmp->spfx = spfx_get(xml_get(node));
tmp->u.amm.spfx = spfx_get(xml_get(node));
else if(xml_isNode(node, "sound"))
tmp->sound = sound_get(xml_get(node));
tmp->u.amm.sound = sound_get(xml_get(node));
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);
if(xml_isNode(cur, "armour")) tmp->u.amm.damage_armour = xml_getFloat(cur);
else if(xml_isNode(cur, "shield")) tmp->u.amm.damage_shield = xml_getFloat(cur);
} while((cur = cur->next));
}
} while((node = node->next));
#define MELEMENT(o,s) if(o) WARN("Outfit '%s' missing '"s"' element", tmp->name)
MELEMENT(tmp->gfx_space == NULL, "gfx");
MELEMENT((sound_lock != NULL) && (tmp->sound == 0), "sound");
MELEMENT(tmp->thrust==0, "thrust");
MELEMENT(tmp->turn==0, "turn");
MELEMENT(tmp->speed==0, "speed");
MELEMENT(tmp->range==0, "duration");
MELEMENT(tmp->damage_armour==0, "armour' from element 'damage");
MELEMENT(tmp->damage_shield==0, "shield' from element 'damage");
MELEMENT(tmp->u.amm.gfx_space == NULL, "gfx");
MELEMENT((sound_lock != NULL) && (tmp->u.amm.sound == 0), "sound");
MELEMENT(tmp->u.amm.thrust==0, "thrust");
MELEMENT(tmp->u.amm.turn==0, "turn");
MELEMENT(tmp->u.amm.speed==0, "speed");
MELEMENT(tmp->u.amm.duration==0, "duration");
MELEMENT(tmp->u.amm.lockon==0, "lockon");
MELEMENT(tmp->u.amm.damage_armour==0, "armour' from element 'damage");
MELEMENT(tmp->u.amm.damage_shield==0, "shield' from element 'damage");
#undef MELEMENT
}
@ -295,10 +327,13 @@ void outfit_free(void) {
int i;
for(i = 0; i < outfits; i++) {
// Free graphics.
if(outfit_stack[i].gfx_space) gl_freeTexture(outfit_stack[i].gfx_space);
if(outfit_isWeapon(&outfit_stack[i]) && outfit_stack[i].u.wpn.gfx_space)
gl_freeTexture(outfit_stack[i].u.wpn.gfx_space);
else if(outfit_isAmmo(&outfit_stack[i]) && outfit_stack[i].u.amm.gfx_space)
gl_freeTexture(outfit_stack[i].u.amm.gfx_space);
if(outfit_isLauncher(&outfit_stack[i]) && outfit_stack[i].ammo)
free(outfit_stack[i].ammo);
if(outfit_isLauncher(&outfit_stack[i]) && outfit_stack[i].u.lau.ammo)
free(outfit_stack[i].u.lau.ammo);
free(outfit_stack[i].name);
}

View File

@ -49,21 +49,24 @@ typedef struct Outfit_ {
glTexture* gfx_space;
ALuint sound; // Sound to play.
int spfx; // Special effect on hit.
};
} wpn;
struct { // Launcher.
//unsigned int delay; // Delay between shots.
unsigned int delay; // Delay between shots.
char* ammo;
};
} lau;
struct { // Ammo.
//double speed; // Max speed.
unsigned int duration; // Duration.
double speed; // Max speed.
double turn; // Turn vel.
double thrust; // Acceleration.
unsigned int duration; // Duration.
//double damage_armour, damage_shield; // Damage.
double damage_armour, damage_shield; // Damage.
//glTexture* gfx_space;
};
};
glTexture* gfx_space;
ALuint sound; // Sound to play.
int spfx; // Special effect on hit.
unsigned int lockon; // Time taken to lock on the target.
} amm;
} u;
} Outfit;
Outfit* outfit_get(const char* name);
@ -74,6 +77,12 @@ int outfit_isAmmo(const Outfit* o);
const char* outfit_getType(const Outfit* o);
const char* outfit_getTypeBroad(const Outfit* o);
// Get data from outfit.
glTexture* outfit_gfx(const Outfit* o);
int outfit_spfx(const Outfit* o);
double outfit_dmgShield(const Outfit* o);
double outfit_dmgArmour(const Outfit* o);
// Load/free outfit stack.
int outfit_load(void);
void outfit_free(void);

View File

@ -146,12 +146,14 @@ void pilot_shoot(Pilot* p, const unsigned int target, const int secondary) {
}
static void pilot_shootWeapon(Pilot* p, PilotOutfit* w, const unsigned int t) {
int quantity, delay;
// WElll... Trying to shoot when you have no ammo?? FUUU
int quantity = (outfit_isAmmo(w->outfit) && p->secondary) ?
quantity = (outfit_isAmmo(w->outfit) && p->secondary) ?
p->secondary->quantity : w->quantity;
// Check to see if weapon is ready.
if((SDL_GetTicks() - w->timer) < (w->outfit->delay / quantity)) return;
delay = (outfit_isWeapon(w->outfit)) ? w->outfit->u.wpn.delay : w->outfit->u.lau.delay;
// Check to see if weapon is ready.
if((SDL_GetTicks() - w->timer) < (unsigned int)(delay/quantity)) return;
// Regular weapons.
if(outfit_isWeapon(w->outfit)) {
// Different weapons.
@ -228,7 +230,7 @@ void pilot_setAmmo(Pilot* p) {
return;
}
name = p->secondary->outfit->ammo;
name = p->secondary->outfit->u.lau.ammo;
for(i = 0; i < p->noutfits; i++)
if(strcmp(p->outfits[i].outfit->name, name)==0) {

View File

@ -106,22 +106,26 @@ void weapons_unpause(void) {
}
static void think_seeker(Weapon* w) {
double diff;
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;
// Ammo isn't locked on yet..
if(SDL_GetTicks() > (w->timer + w->outfit->u.amm.lockon)) {
diff = angle_diff(w->solid->dir, vect_angle(&w->solid->pos, &p->solid->pos));
w->solid->dir_vel = 10 * diff * w->outfit->u.amm.turn;
// Face the target.
if(w->solid->dir_vel > w->outfit->u.amm.turn) w->solid->dir_vel = w->outfit->u.amm.turn;
else if(w->solid->dir_vel < -w->outfit->u.amm.turn) w->solid->dir_vel = -w->outfit->u.amm.turn;
}
vect_pset(&w->solid->force, w->outfit->thrust, w->solid->dir);
vect_pset(&w->solid->force, w->outfit->u.amm.thrust, w->solid->dir);
if(VMOD(w->solid->vel) > w->outfit->speed)
if(VMOD(w->solid->vel) > w->outfit->u.amm.speed)
// We should not go any faster.
vect_pset(&w->solid->vel, w->outfit->speed, VANGLE(w->solid->vel));
vect_pset(&w->solid->vel, w->outfit->u.amm.speed, VANGLE(w->solid->vel));
}
// Update all the weapon layers.
@ -151,19 +155,21 @@ static void weapons_updateLayer(const double dt, const WeaponLayer layer) {
w = wlayer[i];
switch(wlayer[i]->outfit->type) {
case OUTFIT_TYPE_MISSILE_SEEK_AMMO:
if(SDL_GetTicks() > (wlayer[i]->timer + wlayer[i]->outfit->duration)) {
if(SDL_GetTicks() > (wlayer[i]->timer + wlayer[i]->outfit->u.amm.duration)) {
weapon_destroy(wlayer[i], layer);
continue;
}
break;
default:
case OUTFIT_TYPE_BOLT:
// Check see if it exceeds distance.
if(SDL_GetTicks() > (wlayer[i]->timer + 1000*(unsigned int)
wlayer[i]->outfit->range/wlayer[i]->outfit->speed)) {
wlayer[i]->outfit->u.wpn.range/wlayer[i]->outfit->u.wpn.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.
@ -194,17 +200,24 @@ void weapons_render(const WeaponLayer layer) {
// Render the weapons.
static void weapon_render(const Weapon* w) {
int sx, sy;
glTexture* gfx;
gfx = outfit_gfx(w->outfit);
// Get the sprite corresponding to the direction facing.
gl_getSpriteFromDir(&sx, &sy, w->outfit->gfx_space, w->solid->dir);
gl_getSpriteFromDir(&sx, &sy, gfx, w->solid->dir);
gl_blitSprite(w->outfit->gfx_space, w->solid->pos.x, w->solid->pos.y, sx, sy, NULL);
gl_blitSprite(gfx, w->solid->pos.x, w->solid->pos.y, sx, sy, NULL);
}
// Update the weapon.
static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
int i, wsx, wsy, psx, psy;
gl_getSpriteFromDir(&wsx, &wsy, w->outfit->gfx_space, w->solid->dir);
glTexture* gfx;
gfx = outfit_gfx(w->outfit);
gl_getSpriteFromDir(&wsx, &wsy, gfx, w->solid->dir);
for(i = 0; i < pilots; i++) {
gl_getSpriteFromDir(&psx, &psy, pilot_stack[i]->ship->gfx_space,
@ -212,14 +225,14 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
if(w->parent == pilot_stack[i]->id) continue; // Hey! That's you.
if((weapon_isSmart(w)) && (pilot_stack[i]->id == w->target) &&
CollideSprite(w->outfit->gfx_space, wsx, wsy, &w->solid->pos,
CollideSprite(gfx, 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,
CollideSprite(gfx, 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;
@ -239,15 +252,15 @@ 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);
spfx_add(w->outfit->spfx, &w->solid->pos, &p->solid->vel, SPFX_LAYER_BACK);
spfx_add(outfit_spfx(w->outfit), &w->solid->pos, &p->solid->vel, SPFX_LAYER_BACK);
} else
spfx_add(w->outfit->spfx, &w->solid->pos, &p->solid->vel, SPFX_LAYER_FRONT);
spfx_add(outfit_spfx(w->outfit), &w->solid->pos, &p->solid->vel, SPFX_LAYER_FRONT);
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->solid, w->parent, w->outfit->damage_shield, w->outfit->damage_armour);
pilot_hit(p, w->solid, w->parent, outfit_dmgShield(w->outfit), outfit_dmgShield(w->outfit));
// We don't need the weapon particle any longer.
weapon_destroy(w, layer);
}
@ -268,14 +281,14 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
switch(outfit->type) {
case OUTFIT_TYPE_BOLT:
// Need accuracy and speed based on player. -- Another contribution from VLack.
rdir += RNG(-outfit->accuracy/2., outfit->accuracy/2.)/180.*M_PI;
rdir += RNG(-outfit->u.wpn.accuracy/2., outfit->u.wpn.accuracy/2.)/180.*M_PI;
if((rdir > 2.*M_PI) || (rdir < 0.)) rdir = fmod(rdir, 2.*M_PI);
vectcpy(&v, vel);
vect_cadd(&v, outfit->speed*cos(rdir), outfit->speed*sin(rdir));
vect_cadd(&v, outfit->u.wpn.speed*cos(rdir), outfit->u.wpn.speed*sin(rdir));
w->solid = solid_create(mass, rdir, pos, &v);
w->voice = sound_addVoice(VOICE_PRIORITY_BOLT,
w->solid->pos.x, w->solid->pos.y,
w->solid->vel.x, w->solid->vel.y, w->outfit->sound, 0);
w->solid->vel.x, w->solid->vel.y, w->outfit->u.wpn.sound, 0);
break;
case OUTFIT_TYPE_MISSILE_SEEK_AMMO:
mass = w->outfit->mass;
@ -283,7 +296,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
w->think = think_seeker; // Eeek!!!
w->voice = sound_addVoice(VOICE_PRIORITY_AMMO,
w->solid->pos.x, w->solid->pos.y,
w->solid->vel.x, w->solid->vel.y, w->outfit->sound, 0);
w->solid->vel.x, w->solid->vel.y, w->outfit->u.amm.sound, 0);
break;
default: