1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
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)
}
clear(&state.enemy_list)
}
on_room_open_enemies :: proc(room_id: Room_Id) {
clear_enemies()
}
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")
}
|