-
Notifications
You must be signed in to change notification settings - Fork 0
/
ai.lua
162 lines (139 loc) · 4.77 KB
/
ai.lua
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
local ai = {actions = {}, routines = {}, sequences = {}}
-- enemy ai consists of:
-- control = "enemy" so actor_update runs it
-- routines = {} : a priority list, containing functions in priority order (more important first)
-- these are conditionals like "if the player is within X distance, shoot at her"
-- each function should first test the condition and return FALSE if it's not met
-- if the condition is met, react appropriately by setting a.controls, then return TRUE
-- generally should have a "default" function at the end with no condition
-- data = {} : a place for routines to store stuff like timers
function ai.setup(a, routine)
a.ai.routine = ai.routines[routine] -- remember this is pass by ref, not a copy
a.ai.data = {}
-- routine-specific setup stuff, e.g. assigning wake_time
if a.ai.routine.setup then
a.ai.routine.setup(a)
end
end
function ai.process(a)
for i,v in ipairs(a.ai.routine) do
v(a)
end
if a.controls.fire_1 then
a.controls.aim_x, a.controls.aim_y = player.x, player.y
end
-- face forward
if a.controls.x == 1 then
a.facing = 'r'
else
a.facing = 'l'
end
end
-- actions
ai.actions["jump"] = function(a) a.controls.jump = true end
ai.actions["dash forward"] = function(a) if a.facing == 'r' then a:dash_right() else a:dash_left() end end
ai.actions["reverse"] = function(a) a.controls.x = a.controls.x * -1 end
ai.actions["start shooting"] = function(a) a.controls.fire_1 = true end
ai.actions["stop shooting"] = function(a) a.controls.fire_1 = false end
ai.actions["change color"] = function(a, r, g, b) a.color = {r, g, b} end
ai.actions["set fly height"] = function(a, y) a.ai.data.fly_height = y end
ai.actions["random direction"] = function(a) if mymath.one_chance_in(2) then a.controls.x = 1 else a.controls.x = -1 end end
ai.actions["bounce off walls"] = function(a)
if (a.controls.x == 1 and a:is_touching_right()) or (a.controls.x == -1 and a:is_touching_left()) then
a.controls.x = -a.controls.x
-- return true
end
end
ai.actions["bounce off ledges"] = function(a)
if (a.controls.x == 1 and a:is_on_ledge_right()) or (a.controls.x == -1 and a:is_on_ledge_left()) then
a.controls.x = -a.controls.x
-- return true
end
end
ai.actions["setup fly"] = function(a)
a.ai.data.fly_timer = 0
a.ai.data.fly_height = a.y
end
ai.actions["fly"] = function(a)
-- flap to maintain a height of a.data.fly_height
-- delay is slightly randomized to make it look sort of ragged
-- requires a.flies = true or it'll be very stupid
if ctime > a.ai.data.fly_timer then
a.controls.jump = true
local ky = a.y - a.ai.data.fly_height
if ky > 100 then
a.ai.data.fly_timer = ctime + 0.15 + love.math.random()/10
elseif ky < -100 then
a.ai.data.fly_timer = ctime + 0.35 + love.math.random()/10
else
a.ai.data.fly_timer = ctime + 0.25 - ky/1000 + love.math.random()/10
end
-- return true
end
end
local dist
ai.actions["shoot player if close"] = function(a)
dist = mymath.dist(a.x, a.y, player.x, player.y)
if dist < 200 then
ai.actions["start shooting"](a)
elseif dist > 250 then
ai.actions["stop shooting"](a)
end
end
ai.actions["setup sequence"] = function(a)
a.ai.data.sequence_timer = 0
a.ai.data.sequence_step = 1
end
local action
ai.actions["run sequence"] = function(a)
-- run through a sequence of actions
-- the sequence table needs to be in a.ai.data.sequence
-- should continue if interrupted; run "setup sequence" to restart
if ctime >= a.ai.data.sequence_timer then
action = ai.sequences[a.ai_sequence][a.ai.data.sequence_step]
if type(action) == "string" then
-- run a function
ai.actions[action](a)
elseif type(action) == "number" then
-- sleep for N seconds before processing again
a.ai.data.sequence_timer = a.ai.data.sequence_timer + action
elseif type(action) == "table" then
-- run a function w/ params
ai.actions[action[1]](a, action[2], action[3], action[4])
end
a.ai.data.sequence_step = (a.ai.data.sequence_step + 1)
if a.ai.data.sequence_step > #ai.sequences[a.ai_sequence] then
a.ai.data.sequence_step = 1
end
end
end
ai.sequences["test"] =
{
{"change color", 100, 200, 0}, 5,
"reverse", 1,
{"change color", 200, 0, 100}, 2,
"jump", 0.3,
"jump", 2
}
ai.sequences["fly around"] =
{
{"set fly height", 300, 0, 0}, 4,
{"set fly height", 100, 0, 0}, 4,
}
-- routines
ai.routines["flyer"] =
{
ai.actions["bounce off walls"],
ai.actions["fly"],
-- ai.actions["shoot player if close"],
ai.actions["run sequence"],
setup = function(a) ai.actions["random direction"](a) ai.actions["setup fly"](a) ai.actions["setup sequence"](a) end,
}
ai.routines["walker"] =
{
ai.actions["bounce off walls"],
-- ai.actions["bounce off ledges"],
-- ai.actions["shoot player if close"],
setup = function(a) ai.actions["random direction"](a) end,
}
return ai