-
Notifications
You must be signed in to change notification settings - Fork 40
/
global_game_state.lua
329 lines (274 loc) · 15.5 KB
/
global_game_state.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
_G._savedEnv = getfenv()
module( "global_game_state", package.seeall )
require( GetScriptDirectory().."/buildings_status" )
require( GetScriptDirectory().."/debugging" )
local gHero = require( GetScriptDirectory().."/global_hero_data" )
local utils = require( GetScriptDirectory().."/utility" )
local enemyData = require( GetScriptDirectory().."/enemy_data" )
local laneStates = {[LANE_TOP] = {dontdefend = false},
[LANE_MID] = {dontdefend = false},
[LANE_BOT] = {dontdefend = false}
}
--[[
local shrineStates = {
[SHRINE_BASE_1] = {handle = GetShrine(GetTeam(), SHRINE_BASE_1), pidsLookingForHeal = {}},
[SHRINE_BASE_2] = {handle = GetShrine(GetTeam(), SHRINE_BASE_2), pidsLookingForHeal = {}},
[SHRINE_BASE_3] = {handle = GetShrine(GetTeam(), SHRINE_BASE_3), pidsLookingForHeal = {}},
[SHRINE_BASE_4] = {handle = GetShrine(GetTeam(), SHRINE_BASE_4), pidsLookingForHeal = {}},
[SHRINE_BASE_5] = {handle = GetShrine(GetTeam(), SHRINE_BASE_5), pidsLookingForHeal = {}},
[SHRINE_JUNGLE_1] = {handle = GetShrine(GetTeam(), SHRINE_JUNGLE_1), pidsLookingForHeal = {}},
[SHRINE_JUNGLE_2] = {handle = GetShrine(GetTeam(), SHRINE_JUNGLE_2), pidsLookingForHeal = {}}
}
function GetShrineState(shrineID)
return shrineStates[shrineID]
end
function RemovePIDFromShrine(shrineID, pid)
local pidLoc = utils.PosInTable(shrineStates[shrineID].pidsLookingForHeal, pid)
if pidLoc >= 0 then
table.remove(shrineStates[shrineID].pidsLookingForHeal, pidLoc)
end
end
--]]
-- TODO: used for reading and writing. not really good.
function LaneState(lane)
return laneStates[lane]
end
-- Returns the closest building of team to a unit
function GetClosestBuilding(unit, team)
local min_dist = 99999999
local building = nil
for _, id in pairs(buildings_status.GetStandingBuildingIDs(team)) do
local vec = buildings_status.GetLocation(team, id)
local d = GetUnitToLocationDistance(unit, vec)
if d < min_dist then
min_dist = d
building = vec
end
end
return id, building
end
-- Get the position between buildings (0 = sitting on teams tower, 1 = sitting on enemy's tower)
function GetPositionBetweenBuildings(unit, team)
local _, allied_building = GetClosestBuilding(unit, team)
local d_allied = GetUnitToLocationDistance(unit, allied_building)
local _, enemy_building = GetClosestBuilding(unit, utils.GetOppositeTeamTo(team))
local d_enemy = GetUnitToLocationDistance(unit, enemy_building)
return d_allied / (d_allied + d_enemy)
end
function nearBuilding(unitLoc, buildingLoc)
return utils.GetDistance(unitLoc, buildingLoc) <= 1000
end
function numEnemiesNearBuilding(building)
local num = 0
local enemies = GetUnitList(UNIT_LIST_ENEMY_HEROES)
for _, enemy in pairs(enemies) do
if nearBuilding(enemy:GetLocation(), buildings_status.GetLocation(GetTeam(), building)) then
num = num + 1
end
end
return num
end
-- Detect if a tower is being pushed
function DetectEnemyPushMid()
local building = buildings_status.GetVulnerableBuildingIDs(GetTeam(), LANE_MID)[1]
local hBuilding = buildings_status.GetHandle(GetTeam(), building)
if hBuilding == nil then return 0, building end
if hBuilding and hBuilding:TimeSinceDamagedByAnyHero() < 1.5 then
local num = numEnemiesNearBuilding(building)
return num, building
end
return 0, building
end
function DetectEnemyPushTop()
local building = buildings_status.GetVulnerableBuildingIDs(GetTeam(), LANE_TOP)[1]
local hBuilding = buildings_status.GetHandle(GetTeam(), building)
if hBuilding == nil then return 0, building end
if hBuilding and hBuilding:TimeSinceDamagedByAnyHero() < 1.5 then
local num = numEnemiesNearBuilding(building)
return num, building
end
return 0, building
end
function DetectEnemyPushBot()
local building = buildings_status.GetVulnerableBuildingIDs(GetTeam(), LANE_BOT)[1]
local hBuilding = buildings_status.GetHandle(GetTeam(), building)
if hBuilding == nil then return 0, building end
if hBuilding and hBuilding:TimeSinceDamagedByAnyHero() < 1.5 then
local num = numEnemiesNearBuilding(building)
return num, building
end
return 0, building
end
local lastPushCheck = -1000.0
function DetectEnemyPush()
local bUpdate, newTime = utils.TimePassed(lastPushCheck, 0.5)
if bUpdate then
local numMid, midBuilding = DetectEnemyPushMid()
local numTop, topBuilding = DetectEnemyPushTop()
local numBot, botBuilding = DetectEnemyPushBot()
if numMid > 0 then
return LANE_MID, midBuilding, numMid
elseif numTop > 0 then
return LANE_TOP, topBuilding, numTop
elseif numBot > 0 then
return LANE_BOT, botBuilding, numBot
end
lastPushCheck = newTime
end
return nil, nil, nil
end
local lastBuildingUpdate = -1000.0
local vulnEnemyBuildings = nil
function GetLatestVulnerableEnemyBuildings()
local bUpdate, newTime = utils.TimePassed(lastBuildingUpdate, 3.0)
if bUpdate then
vulnEnemyBuildings = buildings_status.GetDestroyableTowers(utils.GetOtherTeam())
lastBuildingUpdate = newTime
end
return vulnEnemyBuildings
end
local lastGlobalFightDetermination = -1000.0
function GlobalFightDetermination()
local bUpdate, newTime = utils.TimePassed(lastGlobalFightDetermination, 0.25)
if bUpdate then lastGlobalFightDetermination = newTime else return end
local eyeRange = 1600
local listAllies = GetUnitList(UNIT_LIST_ALLIED_HEROES)
local listEnemies = GetUnitList(UNIT_LIST_ENEMY_HEROES)
for _, ally in pairs(listAllies) do
if ally:IsBot() and not ally:IsIllusion() then
if ally:GetHealth()/ally:GetMaxHealth() > 0.4 then
local totalNukeDmg = 0
local numEnemiesThatCanAttackMe = 0
local rawTotalEnemyPower = 0
local numAlliesThatCanHelpMe = 0
for _, enemy in pairs(listEnemies) do
if utils.ValidTarget(enemy) then
local distance = GetUnitToUnitDistance(ally, enemy)
local theirTimeToReachMe = distance/enemy:GetCurrentMovementSpeed()
local timeToReach = distance/ally:GetCurrentMovementSpeed()
local myNukeDmg, myActionQueue, myCastTime, myStun, mySlow, myEngageDist = ally.SelfRef:GetNukeDamage( ally, enemy )
-- update our total nuke damage
totalNukeDmg = totalNukeDmg + myNukeDmg
if distance <= eyeRange then
local nearbyETowers = gHero.GetNearbyEnemyTowers(ally, 900)
if #nearbyETowers > 0 then
rawTotalEnemyPower = rawTotalEnemyPower + #nearbyETowers*110
end
if enemy:GetHealth()/enemy:GetMaxHealth() > 0.25 then
numEnemiesThatCanAttackMe = numEnemiesThatCanAttackMe + 1
rawTotalEnemyPower = rawTotalEnemyPower + enemy:GetRawOffensivePower()
end
--utils.myPrint(utils.GetHeroName(ally), " sees "..enemy.Name.." ", distance, " units away. Time to reach: ", timeToReach)
local allAllyStun = 0
local allAllySlow = 0
local myTimeToKillTarget = fight_simul.estimateTimeToKill(ally, enemy)
local totalTimeToKillTarget = myTimeToKillTarget
local participatingAllies = {}
local globalAllies = {}
for _, ally2 in pairs(listAllies) do
-- this 'if' is for non-implemented bot heroes that are on our team
if not ally2:IsIllusion() and ally2:GetPlayerID() ~= ally:GetPlayerID() then
local distToEnemy = GetUnitToUnitDistance(ally2, enemy)
if GetUnitToUnitDistance(ally, ally2) < eyeRange then
numAlliesThatCanHelpMe = numAlliesThatCanHelpMe + 1
end
local allyTimeToReach = distToEnemy/ally2:GetCurrentMovementSpeed()
if ally2:IsBot() then
local allyNukeDmg, allyActionQueue, allyCastTime, allyStun, allySlow, allyEngageDist = ally2.SelfRef:GetNukeDamage( ally2, enemy )
local globalAbility, globalDmg, globalDmgType, globalDelay = ally2.SelfRef:GetGlobalDamage()
if allyTimeToReach <= 6.0 then
--utils.myPrint("ally ", utils.GetHeroName(ally2), " is ", distToEnemy, " units away. Time to reach: ", allyTimeToReach)
-- update our total nuke damage
totalNukeDmg = totalNukeDmg + allyNukeDmg
allAllyStun = allAllyStun + allyStun
allAllySlow = allAllySlow + allySlow
local allyTimeToKillTarget = fight_simul.estimateTimeToKill(ally2, enemy)
totalTimeToKillTarget = totalTimeToKillTarget + allyTimeToKillTarget
table.insert(participatingAllies, {ally2, allyActionQueue, allyEngageDist})
elseif globalAbility then
totalNukeDmg = totalNukeDmg + enemy:GetActualIncomingDamage(globalDmg, globalDmgType)
table.insert(globalAllies, {ally2, globalAbility, enemy:GetExtrapolatedLocation(globalDelay)})
end
else
if allyTimeToReach <= 6.0 then
totalNukeDmg = totalNukeDmg + ally2:GetOffensivePower()
end
end
end
end
local numAttackers = #participatingAllies+1
local anticipatedTimeToKill = (totalTimeToKillTarget/numAttackers) - 2*#globalAllies
local totalStun = myStun + allAllyStun
local totalSlow = mySlow + allAllySlow
local timeToKillBonus = numAttackers*(totalStun + 0.5*totalSlow)
-- if global we picked a 1v? fight then let it work out at the hero-level
if numAttackers == 1 then break end
local nearbyEnemyHeroes = gHero.GetNearbyEnemies(ally, 1200)
local numEnemiesWithStun = 1
for _, nearEnemy in pairs(nearbyEnemyHeroes) do
if utils.ValidTarget(nearEnemy) and nearEnemy:GetPlayerID() ~= enemy:GetPlayerID() then
local stun = nearEnemy:GetStunDuration(true)
local slow = nearEnemy:GetSlowDuration(true)
numEnemiesWithStun = numEnemiesWithStun + stun + 0.5/slow
end
end
if totalNukeDmg/numEnemiesWithStun >= enemy:GetHealth() then
utils.myPrint(#participatingAllies+1, " of us can Nuke ", enemy:GetUnitName())
utils.myPrint(utils.GetHeroName(ally), " - Engaging!")
local allyID = ally:GetPlayerID()
gHero.SetVar(allyID, "Target", enemy)
ally.teamKill = true
ally.SelfRef:QueueNuke(ally, enemy, myActionQueue, myEngageDist)
for _, v in pairs(participatingAllies) do
gHero.SetVar(v[1]:GetPlayerID(), "Target", enemy)
v[1].teamKill = true
if #v[2] > 0 and GetUnitToUnitDistance(v[1], enemy) < v[3] then
v[1].SelfRef:QueueNuke(v[1], enemy, v[2], v[3])
elseif #v[2] > 0 then
gHero.HeroMoveToUnit(v[1], enemy)
end
end
for _, v in pairs(globalAllies) do
--gHero.SetVar(v[1]:GetPlayerID(), "UseGlobal", {v[2][1], enemy})
v[1].SelfRef:UseGlobal(enemy, v[2], v[3])
utils.myPrint(utils.GetHeroName(v[1]).." casting global skill.")
end
return
elseif (anticipatedTimeToKill - timeToKillBonus) < 6.0/numEnemiesWithStun then
utils.myPrint(#participatingAllies+#globalAllies+1, " of us can Stun for: ", totalStun, " and Slow for: ", totalSlow, ". AnticipatedTimeToKill ", enemy:GetUnitName() ,": ", anticipatedTimeToKill)
utils.myPrint(utils.GetHeroName(ally), " - Engaging! Anticipated Time to kill: ", anticipatedTimeToKill)
gHero.SetVar(ally:GetPlayerID(), "Target", enemy)
ally.teamKill = true
for _, v in pairs(participatingAllies) do
gHero.SetVar(v[1]:GetPlayerID(), "Target", enemy)
v[1].teamKill = true
if #v[2] > 0 and GetUnitToUnitDistance(v[1], enemy) < v[3] then
v[1].SelfRef:QueueNuke(v[1], enemy, v[2], v[3])
elseif #v[2] > 0 then
gHero.HeroMoveToUnit(v[1], enemy)
end
end
for _, v in pairs(globalAllies) do
--gHero.SetVar(v[1]:GetPlayerID(), "UseGlobal", {v[2][1], enemy})
v[1].SelfRef:UseGlobal(enemy, v[2], v[3])
utils.myPrint(utils.GetHeroName(v[1]).." casting global skill.")
end
return
end
end
end
end
if numEnemiesThatCanAttackMe >= numAlliesThatCanHelpMe and rawTotalEnemyPower > 0.9*ally:GetHealth() then
ally.teamKill = false
--utils.myPrint(utils.GetHeroName(ally), "This is a bad idea")
--ally:Action_ClearActions(false)
end
else
ally.teamKill = false
end
else
ally.teamKill = false
end
end
end
for k,v in pairs( global_game_state ) do _G._savedEnv[k] = v end