-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot.lua
395 lines (343 loc) · 11.1 KB
/
bot.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
-- for ao-effect quest3
LatestGameState = LatestGameState or nil
InAction = InAction or false
Paying = Paying or false
LockingTarget = LockingTarget or nil
Game = Game or "y2SumslSgziUYIUYYlGXAXPcxLXexIkbaxxsNa9_VXg"
CRED = CRED or "Sa0iBLPNyJQrwpTTG-tWLQU-1QeUAJA73DdxGGiKoJc"
DirectionMap = {"Up", "Down", "Left", "Right", "UpRight", "UpLeft", "DownRight", "DownLeft"}
targetBotsArr = {
"mKdpg-ehoQBgI-U7xkEU3Op2gx_VQZgbfkinIYYTeGI",
"o7ojWM_2GCpjEq9LbQpNt98rK0yYR5sttDbXn_m7jgA",
"ET1HkDJVwGp9nDDyAeDkCOm7nU4ymi4vkmLS3rdSsXo",
"30mgE3JEqs8AugY6pvU7rULhH6tlG4O3vVaTpkq475o",
"fBxEuKHCJ9BWy9dcuJfXjkSFQa3JzRozZwLQgCzFkuw",
"DdHbetrd4MDVpR9PhfGrp8c0ODaIVcWNWe208CrOtSY",
"LQi8j9zpZbMn4uAsRFttn1Wt282yKiLFHd5fbluW7bk",
"PWu5xrOORfcbVPkCXpOlMuvsXuKUoFhChmrBLcS2t5g",
"M_AiUdJeKFhnOz8HeiUQXcr8NNX-2oHYhSeReuWe_14",
"xLZ0l0HbAFaxq5n-sSmKZhcFGPvDe1weSYr1vTF6EnY",
"6-m4zbMA9VLLpXo6xqq2UCydNPtFiSnHHDfWBbPOQHo",
"M8dBmtGdsa83UQ8npuqdBl0XJwmk6hmPq9JiuPA1kK4",
"a5Qvu1O66ItP55kNWfm_EhNAUXPYGZkLCKkB7zCGvXE",
"4NFvD-hvpyOr4IzRlDYyBaqNQLJR7srtOJbUAkH8Gzc",
"7TR6O945kNFwmtDpW3jlHVU7ZxxjScF2vAmuDdPLn5Q",
"DoXjMdlQXjvf3UiGry5ggSTNt8elOpFEGoqJ4ioz-68",
"EALJxoB5JI-7XfVg4Oi3dzgbGgpZIddBNVqEdx_ES34",
"WfcLC-f72DfFQ-g3ueNzst4e_fB-5OIr8_8nXzLxRU4",
"8DK4qfJ4ZclwSSdEcb8_IucH4pDZghrNd0btwZ1PvU4",
"eHHCy8YcqnvsGjkvB72EzQnrlbEe4ETIForCDrkQGbg",
"GJVGLcouQdkPqDYpS3p6LOUmy7YEfEddQ0U-9dbRih8",
"uCiLRxpyklG7Dr9taYXcSdDpHepSp-FsA-_790ntuuY",
"Umr_HFG5PB8rovJyTcLTGlVgRg0josFPGhwTzEf_cow",
"OZl8GA2JbjNtt2P3l0-fv20TO0G-OPUuwPag-TcOssE",
"EnuADvlYGmlCF9rokuBkhgTiFU13HiJj7qqNd2EZ_-A",
"FPG8Cdbc7ppvhZUAQl6ZFlSkDPT__AajwDrbwVD1wYo",
"aLfaX-zlUXPDObBuEu5vizlWMcOrNV1LNZK59bFq6eA",
"711pp6is-DBvdicL62Kg7SzTLgaC0aVpP-nQz7AHKQE"
}
weakBot = weakBot or nil
botsInfo = botsInfo or {}
Colors = {
red = "\27[31m",
green = "\27[32m",
blue = "\27[34m",
reset = "\27[0m",
gray = "\27[90m"
}
fight = false
--
function isInGame()
for pid, player in pairs(LatestGameState.Players) do
if pid == ao.id then
return true
end
end
return false
end
-- check inrange
function inRange(x1, y1, x2, y2, range)
local rangeX, rangeY = 0, 0
if math.abs(x1 - x2) > 20 then
rangeX = 41 - math.abs(x1 - x2)
else
rangeX = math.abs(x1 - x2)
end
if math.abs(y1 - y2) > 20 then
rangeY = 41 - math.abs(y1 - y2)
else
rangeY = math.abs(y1 - y2)
end
return rangeX <= range and rangeY <= range
end
-- Find the weakest target nearby
function findTargetWeakBot()
local heathValue = 100
local energyValue = 100
local weakPlayer = nil
for pid, player in pairs(botsInfo) do
if pid ~= ao.id and player.health < heathValue then
heathValue = player.health
energyValue = player.energy
weakPlayer = pid
elseif player.health == heathValue and player.energy < energyValue then
weakPlayer = pid
end
end
print(Colors.gray .. "findNearTargetWeakBot:" .. weakPlayer .. Colors.reset)
weakBot = weakPlayer
end
-- find the weakest bot from targetBotsArr
function findNearTargetWeakBot(me)
local weakNearBot = nil
for pid, player in pairs(botsInfo) do
if pid ~= ao.id and player.health <= 50 then
local x1, x2 = adjustPosition(me.x, player.x)
local y1, y2 = adjustPosition(me.y, player.y)
if inRange(x1, y1, x2, y2, 10) then
weakNearBot = pid
break
end
end
end
if weakNearBot then
print(Colors.gray .. "weakNearBot:" .. weakNearBot .. Colors.reset)
end
weakBot = weakNearBot
end
-- calculate the direction
function adjustPosition(n1, n2)
if math.abs(n1 - n2) > 20 then
if n1 < 20 and n2 >= 20 then
n2 = n2 - 40
end
if n1 >= 20 and n2 < 20 then
n1 = n1 - 40
end
end
return n1, n2
end
local function getDirections(x1, y1, x2, y2, isAway)
if isAway == nil then
isAway = false
end
x1, x2 = adjustPosition(x1, x2)
y1, y2 = adjustPosition(y1, y2)
-- print("x1: " .. x1 .. " y1:" .. y1 .. " x2: " .. x2 .. " y2: " .. y2)
local dx, dy = x2 - x1, y2 - y1
local dirX, dirY = "", ""
-- print("dx:" .. dx .. " dy:" .. dy)
if isAway then
if dx > 0 then dirX = "Left" else dirX = "Right" end
if dy > 0 then dirY = "Up" else dirY = "Down" end
else
if dx > 0 then dirX = "Right" else dirX = "Left" end
if dy > 0 then dirY = "Down" else dirY = "Up" end
end
print(dirY .. dirX)
return dirY .. dirX
end
--
function isFight(me, player)
if fight then
return true
end
return player.health <= me.energy * 2/3 or me.health == 100
end
function moveToTarget(me, player)
if not isFight(me, player) and inRange(me.x, me.y, player.x, player.y, 3) then
runaway(me, player)
elseif isFight(me, player) and inRange(me.x, me.y, player.x, player.y, 1) then
local playerEnergy = LatestGameState.Players[ao.id].energy
if playerEnergy == 0 then
fight = false
end
print(Colors.red .. "Target in range, Attacking!" .. Colors.reset)
ao.send({Target = Game, Action = "PlayerAttack", Player = ao.id, AttackEnergy = tostring(playerEnergy)})
else
local moveDir = getDirections(me.x, me.y, player.x, player.y, false)
print(Colors.red .. "Approaching the enemy. Move " .. moveDir .. Colors.reset)
ao.send({Target = Game, Action = "PlayerMove", Player = ao.id, Direction = moveDir})
end
end
-- runaway from target
function runaway(me, player)
local moveDir = getDirections(me.x, me.y, player.x, player.y, true)
print(Colors.red .. "Runaway, Move " .. moveDir .. Colors.reset)
ao.send({Target = Game, Action = "PlayerMove", Player = ao.id, Direction = moveDir})
end
-- attack
function attack()
local playerEnergy = LatestGameState.Players[ao.id].energy
if playerEnergy == undefined then
print(Colors.red .. "Attack-Failed. Unable to read energy." .. Colors.reset)
elseif playerEnergy == 0 then
fight = false
print(Colors.red .. "Attack-Failed. Player has insufficient energy." .. Colors.reset)
else
ao.send({Target = Game, Action = "PlayerAttack", Player = ao.id, AttackEnergy = tostring(playerEnergy)})
print(Colors.red .. "Attacked." .. Colors.reset)
end
end
-- randomMove
function randomMove()
print("Moving randomly.")
local randomIndex = math.random(#DirectionMap)
ao.send({Target = Game, Action = "PlayerMove", Player = ao.id, Direction = DirectionMap[randomIndex]})
end
-- mapping
function targetBotMaps()
local cache = {}
for target, state in pairs(LatestGameState.Players) do
for i = 1, #targetBotsArr do
if target == targetBotsArr[i] then
cache[target] = state
end
end
end
botsInfo = cache
end
--#region
-- find the nearest targetBot from targetBotsArr then lockTarget and attack at the suitable time
--#endregion
function decideNextAction()
local me = LatestGameState.Players[ao.id]
if me.health < 10 then
ao.send({Target = Game, Action = "Withdraw" })
Paying = false
end
findNearTargetWeakBot(me)
if weakBot == nil then
findTargetWeakBot()
end
local player = botsInfo[weakBot]
-- no targetPlayers
if not player then
ao.send({ Target = Game, Action = "Refresh"})
return
end
if t and LatestGameState.Players[t] then
print(Colors.gray .. "Target:" .. t .. Colors.reset)
player = LatestGameState.Players[t]
else
t = nil
end
moveToTarget(me, player)
InAction = false
print("Player state: (health:" .. player.health .. ", energy:" .. player.energy .. ")")
print("Player Position: (x:" .. player.x .. ", y:" .. player.y .. ")")
print("You state: (health:" .. me.health .. ", energy:" .. me.energy .. ")")
print("You Position: (x:" .. me.x .. ", y:" .. me.y .. ")")
end
Handlers.add(
"HandlerPlaying",
function (msg)
if msg.Action == "Player-Moved" or msg.Action == "Successful-Hit" or msg.Action == "Refresh" then
return true
else
return false
end
end,
function (msg)
print(msg.Action .. " " .. msg.Data)
print(Colors.blue .. "Getting game state...after Player-Action" .. Colors.reset)
ao.send({Target = Game, Action = "GetGameState", Name = Name, Owner = Owner })
InAction = true
end
)
-- Withdraw auto pay
Handlers.add(
"AutoPayAfterWithdraw",
function (msg)
if msg.Action == "Removed" then
return true
else
return false
end
end,
function (msg)
if Paying then
print("You have paid just now.")
else
Paying = true
print(Colors.red .. "Withdraw CRED. Removed from the Game." .. Colors.reset)
print("Auto-paying confirmation fees.")
Send({Target = CRED, Action = "Transfer", Quantity = "1000", Recipient = Game})
end
end
)
-- Eliminated auto pay
Handlers.add(
"AutoPayAfterEliminated",
Handlers.utils.hasMatchingTag("Action", "Eliminated"),
function ()
print("After Eliminated. Auto-paying confirmation fees.")
ao.send({Target = CRED, Action = "Transfer", Quantity = "1000", Recipient = Game})
InAction = true
end
)
Handlers.add(
"AutoStart",
Handlers.utils.hasMatchingTag("Action", "Payment-Received"),
function (msg)
print(Colors.gray .. "Auto start game...GetGameState... From AutoStart" .. Colors.reset)
ao.send({Target = Game, Action = "GetGameState", Name = Name, Owner = Owner })
InAction = true
end
)
-- Announcement
Handlers.add(
"PrintAnnouncements",
Handlers.utils.hasMatchingTag("Action", "Announcement"),
function (msg)
if (msg.Event == "Tick" or msg.Event == "Started-Game" or msg.Event == "Cok") and not InAction then
InAction = true
ao.send({Target = Game, Action = "GetGameState", Name = Name, Owner = Owner })
elseif msg.Event == "Attack" then
print(Colors.red .. msg.Data .. Colors.reset)
InAction = false
elseif InAction then
print(Colors.gray .. "Previous action still in progress. Skipping." .. Colors.reset)
end
print(Colors.green .. msg.Event .. ": " .. msg.Data .. Colors.reset)
end
)
-- GameState
Handlers.add(
"UpdateGameState",
Handlers.utils.hasMatchingTag("Action", "GameState"),
function (msg)
local json = require("json")
LatestGameState = json.decode(msg.Data)
print("Game state updated. Print \'LatestGameState\' for detailed view.")
targetBotMaps()
print("Game state updates. Print \'botsInfo\' for targetBotsArr detailed view.")
if LatestGameState.GameMode ~= "Playing" then
InAction = false
print("Not playing state.")
return
end
if isInGame() then
print(Colors.gray .. "Deciding next action." .. Colors.reset)
decideNextAction()
else
print(Colors.red .. "You are not in game. auto pay now" ..Colors.reset)
ao.send({Target = CRED, Action = "Transfer", Quantity = "1000", Recipient = Game})
end
end
)
Handlers.add(
"ReturnCred",
Handlers.utils.hasMatchingTag("Action", "Credit-Notice"),
function (msg)
print(Colors.blue .. "Credit Received. Auto Withdraw." .. Colors.reset)
print(msg.Data)
ao.send({Target = Game, Action = "Withdraw" })
Paying = false
end
)
-- ignore cron
Handlers.add('ignore-cron',
Handlers.utils.hasMatchingTag('Action', 'Cron'),
function () return "" end
)