1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-07 23:01:39 +02:00
Rampant/control.lua

317 lines
11 KiB
Lua
Raw Normal View History

-- imports
local entityUtils = require("libs/EntityUtils")
2017-01-20 07:58:36 +02:00
local mapUtils = require("libs/MapUtils")
2016-08-07 05:38:47 +02:00
local unitGroupUtils = require("libs/UnitGroupUtils")
local chunkProcessor = require("libs/ChunkProcessor")
2017-05-19 09:47:24 +02:00
local baseProcessor = require("libs/BaseProcessor")
local mapProcessor = require("libs/MapProcessor")
local constants = require("libs/Constants")
local pheromoneUtils = require("libs/PheromoneUtils")
local aiDefense = require("libs/AIDefense")
local aiAttack = require("libs/AIAttack")
2016-08-19 04:02:13 +02:00
local aiBuilding = require("libs/AIBuilding")
2016-10-15 02:00:18 +02:00
local aiPlanning = require("libs/AIPlanning")
2017-05-06 11:03:28 +02:00
local interop = require("libs/Interop")
2016-08-22 00:59:17 +02:00
local tests = require("tests")
2017-05-19 09:47:24 +02:00
local upgrade = require("Upgrade")
2016-10-15 02:00:18 +02:00
-- constants
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
2017-01-20 07:58:36 +02:00
local MAX_RALLY_CRIES = constants.MAX_RALLY_CRIES
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local BASE_RALLY_CHANCE = constants.BASE_RALLY_CHANCE
local BONUS_RALLY_CHANCE = constants.BONUS_RALLY_CHANCE
local RETREAT_MOVEMENT_PHEROMONE_LEVEL = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL
2017-05-01 00:51:07 +02:00
local CHUNK_SIZE = constants.CHUNK_SIZE
-- imported functions
2017-01-20 07:58:36 +02:00
local getChunkByPosition = mapUtils.getChunkByPosition
local processPendingChunks = chunkProcessor.processPendingChunks
local processMap = mapProcessor.processMap
2016-10-15 02:00:18 +02:00
local processPlayers = mapProcessor.processPlayers
2016-08-29 02:05:28 +02:00
local scanMap = mapProcessor.scanMap
2016-10-15 02:00:18 +02:00
local planning = aiPlanning.planning
2017-01-20 07:58:36 +02:00
local rallyUnits = aiBuilding.rallyUnits
local deathScent = pheromoneUtils.deathScent
2017-04-22 01:14:04 +02:00
local victoryScent = pheromoneUtils.victoryScent
local regroupSquads = unitGroupUtils.regroupSquads
local convertUnitGroupToSquad = unitGroupUtils.convertUnitGroupToSquad
local squadAttack = aiAttack.squadAttack
local squadBeginAttack = aiAttack.squadBeginAttack
local retreatUnits = aiDefense.retreatUnits
2017-05-19 09:47:24 +02:00
local addRemovePlayerEntity = entityUtils.addRemovePlayerEntity
local removeEnemyBase = entityUtils.removeEnemyBase
2017-05-06 11:03:28 +02:00
--local makeImmortalEntity = entityUtils.makeImmortalEntity
2017-05-19 09:47:24 +02:00
local processBases = baseProcessor.processBases
2016-08-25 02:05:20 +02:00
-- local references to global
local regionMap
local natives
local pendingChunks
-- hook functions
2016-09-13 00:33:00 +02:00
local function onLoad()
2016-08-25 02:05:20 +02:00
regionMap = global.regionMap
natives = global.natives
pendingChunks = global.pendingChunks
end
2016-09-13 00:33:00 +02:00
local function onChunkGenerated(event)
-- queue generated chunk for delayed processing, queuing is required because some mods (RSO) mess with chunk as they
-- are generated, which messes up the scoring.
if (event.surface.index == 1) then
pendingChunks[#pendingChunks+1] = event
end
2016-08-25 02:05:20 +02:00
end
2017-05-06 11:03:28 +02:00
local function onModSettingsChange(event)
if event and (string.sub(event.setting, 1, 7) ~= "rampant") then
return
end
natives.safeBuildings = settings.global["rampant-safeBuildings"].value
natives.safeEntities["curved-rail"] = settings.global["rampant-safeBuildings-curvedRail"].value
natives.safeEntities["straight-rail"] = settings.global["rampant-safeBuildings-straightRail"].value
natives.safeEntities["rail-signal"] = settings.global["rampant-safeBuildings-railSignals"].value
natives.safeEntities["rail-chain-signal"] = settings.global["rampant-safeBuildings-railChainSignals"].value
natives.safeEntities["train-stop"] = settings.global["rampant-safeBuildings-trainStops"].value
natives.safeEntityName["big-electric-pole"] = settings.global["rampant-safeBuildings-bigElectricPole"].value
natives.attackUsePlayer = settings.global["rampant-attackWaveGenerationUsePlayerProximity"].value
natives.attackUsePollution = settings.global["rampant-attackWaveGenerationUsePollution"].value
natives.attackThresholdMin = settings.global["rampant-attackWaveGenerationThresholdMin"].value
natives.attackThresholdMax = settings.global["rampant-attackWaveGenerationThresholdMax"].value
natives.attackThresholdRange = natives.attackThresholdMax - natives.attackThresholdMin
natives.attackWaveMaxSize = settings.global["rampant-attackWaveMaxSize"].value
natives.attackPlayerThreshold = settings.global["rampant-attackPlayerThreshold"].value
2017-05-14 00:32:16 +02:00
natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value
natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value
2017-05-06 11:03:28 +02:00
end
2016-09-13 00:33:00 +02:00
local function onConfigChanged()
if upgrade.attempt(natives, regionMap) then
2017-05-06 11:03:28 +02:00
onModSettingsChange(nil)
2017-05-14 08:31:31 +02:00
game.surfaces[1].print("Reindexing chunks, please wait")
2016-10-15 02:00:18 +02:00
-- clear old regionMap processing Queue
-- prevents queue adding duplicate chunks
-- chunks are by key, so should overwrite old
regionMap.processQueue = {}
regionMap.processPointer = 1
regionMap.scanPointer = 1
-- clear pending chunks, will be added when loop runs below
2017-04-16 08:04:22 +02:00
pendingChunks = {}
2016-10-15 02:00:18 +02:00
-- queue all current chunks that wont be generated during play
local surface = game.surfaces[1]
for chunk in surface.get_chunks() do
2017-05-08 08:56:11 +02:00
onChunkGenerated({ tick = game.tick,
surface = surface,
2016-10-15 02:00:18 +02:00
area = { left_top = { x = chunk.x * 32,
y = chunk.y * 32 }}})
end
end
end
2016-11-04 01:51:35 +02:00
local function onTick(event)
local tick = event.tick
2017-01-20 07:58:36 +02:00
if (tick == regionMap.processTick) then
regionMap.processTick = regionMap.processTick + INTERVAL_PROCESS
2016-09-13 00:33:00 +02:00
local surface = game.surfaces[1]
2017-04-25 06:08:41 +02:00
local evolutionFactor = game.forces.enemy.evolution_factor
2016-10-15 02:00:18 +02:00
local players = game.players
2017-05-08 08:56:11 +02:00
processPendingChunks(regionMap, surface, pendingChunks, natives)
scanMap(regionMap, surface, natives, evolutionFactor)
2016-10-15 02:00:18 +02:00
2017-01-20 07:58:36 +02:00
if (tick == regionMap.logicTick) then
regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC
natives.rallyCries = MAX_RALLY_CRIES
planning(natives, evolutionFactor, tick, surface)
2016-10-15 02:00:18 +02:00
2017-01-20 07:58:36 +02:00
regroupSquads(natives, evolutionFactor)
2016-10-15 02:00:18 +02:00
processPlayers(players, regionMap, surface, natives, evolutionFactor, tick)
2017-05-19 09:47:24 +02:00
processBases(regionMap, surface, natives, tick)
2016-10-15 02:00:18 +02:00
squadBeginAttack(natives, players, evolutionFactor)
squadAttack(regionMap, surface, natives)
end
2016-09-13 00:33:00 +02:00
2016-10-15 02:00:18 +02:00
processMap(regionMap, surface, natives, evolutionFactor)
2016-08-20 20:24:22 +02:00
end
end
2016-09-13 00:33:00 +02:00
local function onBuild(event)
2017-05-19 09:47:24 +02:00
addRemovePlayerEntity(regionMap, event.created_entity, natives, true, false)
end
2016-09-13 00:33:00 +02:00
local function onPickUp(event)
2017-05-19 09:47:24 +02:00
addRemovePlayerEntity(regionMap, event.entity, natives, false, false)
end
2016-09-13 00:33:00 +02:00
local function onDeath(event)
local entity = event.entity
local surface = entity.surface
if (surface.index == 1) then
if (entity.force.name == "enemy") then
if (entity.type == "unit") then
2017-05-19 09:47:24 +02:00
local entityPosition = entity.position
2017-01-20 07:58:36 +02:00
local deathChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y)
if (deathChunk ~= nil) then
-- drop death pheromone where unit died
deathScent(deathChunk)
if ((event.force ~= nil) and (event.force.name == "player")) then
2017-04-25 06:08:41 +02:00
local evolutionFactor = game.forces.enemy.evolution_factor
2017-01-20 07:58:36 +02:00
if (deathChunk[MOVEMENT_PHEROMONE] < -(evolutionFactor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) then
2017-04-22 01:14:04 +02:00
retreatUnits(deathChunk,
convertUnitGroupToSquad(natives,
entity.unit_group),
regionMap,
surface,
natives,
event.tick)
2017-01-20 07:58:36 +02:00
local rallyThreshold = BASE_RALLY_CHANCE + (evolutionFactor * BONUS_RALLY_CHANCE)
if (natives.rallyCries >= 0) and (math.random() < rallyThreshold) then
natives.rallyCries = natives.rallyCries - 1
rallyUnits(deathChunk,
regionMap,
surface,
natives,
evolutionFactor)
end
end
end
end
2017-04-16 08:04:22 +02:00
elseif (entity.type == "unit-spawner") or (entity.type == "turret") then
2017-05-19 09:47:24 +02:00
removeEnemyBase(regionMap, entity)
end
elseif (entity.force.name == "player") then
2016-11-04 01:51:35 +02:00
local creditNatives = false
2017-05-01 00:51:07 +02:00
local entityPosition = entity.position
2016-11-04 01:51:35 +02:00
if (event.force ~= nil) and (event.force.name == "enemy") then
creditNatives = true
2017-04-22 01:14:04 +02:00
local victoryChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y)
victoryScent(victoryChunk, entity.type)
2016-11-04 01:51:35 +02:00
end
2017-05-06 11:03:28 +02:00
if creditNatives and natives.safeBuildings and (natives.safeEntities[entity.type] or natives.safeEntityName[entity.name]) then
2017-05-01 00:51:07 +02:00
-- makeImmortalEntity(surface, entity)
-- patch (Needs to be removed)
local repairPosition = entityPosition
local repairName = entity.name
local repairForce = entity.force
local repairDirection = entity.direction
entity.destroy()
surface.create_entity({position=repairPosition,
name=repairName,
direction=repairDirection,
force=repairForce})
-- forces enemy to disperse
local enemies = surface.find_enemy_units({repairPosition.x, repairPosition.y}, CHUNK_SIZE)
for i=1, #enemies do
enemies[i].set_command({type=defines.command.wander,
distraction=defines.distraction.by_enemy})
end
else
2017-05-19 09:47:24 +02:00
addRemovePlayerEntity(regionMap, entity, natives, false, creditNatives)
end
end
end
end
local function onSurfaceTileChange(event)
2017-05-08 08:56:11 +02:00
local player = game.players[event.player_index]
if (player.surface.index==1) then
aiBuilding.fillTunnel(regionMap, player.surface, natives, event.positions)
end
end
2016-09-13 00:33:00 +02:00
local function onInit()
global.regionMap = {}
global.pendingChunks = {}
global.natives = {}
regionMap = global.regionMap
natives = global.natives
pendingChunks = global.pendingChunks
onConfigChanged()
end
-- hooks
script.on_init(onInit)
script.on_load(onLoad)
2017-05-06 11:03:28 +02:00
script.on_event(defines.events.on_runtime_mod_setting_changed,
onModSettingsChange)
2016-08-25 02:05:20 +02:00
script.on_configuration_changed(onConfigChanged)
script.on_event(defines.events.on_player_built_tile, onSurfaceTileChange)
script.on_event({defines.events.on_preplayer_mined_item,
defines.events.on_robot_pre_mined},
2016-11-04 09:26:19 +02:00
onPickUp)
script.on_event({defines.events.on_built_entity,
defines.events.on_robot_built_entity},
2016-11-04 09:26:19 +02:00
onBuild)
2016-09-09 12:02:50 +02:00
script.on_event(defines.events.on_entity_died, onDeath)
script.on_event(defines.events.on_tick, onTick)
script.on_event(defines.events.on_chunk_generated, onChunkGenerated)
2017-05-08 08:56:11 +02:00
remote.add_interface("rampantTests",
{
pheromoneLevels = tests.pheromoneLevels,
activeSquads = tests.activeSquads,
entitiesOnPlayerChunk = tests.entitiesOnPlayerChunk,
findNearestPlayerEnemy = tests.findNearestPlayerEnemy,
aiStats = tests.aiStats,
fillableDirtTest = tests.fillableDirtTest,
tunnelTest = tests.tunnelTest,
createEnemy = tests.createEnemy,
attackOrigin = tests.attackOrigin,
cheatMode = tests.cheatMode,
gaussianRandomTest = tests.gaussianRandomTest,
reveal = tests.reveal,
showMovementGrid = tests.showMovementGrid,
baseStats = tests.baseStats,
baseTiles = tests.baseTiles,
mergeBases = tests.mergeBases,
clearBases = tests.clearBases
}
)
2017-05-06 11:03:28 +02:00
remote.add_interface("rampant", interop)