diff --git a/dat/outfit.xml b/dat/outfit.xml index fd57f8a..eda7059 100644 --- a/dat/outfit.xml +++ b/dat/outfit.xml @@ -279,6 +279,43 @@ <speed>550</speed> <damage type="kinetic">20</damage> </specific> +</outfit> + <outfit name="Banshee Launcher"> + <general> + <max>2</max> + <tech>4</tech> + <license>Medium Weapon License</license> + <mass>10</mass> + <price>25000</price> + <gfx_store>bansheelauncher</gfx_store> + <description>The Banshee Launcher uses a quick action firing mechanism to be able to quickly launch the banshee rockets. The only drawback is that this mechanism can only be used with light rockets, limiting the payload the rockets can have.</description> + </general> + <specific type="missile dumb" secondary="1"> + <ammo>Banshee Rocket</ammo> + <delay>300</delay> + </specific> + </outfit> + <outfit name="Banshee Rocket"> + <general> + <max>40</max> + <tech>7</tech> + <license>Medium Weapon License</license> + <mass>0</mass> + <price>100</price> + <description>The Banshee Rocket gets it's name from the wail it makes when launched. They carry an EMP payload which is very helpful when attempting to disable ships.</description> + <gfx_store>banshee</gfx_store> + </general> + <specific type="missile dumb ammo"> + <gfx>banshee</gfx> + <sound>missile</sound> + <spfx_shield>EmpS</spfx_shield> + <spfx_armour>EmpS</spfx_armour> + <duration>0.8</duration> + <accuracy>12</accuracy> + <thrust>0</thrust> + <speed>600</speed> + <damage type="emp">15</damage> + </specific> </outfit> <outfit name="Neutron Disruptor"> <general> diff --git a/dat/ship.xml b/dat/ship.xml index 78431df..fa0b177 100644 --- a/dat/ship.xml +++ b/dat/ship.xml @@ -32,6 +32,8 @@ <outfits> <outfit quantity="1">Lancelot Fighter Bay</outfit> <outfit quantity="100">Lancelot Fighter</outfit> + <outfit quantity="1">Banshee Launcher</outfit> + <outfit quantity="100">Banshee Rocket</outfit> <outfit quantity="2">Ripper MK2</outfit> <outfit quantity="2">Ragnarok Beam</outfit> <outfit quantity="2">Orion Beam</outfit> diff --git a/gfx/outfit/space/banshee.png b/gfx/outfit/space/banshee.png new file mode 100644 index 0000000..c212cca Binary files /dev/null and b/gfx/outfit/space/banshee.png differ diff --git a/gfx/outfit/store/banshee.png b/gfx/outfit/store/banshee.png new file mode 100644 index 0000000..038b88b Binary files /dev/null and b/gfx/outfit/store/banshee.png differ diff --git a/gfx/outfit/store/bansheelauncher.png b/gfx/outfit/store/bansheelauncher.png new file mode 100644 index 0000000..5214518 Binary files /dev/null and b/gfx/outfit/store/bansheelauncher.png differ diff --git a/src/outfit.c b/src/outfit.c index d27f85b..f9dc664 100644 --- a/src/outfit.c +++ b/src/outfit.c @@ -774,7 +774,7 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) { tmp->u.amm.spfx_shield = -1; tmp->u.amm.sound = -1; - do { + do { /* Load all the data. */ /* Basic. */ xmlr_float(node, "duration", tmp->u.amm.duration); xmlr_float(node, "lockon", tmp->u.amm.lockon); @@ -783,6 +783,7 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) { xmlr_float(node, "thrust", tmp->u.amm.thrust); xmlr_float(node, "turn", tmp->u.amm.turn); xmlr_float(node, "speed", tmp->u.amm.speed); + xmlr_float(node, "accuracy", tmp->u.amm.accuracy); xmlr_float(node, "energy", tmp->u.amm.energy); if(xml_isNode(node, "gfx")) { tmp->u.amm.gfx_space = xml_parseTexture(node, diff --git a/src/outfit.h b/src/outfit.h index 191466f..aa0ab5a 100644 --- a/src/outfit.h +++ b/src/outfit.h @@ -131,6 +131,7 @@ typedef struct OutfitAmmoData_ { double lockon; /**< Time it takes to lock on the target. */ double resist; /**< Lowers chance of jamming by this amount. */ + double accuracy; /**< Desviation accuracy. */ double speed; /**< Max speed. */ double turn; /**< Turn velocity. */ double thrust; /**< Acceleration. */ diff --git a/src/weapon.c b/src/weapon.c index c6c2cc7..b607068 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -749,9 +749,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* w->target = target; /* Non-Changeable. */ w->outfit = outfit; /* Non-Changeable. */ w->update = weapon_update; - w->think = NULL; w->status = WEAPON_STATUS_OK; - w->timer = 0.0; switch(outfit->type) { /* Bolts treated together. */ @@ -816,7 +814,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* vect_angle(pos, &pilot_target->solid->pos); } else rdir = dir; - mass = 1.; + mass = 1.; /**< Needs a mass. */ w->solid = solid_create(mass, rdir, pos, NULL); w->think = think_beam; w->timer = outfit->u.bem.duration; @@ -829,6 +827,15 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* case OUTFIT_TYPE_MISSILE_SEEK_AMMO: case OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO: mass = w->outfit->mass; + + rdir = dir; + if(outfit->u.amm.accuracy != 0.) { + rdir += NormalInverse(RNGF()*0.9 + 0.05) /* Get rid of extreme values. */ + * outfit->u.amm.accuracy/2. * 1./180.*M_PI; + if((rdir > 2.*M_PI) || (rdir < 0.)) + rdir = fmod(rdir, 2.*M_PI); + } + w->lockon = outfit->u.amm.lockon; w->timer = outfit->u.amm.duration; w->solid = solid_create(mass, dir, pos, vel); @@ -860,23 +867,28 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* 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; + /* + * 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); - /* 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(outfit->u.amm.accuracy != 0.) { + rdir += NormalInverse(RNGF()*0.9 + 0.05) /* Get rid of extreme values. */ + * outfit->u.amm.accuracy/2. * 1./180.*M_PI; + if((rdir > 2.*M_PI) || (rdir < 0.)) + rdir = fmod(rdir, 2.*M_PI); + } /* If thrust is 0. We assume it starts out at speed. */ vectcpy(&v, vel); @@ -889,7 +901,6 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* 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); @@ -898,11 +909,24 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* /* Dumb missiles are a mix of missile and bolt. */ case OUTFIT_TYPE_MISSILE_DUMB_AMMO: mass = w->outfit->mass; - w->timer = outfit->u.amm.duration; - w->solid = solid_create(mass, dir, pos, vel); - vect_pset(&w->solid->force, w->outfit->u.amm.thrust, dir); - w->think = NULL; /* No AI. */ + rdir = dir; + + if(outfit->u.amm.accuracy != 0.) { + rdir += NormalInverse(RNGF()*0.9 + 0.05) /* Get rid of extreme values. */ + * outfit->u.amm.accuracy/2. * 1./180.*M_PI; + if((rdir > 2.*M_PI) || (rdir < 0.)) + rdir = fmod(rdir, 2.*M_PI); + } + + /* If thrust is 0. we assume it starts out at speed. */ + if(outfit->u.amm.thrust == 0.) + vect_pset(&v, w->outfit->u.amm.speed, rdir); + else + vectnull(&v); + + w->timer = outfit->u.amm.duration; + w->solid = solid_create(mass, rdir, pos, &v); 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);