#include #include #include #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)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); }