147 lines
3.1 KiB
C
147 lines
3.1 KiB
C
#include "missile.h"
|
|
#include "conf.h"
|
|
#include "level.h"
|
|
#include "polarity.h"
|
|
#include "tile.h"
|
|
#include <gint/display.h>
|
|
#include <stdlib.h>
|
|
|
|
static struct MissileManager manager = {.missiles = NULL};
|
|
|
|
static void missile_init(struct Missile *);
|
|
static void missile_update(struct Missile *, struct VecF target);
|
|
static void missile_draw(const struct Missile *);
|
|
static int collide(int x, int y, int tile);
|
|
static int collide_stopper(int x, int y);
|
|
|
|
void
|
|
missile_manager_init(void)
|
|
{
|
|
int i;
|
|
missile_manager_free();
|
|
manager.n_missiles = level_count(TILE_MISSILE_LAUNCHER);
|
|
manager.missiles = malloc(manager.n_missiles * sizeof(struct Missile));
|
|
|
|
i = manager.n_missiles;
|
|
while (i-- > 0) {
|
|
manager.missiles[i].active = 0;
|
|
manager.missiles[i].cooldown = MISSILE_COOLDOWN;
|
|
}
|
|
}
|
|
|
|
void
|
|
missile_manager_free(void)
|
|
{
|
|
if (manager.missiles != NULL) free(manager.missiles);
|
|
}
|
|
|
|
void
|
|
missile_manager_update(struct VecF target)
|
|
{
|
|
int i = manager.n_missiles;
|
|
while (i-- > 0) {
|
|
struct Missile *const m = &manager.missiles[i];
|
|
if (m->active)
|
|
missile_update(m, target);
|
|
else if (m->cooldown && !--m->cooldown)
|
|
missile_init(m);
|
|
}
|
|
}
|
|
|
|
void
|
|
missile_manager_draw(void)
|
|
{
|
|
int i = manager.n_missiles;
|
|
while (i-- > 0)
|
|
if (manager.missiles[i].active)
|
|
missile_draw(&manager.missiles[i]);
|
|
}
|
|
|
|
void
|
|
missile_new(int x, int y)
|
|
{
|
|
int i = manager.n_missiles;
|
|
struct Missile *m;
|
|
while (i-- > 0 && manager.missiles[i].active)
|
|
;
|
|
m = &manager.missiles[(i > 0) ? (i) : (0)];
|
|
|
|
m->spawn.x = x;
|
|
m->spawn.y = y;
|
|
missile_init(m);
|
|
}
|
|
|
|
void
|
|
missile_init(struct Missile *m)
|
|
{
|
|
m->active = 1;
|
|
m->cooldown = MISSILE_COOLDOWN;
|
|
m->pos.x = m->spawn.x;
|
|
m->pos.y = m->spawn.y;
|
|
m->spd.x = 0.0f;
|
|
m->spd.y = 0.0f;
|
|
}
|
|
|
|
int
|
|
missile_collide_player(const struct Player *p)
|
|
{
|
|
const float x1 = p->pos.x;
|
|
const float y1 = p->pos.y;
|
|
const float x2 = x1 + PLAYER_WIDTH - 1.0f;
|
|
const float y2 = y1 + PLAYER_HEIGHT - 1.0f;
|
|
int i = manager.n_missiles;
|
|
while (i-- > 0) {
|
|
const struct Missile *m = &manager.missiles[i];
|
|
if (m->active && m->pos.x > x1 && m->pos.x < x2 &&
|
|
m->pos.y > y1 && m->pos.y < y2)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
missile_update(struct Missile *m, struct VecF target)
|
|
{
|
|
const struct VecF diff = {target.x - m->pos.x, target.y - m->pos.y};
|
|
const struct VecF dir = normalize(diff);
|
|
|
|
/* acceleration */
|
|
m->spd.x += dir.x * MISSILE_ACCEL;
|
|
m->spd.y += dir.y * MISSILE_ACCEL;
|
|
|
|
/* friction */
|
|
m->spd.x *= 1 - MISSILE_FRICTION;
|
|
m->spd.y *= 1 - MISSILE_FRICTION;
|
|
|
|
/* move */
|
|
m->pos.x += m->spd.x;
|
|
m->pos.y += m->spd.y;
|
|
|
|
/* destroy */
|
|
if (collide_stopper(m->pos.x + 0.5f, m->pos.y + 0.5f))
|
|
m->active = false;
|
|
}
|
|
|
|
static void
|
|
missile_draw(const struct Missile *m)
|
|
{
|
|
extern bopti_image_t bimg_missile;
|
|
const int x = (int)(m->pos.x + 0.5f) - bimg_missile.width / 2;
|
|
const int y = (int)(m->pos.y + 0.5f) - bimg_missile.height / 2;
|
|
dimage(x, y, &bimg_missile);
|
|
}
|
|
|
|
static int
|
|
collide(int x, int y, int tile)
|
|
{
|
|
return level_get_px(x, y) == tile;
|
|
}
|
|
|
|
static int
|
|
collide_stopper(int x, int y)
|
|
{
|
|
return collide(x, y, TILE_SOLID) ||
|
|
(!polarity() && collide(x, y, TILE_RED)) ||
|
|
(polarity() && collide(x, y, TILE_BLUE));
|
|
}
|