Lephisto/src/weapon.c

274 lines
7.9 KiB
C

#include <math.h>
#include <malloc.h>
#include <string.h>
#include "outfit.h"
#include "physics.h"
#include "main.h"
#include "log.h"
#include "rng.h"
#include "pilot.h"
#include "collision.h"
#include "player.h"
#include "weapon.h"
// Some stuff from pilot.
extern Pilot** pilot_stack;
extern int pilots;
// Ai stuff.
extern void ai_attacked(Pilot* attacked, const unsigned int attacker);
typedef struct Weapon {
Solid* solid; // Actually has its own solid. :D
unsigned int parent; // The pilot that just shot at you!
const Outfit* outfit; // Related outfit that fired.
unsigned int timer; // Mainly used to see when the weapon was fired.
// Update position and render.
void(*update)(struct Weapon*, const double, WeaponLayer); // Position update and render.
void(*think)(struct Weapon*); // Some missiles need to be inteligent.
} Weapon;
// Behind Pilot layer.
static Weapon** wbackLayer = NULL; // Behind pilots.
static int nwbackLayer = 0; // Number of elements.
static int mwbackLayer = 0; // Allocated memory size.
// Behind player layer.
static Weapon** wfrontLayer = NULL; // Behind pilots.
static int nwfrontLayer = 0; // Number of elements.
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);
static void weapon_render(const Weapon* w);
static void weapon_update(Weapon* w, const double dt, WeaponLayer layer);
static void weapon_destroy(Weapon* w, WeaponLayer layer);
static void weapon_free(Weapon* w);
// Draw the minimap weapons (player.c).
#define PIXEL(x,y) if((shape == RADAR_RECT && ABS(x) < w/2. && ABS(y)<h/2.) || \
(shape == RADAR_CIRCLE && (((x)*(x)+(y)*(y))<rc))) glVertex2i((x),(y))
void weapon_minimap(const double res, const double w, const double h, const RadarShape shape) {
int i, rc;
double x, y;
if(shape == RADAR_CIRCLE) rc = (int)(w*w);
for(i = 0; i < nwbackLayer; i++) {
x = (wbackLayer[i]->solid->pos.x - player->solid->pos.x) / res;
y = (wbackLayer[i]->solid->pos.y - player->solid->pos.y) / res;
PIXEL(x,y);
}
for(i = 0; i < nwfrontLayer; i++) {
x = (wfrontLayer[i]->solid->pos.x - player->solid->pos.x) / res;
y = (wfrontLayer[i]->solid->pos.y - player->solid->pos.y) / res;
PIXEL(x,y);
}
}
#undef PIXEL
// Update all weapons in the layer.
void weapons_update(const double dt, WeaponLayer layer) {
Weapon** wlayer;
int* nlayer;
switch(layer) {
case WEAPON_LAYER_BG:
wlayer = wbackLayer;
nlayer = &nwbackLayer;
break;
case WEAPON_LAYER_FG:
wlayer = wfrontLayer;
nlayer = &nwfrontLayer;
break;
}
int i;
Weapon* w;
for(i = 0; i < (*nlayer); i++) {
w = wlayer[i];
switch(wlayer[i]->outfit->type) {
case OUTFIT_TYPE_BOLT:
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.
if(w != wlayer[i]) i--;
}
}
// Render the weapons.
static void weapon_render(const Weapon* w) {
int sx, sy;
// Get the sprite corresponding to the direction facing.
gl_getSpriteFromDir(&sx, &sy, w->outfit->gfx_space, w->solid->dir);
gl_blitSprite(w->outfit->gfx_space, &w->solid->pos, 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);
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) && // The pilot hasn't shoot it.
!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_armor);
// No need for the weapon particle anymore.
weapon_destroy(w, layer);
return;
}
}
if(w->think) (*w->think)(w);
(*w->solid->update)(w->solid, dt);
weapon_render(w);
}
static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* pos,
const Vec2* vel, unsigned int parent) {
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->outfit = outfit; // Non-Changeable.
w->update = weapon_update;
w->timer = SDL_GetTicks();
w->think = NULL;
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;
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));
w->solid = solid_create(mass, rdir, pos, &v);
break;
default:
// Just dump it where the player is.
w->solid = solid_create(mass, dir, pos, vel);
break;
}
return w;
}
// 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)) {
ERR("Trying to create a weapon from a non-Weapon type Outfit");
return;
}
Weapon* w = weapon_create(outfit, dir, pos, vel, parent);
// Set the propper layer.
Weapon** curLayer = NULL;
int* mLayer = NULL;
int* nLayer = NULL;
switch(layer) {
case WEAPON_LAYER_BG:
curLayer = wbackLayer;
nLayer = &nwbackLayer;
mLayer = &mwbackLayer;
break;
case WEAPON_LAYER_FG:
curLayer = wfrontLayer;
nLayer = &nwfrontLayer;
mLayer = &mwfrontLayer;
break;
default:
ERR("Invalid WEAPON_LAYER specified.");
return;
}
if(*mLayer > *nLayer) // More memory allocated than what we need.
curLayer[(*nLayer)++] = w;
else { // Need to allocate more memory.
switch(layer) {
case WEAPON_LAYER_BG:
curLayer = wbackLayer = realloc(curLayer, (++(*mLayer))*sizeof(Weapon*));
break;
case WEAPON_LAYER_FG:
curLayer = wfrontLayer = realloc(curLayer, (++(*mLayer))*sizeof(Weapon*));
break;
}
curLayer[(*nLayer)++] = w;
}
}
// Destroy the weapon.
static void weapon_destroy(Weapon* w, WeaponLayer layer) {
int i;
Weapon** wlayer;
int* nlayer;
switch(layer) {
case WEAPON_LAYER_BG:
wlayer = wbackLayer;
nlayer = &nwbackLayer;
break;
case WEAPON_LAYER_FG:
wlayer = wfrontLayer;
nlayer = &nwfrontLayer;
break;
}
for(i = 0; wlayer[i] != w; i++); // Get us to the current posision.
weapon_free(wlayer[i]);
wlayer[i] = NULL;
(*nlayer)--;
for(; i < (*nlayer); i++)
wlayer[i] = wlayer[i+1];
}
// Clear the weapon.
static void weapon_free(Weapon* w) {
solid_free(w->solid);
free(w);
}
// Clear all the weapons, do not free the layers.
void weapon_clear(void) {
int i;
for(i = 0; i < nwbackLayer; i++)
weapon_free(wbackLayer[i]);
nwbackLayer = 0;
for(i = 0; i < nwfrontLayer; i++)
weapon_free(wfrontLayer[i]);
nwfrontLayer = 0;
}
void weapon_exit(void) {
weapon_clear();
free(wbackLayer);
free(wfrontLayer);
}