#include "animation.h" #include "asset.h" #include "config.h" #include "maths.h" #include "obj.h" #include "physics.h" #include "render.h" #include "world.h" enum { enemy_state_patrol, enemy_state_approach, enemy_state_approach2, enemy_state_attack }; int get_enemy_hp(Enemy_Type t) { switch (t) { case enemy_demon: return 3; } return 0; } void get_enemy_rect(Enemy_Type t, Rect* d) { switch (t) { case enemy_demon: d->x = 2; d->y = 2; d->w = 12; d->h = 14; break; } } void init_enemy(Enemy* e, Enemy_Type t, int x, int y) { e->t = t; e->x = x; e->y = y; e->vx = 0; e->vy = 0; e->hp = get_enemy_hp(t); e->frame = 0; e->anim = asset_id_demon_idle_left_anm; e->face = face_left; e->state = enemy_state_patrol; e->inv = 0; } void update_enemy_anim(Enemy* e) { int done; const Animation* anim = get_animation(e->anim); done = update_anim(anim, &e->frame, &e->rect); if ( done && e->t == enemy_demon && e->state == enemy_state_approach ) { e->state = enemy_state_approach2; } } void update_enemy_phys(Enemy* e, const Map* map) { Rect r; get_enemy_rect(e->t, &r); r.x <<= fbits; r.y <<= fbits; r.w <<= fbits; r.h <<= fbits; update_body( map, &e->x, &e->y, &e->vx, &e->vy, &e->grounded, &e->headbutted, &e->on_ramp, &r ); } void update_enemy_hurt(Enemy* e, World* w) { Rect a; int i, cx, cy; if (e->inv) { e->inv--; return; } get_enemy_rect(e->t, &a); a.x += e->x >> fbits; a.y += e->y >> fbits; cx = (a.x << fbits) + ((a.w >> 1) << fbits); cy = (a.y << fbits) + ((a.h >> 1) << fbits); for (i = 0; i < w->deathzone_count; i++) { const Deathzone* dz = &w->deathzones[i]; if (dz->friendly && rects_overlap(&a, &dz->r)) { e->hp -= dz->hp; e->vx -= dz->vx; e->vy -= dz->vy; e->inv = enemy_inv_frames; w->player.charge++; w->freeze += enemy_hurt_freeze; inst_effect(w, cx, cy, -dz->vx, -dz->vy, 32); } } } int tile_at(const Map* m, int x, int y) { return x < 0 || y < 0 || x >= map_w || y >= map_h || m->collision[x + y * map_w] == 1; } void update_demon_move(Enemy* e, World* w) { int nanim = e->anim; const Player* p = &w->player; if (e->state == enemy_state_patrol) { int dx = e->x - p->x; int dy = e->y - p->y; int dx2 = dx >> fbits; int dy2 = dy >> fbits; int dist = fxsqrt(dx * dx2 + dy * dy2) >> fbits; if (e->grounded < 3) { int tx, ty = ((e->y >> fbits) + (map_tile_size >> 1)) / map_tile_size; int ty2 = ty + 1; if (e->face == face_left) { tx = ( (e->x >> fbits) - (map_tile_size >> 1)) / map_tile_size; } else { tx = ( (e->x >> fbits) + map_tile_size + (map_tile_size >> 1)) / map_tile_size; } if ( tile_at(&w->map, tx, ty) || (!e->on_ramp && ty2 < map_h && !tile_at(&w->map, tx, ty2)) ) e->face = !e->face; if (e->face == face_left) { e->vx -= enemy_demon_move_force; } else { e->vx += enemy_demon_move_force; } } if (dist < enemy_demon_attack_dist) { e->state = enemy_state_approach; } } else if (e->state == enemy_state_approach) { if (p->x < e->x) e->face = face_left; else e->face = face_right; } else if (e->state == enemy_state_approach2) { if (e->grounded < 3) { e->vx = (p->x - e->vx) / 120; if (e->face == face_left) e->vx = -e->vx; e->vy = -enemy_demon_jump_force; e->grounded = 100; e->state = enemy_state_attack; } } else if (e->state == enemy_state_attack) { if (e->grounded < 3) { Asset_ID sl; Rect dz; int sx, sy = e->y >> fbits, vx; if (e->face == face_left) { sl = asset_id_smol_slash_left_anm; sx = (e->x >> fbits) - 16; vx = enemy_knockback; } else { sl = asset_id_smol_slash_right_anm; sx = (e->x >> fbits) + 16; vx = -enemy_knockback; } dz.x = sx; dz.y = sy; dz.w = 16; dz.h = 12; inst_particle(w, sx, sy, sl, asset_id_arms_img); inst_deathzone(w, &dz, vx, 0, enemy_slash_damage, 4, 0); e->state = enemy_state_patrol; } } switch (e->face) { case face_left: nanim = e->state == enemy_state_patrol? asset_id_demon_walk_left_anm: e->state == enemy_state_approach? asset_id_demon_jump_left_anm: asset_id_demon_idle_left_anm; break; case face_right: nanim = e->state == enemy_state_patrol? asset_id_demon_walk_right_anm: e->state == enemy_state_approach? asset_id_demon_jump_right_anm: asset_id_demon_idle_right_anm; break; } if (nanim != e->anim) { e->frame = 0; e->anim = nanim; } } void update_enemy_move(Enemy* e, World* w) { switch (e->t) { case enemy_demon: update_demon_move(e, w); break; } } int update_enemy(Enemy* e, World* w) { update_enemy_anim(e); update_enemy_hurt(e, w); update_enemy_move(e, w); update_enemy_phys(e, &w->map); return e->hp <= 0; } void ren_enemy(const Enemy* e, struct Renderer* r) { const Bitmap* b = get_bitmap(asset_id_npc_img); ren_map(r, e->x >> fbits, e->y >> fbits, &e->rect, b); }