Skip to content

Commit

Permalink
move GetEcon to situation, dynamic max build dist, do not ignore buil…
Browse files Browse the repository at this point in the history
…dsitehandler as last ditch placement
  • Loading branch information
eronoobos committed Jul 19, 2016
1 parent 0506c16 commit 6c60e23
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 102 deletions.
8 changes: 2 additions & 6 deletions bomberhandler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,9 @@ function BomberHandler:DoTargetting()
if #recruits >= self.counter then
ai.couldBomb = ai.couldBomb + 1
-- find somewhere to attack
local bombTarget
EchoDebug("getting target for " .. weapon)
if weapon == "torpedo" then
bombTarget = ai.targethandler:GetBestBomberTarget(true)
else
bombTarget = ai.targethandler:GetBestBomberTarget()
end
local torpedo = weapon == 'torpedo'
local bombTarget = ai.targethandler:GetBestBomberTarget(torpedo)
if bombTarget ~= nil then
EchoDebug("got target for " .. weapon)
for i = 1, #recruits do
Expand Down
127 changes: 79 additions & 48 deletions situation.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function Situation:Init()
self.tacticalNukeLimit = 1

self.lastCheckFrame = 0
self.lastEconCheckFrame = 0

self:StaticEvaluate()
self:Evaluate()
Expand All @@ -29,64 +30,94 @@ end
function Situation:Evaluate()
local f = self.game:Frame()
if f > self.lastCheckFrame + 240 then
self:EvaluateSituation()
self.lastCheckFrame = f
self.ai.haveAdvFactory = self.ai.factoriesAtLevel[3] and #self.ai.factoriesAtLevel[3] ~= 0
self.ai.haveExpFactory = self.ai.factoriesAtLevel[5] and #self.ai.factoriesAtLevel[5] ~= 0

self.ai.needToReclaim = self.ai.Metal.full < 0.5 and self.ai.wreckCount > 0
self.AAUnitPerTypeLimit = math.ceil(self.ai.turtlehandler:GetTotalPriority() / 4)
self.heavyPlasmaLimit = math.ceil(self.ai.combatCount / 10)
self.nukeLimit = math.ceil(self.ai.combatCount / 50)
self.tacticalNukeLimit = math.ceil(self.ai.combatCount / 40)
end
if f > self.lastEconCheckFrame + 22 then
self:SetEconomyAliases()
self.lastEconCheckFrame = f
end
end

local attackCounter = self.ai.attackhandler:GetCounter()
local couldAttack = self.ai.couldAttack >= 1 or self.ai.couldBomb >= 1
local bombingTooExpensive = self.ai.bomberhandler:GetCounter() == maxBomberCounter
local attackTooExpensive = attackCounter == maxAttackCounter
local controlMetalSpots = self.ai.mexCount > #self.ai.mobNetworkMetals["air"][1] * 0.4
local needUpgrade = couldAttack or bombingTooExpensive or attackTooExpensive
local lotsOfMetal = self.ai.Metal.income > 25 or controlMetalSpots
local economyGreat = self.ai.Energy.income > 5000 and self.ai.Metal.income > 100 and self.ai.Metal.reserves > 4000 and self.ai.factoryBuilded['air'][1] > 2 and self.ai.combatCount > 40
function Situation:EvaluateSituation()
self.ai.haveAdvFactory = self.ai.factoriesAtLevel[3] and #self.ai.factoriesAtLevel[3] ~= 0
self.ai.haveExpFactory = self.ai.factoriesAtLevel[5] and #self.ai.factoriesAtLevel[5] ~= 0

self.ai.needToReclaim = self.ai.Metal.full < 0.5 and self.ai.wreckCount > 0
self.AAUnitPerTypeLimit = math.ceil(self.ai.turtlehandler:GetTotalPriority() / 4)
self.heavyPlasmaLimit = math.ceil(self.ai.combatCount / 10)
self.nukeLimit = math.ceil(self.ai.combatCount / 50)
self.tacticalNukeLimit = math.ceil(self.ai.combatCount / 40)

