mirror of
https://github.com/veden/Rampant.git
synced 2025-01-07 23:01:39 +02:00
353 lines
14 KiB
Lua
Executable File
353 lines
14 KiB
Lua
Executable File
if aiPlanningG then
|
|
return aiPlanningG
|
|
end
|
|
local aiPlanning = {}
|
|
|
|
-- imports
|
|
|
|
local constants = require("Constants")
|
|
local mathUtils = require("MathUtils")
|
|
-- local aiPredicates = require("AIPredicates")
|
|
|
|
-- constants
|
|
|
|
local NO_RETREAT_BASE_PERCENT = constants.NO_RETREAT_BASE_PERCENT
|
|
local NO_RETREAT_EVOLUTION_BONUS_MAX = constants.NO_RETREAT_EVOLUTION_BONUS_MAX
|
|
|
|
local AI_STATE_PEACEFUL = constants.AI_STATE_PEACEFUL
|
|
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
|
|
local AI_STATE_RAIDING = constants.AI_STATE_RAIDING
|
|
local AI_STATE_MIGRATING = constants.AI_STATE_MIGRATING
|
|
local AI_STATE_ONSLAUGHT = constants.AI_STATE_ONSLAUGHT
|
|
local AI_STATE_SIEGE = constants.AI_STATE_SIEGE
|
|
|
|
local AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION
|
|
local AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION
|
|
|
|
local AI_UNIT_REFUND = constants.AI_UNIT_REFUND
|
|
|
|
local AI_MAX_POINTS = constants.AI_MAX_POINTS
|
|
local AI_POINT_GENERATOR_AMOUNT = constants.AI_POINT_GENERATOR_AMOUNT
|
|
|
|
local AI_MIN_STATE_DURATION = constants.AI_MIN_STATE_DURATION
|
|
local AI_MIN_TEMPERAMENT_DURATION = constants.AI_MIN_TEMPERAMENT_DURATION
|
|
local AI_MAX_STATE_DURATION = constants.AI_MAX_STATE_DURATION
|
|
local AI_MAX_TEMPERAMENT_DURATION = constants.AI_MAX_TEMPERAMENT_DURATION
|
|
|
|
local BASE_RALLY_CHANCE = constants.BASE_RALLY_CHANCE
|
|
local BONUS_RALLY_CHANCE = constants.BONUS_RALLY_CHANCE
|
|
|
|
local RETREAT_MOVEMENT_PHEROMONE_LEVEL_MIN = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL_MIN
|
|
local RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX
|
|
|
|
-- imported functions
|
|
|
|
local randomTickEvent = mathUtils.randomTickEvent
|
|
|
|
local linearInterpolation = mathUtils.linearInterpolation
|
|
|
|
local mFloor = math.floor
|
|
|
|
local mRandom = math.random
|
|
|
|
local mMax = math.max
|
|
local mMin = math.min
|
|
|
|
-- module code
|
|
|
|
function aiPlanning.planning(natives, evolution_factor, tick)
|
|
natives.evolutionLevel = evolution_factor
|
|
|
|
local maxPoints = AI_MAX_POINTS * evolution_factor
|
|
|
|
if not natives.ranIncompatibleMessage and natives.newEnemies and (game.active_mods["bobenemies"] or game.active_mods["Natural_Evolution_Enemies"]) then
|
|
natives.ranIncompatibleMessage = true
|
|
for i,p in ipairs(game.connected_players) do
|
|
p.print("Bobs enemies or NEE has been detected with Rampant's new enemies, the artifacts from each of these mods will still work with Rampant's new enemies. The generation of bobs or NEE unit spawners explicitly by Rampant is no longer supported when the Rampant's new enemies are active.")
|
|
end
|
|
end
|
|
|
|
local maxOverflowPoints = maxPoints * 3
|
|
|
|
local attackWaveMaxSize = natives.attackWaveMaxSize
|
|
natives.retreatThreshold = linearInterpolation(evolution_factor, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MIN, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX)
|
|
natives.rallyThreshold = BASE_RALLY_CHANCE + (evolution_factor * BONUS_RALLY_CHANCE)
|
|
natives.formSquadThreshold = mMax((0.25 * evolution_factor), 0.10)
|
|
|
|
natives.attackWaveSize = attackWaveMaxSize * (evolution_factor ^ 1.66667)
|
|
natives.attackWaveDeviation = (attackWaveMaxSize * 0.5) * 0.333
|
|
natives.attackWaveUpperBound = attackWaveMaxSize + (attackWaveMaxSize * 0.25)
|
|
|
|
natives.settlerWaveSize = linearInterpolation(evolution_factor ^ 1.66667, natives.expansionMinSize, natives.expansionMaxSize)
|
|
natives.settlerWaveDeviation = (natives.settlerWaveSize * 0.33)
|
|
|
|
natives.settlerCooldown = mFloor(linearInterpolation(evolution_factor ^ 1.66667, natives.expansionMaxTime, natives.expansionMinTime))
|
|
|
|
natives.unitRefundAmount = AI_UNIT_REFUND * evolution_factor
|
|
natives.kamikazeThreshold = NO_RETREAT_BASE_PERCENT + (evolution_factor * NO_RETREAT_EVOLUTION_BONUS_MAX)
|
|
|
|
local points = mFloor((AI_POINT_GENERATOR_AMOUNT * mRandom()) + ((AI_POINT_GENERATOR_AMOUNT * 0.7) * (evolution_factor ^ 2.5)) * natives.aiPointsScaler)
|
|
|
|
if (natives.state == AI_STATE_ONSLAUGHT) then
|
|
points = points * 2
|
|
end
|
|
|
|
natives.baseIncrement = points
|
|
|
|
local currentPoints = natives.points
|
|
|
|
if (currentPoints < maxPoints) then
|
|
natives.points = currentPoints + points
|
|
end
|
|
|
|
if (currentPoints > maxOverflowPoints) then
|
|
natives.points = maxOverflowPoints
|
|
end
|
|
|
|
if (natives.stateTick <= tick) then
|
|
-- local roll = mRandom() * mMax(1 - evolution_factor, 0.15) * natives.aiAggressiveness
|
|
|
|
local roll = mRandom()
|
|
if (natives.temperament < 0.05) then -- 0 - 0.05
|
|
if natives.enabledMigration then
|
|
natives.state = AI_STATE_SIEGE
|
|
else
|
|
if natives.raidAIToggle then
|
|
if (roll < 0.85) then
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
else
|
|
natives.state = AI_STATE_RAIDING
|
|
end
|
|
else
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
end
|
|
end
|
|
elseif (natives.temperament < 0.20) then -- 0.05 - 0.2
|
|
if (natives.enabledMigration) then
|
|
if (roll < 0.4) then
|
|
natives.state = AI_STATE_SIEGE
|
|
else
|
|
natives.state = AI_STATE_MIGRATING
|
|
end
|
|
else
|
|
if natives.raidAIToggle then
|
|
if (roll < 0.95) then
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
else
|
|
natives.state = AI_STATE_RAIDING
|
|
end
|
|
else
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
end
|
|
end
|
|
elseif (natives.temperament < 0.4) then -- 0.2 - 0.4
|
|
if (natives.enabledMigration) then
|
|
if (roll < 0.2) then
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
elseif (roll < 0.8) then
|
|
natives.state = AI_STATE_MIGRATING
|
|
else
|
|
natives.state = AI_STATE_PEACEFUL
|
|
end
|
|
else
|
|
if (roll < 0.6) then
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
else
|
|
natives.state = AI_STATE_PEACEFUL
|
|
end
|
|
end
|
|
elseif (natives.temperament < 0.6) then -- 0.4 - 0.6
|
|
if (roll < 0.5) then
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
else
|
|
natives.state = AI_STATE_PEACEFUL
|
|
end
|
|
elseif (natives.temperament < 0.8) then -- 0.6 - 0.8
|
|
if (roll < 0.6) then
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
elseif (roll < 0.8) then
|
|
natives.state = AI_STATE_ONSLAUGHT
|
|
else
|
|
natives.state = AI_STATE_PEACEFUL
|
|
end
|
|
else -- 0.8 - 1
|
|
if (natives.enabledMigration and natives.raidAIToggle) then
|
|
if (roll < 0.3) then
|
|
natives.state = AI_STATE_SIEGE
|
|
elseif (roll < 0.6) then
|
|
natives.state = AI_STATE_ONSLAUGHT
|
|
elseif (roll < 0.8) then
|
|
natives.state = AI_STATE_RAIDING
|
|
else
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
end
|
|
elseif (natives.enabledMigration) then
|
|
if (roll < 0.3) then
|
|
natives.state = AI_STATE_SIEGE
|
|
elseif (roll < 0.7) then
|
|
natives.state = AI_STATE_ONSLAUGHT
|
|
else
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
end
|
|
elseif (natives.raidAIToggle) then
|
|
if (roll < 0.4) then
|
|
natives.state = AI_STATE_ONSLAUGHT
|
|
elseif (roll < 0.7) then
|
|
natives.state = AI_STATE_RAIDING
|
|
else
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
end
|
|
else
|
|
if (roll < 0.6) then
|
|
natives.state = AI_STATE_ONSLAUGHT
|
|
else
|
|
natives.state = AI_STATE_AGGRESSIVE
|
|
natives.canAttackTick = randomTickEvent(tick,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
|
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- print("changing state", natives.state)
|
|
|
|
natives.stateTick = randomTickEvent(tick, AI_MIN_STATE_DURATION, AI_MAX_STATE_DURATION)
|
|
end
|
|
|
|
end
|
|
|
|
|
|
function aiPlanning.temperamentPlanner(natives)
|
|
local destroyPlayerBuildings = natives.destroyPlayerBuildings
|
|
local lostEnemyUnits = natives.lostEnemyUnits
|
|
local lostEnemyBuilding = natives.lostEnemyBuilding
|
|
local rocketLaunched = natives.rocketLaunched
|
|
local builtEnemyBuilding = natives.builtEnemyBuilding
|
|
local ionCannonBlasts = natives.ionCannonBlasts
|
|
local artilleryBlasts = natives.artilleryBlasts
|
|
local activeNests = natives.activeNests
|
|
local activeRaidNests = natives.activeRaidNests
|
|
|
|
local currentTemperament = natives.temperamentScore
|
|
local delta = 0
|
|
|
|
if activeNests > 0 then
|
|
local val = (1.5 * activeNests)
|
|
delta = delta + val
|
|
|
|
if destroyPlayerBuildings > 0 then
|
|
delta = delta - (200 * destroyPlayerBuildings)
|
|
end
|
|
|
|
else
|
|
delta = delta - 1
|
|
|
|
if destroyPlayerBuildings > 0 then
|
|
if (currentTemperament > 0) then
|
|
delta = delta - (200 * destroyPlayerBuildings)
|
|
else
|
|
delta = delta + (200 * destroyPlayerBuildings)
|
|
end
|
|
end
|
|
end
|
|
|
|
if activeRaidNests > 0 then
|
|
local val = (0.008 * activeRaidNests)
|
|
delta = delta - val
|
|
else
|
|
delta = delta - 0.5
|
|
end
|
|
|
|
if lostEnemyUnits > 0 then
|
|
local val = (0.04 * lostEnemyUnits)
|
|
if (currentTemperament > 0) then
|
|
delta = delta - val
|
|
else
|
|
delta = delta + val
|
|
end
|
|
end
|
|
|
|
if lostEnemyBuilding > 0 then
|
|
delta = delta + (20 * lostEnemyBuilding)
|
|
end
|
|
|
|
if (builtEnemyBuilding > 0) then
|
|
local val = (50 * builtEnemyBuilding)
|
|
if (currentTemperament > 0) then
|
|
delta = delta - val
|
|
else
|
|
delta = delta + val
|
|
end
|
|
else
|
|
delta = delta - 0.5
|
|
end
|
|
|
|
if (rocketLaunched > 0) then
|
|
local val = (100 * rocketLaunched)
|
|
delta = delta + val
|
|
end
|
|
|
|
if (ionCannonBlasts > 0) then
|
|
local val = (50 * ionCannonBlasts)
|
|
delta = delta + val
|
|
end
|
|
|
|
if (artilleryBlasts > 0) then
|
|
local val = (50 * artilleryBlasts)
|
|
delta = delta + val
|
|
end
|
|
|
|
-- print(natives.activeNests, natives.activeRaidNests, natives.destroyPlayerBuildings, natives.lostEnemyUnits,
|
|
-- natives.lostEnemyBuilding, natives.rocketLaunched, natives.builtEnemyBuilding, natives.ionCannonBlasts,
|
|
-- natives.artilleryBlasts)
|
|
|
|
natives.destroyPlayerBuildings = 0
|
|
natives.lostEnemyUnits = 0
|
|
natives.lostEnemyBuilding = 0
|
|
natives.rocketLaunched = 0
|
|
natives.builtEnemyBuilding = 0
|
|
natives.ionCannonBlasts = 0
|
|
natives.artilleryBlasts = 0
|
|
|
|
natives.temperamentScore = mMin(10000, mMax(-10000, currentTemperament + (natives.evolutionLevel * delta)))
|
|
natives.temperament = ((natives.temperamentScore + 10000) * 0.00005)
|
|
-- print(natives.temperament, natives.temperamentScore)
|
|
-- print("--")
|
|
end
|
|
|
|
aiPlanningG = aiPlanning
|
|
return aiPlanning
|