PCBrawl/src/sandbag.c

212 lines
5.4 KiB
C

#include "sandbag.h"
#include "attack.h"
#include "conf.h"
#include "level.h"
#include "lzy.h"
#include "particle.h"
#include "tools.h"
static struct Sandbag sandbag;
static void sandbag_move(struct Vec2 spd);
static struct Vec2 sandbag_update_rem();
static int sandbag_collide_pixel(int x, int y, tile_t id);
static int sandbag_collide(int x, int y, tile_t id, int h);
void sandbag_init(void) {
sandbag.pos = (struct Vec2){300, 96};
sandbag.spd = (struct FVec2){0.0f, 0.0f};
sandbag.rem = (struct FVec2){0.0f, 0.0f};
sandbag.dir = (struct Vec2){1, 0};
sandbag.hitstun = 0;
sandbag.iced = 0;
sandbag.life = 0;
sandbag.active = 1;
}
void sandbag_update(int frame) {
const struct Vec2 level_dim = level_get_dim();
if (!sandbag.active)
return;
const struct Attack *attack =
attack_table_collide(sandbag.pos.x, sandbag.pos.y, 24, 24, 0);
if (attack != NULL) {
sandbag.spd.x =
attack->dir.x * 5 * (sandbag.life > 50 ? (float)sandbag.life / 50 : 1);
sandbag.spd.y = -attack->dir.y * 5 *
(sandbag.life > 50 ? (float)sandbag.life / 100 + 0.5 : 1);
if (!sandbag.hitstun) {
sandbag.life += attack->dam;
LZY_Sleep(10);
};
sandbag.hitstun = 5;
if (attack->ice) {
sandbag.iced = 30;
}
}
sandbag.spd.x *= (1 - AIR_FRIC) / (sandbag.iced ? 2 : 1);
sandbag.spd.y += GRAVITY;
if (sandbag.spd.x) {
sandbag.dir.x = sign(sandbag.spd.x);
}
sandbag_move(sandbag_update_rem());
if (sandbag.hitstun > 0) {
sandbag.hitstun -= 1;
}
if (sandbag.iced > 0) {
sandbag.iced -= 1;
}
if (sandbag.hitstun && frame % 2 && sandbag.life > 80) {
particle_new(sandbag.pos.x + 12, sandbag.pos.y + 12, 10 + rand() % 2, 5);
}
if (frame % 4 && sandbag.life > 120) {
particle_new(sandbag.pos.x + 12, sandbag.pos.y + 12,
12 + (frame % 8) / 2 % 2, 2);
}
if (sandbag.pos.x > level_dim.x * TILE_S + 48 || sandbag.pos.x < -72 ||
sandbag.pos.y > level_dim.y * TILE_S + 48 || sandbag.pos.y < -96) {
sandbag_init();
}
}
static struct Vec2 sandbag_update_rem(void) {
struct FVec2 spdrem = (struct FVec2){sandbag.spd.x + sandbag.rem.x,
sandbag.spd.y + sandbag.rem.y};
struct Vec2 ispd = (struct Vec2){spdrem.x, spdrem.y};
sandbag.rem.x = spdrem.x - (float)ispd.x;
sandbag.rem.y = spdrem.y - (float)ispd.y;
return ispd;
}
static void sandbag_move(struct Vec2 spd) {
if (sandbag_collide(sandbag.pos.x, sandbag.pos.y, 1, 4)) {
return;
}
/* OOB */
const struct Vec2 level_dim = level_get_dim();
int coll_shift = 0;
const int sign_x = sign(spd.x);
if (sign_x) {
sandbag.dir.x = sign_x;
}
if (spd.x) {
sandbag.pos.x += spd.x;
if (sandbag_collide(sandbag.pos.x, sandbag.pos.y, 1, 1)) {
for (float i = 0.1f; i < 4; i += 0.1) {
if (!sandbag_collide(sandbag.pos.x, sandbag.pos.y + i, 1, 1)) {
sandbag.pos.y += i;
coll_shift = 1;
break;
}
if (!sandbag_collide(sandbag.pos.x, sandbag.pos.y - i, 1, 1)) {
sandbag.pos.y -= i;
coll_shift = 1;
break;
}
}
}
if (sandbag_collide(sandbag.pos.x, sandbag.pos.y, 1, 1)) {
if (abs(sandbag.spd.x) > 16) {
sandbag.spd.x = -sandbag.spd.x / 4;
} else {
sandbag.spd.x = 0.0f;
}
sandbag.rem.x = 0.0f;
while (sandbag_collide(sandbag.pos.x, sandbag.pos.y, 1, 1)) {
sandbag.pos.x -= sign_x;
}
}
}
const int sign_y = sign(spd.y);
if (sign_y) {
sandbag.dir.y = sign_y;
}
if (spd.y && !coll_shift) {
sandbag.pos.y += spd.y;
if (sandbag_collide(sandbag.pos.x, sandbag.pos.y, 1, 1)) {
for (float i = 0.1f; i < 4; i += 0.1) {
if (!sandbag_collide(sandbag.pos.x + i, sandbag.pos.y, 1, 1)) {
sandbag.pos.x += i;
break;
}
if (!sandbag_collide(sandbag.pos.x - i, sandbag.pos.y, 1, 1)) {
sandbag.pos.x -= i;
break;
}
}
}
if (sandbag_collide(sandbag.pos.x, sandbag.pos.y, 1, 1)) {
if (abs(sandbag.spd.y) > 16) {
sandbag.spd.y = -sandbag.spd.y / 4;
} else {
sandbag.spd.y = 0.0f;
}
sandbag.rem.y = 0.0f;
while (sandbag_collide(sandbag.pos.x, sandbag.pos.y, 1, 1)) {
sandbag.pos.y -= sign_y;
}
}
}
}
void sandbag_draw(int frame) {
if (!sandbag.active)
return;
if (sandbag.hitstun) {
LZY_DrawTile(39, sandbag.pos.x, sandbag.pos.y);
} else {
LZY_DrawTile(38, sandbag.pos.x, sandbag.pos.y);
}
if (sandbag.iced > 0) {
LZY_DrawTile(16, sandbag.pos.x, sandbag.pos.y);
}
}
static int sandbag_collide_pixel(int x, int y, tile_t id) {
const tile_t tile = level_get_px(x, y);
if (!tile) {
return 0;
}
if (id == 1) {
return (tile) % TILESET_W;
}
return tile == id;
}
static int sandbag_collide(int x, int y, tile_t id, int h) {
const struct Vec2 pos_tl = (struct Vec2){x + h, y + h};
const struct Vec2 pos_br =
(struct Vec2){x + PLAYER_S - h - 1, y + PLAYER_S - h - 1};
const struct Vec2 middle = (struct Vec2){x + PLAYER_S / 2, y + PLAYER_S / 2};
if (sandbag_collide_pixel(pos_tl.x, pos_tl.y, id) ||
sandbag_collide_pixel(pos_br.x, pos_br.y, id) ||
sandbag_collide_pixel(pos_tl.x, pos_br.y, id) ||
sandbag_collide_pixel(pos_br.x, pos_tl.y, id)) {
return 1;
}
return 0;
}
int sandbag_get_life(void) { return sandbag.life; }