self.ai.keepCommanderSafe = self.ai.totalEnemyThreat > 3000
local attackCounter = self.ai.attackhandler:GetCounter()
local couldAttack = self.ai.couldAttack >= 1 or self.ai.couldBomb >= 1
local bombingTooExpensive = self.ai.bomberhandler:GetCounter() == maxBomberCounter
local attackTooExpensive = attackCounter == maxAttackCounter
local controlMetalSpots = self.ai.mexCount > #self.ai.mobNetworkMetals["air"][1] * 0.4
local needUpgrade = couldAttack or bombingTooExpensive or attackTooExpensive
local lotsOfMetal = self.ai.Metal.income > 25 or controlMetalSpots
local economyGreat = self.ai.Energy.income > 5000 and self.ai.Metal.income > 100 and self.ai.Metal.reserves > 4000 and self.ai.factoryBuilded['air'][1] > 2 and self.ai.combatCount > 40

self:EchoDebug(self.ai.totalEnemyThreat .. " " .. self.ai.totalEnemyImmobileThreat .. " " .. self.ai.totalEnemyMobileThreat)
-- build siege units if the enemy is turtling, if a lot of our attackers are getting destroyed, or if we control over 40% of the metal spots
self.needSiege = (self.ai.totalEnemyImmobileThreat > self.ai.totalEnemyMobileThreat * 3.5 and self.ai.totalEnemyImmobileThreat > 50000) or attackCounter >= siegeAttackCounter or controlMetalSpots
local needAdvanced = (self.ai.Metal.income > 10 or controlMetalSpots) and self.ai.factories > 0 and (needUpgrade or lotsOfMetal)
if needAdvanced ~= self.ai.needAdvanced then
self.ai.factorybuildershandler:UpdateFactories()
end
self.ai.needAdvanced = needAdvanced
local needExperimental
self.ai.needNukes = false
if self.ai.Metal.income > 50 and self.ai.haveAdvFactory and (needUpgrade or economyGreat) and self.ai.enemyBasePosition then
if not self.ai.haveExpFactory then
for i, factory in pairs(self.ai.factoriesAtLevel[self.ai.maxFactoryLevel]) do
for expFactName, _ in pairs(expFactories) do
for _, mtype in pairs(factoryMobilities[expFactName]) do
local myNet = self.ai.maphandler:MobilityNetworkHere(mtype, factory.position)
local enemyNet = self.ai.maphandler:MobilityNetworkHere(mtype, self.ai.enemyBasePosition)
if myNet and enemyNet and myNet == enemyNet then
needExperimental = true
break
end
self.ai.keepCommanderSafe = self.ai.totalEnemyThreat > 3000

