2016-08-20 04:52:27 +02:00
|
|
|
-- imports
|
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local baseUtils = require("libs/BaseUtils")
|
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")
|
2016-08-05 06:47:51 +02:00
|
|
|
local chunkProcessor = require("libs/ChunkProcessor")
|
2017-05-19 09:47:24 +02:00
|
|
|
local baseProcessor = require("libs/BaseProcessor")
|
2016-08-05 06:47:51 +02:00
|
|
|
local mapProcessor = require("libs/MapProcessor")
|
2016-08-04 00:22:20 +02:00
|
|
|
local constants = require("libs/Constants")
|
2016-08-05 06:47:51 +02:00
|
|
|
local pheromoneUtils = require("libs/PheromoneUtils")
|
2017-06-13 05:16:43 +02:00
|
|
|
local squadDefense = require("libs/SquadDefense")
|
|
|
|
local squadAttack = require("libs/SquadAttack")
|
|
|
|
local aiAttackWave = require("libs/AIAttackWave")
|
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-11-21 09:27:03 +02:00
|
|
|
local chunkUtils = require("libs/ChunkUtils")
|
2017-05-19 09:47:24 +02:00
|
|
|
local upgrade = require("Upgrade")
|
2017-06-01 03:46:53 +02:00
|
|
|
local mathUtils = require("libs/MathUtils")
|
2017-06-01 09:03:07 +02:00
|
|
|
local config = require("config")
|
2016-08-04 00:22:20 +02:00
|
|
|
|
2016-10-15 02:00:18 +02:00
|
|
|
-- constants
|
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local SUICIDE_BITER_NEST_TIERS = constants.SUICIDE_BITER_NEST_TIERS
|
|
|
|
local SUICIDE_BITER_NEST_VARIATIONS = constants.SUICIDE_BITER_NEST_VARIATIONS
|
|
|
|
local NEUTRAL_NEST_TIERS = constants.NEUTRAL_NEST_TIERS
|
|
|
|
local NEUTRAL_NEST_VARIATIONS = constants.NEUTRAL_NEST_VARIATIONS
|
|
|
|
|
|
|
|
local BASE_ALIGNMENT_NEUTRAL = constants.BASE_ALIGNMENT_NEUTRAL
|
|
|
|
local BASE_ALIGNMENT_SUICIDE = constants.BASE_ALIGNMENT_SUICIDE
|
|
|
|
|
2016-10-15 02:00:18 +02:00
|
|
|
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
|
|
|
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
|
2018-01-01 07:49:36 +02:00
|
|
|
local INTERVAL_CHUNK = constants.INTERVAL_CHUNK
|
|
|
|
local INTERVAL_SCAN = constants.INTERVAL_SCAN
|
|
|
|
local INTERVAL_SQUAD = constants.INTERVAL_SQUAD
|
2016-10-15 02:00:18 +02:00
|
|
|
|
2017-01-20 07:58:36 +02:00
|
|
|
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
|
|
|
|
2017-11-21 09:27:03 +02:00
|
|
|
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
2017-08-08 10:19:51 +02:00
|
|
|
|
2017-06-01 09:03:07 +02:00
|
|
|
local AI_MAX_OVERFLOW_POINTS = constants.AI_MAX_OVERFLOW_POINTS
|
|
|
|
|
2018-01-02 01:31:14 +02:00
|
|
|
local RETREAT_GRAB_RADIUS = constants.RETREAT_GRAB_RADIUS
|
|
|
|
|
|
|
|
local RETREAT_SPAWNER_GRAB_RADIUS = constants.RETREAT_SPAWNER_GRAB_RADIUS
|
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
local DEFINES_COMMAND_GROUP = defines.command.group
|
|
|
|
local DEFINES_COMMAND_ATTACK_AREA = defines.command.attack_area
|
|
|
|
|
|
|
|
local CHUNK_SIZE = constants.CHUNK_SIZE
|
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local EVOLUTION_INCREMENTS = constants.EVOLUTION_INCREMENTS
|
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
local DEFINES_DISTRACTION_NONE = defines.distraction.none
|
|
|
|
local DEFINES_DISTRACTION_BY_ENEMY = defines.distraction.by_enemy
|
|
|
|
|
2017-06-01 03:46:53 +02:00
|
|
|
-- imported functions
|
2017-01-20 07:58:36 +02:00
|
|
|
|
2017-06-01 03:46:53 +02:00
|
|
|
local roundToNearest = mathUtils.roundToNearest
|
2017-01-20 07:58:36 +02:00
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
-- imported functions
|
|
|
|
|
2017-01-20 07:58:36 +02:00
|
|
|
local getChunkByPosition = mapUtils.getChunkByPosition
|
|
|
|
|
2018-01-02 20:36:23 +02:00
|
|
|
local entityForPassScan = chunkUtils.entityForPassScan
|
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
local processPendingChunks = chunkProcessor.processPendingChunks
|
2018-01-02 08:05:21 +02:00
|
|
|
local processScanChunks = chunkProcessor.processScanChunks
|
2016-08-20 04:52:27 +02:00
|
|
|
|
|
|
|
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-08-20 04:52:27 +02:00
|
|
|
|
2016-10-15 02:00:18 +02:00
|
|
|
local planning = aiPlanning.planning
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2017-06-13 05:16:43 +02:00
|
|
|
local rallyUnits = aiAttackWave.rallyUnits
|
2017-01-20 07:58:36 +02:00
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
local deathScent = pheromoneUtils.deathScent
|
2017-04-22 01:14:04 +02:00
|
|
|
local victoryScent = pheromoneUtils.victoryScent
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2017-05-24 08:46:23 +02:00
|
|
|
local cleanSquads = unitGroupUtils.cleanSquads
|
2016-08-20 04:52:27 +02:00
|
|
|
local regroupSquads = unitGroupUtils.regroupSquads
|
|
|
|
local convertUnitGroupToSquad = unitGroupUtils.convertUnitGroupToSquad
|
|
|
|
|
2017-06-13 05:16:43 +02:00
|
|
|
local squadsAttack = squadAttack.squadsAttack
|
|
|
|
local squadsBeginAttack = squadAttack.squadsBeginAttack
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2017-06-13 05:16:43 +02:00
|
|
|
local retreatUnits = squadDefense.retreatUnits
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2017-11-21 09:27:03 +02:00
|
|
|
local addRemovePlayerEntity = chunkUtils.addRemovePlayerEntity
|
|
|
|
local unregisterEnemyBaseStructure = chunkUtils.unregisterEnemyBaseStructure
|
|
|
|
local registerEnemyBaseStructure = chunkUtils.registerEnemyBaseStructure
|
|
|
|
local makeImmortalEntity = chunkUtils.makeImmortalEntity
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2018-01-15 01:10:56 +02:00
|
|
|
local upgradeEntity = baseUtils.upgradeEntity
|
|
|
|
|
2017-05-19 09:47:24 +02:00
|
|
|
local processBases = baseProcessor.processBases
|
2016-10-15 02:00:18 +02:00
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local mFloor = math.floor
|
2017-07-01 06:36:23 +02:00
|
|
|
local mRandom = math.random
|
|
|
|
|
2016-08-25 02:05:20 +02:00
|
|
|
-- local references to global
|
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
local map -- manages the chunks that make up the game world
|
2017-07-23 03:07:44 +02:00
|
|
|
local natives -- manages the enemy units, structures, and ai
|
|
|
|
local pendingChunks -- chunks that have yet to be processed by the mod
|
2016-08-25 02:05:20 +02:00
|
|
|
|
2016-07-30 00:44:31 +02:00
|
|
|
-- hook functions
|
|
|
|
|
2017-07-05 00:52:20 +02:00
|
|
|
local function onIonCannonFired(event)
|
|
|
|
--[[
|
|
|
|
event.force, event.surface, event.player_index, event.position, event.radius
|
|
|
|
--]]
|
|
|
|
local surface = event.surface
|
|
|
|
if (surface.index == 1) then
|
|
|
|
natives.points = natives.points + 3000
|
|
|
|
if (natives.points > AI_MAX_OVERFLOW_POINTS) then
|
|
|
|
natives.points = AI_MAX_OVERFLOW_POINTS
|
|
|
|
end
|
2018-01-14 07:48:21 +02:00
|
|
|
local chunk = getChunkByPosition(map, event.position)
|
2017-11-21 09:27:03 +02:00
|
|
|
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
2018-01-14 07:48:21 +02:00
|
|
|
rallyUnits(chunk, map, surface, natives, event.tick)
|
2017-07-05 00:52:20 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function hookEvents()
|
|
|
|
if config.ionCannonPresent then
|
|
|
|
script.on_event(remote.call("orbital_ion_cannon", "on_ion_cannon_fired"),
|
|
|
|
onIonCannonFired)
|
|
|
|
-- script.on_event(remote.call("orbital_ion_cannon", "on_ion_cannon_targeted"),
|
|
|
|
-- onIonCannonTargeted)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-09-13 00:33:00 +02:00
|
|
|
local function onLoad()
|
2018-01-14 07:48:21 +02:00
|
|
|
map = global.map
|
2016-08-25 02:05:20 +02:00
|
|
|
natives = global.natives
|
|
|
|
pendingChunks = global.pendingChunks
|
2017-07-05 00:52:20 +02:00
|
|
|
|
|
|
|
hookEvents()
|
2016-07-30 00:44:31 +02:00
|
|
|
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
|
|
|
|
|
2018-01-15 01:10:56 +02:00
|
|
|
local function rebuildMap()
|
2017-06-01 03:46:53 +02:00
|
|
|
game.surfaces[1].print("Rampant - Reindexing chunks, please wait.")
|
2018-01-14 07:48:21 +02:00
|
|
|
-- clear old map processing Queue
|
2017-05-28 06:50:37 +02:00
|
|
|
-- prevents queue adding duplicate chunks
|
|
|
|
-- chunks are by key, so should overwrite old
|
2017-06-01 03:46:53 +02:00
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
global.map = {}
|
|
|
|
map = global.map
|
|
|
|
map.processQueue = {}
|
|
|
|
map.processIndex = 1
|
|
|
|
map.scanIndex = 1
|
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
map.chunkToBase = {}
|
2018-01-14 07:48:21 +02:00
|
|
|
map.chunkToHives = {}
|
|
|
|
map.chunkToNests = {}
|
|
|
|
map.chunkToWorms = {}
|
|
|
|
map.chunkToRetreats = {}
|
|
|
|
map.chunkToRallys = {}
|
|
|
|
map.chunkToPlayerBase = {}
|
|
|
|
map.chunkToResource = {}
|
|
|
|
map.chunkToPassScan = {}
|
|
|
|
map.chunkToSquad = {}
|
2018-01-16 09:21:12 +02:00
|
|
|
|
|
|
|
natives.bases = {}
|
2018-01-15 01:10:56 +02:00
|
|
|
|
2017-06-16 03:30:26 +02:00
|
|
|
-- preallocating memory to be used in code, making it fast by reducing garbage generated.
|
2018-01-14 07:48:21 +02:00
|
|
|
map.neighbors = { SENTINEL_IMPASSABLE_CHUNK,
|
2018-01-15 01:10:56 +02:00
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK }
|
2018-01-14 07:48:21 +02:00
|
|
|
map.cardinalNeighbors = { SENTINEL_IMPASSABLE_CHUNK,
|
2018-01-15 01:10:56 +02:00
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK,
|
|
|
|
SENTINEL_IMPASSABLE_CHUNK }
|
2018-01-14 07:48:21 +02:00
|
|
|
map.position = {x=0,
|
2018-01-15 01:10:56 +02:00
|
|
|
y=0}
|
2017-12-21 05:50:36 +02:00
|
|
|
|
|
|
|
--this is shared between two different queries
|
2018-01-14 07:48:21 +02:00
|
|
|
map.area = {{0, 0}, {0, 0}}
|
|
|
|
map.countResourcesQuery = { area=map.area, type="resource" }
|
|
|
|
map.filteredEntitiesEnemyQuery = { area=map.area, force="enemy" }
|
|
|
|
map.filteredEntitiesEnemyUnitQuery = { area=map.area, force="enemy", type="unit", limit=301 }
|
|
|
|
map.filteredEntitiesEnemyTypeQuery = { area=map.area, force="enemy", type="unit-spawner" }
|
|
|
|
map.filteredEntitiesPlayerQuery = { area=map.area, force="player" }
|
|
|
|
map.canPlaceQuery = { name="", position={0,0} }
|
|
|
|
map.filteredTilesQuery = { name="", area=map.area }
|
|
|
|
|
|
|
|
map.attackAreaCommand = {
|
|
|
|
type = DEFINES_COMMAND_ATTACK_AREA,
|
|
|
|
destination = map.position,
|
|
|
|
radius = CHUNK_SIZE,
|
|
|
|
distraction = DEFINES_DISTRACTION_BY_ENEMY
|
|
|
|
}
|
|
|
|
|
|
|
|
map.retreatCommand = { type = DEFINES_COMMAND_GROUP,
|
|
|
|
group = nil,
|
|
|
|
distraction = DEFINES_DISTRACTION_NONE }
|
|
|
|
|
2017-06-01 03:46:53 +02:00
|
|
|
-- switched over to tick event
|
2018-01-14 07:48:21 +02:00
|
|
|
map.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
|
|
|
map.scanTick = roundToNearest(game.tick + INTERVAL_SCAN, INTERVAL_SCAN)
|
|
|
|
map.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS)
|
|
|
|
map.chunkTick = roundToNearest(game.tick + INTERVAL_CHUNK, INTERVAL_CHUNK)
|
|
|
|
map.squadTick = roundToNearest(game.tick + INTERVAL_SQUAD, INTERVAL_SQUAD)
|
2017-06-01 03:46:53 +02:00
|
|
|
|
2017-05-28 06:50:37 +02:00
|
|
|
-- clear pending chunks, will be added when loop runs below
|
2017-06-11 02:59:06 +02:00
|
|
|
global.pendingChunks = {}
|
|
|
|
pendingChunks = global.pendingChunks
|
2017-05-28 06:50:37 +02:00
|
|
|
|
|
|
|
-- queue all current chunks that wont be generated during play
|
|
|
|
local surface = game.surfaces[1]
|
2017-06-01 03:46:53 +02:00
|
|
|
local tick = game.tick
|
2017-05-28 06:50:37 +02:00
|
|
|
for chunk in surface.get_chunks() do
|
2017-06-01 03:46:53 +02:00
|
|
|
onChunkGenerated({ tick = tick,
|
2017-05-28 06:50:37 +02:00
|
|
|
surface = surface,
|
|
|
|
area = { left_top = { x = chunk.x * 32,
|
|
|
|
y = chunk.y * 32 }}})
|
2017-06-01 03:46:53 +02:00
|
|
|
end
|
2017-06-24 20:41:57 +02:00
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
processPendingChunks(natives, map, surface, pendingChunks, tick, game.forces.enemy.evolution_factor)
|
2017-05-28 06:50:37 +02:00
|
|
|
end
|
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local function rebuildNativeTables()
|
|
|
|
natives.evolutionTable = {}
|
|
|
|
|
|
|
|
local fileEntity = function(baseAlignment, entity)
|
|
|
|
local evoRequirement = mFloor(entity.prototype.build_base_evolution_requirement/EVOLUTION_INCREMENTS) * EVOLUTION_INCREMENTS
|
|
|
|
local eTable = natives.evolutionTable[baseAlignment]
|
|
|
|
if not eTable then
|
|
|
|
eTable = {}
|
|
|
|
natives.evolutionTable[baseAlignment] = eTable
|
|
|
|
end
|
|
|
|
local aTable = eTable[evoRequirement]
|
|
|
|
if not aTable then
|
|
|
|
aTable = {}
|
|
|
|
eTable[evoRequirement] = aTable
|
|
|
|
end
|
|
|
|
aTable[#aTable+1] = entity.name
|
2017-05-06 11:03:28 +02:00
|
|
|
end
|
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local surface = game.surfaces[1]
|
2017-05-24 08:46:23 +02:00
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local position = { x = 0, y = 0 }
|
2017-05-06 11:03:28 +02:00
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
for v = 1, SUICIDE_BITER_NEST_VARIATIONS do
|
|
|
|
for t = 1, SUICIDE_BITER_NEST_TIERS do
|
2018-01-15 09:41:55 +02:00
|
|
|
local entity = surface.create_entity({
|
2018-01-16 09:21:12 +02:00
|
|
|
name="suicide-biter-nest-v" .. v .. "-t" .. t .. "-rampant",
|
|
|
|
position = position
|
2018-01-15 09:41:55 +02:00
|
|
|
})
|
2018-01-16 09:21:12 +02:00
|
|
|
fileEntity(BASE_ALIGNMENT_SUICIDE, entity)
|
|
|
|
entity.destroy()
|
2018-01-15 09:41:55 +02:00
|
|
|
end
|
2018-01-15 01:10:56 +02:00
|
|
|
end
|
2018-01-16 09:21:12 +02:00
|
|
|
for v=1,NEUTRAL_NEST_VARIATIONS do
|
|
|
|
for t=1,NEUTRAL_NEST_TIERS do
|
|
|
|
local entity = surface.create_entity({
|
|
|
|
name="neutral-biter-nest-v" .. v .. "-t" .. t .. "-rampant",
|
|
|
|
position = position
|
|
|
|
})
|
|
|
|
fileEntity(BASE_ALIGNMENT_NEUTRAL, entity)
|
|
|
|
entity.destroy()
|
|
|
|
end
|
|
|
|
end
|
2018-01-15 09:41:55 +02:00
|
|
|
-- for v=1,ACID_NEST_VARIATIONS do
|
|
|
|
-- for t=1,ACID_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,FIRE_NEST_VARIATIONS do
|
|
|
|
-- for t=1,FIRE_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,PHYSICAL_NEST_VARIATIONS do
|
|
|
|
-- for t=1,PHYSICAL_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,LASER_NEST_VARIATIONS do
|
|
|
|
-- for t=1,LASER_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,INFERNO_NEST_VARIATIONS do
|
|
|
|
-- for t=1,INFERNO_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,POSION_NEST_VARIATIONS do
|
|
|
|
-- for t=1,POSION_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,INFESTER_NEST_VARIATIONS do
|
|
|
|
-- for t=1,INFESTER_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,TROLL_NEST_VARIATIONS do
|
|
|
|
-- for t=1,TROLL_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,FAST_NEST_VARIATIONS do
|
|
|
|
-- for t=1,FAST_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,WEB_NEST_VARIATIONS do
|
|
|
|
-- for t=1,WEB_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,DECAYING_NEST_VARIATIONS do
|
|
|
|
-- for t=1,DECAYING_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- for v=1,UNDYING_NEST_VARIATIONS do
|
|
|
|
-- for t=1,UNDYING_NEST_TIERS do
|
|
|
|
|
|
|
|
-- end
|
|
|
|
-- end
|
2018-01-15 01:10:56 +02:00
|
|
|
end
|
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
local function onModSettingsChange(event)
|
|
|
|
|
|
|
|
if event and (string.sub(event.setting, 1, 7) ~= "rampant") then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
upgrade.compareTable(natives, "safeBuildings", settings.global["rampant-safeBuildings"].value)
|
|
|
|
|
|
|
|
upgrade.compareTable(natives.safeEntities, "curved-rail", settings.global["rampant-safeBuildings-curvedRail"].value)
|
|
|
|
upgrade.compareTable(natives.safeEntities, "straight-rail", settings.global["rampant-safeBuildings-straightRail"].value)
|
|
|
|
upgrade.compareTable(natives.safeEntities, "rail-signal", settings.global["rampant-safeBuildings-railSignals"].value)
|
|
|
|
upgrade.compareTable(natives.safeEntities, "rail-chain-signal", settings.global["rampant-safeBuildings-railChainSignals"].value)
|
|
|
|
upgrade.compareTable(natives.safeEntities, "train-stop", settings.global["rampant-safeBuildings-trainStops"].value)
|
|
|
|
upgrade.compareTable(natives.safeEntities, "lamp", settings.global["rampant-safeBuildings-lamps"].value)
|
|
|
|
|
|
|
|
local changed, newValue = upgrade.compareTable(natives.safeEntityName,
|
|
|
|
"big-electric-pole",
|
|
|
|
settings.global["rampant-safeBuildings-bigElectricPole"].value)
|
|
|
|
if changed then
|
|
|
|
natives.safeEntityName["big-electric-pole"] = newValue
|
|
|
|
natives.safeEntityName["big-electric-pole-2"] = newValue
|
|
|
|
natives.safeEntityName["big-electric-pole-3"] = newValue
|
|
|
|
natives.safeEntityName["big-electric-pole-4"] = newValue
|
|
|
|
end
|
|
|
|
|
|
|
|
upgrade.compareTable(natives, "attackUsePlayer", settings.global["rampant-attackWaveGenerationUsePlayerProximity"].value)
|
|
|
|
upgrade.compareTable(natives, "attackUsePollution", settings.global["rampant-attackWaveGenerationUsePollution"].value)
|
|
|
|
|
|
|
|
upgrade.compareTable(natives, "attackThresholdMin", settings.global["rampant-attackWaveGenerationThresholdMin"].value)
|
|
|
|
upgrade.compareTable(natives, "attackThresholdMax", settings.global["rampant-attackWaveGenerationThresholdMax"].value)
|
|
|
|
upgrade.compareTable(natives, "attackThresholdRange", natives.attackThresholdMax - natives.attackThresholdMin)
|
|
|
|
upgrade.compareTable(natives, "attackWaveMaxSize", settings.global["rampant-attackWaveMaxSize"].value)
|
|
|
|
upgrade.compareTable(natives, "attackPlayerThreshold", settings.global["rampant-attackPlayerThreshold"].value)
|
|
|
|
upgrade.compareTable(natives, "aiNocturnalMode", settings.global["rampant-permanentNocturnal"].value)
|
|
|
|
upgrade.compareTable(natives, "aiPointsScaler", settings.global["rampant-aiPointsScaler"].value)
|
|
|
|
|
|
|
|
if upgrade.compareTable(natives, "enemySeed", settings.startup["rampant-enemySeed"].value) then
|
|
|
|
rebuildNativeTables()
|
|
|
|
end
|
|
|
|
-- RE-ENABLE WHEN COMPLETE
|
|
|
|
natives.useCustomAI = constants.DEV_CUSTOM_AI
|
|
|
|
-- changed, newValue = upgrade.compareTable(natives, "useCustomAI", settings.startup["rampant-useCustomAI"].value)
|
|
|
|
-- if natives.useCustomAI then
|
|
|
|
-- game.forces.enemy.ai_controllable = false
|
|
|
|
-- else
|
|
|
|
-- game.forces.enemy.ai_controllable = true
|
|
|
|
-- end
|
|
|
|
-- if changed and newValue then
|
|
|
|
-- rebuildMap()
|
|
|
|
-- return false
|
|
|
|
-- end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2017-05-28 06:50:37 +02:00
|
|
|
local function onConfigChanged()
|
2017-07-23 03:07:44 +02:00
|
|
|
local upgraded
|
2017-11-21 09:27:03 +02:00
|
|
|
upgraded, natives = upgrade.attempt(natives)
|
2017-07-23 03:07:44 +02:00
|
|
|
if upgraded and onModSettingsChange(nil) then
|
2018-01-15 01:10:56 +02:00
|
|
|
rebuildMap()
|
|
|
|
rebuildNativeTables()
|
2017-05-27 02:58:33 +02:00
|
|
|
end
|
2016-07-30 00:44:31 +02:00
|
|
|
end
|
|
|
|
|
2016-11-04 01:51:35 +02:00
|
|
|
local function onTick(event)
|
|
|
|
local tick = event.tick
|
2018-01-14 07:48:21 +02:00
|
|
|
if (tick == map.processTick) then
|
|
|
|
map.processTick = map.processTick + INTERVAL_PROCESS
|
2018-01-01 07:49:36 +02:00
|
|
|
|
|
|
|
local gameRef = game
|
2017-08-11 08:37:23 +02:00
|
|
|
local surface = gameRef.surfaces[1]
|
2018-01-01 07:49:36 +02:00
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
processPlayers(gameRef.players, map, surface, natives, tick)
|
2017-05-27 02:58:33 +02:00
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
processMap(map, surface, natives, tick)
|
2018-01-01 07:49:36 +02:00
|
|
|
end
|
2018-01-14 07:48:21 +02:00
|
|
|
if (tick == map.scanTick) then
|
|
|
|
map.scanTick = map.scanTick + INTERVAL_SCAN
|
2018-01-01 07:49:36 +02:00
|
|
|
local surface = game.surfaces[1]
|
2016-10-15 02:00:18 +02:00
|
|
|
|
2018-01-16 09:21:12 +02:00
|
|
|
processPendingChunks(natives, map, surface, pendingChunks, tick, game.forces.enemy.evolution_factor)
|
2017-01-20 07:58:36 +02:00
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
scanMap(map, surface, natives)
|
2018-01-02 08:05:21 +02:00
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
map.chunkToPassScan = processScanChunks(map, surface)
|
2018-01-01 07:49:36 +02:00
|
|
|
end
|
2018-01-14 07:48:21 +02:00
|
|
|
if (tick == map.logicTick) then
|
|
|
|
map.logicTick = map.logicTick + INTERVAL_LOGIC
|
2017-06-01 03:46:53 +02:00
|
|
|
|
2018-01-01 07:49:36 +02:00
|
|
|
local gameRef = game
|
|
|
|
local surface = gameRef.surfaces[1]
|
2018-01-02 08:05:21 +02:00
|
|
|
|
2018-01-01 07:49:36 +02:00
|
|
|
planning(natives,
|
|
|
|
gameRef.forces.enemy.evolution_factor,
|
|
|
|
tick,
|
|
|
|
surface)
|
2017-05-19 09:47:24 +02:00
|
|
|
|
2018-01-01 07:49:36 +02:00
|
|
|
if natives.useCustomAI then
|
2018-01-14 07:48:21 +02:00
|
|
|
processBases(map, surface, natives, tick)
|
2017-12-31 21:12:40 +02:00
|
|
|
end
|
2018-01-01 07:49:36 +02:00
|
|
|
end
|
2018-01-14 07:48:21 +02:00
|
|
|
if (tick == map.squadTick) then
|
|
|
|
map.squadTick = map.squadTick + INTERVAL_SQUAD
|
2016-09-13 00:33:00 +02:00
|
|
|
|
2018-01-01 07:49:36 +02:00
|
|
|
local gameRef = game
|
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
cleanSquads(natives, map)
|
|
|
|
regroupSquads(natives, map)
|
2018-01-01 07:49:36 +02:00
|
|
|
|
|
|
|
squadsBeginAttack(natives, gameRef.players)
|
2018-01-14 07:48:21 +02:00
|
|
|
squadsAttack(map, gameRef.surfaces[1], natives)
|
2016-08-20 20:24:22 +02:00
|
|
|
end
|
2016-08-05 06:47:51 +02:00
|
|
|
end
|
|
|
|
|
2016-09-13 00:33:00 +02:00
|
|
|
local function onBuild(event)
|
2017-11-21 09:27:03 +02:00
|
|
|
local entity = event.created_entity
|
2018-01-02 08:05:21 +02:00
|
|
|
if (entity.surface.index == 1) then
|
2018-01-14 07:48:21 +02:00
|
|
|
addRemovePlayerEntity(map, entity, natives, true, false)
|
2018-01-02 08:05:21 +02:00
|
|
|
if natives.safeBuildings then
|
|
|
|
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
|
|
|
|
entity.destructible = false
|
|
|
|
end
|
2017-05-24 08:46:23 +02:00
|
|
|
end
|
|
|
|
end
|
2016-08-18 07:55:08 +02:00
|
|
|
end
|
|
|
|
|
2017-08-08 10:19:51 +02:00
|
|
|
local function onMine(event)
|
2018-01-02 08:05:21 +02:00
|
|
|
local entity = event.entity
|
|
|
|
local surface = entity.surface
|
|
|
|
if (surface.index == 1) then
|
2018-01-14 07:48:21 +02:00
|
|
|
addRemovePlayerEntity(map, entity, natives, false, false)
|
2018-01-02 08:05:21 +02:00
|
|
|
end
|
2016-08-18 07:55:08 +02:00
|
|
|
end
|
|
|
|
|
2016-09-13 00:33:00 +02:00
|
|
|
local function onDeath(event)
|
2016-08-05 06:47:51 +02:00
|
|
|
local entity = event.entity
|
2016-08-27 08:44:17 +02:00
|
|
|
local surface = entity.surface
|
|
|
|
if (surface.index == 1) then
|
2017-11-21 09:27:03 +02:00
|
|
|
local entityPosition = entity.position
|
2018-01-14 07:48:21 +02:00
|
|
|
local chunk = getChunkByPosition(map, entityPosition)
|
2018-01-02 01:31:14 +02:00
|
|
|
local cause = event.cause
|
2016-08-25 01:30:45 +02:00
|
|
|
if (entity.force.name == "enemy") then
|
|
|
|
if (entity.type == "unit") then
|
2017-05-24 08:46:23 +02:00
|
|
|
|
2017-12-29 07:38:10 +02:00
|
|
|
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
2017-01-20 07:58:36 +02:00
|
|
|
-- drop death pheromone where unit died
|
2017-12-29 07:38:10 +02:00
|
|
|
deathScent(chunk)
|
2017-01-20 07:58:36 +02:00
|
|
|
|
2017-12-29 07:38:10 +02:00
|
|
|
if event.force and (event.force.name == "player") and (chunk[MOVEMENT_PHEROMONE] < natives.retreatThreshold) then
|
2017-05-24 08:46:23 +02:00
|
|
|
local tick = event.tick
|
2017-06-01 03:46:53 +02:00
|
|
|
|
2018-01-02 01:31:14 +02:00
|
|
|
local artilleryBlast = (cause and ((cause.type == "artillery-wagon") or (cause.type == "artillery-turret")))
|
|
|
|
|
2017-12-29 07:38:10 +02:00
|
|
|
retreatUnits(chunk,
|
2017-06-09 07:18:59 +02:00
|
|
|
entityPosition,
|
2017-11-21 09:27:03 +02:00
|
|
|
convertUnitGroupToSquad(natives, entity.unit_group),
|
2018-01-14 07:48:21 +02:00
|
|
|
map,
|
2017-06-01 03:46:53 +02:00
|
|
|
surface,
|
|
|
|
natives,
|
2018-01-02 01:31:14 +02:00
|
|
|
tick,
|
|
|
|
(artilleryBlast and RETREAT_SPAWNER_GRAB_RADIUS) or RETREAT_GRAB_RADIUS,
|
|
|
|
artilleryBlast)
|
2017-11-21 09:27:03 +02:00
|
|
|
|
2017-07-01 06:36:23 +02:00
|
|
|
if (mRandom() < natives.rallyThreshold) and not surface.peaceful_mode then
|
2018-01-14 07:48:21 +02:00
|
|
|
rallyUnits(chunk, map, surface, natives, tick)
|
2017-01-20 07:58:36 +02:00
|
|
|
end
|
|
|
|
end
|
2016-08-25 01:30:45 +02:00
|
|
|
end
|
|
|
|
|
2018-01-02 08:05:21 +02:00
|
|
|
elseif event.force and (event.force.name == "player") and (entity.type == "unit-spawner") or (entity.type == "turret") then
|
2018-01-02 01:31:14 +02:00
|
|
|
local tick = event.tick
|
|
|
|
|
2018-01-02 08:05:21 +02:00
|
|
|
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
2018-01-14 07:48:21 +02:00
|
|
|
unregisterEnemyBaseStructure(map, entity)
|
2018-01-02 01:31:14 +02:00
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
rallyUnits(chunk, map, surface, natives, tick)
|
2018-01-02 01:31:14 +02:00
|
|
|
|
|
|
|
retreatUnits(chunk,
|
|
|
|
entityPosition,
|
|
|
|
nil,
|
2018-01-14 07:48:21 +02:00
|
|
|
map,
|
2018-01-02 01:31:14 +02:00
|
|
|
surface,
|
|
|
|
natives,
|
|
|
|
tick,
|
|
|
|
RETREAT_SPAWNER_GRAB_RADIUS,
|
|
|
|
(cause and ((cause.type == "artillery-wagon") or (cause.type == "artillery-turret"))))
|
|
|
|
end
|
2016-08-18 07:55:08 +02:00
|
|
|
end
|
2016-08-25 01:30:45 +02:00
|
|
|
elseif (entity.force.name == "player") then
|
2016-11-04 01:51:35 +02:00
|
|
|
local creditNatives = false
|
|
|
|
if (event.force ~= nil) and (event.force.name == "enemy") then
|
|
|
|
creditNatives = true
|
2017-12-29 07:38:10 +02:00
|
|
|
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
|
|
|
victoryScent(chunk, entity.type)
|
2017-05-27 02:58:33 +02:00
|
|
|
end
|
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-24 08:46:23 +02:00
|
|
|
makeImmortalEntity(surface, entity)
|
2017-04-17 04:46:36 +02:00
|
|
|
else
|
2018-01-14 07:48:21 +02:00
|
|
|
addRemovePlayerEntity(map, entity, natives, false, creditNatives)
|
2017-04-17 04:46:36 +02:00
|
|
|
end
|
2016-08-09 04:54:41 +02:00
|
|
|
end
|
2016-08-03 17:54:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-06-01 03:46:53 +02:00
|
|
|
local function onEnemyBaseBuild(event)
|
2018-01-02 08:05:21 +02:00
|
|
|
local entity = event.entity
|
|
|
|
local surface = entity.surface
|
|
|
|
if (surface.index == 1) then
|
2018-01-15 01:10:56 +02:00
|
|
|
entity = upgradeEntity(map, entity, surface, natives)
|
2018-01-16 09:21:12 +02:00
|
|
|
event.entity = registerEnemyBaseStructure(map, entity, natives, game.forces.enemy.evolution_factor, surface, event.tick)
|
2018-01-02 08:05:21 +02:00
|
|
|
end
|
2017-06-01 03:46:53 +02:00
|
|
|
end
|
|
|
|
|
2016-09-13 01:23:26 +02:00
|
|
|
local function onSurfaceTileChange(event)
|
2018-01-18 07:34:23 +02:00
|
|
|
local surfaceIndex = event.surface_index or (event.robot and event.robot.surface.index)
|
2018-01-02 08:05:21 +02:00
|
|
|
if (event.item.name == "landfill") and (surfaceIndex == 1) then
|
|
|
|
local chunks = {}
|
|
|
|
local positions = event.positions
|
|
|
|
for i=1,#positions do
|
|
|
|
local position = positions[i]
|
2018-01-14 07:48:21 +02:00
|
|
|
local chunk = mapUtils.getChunkByPosition(map, position, true)
|
2018-01-02 08:05:21 +02:00
|
|
|
|
2018-01-14 09:07:29 +02:00
|
|
|
-- weird bug with table pointer equality using name instead of pointer comparison
|
2018-01-02 08:05:21 +02:00
|
|
|
if not chunk.name then
|
2018-01-14 07:48:21 +02:00
|
|
|
map.chunkToPassScan[chunk] = true
|
2018-01-02 08:05:21 +02:00
|
|
|
else
|
|
|
|
local x,y = mapUtils.positionToChunkXY(position)
|
|
|
|
local addMe = true
|
|
|
|
for ci=1,#chunks do
|
|
|
|
local c = chunks[ci]
|
|
|
|
if (c.x == x) and (c.y == y) then
|
|
|
|
addMe = false
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if addMe then
|
|
|
|
chunks[#chunks+1] = {x=x,y=y}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for i=1,#chunks do
|
|
|
|
onChunkGenerated({area = { left_top = chunks[i] },
|
|
|
|
surface = game.surfaces[surfaceIndex]})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function onResourceDepleted(event)
|
|
|
|
local entity = event.entity
|
|
|
|
if (entity.surface.index == 1) then
|
2018-01-14 07:48:21 +02:00
|
|
|
chunkUtils.unregisterResource(entity, map)
|
2018-01-02 08:05:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function onUsedCapsule(event)
|
|
|
|
local surface = game.players[event.player_index].surface
|
|
|
|
if (event.item.name == "cliff-explosives") and (surface.index == 1) then
|
|
|
|
local cliffs = surface.find_entities_filtered({area={{event.position.x-0.75,event.position.y-0.75},
|
|
|
|
{event.position.x+0.75,event.position.y+0.75}},
|
|
|
|
type="cliff"})
|
|
|
|
for i=1,#cliffs do
|
2018-01-14 07:48:21 +02:00
|
|
|
entityForPassScan(map, cliffs[i])
|
2018-01-02 08:05:21 +02:00
|
|
|
end
|
|
|
|
end
|
2016-08-21 02:28:35 +02:00
|
|
|
end
|
|
|
|
|
2016-09-13 00:33:00 +02:00
|
|
|
local function onInit()
|
2018-01-14 07:48:21 +02:00
|
|
|
global.map = {}
|
2016-09-13 00:33:00 +02:00
|
|
|
global.pendingChunks = {}
|
|
|
|
global.natives = {}
|
|
|
|
|
2018-01-14 07:48:21 +02:00
|
|
|
map = global.map
|
2016-09-13 00:33:00 +02:00
|
|
|
natives = global.natives
|
|
|
|
pendingChunks = global.pendingChunks
|
|
|
|
|
|
|
|
onConfigChanged()
|
2017-07-05 00:52:20 +02:00
|
|
|
hookEvents()
|
2016-09-13 00:33:00 +02:00
|
|
|
end
|
|
|
|
|
2016-08-04 02:22:27 +02:00
|
|
|
-- hooks
|
|
|
|
|
2016-07-30 00:44:31 +02:00
|
|
|
script.on_init(onInit)
|
|
|
|
script.on_load(onLoad)
|
2017-11-21 09:27:03 +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)
|
2016-07-30 00:44:31 +02:00
|
|
|
|
2018-01-02 08:05:21 +02:00
|
|
|
script.on_event(defines.events.on_resource_depleted, onResourceDepleted)
|
|
|
|
script.on_event({defines.events.on_player_built_tile,
|
|
|
|
defines.events.on_robot_built_tile}, onSurfaceTileChange)
|
|
|
|
|
|
|
|
script.on_event(defines.events.on_player_used_capsule, onUsedCapsule)
|
2016-08-21 02:28:35 +02:00
|
|
|
|
2017-11-21 09:27:03 +02:00
|
|
|
script.on_event(defines.events.on_biter_base_built, onEnemyBaseBuild)
|
2017-08-14 02:35:44 +02:00
|
|
|
script.on_event({defines.events.on_player_mined_entity,
|
2017-11-21 09:27:03 +02:00
|
|
|
defines.events.on_robot_mined_entity}, onMine)
|
2016-08-18 07:55:08 +02:00
|
|
|
script.on_event({defines.events.on_built_entity,
|
2017-11-21 09:27:03 +02:00
|
|
|
defines.events.on_robot_built_entity}, onBuild)
|
2016-09-09 12:02:50 +02:00
|
|
|
|
|
|
|
script.on_event(defines.events.on_entity_died, onDeath)
|
2016-08-20 04:52:27 +02:00
|
|
|
script.on_event(defines.events.on_tick, onTick)
|
2016-07-30 00:44:31 +02:00
|
|
|
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,
|
2017-12-31 21:36:23 +02:00
|
|
|
showMovementGrid = tests.showMovementGrid,
|
2018-01-16 09:21:12 +02:00
|
|
|
showBaseGrid = tests.showBaseGrid,
|
2017-05-08 08:56:11 +02:00
|
|
|
baseStats = tests.baseStats,
|
|
|
|
mergeBases = tests.mergeBases,
|
2017-05-28 06:50:37 +02:00
|
|
|
clearBases = tests.clearBases,
|
|
|
|
getOffsetChunk = tests.getOffsetChunk,
|
2017-06-08 02:57:24 +02:00
|
|
|
registeredNest = tests.registeredNest,
|
2017-12-31 21:36:23 +02:00
|
|
|
colorResourcePoints = tests.colorResourcePoints,
|
2018-01-16 09:21:12 +02:00
|
|
|
entityStats = tests.entityStats,
|
2017-12-29 07:38:10 +02:00
|
|
|
stepAdvanceTendrils = tests.stepAdvanceTendrils,
|
2018-01-01 07:49:36 +02:00
|
|
|
exportAiState = tests.exportAiState(onTick)
|
2017-05-08 08:56:11 +02:00
|
|
|
}
|
|
|
|
)
|
2017-05-06 11:03:28 +02:00
|
|
|
|
|
|
|
remote.add_interface("rampant", interop)
|