Merge branch 'dev'

This commit is contained in:
Allanis 2014-04-25 20:33:51 +01:00
commit 67da34e9c0
12 changed files with 209 additions and 43 deletions

View File

@ -555,6 +555,40 @@
<damage type="kinetic">35</damage> <damage type="kinetic">35</damage>
</specific> </specific>
</outfit> </outfit>
<outfit name="EMP Grenade Launcher">
<general>
<max>2</max>
<tech>7</tech>
<mass>17</mass>
<price>31000</price>
<gfx_store>empgrenadelauncher</gfx_store>
<description>This launcher can fire EMP grenades in any direction using a unique internal guidance system. These are favored by Traders for escaping from pirates.</description>
</general>
<specific type="turret dumb" secondary="1">
<ammo>EMP Grenade</ammo>
<delay>2000</delay>
</specific>
</outfit>
<outfit name="EMP Grenade">
<general>
<max>30</max>
<tech>6</tech>
<mass>1</mass>
<price>600</price>
<gfx_store>empgrenade</gfx_store>
<description>This is a grenade that can be launched to unleash EMP blasts rendering most electronics in the area useless. Good for taking ships alive instead of killing them as the EMP blasts rarely destroy the ship instead leaving it intact with non-working electronics.</description>
</general>
<specific type="turret dumb ammo">
<gfx spin="0.3">empgrenade</gfx>
<sound>missile</sound>
<spfx_shield>EmpS</spfx_shield>
<spfx_armour>EmpM</spfx_armour>
<duration>1.3</duration>
<thrust>0</thrust>
<speed>400</speed>
<damage type="emp">40</damage>
</specific>
</outfit>
<outfit name="Plasteel Plating"> <outfit name="Plasteel Plating">
<general> <general>
<max>1</max> <max>1</max>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
gfx/spfx/empm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
gfx/spfx/emps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -21,7 +21,22 @@ function control()
-- Try to jump when far enough away. -- Try to jump when far enough away.
elseif task == "runaway" then elseif task == "runaway" then
if ai.dist(ai.pos(ai.target())) > 400 then target = ai.target()
-- Check if should still run.
if not ai.exists(target) then
ai.poptask()
return
end
-- See if another enemy is closer.
if enemy ~= target then
ai.poptask()
ai.pushtask(0, "runaway", enemy)
end
-- Try to jump.
if ai.dist(target) > 400 then
ai.hyperspace() ai.hyperspace()
end end

View File

