package demonchime import "base:intrinsics" import "core:math" import "core:log" import hm "core:container/handle_map" import "fw" import "phys" Enemy_Ai :: enum(u16) { None, Corpse, Muntik, } Enemy_Update_Callback :: #type proc(^Enemy, f32) update_funcs := [Enemy_Ai]Enemy_Update_Callback{ .None = noop_ai, .Corpse = corpse_ai, .Muntik = update_muntik, } Enemy_Stats :: struct { max_health: i16, defense: i16, } Enemy :: struct { handle: int, sprite: Sprite, body: phys.Body_Handle, stats: ^Enemy_Stats, hit_timestamp: f32, ai: Enemy_Ai, health: i16, variant: union { ^Muntik, }, } make_enemy :: proc( $T: typeid, stats: ^Enemy_Stats, sprite: Sprite, body: phys.Body_Handle ) -> ^T where intrinsics.type_has_field(T, "enemy"), intrinsics.type_field_type(T, "enemy") == Enemy { e := new(T) e.enemy.stats = stats e.enemy.sprite = sprite e.enemy.body = body e.enemy.health = stats.max_health e.enemy.variant = e phys.set_udata(body, &e.enemy) e.enemy.handle = len(state.enemy_list) append(&state.enemy_list, e) return e } enemy_take_damage :: proc(e: ^Enemy, damage: i16, kb_dir: Vec2) { kb_dir := kb_dir e.hit_timestamp = f32(fw.get_time()) total_damage := math.max(damage - e.stats.defense, 1) e.health -= total_damage e.health = math.max(e.health, 0) if e.health == 0 { e.ai = .Corpse phys.set_velocity(e.body, kb_dir) } else { vel := phys.get_velocity(e.body) + kb_dir phys.set_velocity(e.body, vel) } } update_enemies :: proc(dt: f32) { for e in state.enemy_list { update_funcs[e^.ai](e, dt) e.sprite.pos = phys.get_position(e.body) update_sprite(&e.sprite, dt) phys.update_body(e.body) } } draw_enemies :: proc() { for e in state.enemy_list { draw_sprite(e^.sprite) } } clear_enemies :: proc() { for e in state.enemy_list { phys.remove_body(e^.body) free(e) } } noop_ai :: proc(e: ^Enemy, _: f32) {} corpse_ai :: proc(e: ^Enemy, dt: f32) { e.sprite.tint = Color{0.5, 0.5, 0.5, 1} vel := phys.get_velocity(e.body) vel.x = dt_lerp(vel.x, 0, 20) vel.y = math.min(vel.y + GRAVITY * dt, TERMINAL_VELOCITY) phys.set_velocity(e.body, vel) set_sprite_active_tag(&e.sprite, "dead") }