self:EchoDebug(self.ai.totalEnemyThreat .. " " .. self.ai.totalEnemyImmobileThreat .. " " .. self.ai.totalEnemyMobileThreat)
-- build siege units if the enemy is turtling, if a lot of our attackers are getting destroyed, or if we control over 40% of the metal spots
self.needSiege = (self.ai.totalEnemyImmobileThreat > self.ai.totalEnemyMobileThreat * 3.5 and self.ai.totalEnemyImmobileThreat > 50000) or attackCounter >= siegeAttackCounter or controlMetalSpots
local needAdvanced = (self.ai.Metal.income > 10 or controlMetalSpots) and self.ai.factories > 0 and (needUpgrade or lotsOfMetal)
if needAdvanced ~= self.ai.needAdvanced then
self.ai.factorybuildershandler:UpdateFactories()
end
self.ai.needAdvanced = needAdvanced
local needExperimental
self.ai.needNukes = false
if self.ai.Metal.income > 50 and self.ai.haveAdvFactory and (needUpgrade or economyGreat) and self.ai.enemyBasePosition then
if not self.ai.haveExpFactory then
for i, factory in pairs(self.ai.factoriesAtLevel[self.ai.maxFactoryLevel]) do
for expFactName, _ in pairs(expFactories) do
for _, mtype in pairs(factoryMobilities[expFactName]) do
local myNet = self.ai.maphandler:MobilityNetworkHere(mtype, factory.position)
local enemyNet = self.ai.maphandler:MobilityNetworkHere(mtype, self.ai.enemyBasePosition)
if myNet and enemyNet and myNet == enemyNet then
needExperimental = true
break
end
end
end
end
self.ai.needNukes = true
end
if needExperimental ~= self.ai.needExperimental then
self.ai.factorybuildershandler:UpdateFactories()
end
self.ai.needExperimental = needExperimental
self:EchoDebug("need experimental? " .. tostring(self.ai.needExperimental) .. ", need nukes? " .. tostring(self.ai.needNukes) .. ", have advanced? " .. tostring(self.ai.haveAdvFactory) .. ", need upgrade? " .. tostring(needUpgrade) .. ", have enemy base position? " .. tostring(self.ai.enemyBasePosition))
self:EchoDebug("metal income: " .. self.ai.Metal.income .. " combat units: " .. self.ai.combatCount)
self:EchoDebug("have advanced? " .. tostring(self.ai.haveAdvFactory) .. " have experimental? " .. tostring(self.ai.haveExpFactory))
self:EchoDebug("need advanced? " .. tostring(self.ai.needAdvanced) .. " need experimental? " .. tostring(self.ai.needExperimental))
self:EchoDebug("need advanced? " .. tostring(self.ai.needAdvanced) .. ", need upgrade? " .. tostring(needUpgrade) .. ", have attacked enough? " .. tostring(couldAttack) .. " (" .. self.ai.couldAttack .. "), have " .. self.ai.factories .. " factories, " .. math.floor(self.ai.Metal.income) .. " metal income")
self.ai.needNukes = true
end
if needExperimental ~= self.ai.needExperimental then
self.ai.factorybuildershandler:UpdateFactories()
end
self.ai.needExperimental = needExperimental
self:EchoDebug("need experimental? " .. tostring(self.ai.needExperimental) .. ", need nukes? " .. tostring(self.ai.needNukes) .. ", have advanced? " .. tostring(self.ai.haveAdvFactory) .. ", need upgrade? " .. tostring(needUpgrade) .. ", have enemy base position? " .. tostring(self.ai.enemyBasePosition))
self:EchoDebug("metal income: " .. self.ai.Metal.income .. " combat units: " .. self.ai.combatCount)
self:EchoDebug("have advanced? " .. tostring(self.ai.haveAdvFactory) .. " have experimental? " .. tostring(self.ai.haveExpFactory))
self:EchoDebug("need advanced? " .. tostring(self.ai.needAdvanced) .. " need experimental? " .. tostring(self.ai.needExperimental))
self:EchoDebug("need advanced? " .. tostring(self.ai.needAdvanced) .. ", need upgrade? " .. tostring(needUpgrade) .. ", have attacked enough? " .. tostring(couldAttack) .. " (" .. self.ai.couldAttack .. "), have " .. self.ai.factories .. " factories, " .. math.floor(self.ai.Metal.income) .. " metal income")
end

function Situation:SetEconomyAliases()
self.ai.realMetal = self.ai.Metal.income / self.ai.Metal.usage
self.ai.realEnergy = self.ai.Energy.income / self.ai.Energy.usage
self.ai.scaledMetal = self.ai.Metal.reserves * self.ai.realMetal
self.ai.scaledEnergy = self.ai.Energy.reserves * self.ai.realEnergy
self.extraEnergy = self.ai.Energy.income - self.ai.Energy.usage
self.extraMetal = self.ai.Metal.income - self.ai.Metal.usage
local enoughMetalReserves = math.min(self.ai.Metal.income, self.ai.Metal.capacity * 0.1)
local lotsMetalReserves = math.min(self.ai.Metal.income * 10, self.ai.Metal.capacity * 0.5)
local enoughEnergyReserves = math.min(self.ai.Energy.income * 2, self.ai.Energy.capacity * 0.25)
-- local lotsEnergyReserves = math.min(self.ai.Energy.income * 3, self.ai.Energy.capacity * 0.5)
self.energyTooLow = self.ai.Energy.reserves < enoughEnergyReserves or self.ai.Energy.income < 40
self.energyOkay = self.ai.Energy.reserves >= enoughEnergyReserves and self.ai.Energy.income >= 40
self.metalTooLow = self.ai.Metal.reserves < enoughMetalReserves
self.metalOkay = self.ai.Metal.reserves >= enoughMetalReserves
self.metalBelowHalf = self.ai.Metal.reserves < lotsMetalReserves
self.metalAboveHalf = self.ai.Metal.reserves >= lotsMetalReserves
local attackCounter = self.self.ai.attackhandler:GetCounter()
self.notEnoughCombats = self.ai.combatCount < attackCounter * 0.6
self.farTooFewCombats = self.ai.combatCount < attackCounter * 0.2
end

function Situation:StaticEvaluate()
Expand Down
84 changes: 36 additions & 48 deletions taskqueuebehaviour.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,33 @@ local function EchoDebug(inStr)
end
end

local CMD_GUARD = 25

local extraEnergy, extraMetal, energyTooLow, energyOkay, metalTooLow, metalOkay, metalBelowHalf, metalAboveHalf, notEnoughCombats, farTooFewCombats

