#include "missile.h" #include "conf.h" #include "level.h" #include "polarity.h" #include "tile.h" #include #include 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)); }