#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, const World* w) { Rect a; int i; if (e->inv) { e->inv--; return; } get_enemy_rect(e->t, &a); a.x += e->x >> fbits; a.y += e->y >> fbits; for (i = 0; i < w->deathzone_count; i++) { const Deathzone* dz = &w->deathzones[i]; if (rects_overlap(&a, &dz->r)) { e->hp -= dz->hp; e->vx -= dz->vx; e->vy -= dz->vy; e->inv = enemy_inv_frames; } } } 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, const 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 + 2; 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) || (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) / 100; 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) { 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, const 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); }