Lephisto/src/pilot.c

254 lines
6.9 KiB
C

#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "main.h"
#include "log.h"
#include "weapon.h"
#include "pilot.h"
// Stack of pilot id's to assure uniqueness.
static unsigned int pilot_id = 0;
// Stack of pilots - yes, they come in stacks now.
Pilot** pilot_stack;
int pilots = 0;
extern Pilot* player;
// External.
extern void ai_destroy(Pilot* p); // Ai.
extern void player_think(Pilot* pilot); // Player.c
extern void ai_think(Pilot* pilot); // Ai.c
// Internal.
static void pilot_update(Pilot* pilot, const double dt);
void pilot_render(Pilot* pilot);
static void pilot_free(Pilot* p);
// Pull a pilot out of the pilot_stack based on id.
Pilot* get_pilot(unsigned int id) {
// Regular search.
#if 0
for(int i = 0; i < pilots; i++)
if(pilot_stack[i]->id == id)
return pilot_stack[i];
return NULL;
#endif
if(id == 0) return player;
// Dichotomical search.
int i, n;
for(i = 0, n = pilots/2; n > 0; n /= 2)
i += (pilot_stack[i+n]->id > id) ? 0 : n;
return (pilot_stack[i]->id == id) ? pilot_stack[i] : NULL;
}
// Mkay, this is how we shoot. Listen up.
void pilot_shoot(Pilot* p, int secondary) {
int i;
if(!secondary) {
// Primary weapons.
if(!p->outfits) return; // No outfits.
for(i = 0; p->outfits[i].outfit; i++) // Cycle through outfits to find weapons.
if(outfit_isWeapon(p->outfits[i].outfit) || // Is a weapon or launch?
outfit_isLauncher(p->outfits[i].outfit))
// Ready to shoot again.
if((SDL_GetTicks()-p->outfits[i].timer) > (p->outfits[i].outfit->delay/p->outfits[i].quantity))
// Different weapons have different behaviours.
switch(p->outfits[i].outfit->type) {
case OUTFIT_TYPE_BOLT:
weapon_add(p->outfits[i].outfit, p->solid->dir, &p->solid->pos,
&p->solid->vel, p->id, (p==player) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG);
p->outfits[i].timer = SDL_GetTicks();
break;
default:
break;
}
}
}
// Damage the pilot.
void pilot_hit(Pilot* p, double damage_shield, double damage_armor) {
if(p->shield - damage_shield > 0.)
p->shield -= damage_shield;
else if(p->shield > 0.) {
// Shields can take part of the blow.
p->armor -= p->shield/damage_shield*damage_armor;
p->shield = 0.;
}
else if(p->armor-damage_armor > 0.)
p->armor -= damage_armor;
else
p->armor = 0.;
}
// Render the pilot.
void pilot_render(Pilot* p) {
int sprite;
gl_texture* t = p->ship->gfx_space;
// Get the sprite corresponding to the direction facing.
sprite = (int)(p->solid->dir / (2.0*M_PI / (t->sy * t->sx)));
gl_blitSprite(t, &p->solid->pos, sprite % (int)t->sx, sprite / (int)t->sy);
}
// Update the pilot.
static void pilot_update(Pilot* pilot, const double dt) {
// Regeneration.
if(pilot->armor < pilot->armor_max)
pilot->armor += pilot->ship->armor_regen*dt;
else
pilot->shield += pilot->ship->shield_regen*dt;
if(pilot->armor > pilot->armor_max) pilot->armor = pilot->armor_max;
if(pilot->armor > pilot->armor_max) pilot->armor = pilot->armor_max;
if((pilot->solid->dir > 2.*M_PI) || (pilot->solid->dir < 0.0))
pilot->solid->dir = fmod(pilot->solid->dir, 2.*M_PI);
// Update the solid.
pilot->solid->update(pilot->solid, dt);
if(VMOD(pilot->solid->vel) > pilot->ship->speed) {
// Should not go faster.
vect_pset(&pilot->solid->vel, pilot->ship->speed, VANGLE(pilot->solid->vel));
}
pilot_render(pilot);
}
// ==Init pilot.===========================================
// ship : Ship pilot is flying.
// name : Pilot's name, if NULL, ships name will be used.
// dir : Initial facing direction. (radians)
// vel : Initial velocity.
// pos : Initial position.
// flags : Tweaking the pilot.
// ========================================================
void pilot_init(Pilot* pilot, Ship* ship, char* name, const double dir, const Vec2* pos,
const Vec2* vel, const int flags) {
if(flags & PILOT_PLAYER) // Player is ID 0
pilot->id = 0;
else
pilot->id = ++pilot_id; // New unique pilot id based on pilot_id, Can't be 0.
pilot->ship = ship;
pilot->name = strdup((name == NULL) ? ship->name : name);
pilot->solid = solid_create(ship->mass, dir, pos, vel);
// Max shields armor.
pilot->armor_max = ship->armor;
pilot->shield_max = ship->shield;
pilot->energy_max = ship->energy;
pilot->armor = pilot->armor_max;
pilot->shield = pilot->shield_max;
pilot->energy = pilot->energy_max;
// Initially idle.
pilot->task = NULL;
// Outfits.
pilot->outfits = NULL;
ShipOutfit* so;
if(ship->outfit) {
int noutfits = 0;
for(so = ship->outfit; so; so = so->next) {
pilot->outfits = realloc(pilot->outfits, (noutfits+1)*sizeof(PilotOutfit));
pilot->outfits[noutfits].outfit = so->data;
pilot->outfits[noutfits].quantity = so->quantity;
pilot->outfits[noutfits].timer = 0;
noutfits++;
}
// Sentinal.
pilot->outfits = realloc(pilot->outfits, (noutfits+1)*sizeof(PilotOutfit));
pilot->outfits[noutfits].outfit = NULL;
pilot->outfits[noutfits].quantity = 0;
pilot->outfits[noutfits].timer = 0;
}
if(flags & PILOT_PLAYER) {
pilot->think = player_think; // Players don't need to thing! :P
pilot->render = NULL;
pilot->properties |= PILOT_PLAYER;
player = pilot;
} else {
pilot->think = ai_think;
pilot->render = pilot_render;
}
pilot->update = pilot_update;
}
// Create a new pilot - Params are same as pilot_init. Return pilot's id.
unsigned int pilot_create(Ship* ship, char* name, const double dir,
const Vec2* pos, const Vec2* vel, const int flags) {
Pilot* dyn = MALLOC_L(Pilot);
if(dyn == NULL) {
WARN("Unable to allocate memory.");
return 0;
}
pilot_init(dyn, ship, name, dir, pos, vel, flags);
if(flags & PILOT_PLAYER) {
// Player.
if(!pilot_stack) {
pilot_stack = MALLOC_L(Pilot*);
pilots = 1;
}
pilot_stack[0] = dyn;
} else {
// Add to the stack.
pilot_stack = realloc(pilot_stack, ++pilots*sizeof(Pilot*));
pilot_stack[pilots-1] = dyn;
}
return dyn->id;
}
// Frees and cleans up a pilot.
static void pilot_free(Pilot* p) {
solid_free(p->solid);
free(p->outfits);
free(p->name);
ai_destroy(p);
free(p);
}
// Destroy pilot from stack.
void pilot_destroy(Pilot* p) {
int i;
for(i = 0; i < pilots; i++)
if(pilot_stack[i] == p)
break;
while(i < pilots) {
pilot_stack[i] = pilot_stack[i+1];
i++;
}
pilot_free(p);
}
// Free the prisoned pilot!
void pilots_free(void) {
int i;
for(i = 0; i < pilots; i++)
pilot_free(pilot_stack[i]);
free(pilot_stack);
}
// Update all pilots.
void pilots_update(double dt) {
int i;
for(i = 0; i < pilots; i++) {
if(pilot_stack[i]->think)
pilot_stack[i]->think(pilot_stack[i]);
if(pilot_stack[i]->update)
pilot_stack[i]->update(pilot_stack[i], dt);
if(pilot_stack[i]->render)
pilot_stack[i]->render(pilot_stack[i]);
}
}