local function GetEcon()
ai.realMetal = ai.Metal.income / ai.Metal.usage
ai.realEnergy = ai.Energy.income / ai.Energy.usage
ai.scaledMetal = ai.Metal.reserves * ai.realMetal
ai.scaledEnergy = ai.Energy.reserves * ai.realEnergy
extraEnergy = ai.Energy.income - ai.Energy.usage
extraMetal = ai.Metal.income - ai.Metal.usage
local enoughMetalReserves = math.min(ai.Metal.income, ai.Metal.capacity * 0.1)
local lotsMetalReserves = math.min(ai.Metal.income * 10, ai.Metal.capacity * 0.5)
local enoughEnergyReserves = math.min(ai.Energy.income * 2, ai.Energy.capacity * 0.25)
-- local lotsEnergyReserves = math.min(ai.Energy.income * 3, ai.Energy.capacity * 0.5)
energyTooLow = ai.Energy.reserves < enoughEnergyReserves or ai.Energy.income < 40
energyOkay = ai.Energy.reserves >= enoughEnergyReserves and ai.Energy.income >= 40
metalTooLow = ai.Metal.reserves < enoughMetalReserves
metalOkay = ai.Metal.reserves >= enoughMetalReserves
metalBelowHalf = ai.Metal.reserves < lotsMetalReserves
metalAboveHalf = ai.Metal.reserves >= lotsMetalReserves
local attackCounter = ai.attackhandler:GetCounter()
notEnoughCombats = ai.combatCount < attackCounter * 0.6
farTooFewCombats = ai.combatCount < attackCounter * 0.2
end

TaskQueueBehaviour = class(Behaviour)

function TaskQueueBehaviour:Name()
return "TaskQueueBehaviour"
end

local CMD_GUARD = 25

local maxBuildDists = {}
local maxBuildSpeedDists = {}

-- for non-defensive buildings
local function MaxBuildDist(unitName, speed)
local dist = maxBuildDists[unitName]
if not dist then
dist = math.sqrt(unitTable[value].metalCost)
maxBuildDists[unitName] = dist
end
maxBuildSpeedDists[unitName] = maxBuildSpeedDists[unitName] or {}
local speedDist = maxBuildDists[unitName][speed]
if not speedDist then
speedDist = dist * (speed / 2)
maxBuildSpeedDists[unitName][speed] = speedDist
end
return speedDist
end

function TaskQueueBehaviour:CategoryEconFilter(value)
if value == nil then return DummyUnitName end
if value == DummyUnitName then return DummyUnitName end
Expand All @@ -51,7 +46,7 @@ function TaskQueueBehaviour:CategoryEconFilter(value)
if reclaimerList[value] then
-- dedicated reclaimer
EchoDebug(" dedicated reclaimer")
if metalAboveHalf or energyTooLow or farTooFewCombats then
if self.situation.metalAboveHalf or self.situation.energyTooLow or self.situation.farTooFewCombats then
value = DummyUnitName
end
elseif unitTable[value].isBuilding then
Expand All @@ -66,29 +61,29 @@ function TaskQueueBehaviour:CategoryEconFilter(value)
EchoDebug(" defense")
if bigPlasmaList[value] or nukeList[value] then
-- long-range plasma and nukes aren't really defense
if metalTooLow or energyTooLow or ai.Metal.income < 35 or ai.factories == 0 or notEnoughCombats then
if self.situation.metalTooLow or self.situation.energyTooLow or ai.Metal.income < 35 or ai.factories == 0 or self.situation.notEnoughCombats then
value = DummyUnitName
end
elseif littlePlasmaList[value] then
-- plasma turrets need units to back them up
if metalTooLow or energyTooLow or ai.Metal.income < 10 or ai.factories == 0 or notEnoughCombats then
if self.situation.metalTooLow or self.situation.energyTooLow or ai.Metal.income < 10 or ai.factories == 0 or self.situation.notEnoughCombats then
value = DummyUnitName
end
else
if metalTooLow or ai.Metal.income < (unitTable[value].metalCost / 35) + 2 or energyTooLow or ai.factories == 0 then
if self.situation.metalTooLow or ai.Metal.income < (unitTable[value].metalCost / 35) + 2 or self.situation.energyTooLow or ai.factories == 0 then
value = DummyUnitName
end
end
elseif unitTable[value].radarRadius > 0 then
-- radar
EchoDebug(" radar")
if metalTooLow or energyTooLow or ai.factories == 0 or ai.Energy.full < 0.5 then
if self.situation.metalTooLow or self.situation.energyTooLow or ai.factories == 0 or ai.Energy.full < 0.5 then
value = DummyUnitName
end
else
-- other building
EchoDebug(" other building")
if notEnoughCombats or metalTooLow or energyTooLow or ai.Energy.income < 200 or ai.Metal.income < 8 or ai.factories == 0 then
if self.situation.notEnoughCombats or self.situation.metalTooLow or self.situation.energyTooLow or ai.Energy.income < 200 or ai.Metal.income < 8 or ai.factories == 0 then
value = DummyUnitName
end
end
Expand All @@ -115,7 +110,7 @@ function TaskQueueBehaviour:CategoryEconFilter(value)
else
-- other unit
EchoDebug(" other unit")
if notEnoughCombats or ai.Energy.full < 0.3 or ai.Metal.full < 0.3 then
if self.situation.notEnoughCombats or ai.Energy.full < 0.3 or ai.Metal.full < 0.3 then
value = DummyUnitName
end
end
Expand All @@ -130,7 +125,7 @@ function TaskQueueBehaviour:Init()
end
if ai.outmodedFactories == nil then ai.outmodedFactories = 0 end

