diff --git a/src/explosion.c b/src/explosion.c new file mode 100644 index 0000000..d4050fa --- /dev/null +++ b/src/explosion.c @@ -0,0 +1,87 @@ +/** + * @file explosion.c + */ +#include "lephisto.h" +#include "log.h" +#include "pilot.h" +#include "weapon.h" +#include "spfx.h" +#include "rng.h" +#include "explosion.h" + +/** + * @fn void expl_explode(double x, double y, double vx, double vy, + * double radius, DamageType dtype, double damage, + * unsigned int parent, int mode) + * + * @brief + */ +void expl_explode(double x, double y, double vx, double vy, + double radius, DamageType dtype, double damage, + unsigned int parent, int mode) { + + int i, n; + double a, d; + double area; + double ex, ey; + double layer; + int efx; + int exp_s, exp_m, exp_l; + + /* Standard stuff. */ + exp_s = spfx_get("ExpS"); + exp_m = spfx_get("ExpM"); + exp_s = spfx_get("ExpL"); + layer = SPFX_LAYER_FRONT; + + /* Number of explosions. */ + area = M_PI * pow2(radius); + n = (int)(area / 100.); + + /* Create explosions. */ + for(i = 0; i < n; i++) { + /* Get position. */ + a = RNGF()*360.; + d = RNGF()*(radius-5.) + 5.; + ex = d*cos(a); + ey = d*sin(a); + + /* Create explosion. */ + efx = (RNG(0,2)==0) ? exp_m : exp_s; + spfx_add(efx, x+ex, y+ey, vx, vy, layer); + } + + /* Final explosion. */ + spfx_add(exp_l, x, y, vx, vy, layer); + + /* Run the damage. */ + if(damage > 0.) + expl_explodeDamage(x, y, radius, dtype, damage, parent, mode); +} + +/** + * @fn + * + * @brief + */ +void expl_explodeDamage(double x, double y, double radius, + DamageType dtype, double damage, + unsigned int parent, int mode) { + + /* Explosion affects ships. */ + if(mode & EXPL_MODE_SHIP) + pilot_explode(x, y, radius, dtype, damage, parent); + + /* Explosion affects missiles and bolts. */ + if((mode & EXPL_MODE_MISSILE) && (mode & EXPL_MODE_BOLT)) + weapon_explode(x, y, radius, dtype, damage, parent, mode); + + /* Explosion affects missiles. */ + else if(mode & EXPL_MODE_MISSILE) + weapon_explode(x, y, radius, dtype, damage, parent, mode); + + /* Explosion affects bolts. */ + else if(mode & EXPL_MODE_BOLT) + weapon_explode(x, y, radius, dtype, damage, parent, mode); +} + diff --git a/src/explosion.h b/src/explosion.h new file mode 100644 index 0000000..6e5976a --- /dev/null +++ b/src/explosion.h @@ -0,0 +1,15 @@ +#pragma once +#include "outfit.h" + +#define EXPL_MODE_SHIP (1<<0) /**< Affects ships. */ +#define EXPL_MODE_MISSILE (1<<1) /**< Affects missiles. */ +#define EXPL_MODE_BOLT (1<<2) /**< Affects bots. */ + +void expl_explode(double x, double y, double vx, double vy, + double radius, DamageType dtype, double damage, + unsigned int parent, int mode); + +void expl_explodeDamage(double x, double y, double radius, + DamageType dtype, double damage, + unsigned int parent, int mode); + diff --git a/src/pilot.c b/src/pilot.c index a6353e7..2b45c49 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -17,6 +17,7 @@ #include "rng.h" #include "hook.h" #include "map.h" +#include "explosion.h" #include "pilot.h" #define XML_ID "Fleets" /**< XML document identifier. */ @@ -554,6 +555,40 @@ void pilot_setAfterburner(Pilot* p) { p->afterburner = NULL; } +/** + */ +void pilot_explode(double x, double y, double radius, + DamageType dtype, double damage, unsigned int parent) { + + int i; + double rx, ry; + double dist, rad2; + Pilot* p; + Solid s; /* Only need to manipulate mass and vel. */ + + rad2 = radius*radius; + + for(i = 0; i < pilot_nstack; i++) { + p = pilot_stack[i]; + + /* Calculate a bit. */ + rx = p->solid->pos.x - x; + ry = p->solid->pos.y - y; + dist = pow2(rx) + pow2(ry); + + /* Pilot is hit. */ + if(dist < rad2) { + /* Impact settings. */ + s.mass = (rad2 - dist) / 10.; + s.vel.x = rx; + s.vel.y = ry; + + /* Actual damage calculations. */ + pilot_hit(p, &s, parent, dtype, damage); + } + } +} + /** * @fn void pilot_render(Pilot* p) * @@ -601,9 +636,13 @@ static void pilot_update(Pilot* pilot, const double dt) { /* Final explosion. */ else if(!pilot_isFlag(pilot, PILOT_EXPLODED) && (t > pilot->ptimer - 200)) { - spfx_add(spfx_get("ExpL"), - VX(pilot->solid->pos), VY(pilot->solid->pos), - VX(pilot->solid->vel), VY(pilot->solid->vel), SPFX_LAYER_BACK); + /* Damage from explosion. */ + a = sqrt(pilot->solid->mass); + expl_explode(pilot->solid->pos.x, pilot->solid->pos.y, + pilot->solid->vel.x, pilot->solid->vel.y, + pilot->ship->gfx_space->sw / 2. + a, + DAMAGE_TYPE_KINETIC, 2.*a - 20., + 0, EXPL_MODE_SHIP); pilot_setFlag(pilot, PILOT_EXPLODED); /* Release cargo. */ diff --git a/src/pilot.h b/src/pilot.h index 92aad51..ad80af8 100644 --- a/src/pilot.h +++ b/src/pilot.h @@ -219,13 +219,17 @@ void pilot_shoot(Pilot* p, const unsigned int target, const int secondary); void pilot_shootStop(Pilot* p, const int secondary); void pilot_hit(Pilot* p, const Solid* w, const unsigned int shooter, const DamageType dtype, const double damage); +double pilot_face(Pilot* p, const double dir); +void pilot_hyperspaceAbort(Pilot* p); +/* Special outfit stuff. */ void pilot_switchSecondary(Pilot* p, int i); void pilot_setSecondary(Pilot* p, const char* secondary); void pilot_setAmmo(Pilot* p); int pilot_getAmmo(Pilot* p, Outfit* o); void pilot_setAfterburner(Pilot* p); -double pilot_face(Pilot* p, const double dir); -void pilot_hyperspaceAbort(Pilot* p); +/* Explosion. */ +void pilot_explode(double x, double y, double radius, + DamageType dtype, double damage, unsigned int parent); /* Outfits. */ int pilot_freeSpace(Pilot* p); /* Pilot space. */ int pilot_addOutfit(Pilot* pilot, Outfit* outfit, int quantity); diff --git a/src/weapon.c b/src/weapon.c index a62918c..9c612eb 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -21,6 +21,7 @@ #include "player.h" #include "spfx.h" #include "opengl.h" +#include "explosion.h" #include "weapon.h" #define weapon_isSmart(w) (w->think != NULL) /**< Checks if the weapon w is smart. */ @@ -98,6 +99,9 @@ static void weapon_hitBeam(Weapon* w, Pilot* p, WeaponLayer layer, Vec2 pos[2], const double dt); static void weapon_destroy(Weapon* w, WeaponLayer layer); static void weapon_free(Weapon* w); +static void weapon_explodeLayer(WeaponLayer layer, + double x, double y, double radius, + unsigned int parent, int mode); /* Think. */ static void think_seeker(Weapon* w, const double dt); static void think_beam(Weapon* w, const double dt); @@ -1039,3 +1043,62 @@ void weapon_exit(void) { } } +/** + * @fn void weapon_explode(double x, double y, double radius, + DamageType dtype, double damage, + unsigned int parent, int mode) + + @brief Clear possible exploded weapons. + */ +void weapon_explode(double x, double y, double radius, + DamageType dtype, double damage, + unsigned int parent, int mode) { + + (void)dtype; + (void)damage; + weapon_explodeLayer(WEAPON_LAYER_FG, x, y, radius, parent, mode); + weapon_explodeLayer(WEAPON_LAYER_BG, x, y, radius, parent, mode); +} + +static void weapon_explodeLayer(WeaponLayer layer, + double x, double y, double radius, + unsigned int parent, int mode) { + + (void)parent; + int i; + Weapon** curLayer; + int *nLayer; + double dist, rad2; + + /* Set the proper layer. */ + switch(layer) { + case WEAPON_LAYER_BG: + curLayer = wbackLayer; + nLayer = &nwbackLayer; + break; + case WEAPON_LAYER_FG: + curLayer = wfrontLayer; + nLayer = &nwbackLayer; + break; + default: + ERR("Invalid WEAPON_LAYER specified."); + return; + } + + rad2 = radius*radius; + + /* Now try to destroy the weapons affected. */ + for(i = 0; i < *nLayer; i++) { + if(((mode & EXPL_MODE_MISSILE) && outfit_isAmmo(curLayer[i]->outfit)) || + ((mode & EXPL_MODE_BOLT) && outfit_isBolt(curLayer[i]->outfit))) { + dist = pow2(curLayer[i]->solid->pos.x - x) + + pow2(curLayer[i]->solid->pos.y - y); + + if(dist < rad2) { + weapon_destroy(curLayer[i], layer); + i--; + } + } + } +} + diff --git a/src/weapon.h b/src/weapon.h index 03f9cd7..1ee8471 100644 --- a/src/weapon.h +++ b/src/weapon.h @@ -22,6 +22,10 @@ int beam_start(const Outfit* outfit, void beam_end(const unsigned int parent, int beam); +void weapon_explode(double x, double y, double radius, + DamageType dtype, double damage, + unsigned int parent, int mode); + /* Update. */ void weapons_update(const double dt); void weapons_render(const WeaponLayer layer);