@ -142,6 +142,11 @@ void outfit_calcDamage(double* dshield, double* darmour, double* knockback,
ds = dmg*0.15; /* Still take damage, just very little. */ ds = dmg*0.15; /* Still take damage, just very little. */
da = dmg; da = dmg;
kn = 0.8; kn = 0.8;
case DAMAGE_TYPE_EMP:
ds = dmg*0.6;
da = dmg*1.3;
kn = 0.;
break;
default: default:
WARN("Unknown damage type: %d!", dtype); WARN("Unknown damage type: %d!", dtype);
ds = da = kn = 0.; ds = da = kn = 0.;
@ -188,6 +193,7 @@ int outfit_isBeam(const Outfit* o) {
int outfit_isLauncher(const Outfit* o) { int outfit_isLauncher(const Outfit* o) {
return((o->type == OUTFIT_TYPE_MISSILE_DUMB) || return((o->type == OUTFIT_TYPE_MISSILE_DUMB) ||
(o->type == OUTFIT_TYPE_TURRET_DUMB) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK) || (o->type == OUTFIT_TYPE_MISSILE_SEEK) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART) || (o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART) ||
(o->type == OUTFIT_TYPE_MISSILE_SWARM) || (o->type == OUTFIT_TYPE_MISSILE_SWARM) ||
@ -203,6 +209,7 @@ int outfit_isLauncher(const Outfit* o) {
*/ */
int outfit_isAmmo(const Outfit* o) { int outfit_isAmmo(const Outfit* o) {
return((o->type == OUTFIT_TYPE_MISSILE_DUMB_AMMO) || return((o->type == OUTFIT_TYPE_MISSILE_DUMB_AMMO) ||
(o->type == OUTFIT_TYPE_TURRET_DUMB_AMMO) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK_AMMO) || (o->type == OUTFIT_TYPE_MISSILE_SEEK_AMMO) ||
(o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO) || (o->type == OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO) ||
(o->type == OUTFIT_TYPE_MISSILE_SWARM_AMMO) || (o->type == OUTFIT_TYPE_MISSILE_SWARM_AMMO) ||
@ -234,8 +241,9 @@ int outfit_isSeeker(const Outfit* o) {
* @return 1 if o is a turret class weapon. * @return 1 if o is a turret class weapon.
*/ */
int outfit_isTurret(const Outfit* o) { int outfit_isTurret(const Outfit* o) {
return ((o->type == OUTFIT_TYPE_TURRET_BOLT) || return ((o->type==OUTFIT_TYPE_TURRET_BOLT) ||
(o->type == OUTFIT_TYPE_TURRET_BEAM)); (o->type==OUTFIT_TYPE_TURRET_BEAM) ||
(o->type==OUTFIT_TYPE_TURRET_DUMB));
} }
/** /**
@ -437,6 +445,16 @@ double outfit_speed(const Outfit* o) {
return -1.; return -1.;
} }
/**
* @brief Get the outfit animation spin.
* @param o Outfit to get information from.
*/
double outfit_spin(const Outfit* o) {
if(outfit_isBolt(o)) return o->u.blt.spin;
else if(outfit_isAmmo(o)) return o->u.amm.spin;
return -1;
}
/** /**
* @fn const char* outfit_getType(const Outfit* o) * @fn const char* outfit_getType(const Outfit* o)
* *
@ -453,6 +471,8 @@ const char* outfit_getType(const Outfit* o) {
"Beam Turret", "Beam Turret",
"Dumb Missile", "Dumb Missile",
"Dumb Missile Ammunition", "Dumb Missile Ammunition",
"Projectile Turret",
"Projectile Turret Ammunition",
"Seeker Missile", "Seeker Missile",
"Seeker Missile Ammunition", "Seeker Missile Ammunition",
"Smart Seeker Missile", "Smart Seeker Missile",
@ -502,6 +522,7 @@ static DamageType outfit_strToDamageType(char* buf) {
else if(strcmp(buf, "kinetic")==0) return DAMAGE_TYPE_KINETIC; else if(strcmp(buf, "kinetic")==0) return DAMAGE_TYPE_KINETIC;
else if(strcmp(buf, "ion")==0) return DAMAGE_TYPE_ION; else if(strcmp(buf, "ion")==0) return DAMAGE_TYPE_ION;
else if(strcmp(buf, "radiation")==0) return DAMAGE_TYPE_RADIATION; else if(strcmp(buf, "radiation")==0) return DAMAGE_TYPE_RADIATION;
else if(strcmp(buf, "emp")==0) return DAMAGE_TYPE_EMP;
WARN("Invalid damage type: '%s'", buf); WARN("Invalid damage type: '%s'", buf);
return DAMAGE_TYPE_NULL; return DAMAGE_TYPE_NULL;
@ -517,6 +538,8 @@ static OutfitType outfit_strToOutfitType(char* buf) {
O_CMP("turret beam", OUTFIT_TYPE_TURRET_BEAM); O_CMP("turret beam", OUTFIT_TYPE_TURRET_BEAM);
O_CMP("missile dumb", OUTFIT_TYPE_MISSILE_DUMB); O_CMP("missile dumb", OUTFIT_TYPE_MISSILE_DUMB);
O_CMP("missile dumb ammo", OUTFIT_TYPE_MISSILE_DUMB_AMMO); O_CMP("missile dumb ammo", OUTFIT_TYPE_MISSILE_DUMB_AMMO);
O_CMP("turret dumb", OUTFIT_TYPE_TURRET_DUMB);
O_CMP("turret dumb ammo", OUTFIT_TYPE_TURRET_DUMB_AMMO);
O_CMP("missile seek", OUTFIT_TYPE_MISSILE_SEEK); O_CMP("missile seek", OUTFIT_TYPE_MISSILE_SEEK);
O_CMP("missile seek ammo", OUTFIT_TYPE_MISSILE_SEEK_AMMO); O_CMP("missile seek ammo", OUTFIT_TYPE_MISSILE_SEEK_AMMO);
O_CMP("missile smart", OUTFIT_TYPE_MISSILE_SEEK_SMART); O_CMP("missile smart", OUTFIT_TYPE_MISSILE_SEEK_SMART);
@ -562,7 +585,7 @@ static int outfit_parseDamage(DamageType* dtype, double* dmg, xmlNodePtr node) {
/* Parses the specific area for a weapon and loads it into outfit. */ /* Parses the specific area for a weapon and loads it into outfit. */
static void outfit_parseSBolt(Outfit* tmp, const xmlNodePtr parent) { static void outfit_parseSBolt(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node; xmlNodePtr node;
char str[PATH_MAX] = "\0"; char* buf;
/* Defaults. */ /* Defaults. */
tmp->u.blt.spfx_armour = -1; tmp->u.blt.spfx_armour = -1;
@ -579,8 +602,14 @@ static void outfit_parseSBolt(Outfit* tmp, const xmlNodePtr parent) {
xmlr_float(node, "energy", tmp->u.blt.energy); xmlr_float(node, "energy", tmp->u.blt.energy);
if(xml_isNode(node, "gfx")) { if(xml_isNode(node, "gfx")) {
snprintf(str, PATH_MAX, OUTFIT_GFX"space/%s.png", xml_get(node)); tmp->u.blt.gfx_space = xml_parseTexture(node,
tmp->u.blt.gfx_space = gl_newSprite(str, 6, 6); OUTFIT_GFX"space/%s.png", 6, 6);
xmlr_attr(node, "spin", buf);
if(buf != NULL) {
outfit_setProp(tmp, OUTFIT_PROP_WEAP_SPIN);
tmp->u.blt.spin = atof(buf);
free(buf);
}
continue; continue;
} }
if(xml_isNode(node, "spfx_shield")) { if(xml_isNode(node, "spfx_shield")) {
@ -624,7 +653,6 @@ static void outfit_parseSBolt(Outfit* tmp, const xmlNodePtr parent) {
*/ */
static void outfit_parseSBeam(Outfit* tmp, const xmlNodePtr parent) { static void outfit_parseSBeam(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node; xmlNodePtr node;
char str[PATH_MAX] = "\0";
/* Defaults. */ /* Defaults. */
tmp->u.bem.spfx_armour = -1; tmp->u.bem.spfx_armour = -1;
@ -649,8 +677,8 @@ static void outfit_parseSBeam(Outfit* tmp, const xmlNodePtr parent) {
/* Graphics stuff. */ /* Graphics stuff. */
if(xml_isNode(node, "gfx")) { if(xml_isNode(node, "gfx")) {
snprintf(str, PATH_MAX, OUTFIT_GFX"space/%s.png", xml_get(node)); tmp->u.bem.gfx = xml_parseTexture(node,
tmp->u.bem.gfx = gl_newSprite(str, 1, 1); OUTFIT_GFX"space/%s.png", 1, 1);
continue; continue;
} }
@ -719,9 +747,9 @@ static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent) {
/* Parse the specific area for a weapon and load it into Outfit. */ /* Parse the specific area for a weapon and load it into Outfit. */
static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) { static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node; xmlNodePtr node;
node = parent->xmlChildrenNode; char* buf;
char str[PATH_MAX] = "\0"; node = parent->xmlChildrenNode;
/* Defaults. */ /* Defaults. */
tmp->u.amm.spfx_armour = -1; tmp->u.amm.spfx_armour = -1;
@ -739,8 +767,14 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
xmlr_float(node, "speed", tmp->u.amm.speed); xmlr_float(node, "speed", tmp->u.amm.speed);
xmlr_float(node, "energy", tmp->u.amm.energy); xmlr_float(node, "energy", tmp->u.amm.energy);
if(xml_isNode(node, "gfx")) { if(xml_isNode(node, "gfx")) {
snprintf(str, PATH_MAX, OUTFIT_GFX"space/%s.png", xml_get(node)); tmp->u.amm.gfx_space = xml_parseTexture(node,
tmp->u.amm.gfx_space = gl_newSprite(str, 6, 6); OUTFIT_GFX"space/%s.png", 6, 6);
xmlr_attr(node, "spin", buf);
if(buf != NULL) {
outfit_setProp(tmp, OUTFIT_PROP_WEAP_SPIN);
tmp->u.blt.spin = atof(buf);
free(buf);
}
continue; continue;
} }
else if(xml_isNode(node, "spfx_armour")) else if(xml_isNode(node, "spfx_armour"))
@ -761,9 +795,9 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
MELEMENT(tmp->u.amm.spfx_shield==-1, "spfx_shield"); MELEMENT(tmp->u.amm.spfx_shield==-1, "spfx_shield");
MELEMENT(tmp->u.amm.spfx_armour==-1, "spfx_armour"); MELEMENT(tmp->u.amm.spfx_armour==-1, "spfx_armour");
MELEMENT((sound_disabled != 0) && (tmp->u.amm.sound < 0), "sound"); MELEMENT((sound_disabled != 0) && (tmp->u.amm.sound < 0), "sound");
MELEMENT(tmp->u.amm.thrust==0, "thrust"); /*MELEMENT(tmp->u.amm.thrust==0, "thrust");*/
/* Dumb missiles don't need everything. */ /* Dumb missiles don't need everything. */
if(tmp->type != OUTFIT_TYPE_MISSILE_DUMB_AMMO) { if(outfit_isSeeker(tmp)) {
MELEMENT(tmp->u.amm.turn==0, "turn"); MELEMENT(tmp->u.amm.turn==0, "turn");
MELEMENT(tmp->u.amm.lockon==0, "lockon"); MELEMENT(tmp->u.amm.lockon==0, "lockon");
} }

View File

@ -5,6 +5,7 @@
#define outfit_isProp(o,p) ((o)->properties & p) /**< Check an outfit for property. */ #define outfit_isProp(o,p) ((o)->properties & p) /**< Check an outfit for property. */
/* Property flags. */ /* Property flags. */
#define OUTFIT_PROP_WEAP_SECONDARY (1<<0) /**< Is a secondary weapon? */ #define OUTFIT_PROP_WEAP_SECONDARY (1<<0) /**< Is a secondary weapon? */
#define OUTFIT_PROP_WEAP_SPIN (1<<1) /**< Should weapon spin around? */
struct Outfit_; struct Outfit_;
@ -23,6 +24,8 @@ typedef enum OutfitType_ {
OUTFIT_TYPE_TURRET_BEAM, /**< Rotary bolt turret. */ OUTFIT_TYPE_TURRET_BEAM, /**< Rotary bolt turret. */
OUTFIT_TYPE_MISSILE_DUMB, /**< Dumb missile launcher. */ OUTFIT_TYPE_MISSILE_DUMB, /**< Dumb missile launcher. */
OUTFIT_TYPE_MISSILE_DUMB_AMMO, /**< Dumb missile ammo. */ OUTFIT_TYPE_MISSILE_DUMB_AMMO, /**< Dumb missile ammo. */
OUTFIT_TYPE_TURRET_DUMB, /**< Dumb missile turret launcher. */
OUTFIT_TYPE_TURRET_DUMB_AMMO, /**< Dumb missile turret ammo. */
OUTFIT_TYPE_MISSILE_SEEK, /**< Seeker missile launcher. */ OUTFIT_TYPE_MISSILE_SEEK, /**< Seeker missile launcher. */
OUTFIT_TYPE_MISSILE_SEEK_AMMO, /**< Seeker missile ammo. */ OUTFIT_TYPE_MISSILE_SEEK_AMMO, /**< Seeker missile ammo. */
OUTFIT_TYPE_MISSILE_SEEK_SMART, /**< ATM equivalent to SEEK. */ OUTFIT_TYPE_MISSILE_SEEK_SMART, /**< ATM equivalent to SEEK. */
@ -51,7 +54,8 @@ typedef enum DamageType_ {
DAMAGE_TYPE_ENERGY, /**< Energy-based weapons. */ DAMAGE_TYPE_ENERGY, /**< Energy-based weapons. */
DAMAGE_TYPE_KINETIC, /**< Physic impact weapons. */ DAMAGE_TYPE_KINETIC, /**< Physic impact weapons. */
DAMAGE_TYPE_ION, /**< Ion-based weapons. */ DAMAGE_TYPE_ION, /**< Ion-based weapons. */
DAMAGE_TYPE_RADIATION /**< Radioactive weapons. */ DAMAGE_TYPE_RADIATION, /**< Radioactive weapons. */
DAMAGE_TYPE_EMP /**< Electromagnetic pulse weapons. */
} DamageType; } DamageType;
/** /**
@ -70,6 +74,7 @@ typedef struct OutfitBoltData_ {
/* Sound and graphics. */ /* Sound and graphics. */
glTexture* gfx_space; /**< Graphic. */ glTexture* gfx_space; /**< Graphic. */
double spin; /**< Graphic spin rate. */
int sound; /**< Sound to play. */ int sound; /**< Sound to play. */
int spfx_armour; /**< Special effect on hit. */ int spfx_armour; /**< Special effect on hit. */
int spfx_shield; /**< Special effect on hit. */ int spfx_shield; /**< Special effect on hit. */
@ -134,6 +139,7 @@ typedef struct OutfitAmmoData_ {
double damage; /**< Damage. */ double damage; /**< Damage. */
glTexture* gfx_space; /**< Graphic. */ glTexture* gfx_space; /**< Graphic. */
double spin; /**< Graphic spin rate. */
int sound; /**< Sound to play. */ int sound; /**< Sound to play. */
int spfx_armour; /**< Special effect on hit. */ int spfx_armour; /**< Special effect on hit. */
int spfx_shield; /**< Special effect on hit. */ int spfx_shield; /**< Special effect on hit. */
@ -275,6 +281,7 @@ int outfit_isBolt(const Outfit* o);
int outfit_isBeam(const Outfit* o); int outfit_isBeam(const Outfit* o);
int outfit_isLauncher(const Outfit* o); int outfit_isLauncher(const Outfit* o);
int outfit_isAmmo(const Outfit* o); int outfit_isAmmo(const Outfit* o);
int outfit_isSeeker(const Outfit* o);
int outfit_isTurret(const Outfit* o); int outfit_isTurret(const Outfit* o);
int outfit_isMod(const Outfit* o); int outfit_isMod(const Outfit* o);
int outfit_isAfterburner(const Outfit* o); int outfit_isAfterburner(const Outfit* o);
@ -288,7 +295,8 @@ const char* outfit_getTypeBroad(const Outfit* o);
/* Get data from outfit. */ /* Get data from outfit. */
glTexture* outfit_gfx(const Outfit* o); glTexture* outfit_gfx(const Outfit* o);
int outfit_spfx(const Outfit* o); int outfit_spfxArmour(const Outfit* o);
int outfit_spfxShield(const Outfit* o);
double outfit_damage(const Outfit* o); double outfit_damage(const Outfit* o);
DamageType outfit_damageType(const Outfit* o); DamageType outfit_damageType(const Outfit* o);
int outfit_delay(const Outfit* o); int outfit_delay(const Outfit* o);
@ -296,7 +304,7 @@ Outfit* outfit_ammo(const Outfit* o);
double outfit_energy(const Outfit* o); double outfit_energy(const Outfit* o);
double outfit_range(const Outfit* o); double outfit_range(const Outfit* o);
double outfit_speed(const Outfit* o); double outfit_speed(const Outfit* o);
int outfit_isSeeker(const Outfit* o); double outfit_spin(const Outfit* o);
/* Load/free outfit stack. */ /* Load/free outfit stack. */
int outfit_load(void); int outfit_load(void);

View File

@ -440,29 +440,36 @@ void pilot_hit(Pilot* p, const Solid* w, const unsigned int shooter,
p->shield = 0.; p->shield = 0.;
dam_mod = (damage_shield+damage_armour) / (p->shield_max + p->armour_max); dam_mod = (damage_shield+damage_armour) / (p->shield_max + p->armour_max);
} }
else if(p->armour-damage_armour > 0.) { else if(p->armour > 0.) {
p->armour -= damage_armour; p->armour -= damage_armour;
dam_mod = damage_armour/p->armour_max;
/* Shake us up a bit. */ /* EMP don't kill. */
if(p->id == PLAYER_ID) if((dtype == DAMAGE_TYPE_EMP) &&
spfx_shake(dam_mod*100.); (p->armour < PILOT_DISABLED_ARMOUR * p->armour_max))
} p->armour = PILOT_DISABLED_ARMOUR * p->armour_max - 1.;
else {
/* We are officially dead. */ /* Officially dead. */
if(p->armour <= 0.) {
p->armour = 0.; p->armour = 0.;
dam_mod = 0.; dam_mod = 0.;
if(!pilot_isFlag(p, PILOT_DEAD)) { if(!pilot_isFlag(p, PILOT_DEAD)) {
pilot_dead(p); pilot_dead(p);
/* Adjust the combat rating based on pilot mass and ditto faction. */ /* Adjust the combat rating based on pilot mass and ditto faction. */
pshooter = pilot_get(shooter); pshooter = pilot_get(shooter);
if((pshooter != NULL) && (pshooter->faction == FACTION_PLAYER)) { if((pshooter != NULL) && (pshooter->faction == FACTION_PLAYER)) {
mod = sqrt(p->ship->mass) / 5; mod = sqrt(p->ship->mass) / 5;
player_crating += 2*mod; /* Crating chanes faster. */ player_crating += 2*mod; /* Crating changes faster. */
faction_modPlayer(p->faction, -mod); faction_modPlayer(p->faction, -mod);
} }
} }
} else { /* Some minor effects and stuff. */
dam_mod = damage_armour / p->armour_max;
if(p->id == PLAYER_ID) /* Shake us up a bit. */
spfx_shake(dam_mod*100.);
}
} }
if(shooter != 0) if(shooter != 0)

View File

@ -143,6 +143,8 @@ int spfx_load(void) {
spfx_base_load("ExpM", 450, 450, "expm.png", 6, 5); spfx_base_load("ExpM", 450, 450, "expm.png", 6, 5);
spfx_base_load("ExpL", 500, 500, "expl.png", 6, 5); spfx_base_load("ExpL", 500, 500, "expl.png", 6, 5);
spfx_base_load("cargo", 15000, 5000, "cargo.png", 6, 6); spfx_base_load("cargo", 15000, 5000, "cargo.png", 6, 6);
spfx_base_load("EmpS", 400, 400, "emps.png", 6, 5);
spfx_base_load("EmpM", 450, 450, "empm.png", 6, 5);
return 0; return 0;
} }

View File

@ -62,7 +62,8 @@ typedef struct Weapon_ {
int voice; /**< Weapons voice. */ int voice; /**< Weapons voice. */
double lockon; /**< Some weapons have a lockon delay. */ double lockon; /**< Some weapons have a lockon delay. */
double timer; /**< Mainly used to see when the weapon was fired. */ double timer; /**< Mainly used to see when the weapon was fired. */
double anim; /**< Used for beam weapon graphics. */ double anim; /**< Used for beam weapon graphics and others. */
int sprite; /**< USed for spinning outfits. */
/* Update position and render. */ /* Update position and render. */
void(*update)(struct Weapon_*, const double, WeaponLayer); /**< Update the weapon. */ void(*update)(struct Weapon_*, const double, WeaponLayer); /**< Update the weapon. */
@ -345,6 +346,7 @@ static void weapons_updateLayer(const double dt, const WeaponLayer layer) {
/* Purpose fallthrough. */ /* Purpose fallthrough. */
/* Bolts too. */ /* Bolts too. */
case OUTFIT_TYPE_TURRET_DUMB_AMMO:
case OUTFIT_TYPE_MISSILE_DUMB_AMMO: /* Dumb missiles are like bolts. */ case OUTFIT_TYPE_MISSILE_DUMB_AMMO: /* Dumb missiles are like bolts. */
limit_speed(&w->solid->vel, w->outfit->u.amm.speed, dt); limit_speed(&w->solid->vel, w->outfit->u.amm.speed, dt);
case OUTFIT_TYPE_BOLT: case OUTFIT_TYPE_BOLT:
@ -439,10 +441,29 @@ static void weapon_render(Weapon* w, const double dt) {
case OUTFIT_TYPE_BOLT: case OUTFIT_TYPE_BOLT:
case OUTFIT_TYPE_TURRET_BOLT: case OUTFIT_TYPE_TURRET_BOLT:
case OUTFIT_TYPE_MISSILE_DUMB_AMMO: case OUTFIT_TYPE_MISSILE_DUMB_AMMO:
case OUTFIT_TYPE_TURRET_DUMB_AMMO:
gfx = outfit_gfx(w->outfit); gfx = outfit_gfx(w->outfit);
/* Get the sprite corresponding to the direction facing. */
/* Outfit spins around. */
if(outfit_isProp(w->outfit, OUTFIT_PROP_WEAP_SPIN)) {
/* Check timer. */
w->anim -= dt;
if(w->anim < 0.) {
w->anim = outfit_spin(w->outfit);
/* Increment sprite. */
w->sprite++;
if(w->sprite >= gfx->sx*gfx->sy)
w->sprite = 0;
}
/* Render. */
gl_blitSprite(gfx, w->solid->pos.x, w->solid->pos.y,
w->sprite % (int)gfx->sx, w->sprite / (int)gfx->sx, NULL);
} else { /* Outfit faces direction. */
gl_getSpriteFromDir(&sx, &sy, gfx, w->solid->dir); gl_getSpriteFromDir(&sx, &sy, gfx, w->solid->dir);
gl_blitSprite(gfx, 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);
}
break; break;
/* Beam weapons. */ /* Beam weapons. */
@ -723,7 +744,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
Weapon* w; Weapon* w;
/* Create basic features. */ /* Create basic features. */
w = MALLOC_L(Weapon); w = CALLOC_L(Weapon);
w->faction = pilot_get(parent)->faction; /*Non-Changeable. */ w->faction = pilot_get(parent)->faction; /*Non-Changeable. */
w->parent = parent; /* Non-Changeable. */ w->parent = parent; /* Non-Changeable. */
w->target = target; /* Non-Changeable. */ w->target = target; /* Non-Changeable. */
@ -766,8 +787,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
} }
/* Set angle to face. */ /* Set angle to face. */
vect_cset(&v, x, y); rdir = ANGLE(x, y);
rdir = VANGLE(v);
} }
} else /* Fire straight. */ } else /* Fire straight. */
rdir = dir; rdir = dir;
@ -830,6 +850,52 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
w->solid->pos.y + w->solid->vel.y); w->solid->pos.y + w->solid->vel.y);
break; break;
/* Turrets are a special case. */
case OUTFIT_TYPE_TURRET_DUMB_AMMO:
pilot_target = pilot_get(w->target);
if(pilot_target == NULL)
rdir = dir;
else {
/* Get the distance. */
dist = vect_dist(pos, &pilot_target->solid->pos);
/* Aim. */
if(dist > outfit->u.blt.range * 1.2) {
x = pilot_target->solid->pos.x - pos->x;
y = pilot_target->solid->pos.y - pos->y;
} else {
/* Try to predict where the enemy will be. */
/* Time for shots to reach that distance. */
t = dist / w->outfit->u.amm.speed;
/* Position is calculated on where it should be. */
x = (pilot_target->solid->pos.x + pilot_target->solid->vel.x*t)
- (pos->x + vel->x*t);
y = (pilot_target->solid->pos.y + pilot_target->solid->vel.y*t)
- (pos->y + vel->y*t);
}
/* Set angle to face. */
rdir = ANGLE(x, y);
}
/* If thrust is 0. We assume it starts out at speed. */
vectcpy(&v, vel);
if(outfit->u.amm.thrust == 0.)
vect_cadd(&v, cos(rdir) * w->outfit->u.amm.speed,
sin(rdir) * w->outfit->u.amm.speed);
mass = w->outfit->mass;
w->timer = outfit->u.amm.duration;
w->solid = solid_create(mass, rdir, pos, &v);
if(w->outfit->u.amm.thrust != 0.)
vect_pset(&w->solid->force, w->outfit->u.amm.thrust, rdir);
w->think = NULL; /* No AI. */
w->voice = sound_playPos(w->outfit->u.amm.sound,
w->solid->pos.x + w->solid->vel.x,
w->solid->pos.y + w->solid->vel.y);
break;
/* Dumb missiles are a mix of missile and bolt. */ /* Dumb missiles are a mix of missile and bolt. */
case OUTFIT_TYPE_MISSILE_DUMB_AMMO: case OUTFIT_TYPE_MISSILE_DUMB_AMMO:
mass = w->outfit->mass; mass = w->outfit->mass;