GetEcon()
self:GetEcon()
self.active = false
self.currentProject = nil
self.lastWatchdogCheck = game:Frame()
Expand All @@ -140,6 +135,7 @@ function TaskQueueBehaviour:Init()
self.mtype = mtype
self.name = u:Name()
self.side = unitTable[self.name].side
self.speed = unitTable[self.name].speed
if commanderList[self.name] then self.isCommander = true end
self.id = u:ID()
EchoDebug(self.name .. " " .. self.id .. " initializing...")
Expand Down Expand Up @@ -333,12 +329,10 @@ function TaskQueueBehaviour:LocationFilter(utype, value)
EchoDebug( ' analysis for level ' .. level)
for index, factory in pairs(factories) do
local factoryName = factory.unit:Internal():Name()
for _, factMtype in pairs(factoryMobilities[factoryName]) do
if mtype == factMtype and level > currentLevel then
EchoDebug( self.name .. ' can push up self mtype ' .. factoryName)
currentLevel = level
target = factory
end
if mtype == factoryMobilities[factoryName][1] and level > currentLevel then
EchoDebug( self.name .. ' can push up self mtype ' .. factoryName)
currentLevel = level
target = factory
end
end
end
Expand Down Expand Up @@ -388,13 +382,10 @@ function TaskQueueBehaviour:LocationFilter(utype, value)
-- end
-- end
-- end

if p == nil then
EchoDebug("did NOT find build spot near turtle position")
utype = nil
end


elseif nukeList[value] or bigPlasmaList[value] or littlePlasmaList[value] then
-- bombarders
EchoDebug("seeking bombard build spot")
Expand Down Expand Up @@ -449,7 +440,7 @@ function TaskQueueBehaviour:LocationFilter(utype, value)
end
end
end
if p and Distance(p, builder:GetPosition()) > 300 then
if p and Distance(p, builder:GetPosition()) > MaxBuildDist(value, self.speed) then
-- HERE BECAUSE DEFENSE PLACEMENT SYSTEM SUCKS
-- this prevents cons from wasting time building very far away
p = ai.buildsitehandler:ClosestBuildSpot(builder, builder:GetPosition(), utype)
Expand All @@ -459,9 +450,6 @@ function TaskQueueBehaviour:LocationFilter(utype, value)
if utype ~= nil and p == nil then
local builderPos = builder:GetPosition()
p = ai.buildsitehandler:ClosestBuildSpot(builder, builderPos, utype)
if p == nil then
p = map:FindClosestBuildSite(utype, builderPos, 500, 15)

This comment has been minimized.

Copy link
@eronoobos

eronoobos Jul 19, 2016

Author Owner

i believe this should fix #27

end
end
return utype, value, p
end
Expand Down Expand Up @@ -537,7 +525,7 @@ function TaskQueueBehaviour:Update()
local f = game:Frame()
-- econ check
if f % 22 == 0 then
GetEcon()
self:GetEcon()
end
-- watchdog check
if not self.constructing and not self.isFactory then
Expand Down

0 comments on commit 6c60e23

Please sign in to comment.