@@ -10,9 +10,17 @@ defmodule BotManager.BotStateMachine do
10
10
11
11
@ skill_1_key "1"
12
12
@ skill_2_key "2"
13
- @ dash_skill_key "3"
14
13
15
- def decide_action ( % { enabled?: false , bot_state_machine: bot_state_machine } ) do
14
+ # The minimum distance a tracked player has to move for the tracking path to
15
+ # get recalculated
16
+ @ path_recalculation_min_diff 300
17
+
18
+ def decide_action ( % { bots_enabled?: false , bot_state_machine: bot_state_machine } ) do
19
+ % { action: { :move , % { x: 0 , y: 0 } } , bot_state_machine: bot_state_machine }
20
+ end
21
+
22
+ def decide_action ( % { bot_player: % { aditional_info: { :player , % { health: health } } } , bot_state_machine: bot_state_machine } )
23
+ when health <= 0 do
16
24
% { action: { :move , % { x: 0 , y: 0 } } , bot_state_machine: bot_state_machine }
17
25
end
18
26
@@ -29,31 +37,57 @@ defmodule BotManager.BotStateMachine do
29
37
bot_state_machine = preprocess_bot_state ( bot_state_machine , bot_player )
30
38
next_state = BotStateMachineChecker . move_to_next_state ( bot_player , bot_state_machine , game_state . players )
31
39
32
- if System . get_env ( "PATHFINDING_TEST" ) == "true" do
33
- move ( bot_player , bot_state_machine , game_state . zone . radius )
34
- else
35
- case next_state do
36
- :moving ->
37
- move ( bot_player , bot_state_machine , game_state . zone . radius )
38
-
39
- :attacking ->
40
- use_skill ( % {
41
- bot_player: bot_player ,
42
- bot_state_machine: bot_state_machine ,
43
- game_state: game_state ,
44
- attack_blocked: attack_blocked ,
45
- bot_skills: skills
46
- } )
47
-
48
- :tracking_player ->
49
- track_player ( game_state , bot_player , bot_state_machine )
50
- end
40
+ bot_state_machine = maybe_exit_state ( bot_state_machine , next_state )
41
+
42
+ case next_state do
43
+ :moving ->
44
+ move ( bot_state_machine , game_state . zone . radius )
45
+
46
+ :attacking ->
47
+ use_skill ( % {
48
+ bot_player: bot_player ,
49
+ bot_state_machine: bot_state_machine ,
50
+ game_state: game_state ,
51
+ attack_blocked: attack_blocked ,
52
+ bot_skills: skills
53
+ } )
54
+
55
+ :tracking_player ->
56
+ bot_state_machine = maybe_set_tracking_path ( game_state , bot_player , bot_state_machine )
57
+ track_player ( game_state , bot_player , bot_state_machine )
51
58
end
52
59
end
53
60
54
61
def decide_action ( % { bot_state_machine: bot_state_machine } ) ,
55
62
do: % { action: :idling , bot_state_machine: bot_state_machine }
56
63
64
+ # This function will handle state switching logic to leave the bot state machine in a proper state
65
+ defp maybe_exit_state ( % { state: state } = bot_state_machine , state ) do
66
+ bot_state_machine
67
+ end
68
+
69
+ defp maybe_exit_state ( % { state: state } = bot_state_machine , new_state ) do
70
+ bot_state_machine
71
+ |> Map . put ( :state , new_state )
72
+ |> Map . put ( :last_time_state_changed , :os . system_time ( :millisecond ) )
73
+ |> exit_state ( state )
74
+ end
75
+
76
+ # updates necessary data to exit each specific state
77
+ defp exit_state ( bot_state_machine , :tracking_player ) do
78
+ bot_state_machine
79
+ |> Map . put ( :last_time_tracking_exited , :os . system_time ( :millisecond ) )
80
+ end
81
+
82
+ defp exit_state ( bot_state_machine , :attacking ) do
83
+ bot_state_machine
84
+ |> Map . put ( :last_time_attacking_exited , :os . system_time ( :millisecond ) )
85
+ end
86
+
87
+ defp exit_state ( bot_state_machine , _exited_state ) do
88
+ bot_state_machine
89
+ end
90
+
57
91
@ doc """
58
92
This function will be in charge of using the bot's skill.
59
93
Depending on the bot's state, it will use the basic skill, the ultimate skill or move.
@@ -81,7 +115,7 @@ defmodule BotManager.BotStateMachine do
81
115
)
82
116
83
117
if Enum . empty? ( players_with_distances ) do
84
- move ( bot_player , bot_state_machine , game_state . zone . radius )
118
+ move ( bot_state_machine , game_state . zone . radius )
85
119
else
86
120
bot_state_machine =
87
121
Map . put (
@@ -108,7 +142,7 @@ defmodule BotManager.BotStateMachine do
108
142
)
109
143
110
144
if Enum . empty? ( players_with_distances ) do
111
- move ( bot_player , bot_state_machine , game_state . zone . radius )
145
+ move ( bot_state_machine , game_state . zone . radius )
112
146
else
113
147
bot_state_machine =
114
148
Map . put (
@@ -124,44 +158,49 @@ defmodule BotManager.BotStateMachine do
124
158
end
125
159
126
160
true ->
127
- move ( bot_player , bot_state_machine , game_state . zone . radius )
128
- end
129
- end
130
-
131
- # This function will determine the direction and action the bot will take.
132
- defp determine_player_move_action ( bot_player , direction ) do
133
- { :player , bot_player_info } = bot_player . aditional_info
134
-
135
- if System . get_env ( "PATHFINDING_TEST" ) == "true" do
136
- { :move , direction }
137
- else
138
- if Map . has_key? ( bot_player_info . cooldowns , @ dash_skill_key ) do
139
- { :move , direction }
140
- else
141
- { :use_skill , @ dash_skill_key , bot_player . direction }
142
- end
161
+ move ( bot_state_machine , game_state . zone . radius )
143
162
end
144
163
end
145
164
146
- defp track_player ( game_state , bot_player , bot_state_machine ) do
165
+ defp maybe_set_tracking_path ( game_state , bot_player , bot_state_machine ) do
147
166
players_with_distances =
148
167
Utils . map_directions_to_players (
149
168
game_state . players ,
150
169
bot_player ,
151
- Utils . get_action_distance_based_on_action_type (
170
+ Utils . get_action_distance_by_type (
152
171
bot_state_machine . is_melee ,
153
172
bot_state_machine . melee_tracking_range ,
154
173
bot_state_machine . ranged_tracking_range
155
174
)
156
175
)
157
176
158
- if Enum . empty? ( players_with_distances ) do
159
- move ( bot_player , bot_state_machine , game_state . zone . radius )
177
+ closest_player = Enum . min_by ( players_with_distances , & & 1 . distance )
178
+
179
+ cond do
180
+ is_nil ( bot_state_machine . path_towards_position ) or Enum . empty? ( bot_state_machine . path_towards_position ) or
181
+ Vector . distance ( bot_state_machine . position_to_move_to , closest_player . position ) > @ path_recalculation_min_diff ->
182
+ try_pathing_towards ( bot_state_machine , closest_player . position )
183
+
184
+ BotStateMachineChecker . current_waypoint_reached? ( bot_state_machine ) ->
185
+ Map . put ( bot_state_machine , :path_towards_position , tl ( bot_state_machine . path_towards_position ) )
186
+
187
+ true ->
188
+ bot_state_machine
189
+ end
190
+ end
191
+
192
+ defp track_player ( game_state , bot_player , bot_state_machine ) do
193
+ if is_nil ( bot_state_machine . path_towards_position ) || Enum . empty? ( bot_state_machine . path_towards_position ) do
194
+ move ( bot_state_machine , game_state . zone . radius )
160
195
else
161
- closest_player = Enum . min_by ( players_with_distances , & & 1 . distance )
196
+ current_waypoint = hd ( bot_state_machine . path_towards_position )
197
+
198
+ direction =
199
+ Vector . sub ( current_waypoint , bot_player . position )
200
+ |> Vector . normalize ( )
162
201
163
202
% {
164
- action: determine_player_move_action ( bot_player , closest_player . direction ) ,
203
+ action: { :move , direction } ,
165
204
bot_state_machine: bot_state_machine
166
205
}
167
206
end
@@ -185,8 +224,10 @@ defmodule BotManager.BotStateMachine do
185
224
bot_state_machine . current_position
186
225
)
187
226
227
+ new_progress = min ( bot_state_machine . cap_for_basic_skill * 3 , bot_state_machine . progress_for_basic_skill + distance )
228
+
188
229
bot_state_machine =
189
- Map . put ( bot_state_machine , :progress_for_basic_skill , bot_state_machine . progress_for_basic_skill + distance )
230
+ Map . put ( bot_state_machine , :progress_for_basic_skill , new_progress )
190
231
191
232
cond do
192
233
Vector . distance ( bot_state_machine . previous_position , bot_state_machine . current_position ) < 100 &&
@@ -213,9 +254,9 @@ defmodule BotManager.BotStateMachine do
213
254
end
214
255
end
215
256
216
- defp move ( bot_player , bot_state_machine , safe_zone_radius ) do
257
+ defp move ( bot_state_machine , safe_zone_radius ) do
217
258
bot_state_machine =
218
- determine_position_to_move_to ( bot_state_machine , safe_zone_radius , System . get_env ( "PATHFINDING_TEST" ) == "true" )
259
+ determine_position_to_move_to ( bot_state_machine , safe_zone_radius )
219
260
220
261
# TODO instead of using `get_distance_and_direction_to_positions, use the pathfinding module`
221
262
cond do
@@ -227,7 +268,7 @@ defmodule BotManager.BotStateMachine do
227
268
)
228
269
229
270
% {
230
- action: determine_player_move_action ( bot_player , direction ) ,
271
+ action: { :move , direction } ,
231
272
bot_state_machine: bot_state_machine
232
273
}
233
274
@@ -239,7 +280,7 @@ defmodule BotManager.BotStateMachine do
239
280
)
240
281
241
282
% {
242
- action: determine_player_move_action ( bot_player , direction ) ,
283
+ action: { :move , direction } ,
243
284
bot_state_machine: bot_state_machine
244
285
}
245
286
@@ -251,53 +292,19 @@ defmodule BotManager.BotStateMachine do
251
292
end
252
293
end
253
294
254
- defp determine_position_to_move_to ( bot_state_machine , safe_zone_radius , true = _pathfinding_on ) do
255
- cond do
256
- is_nil ( bot_state_machine . collision_grid ) ->
257
- bot_state_machine
258
-
259
- is_nil ( bot_state_machine . path_towards_position ) ->
260
- position_to_move_to = BotManager.Utils . random_position_within_safe_zone_radius ( floor ( safe_zone_radius ) )
261
-
262
- from = % { x: bot_state_machine . current_position . x , y: bot_state_machine . current_position . y }
263
- to = % { x: position_to_move_to . x , y: position_to_move_to . y }
264
-
265
- shortest_path = AStarNative . a_star_shortest_path ( from , to , bot_state_machine . collision_grid )
295
+ defp determine_position_to_move_to ( % { collision_grid: nil } = bot_state_machine , _safe_zone_radius ) do
296
+ bot_state_machine
297
+ end
266
298
267
- # If we don't have a path, retry finding new position in map
268
- if Enum . empty? ( shortest_path ) do
269
- Map . put ( bot_state_machine , :path_towards_position , nil )
270
- |> Map . put ( :position_to_move_to , nil )
271
- else
272
- Map . put ( bot_state_machine , :position_to_move_to , position_to_move_to )
273
- |> Map . put (
274
- :path_towards_position ,
275
- shortest_path
276
- )
277
- |> Map . put ( :last_time_position_changed , :os . system_time ( :millisecond ) )
278
- end
299
+ defp determine_position_to_move_to ( bot_state_machine , safe_zone_radius ) do
300
+ cond do
301
+ is_nil ( bot_state_machine . path_towards_position ) || Enum . empty? ( bot_state_machine . path_towards_position ) ||
302
+ Vector . distance ( % { x: 0 , y: 0 } , bot_state_machine . position_to_move_to ) > safe_zone_radius ->
303
+ try_pick_random_position_to_move_to ( bot_state_machine , safe_zone_radius )
279
304
280
305
BotStateMachineChecker . current_waypoint_reached? ( bot_state_machine ) and
281
306
BotStateMachineChecker . should_bot_move_to_another_position? ( bot_state_machine ) ->
282
- position_to_move_to = BotManager.Utils . random_position_within_safe_zone_radius ( floor ( safe_zone_radius ) )
283
-
284
- from = % { x: bot_state_machine . current_position . x , y: bot_state_machine . current_position . y }
285
- to = % { x: position_to_move_to . x , y: position_to_move_to . y }
286
-
287
- shortest_path = AStarNative . a_star_shortest_path ( from , to , bot_state_machine . collision_grid )
288
-
289
- # If we don't have a path, retry finding new position in map
290
- if Enum . empty? ( shortest_path ) do
291
- Map . put ( bot_state_machine , :path_towards_position , nil )
292
- |> Map . put ( :position_to_move_to , nil )
293
- else
294
- Map . put ( bot_state_machine , :position_to_move_to , position_to_move_to )
295
- |> Map . put (
296
- :path_towards_position ,
297
- shortest_path
298
- )
299
- |> Map . put ( :last_time_position_changed , :os . system_time ( :millisecond ) )
300
- end
307
+ try_pick_random_position_to_move_to ( bot_state_machine , safe_zone_radius )
301
308
302
309
BotStateMachineChecker . current_waypoint_reached? ( bot_state_machine ) ->
303
310
Map . put ( bot_state_machine , :path_towards_position , tl ( bot_state_machine . path_towards_position ) )
@@ -307,23 +314,29 @@ defmodule BotManager.BotStateMachine do
307
314
end
308
315
end
309
316
310
- defp determine_position_to_move_to ( bot_state_machine , safe_zone_radius , false = _pathfinding_on ) do
311
- cond do
312
- is_nil ( bot_state_machine . position_to_move_to ) ||
313
- not Utils . position_within_radius ( bot_state_machine . position_to_move_to , safe_zone_radius ) ->
314
- position_to_move_to = BotManager.Utils . random_position_within_safe_zone_radius ( floor ( safe_zone_radius ) )
317
+ defp try_pick_random_position_to_move_to ( bot_state_machine , safe_zone_radius ) do
318
+ position_to_move_to = BotManager.Utils . random_position_within_safe_zone_radius ( floor ( safe_zone_radius ) )
315
319
316
- Map . put ( bot_state_machine , :position_to_move_to , position_to_move_to )
317
- |> Map . put ( :last_time_position_changed , :os . system_time ( :millisecond ) )
320
+ try_pathing_towards ( bot_state_machine , position_to_move_to )
321
+ end
318
322
319
- BotStateMachineChecker . should_bot_move_to_another_position? ( bot_state_machine ) ->
320
- position_to_move_to = BotManager.Utils . random_position_within_safe_zone_radius ( floor ( safe_zone_radius ) )
323
+ defp try_pathing_towards ( bot_state_machine , position_to_move_to ) do
324
+ from = % { x: bot_state_machine . current_position . x , y: bot_state_machine . current_position . y }
325
+ to = % { x: position_to_move_to . x , y: position_to_move_to . y }
321
326
322
- Map . put ( bot_state_machine , :position_to_move_to , position_to_move_to )
323
- |> Map . put ( :last_time_position_changed , :os . system_time ( :millisecond ) )
327
+ shortest_path = AStarNative . a_star_shortest_path ( from , to , bot_state_machine . collision_grid )
324
328
325
- true ->
326
- bot_state_machine
329
+ # If we don't have a path, retry finding new position in map
330
+ if Enum . empty? ( shortest_path ) do
331
+ Map . put ( bot_state_machine , :path_towards_position , nil )
332
+ |> Map . put ( :position_to_move_to , nil )
333
+ else
334
+ Map . put ( bot_state_machine , :position_to_move_to , position_to_move_to )
335
+ |> Map . put (
336
+ :path_towards_position ,
337
+ shortest_path
338
+ )
339
+ |> Map . put ( :last_time_position_changed , :os . system_time ( :millisecond ) )
327
340
end
328
341
end
329
342
end
0 commit comments