mirror of
https://github.com/veden/Rampant.git
synced 2025-09-16 09:16:43 +02:00
working adjustments and refactoring
This commit is contained in:
@@ -48,7 +48,6 @@ Configure Options not in game menu:
|
||||
- Pathfinding - Unit groups will use potential fields to perform only single step pathfinding allowing for efficient and dynamic pathing
|
||||
- Peace mode - If something sets peace mode, Rampant will respect it
|
||||
- Ion Cannon Reaction - Firing the Ion Cannon will cause nests around the blast site to form into an attack wave and agitate all biters
|
||||
- Item Collector + Technology to unlock it - An entity that collects the items on the ground around itself
|
||||
|
||||
# Planned Features
|
||||
|
||||
@@ -61,6 +60,14 @@ Configure Options not in game menu:
|
||||
|
||||
# Version History
|
||||
|
||||
0.15.23 -
|
||||
- Fixed: Retreat radius being centered on chunk corner instead of on the unit dying
|
||||
- Fixed: Spitter flamethrower sound fx
|
||||
- Moved: Item Collector into separate mod
|
||||
- Balance: Adjusted spitter and worms damages, ranges, and cooldowns to be more inline with vanilla
|
||||
- Optimization: Reduced memory footprint for faster saving and loading
|
||||
- Framework: Reorganization of files
|
||||
|
||||
0.15.22 -
|
||||
- Contribution - Martok88, Improvement: Added optional attack wave message per player
|
||||
|
||||
|
26
Upgrade.lua
26
Upgrade.lua
@@ -8,7 +8,6 @@ local mathUtils = require("libs/MathUtils")
|
||||
-- constants
|
||||
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
|
||||
|
||||
-- imported functions
|
||||
|
||||
@@ -16,7 +15,7 @@ local roundToNearest = mathUtils.roundToNearest
|
||||
|
||||
-- module code
|
||||
|
||||
function upgrade.attempt(natives, world)
|
||||
function upgrade.attempt(natives)
|
||||
local starting = global.version
|
||||
if (global.version == nil) then
|
||||
natives.squads = {}
|
||||
@@ -157,25 +156,14 @@ function upgrade.attempt(natives, world)
|
||||
game.surfaces[1].print("Rampant - Version 0.15.17")
|
||||
global.version = constants.VERSION_27
|
||||
end
|
||||
if (global.version < constants.VERSION_28) then
|
||||
if (global.version < constants.VERSION_33) then
|
||||
|
||||
if (world == nil) then
|
||||
global.world = {}
|
||||
world = global.world
|
||||
global.world = nil
|
||||
|
||||
game.surfaces[1].print("Rampant - Version 0.15.23")
|
||||
global.version = constants.VERSION_33
|
||||
end
|
||||
|
||||
world.itemCollectorLookup = {}
|
||||
world.itemCollectorEvents = {}
|
||||
|
||||
game.surfaces[1].print("Rampant - Version 0.15.18")
|
||||
global.version = constants.VERSION_28
|
||||
end
|
||||
if (global.version < constants.VERSION_32) then
|
||||
|
||||
game.surfaces[1].print("Rampant - Version 0.15.22")
|
||||
global.version = constants.VERSION_32
|
||||
end
|
||||
return starting ~= global.version, natives, world
|
||||
return starting ~= global.version, natives
|
||||
end
|
||||
|
||||
function upgrade.compareTable(entities, option, new)
|
||||
|
223
control.lua
223
control.lua
@@ -1,6 +1,5 @@
|
||||
-- imports
|
||||
|
||||
local entityUtils = require("libs/EntityUtils")
|
||||
local mapUtils = require("libs/MapUtils")
|
||||
local unitGroupUtils = require("libs/UnitGroupUtils")
|
||||
local chunkProcessor = require("libs/ChunkProcessor")
|
||||
@@ -14,14 +13,10 @@ local aiAttackWave = require("libs/AIAttackWave")
|
||||
local aiPlanning = require("libs/AIPlanning")
|
||||
local interop = require("libs/Interop")
|
||||
local tests = require("tests")
|
||||
local chunkUtils = require("libs/ChunkUtils")
|
||||
local upgrade = require("Upgrade")
|
||||
local baseRegisterUtils = require("libs/BaseRegisterUtils")
|
||||
local mathUtils = require("libs/MathUtils")
|
||||
local config = require("config")
|
||||
local worldProcessor = require("libs/WorldProcessor")
|
||||
local inventoryUtils = require("libs/InventoryUtils")
|
||||
local playerUtils = require("libs/PlayerUtils")
|
||||
local buildUtils = require("libs/BuildUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
@@ -30,12 +25,7 @@ local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
|
||||
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
|
||||
local DEFINES_INVENTORY_PLAYER_MAIN = defines.inventory.player_main
|
||||
local DEFINES_INVENTORY_GOD_MAIN = defines.inventory.god_main
|
||||
local DEFINES_INVENTORY_PLAYER_QUICKBAR = defines.inventory.player_quickbar
|
||||
local DEFINES_INVENTORY_GOD_QUICKBAR = defines.inventory.god_quickbar
|
||||
|
||||
local ITEM_COLLECTOR_MAX_QUEUE_SIZE = constants.ITEM_COLLECTOR_MAX_QUEUE_SIZE
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
local AI_MAX_OVERFLOW_POINTS = constants.AI_MAX_OVERFLOW_POINTS
|
||||
|
||||
@@ -49,17 +39,6 @@ local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
|
||||
local processPendingChunks = chunkProcessor.processPendingChunks
|
||||
|
||||
local buildComplexEntity = buildUtils.buildComplexEntity
|
||||
local mineComplexEntity = buildUtils.mineComplexEntity
|
||||
|
||||
local getPlayerCursorStack = playerUtils.getPlayerCursorStack
|
||||
|
||||
local swapItemStack = inventoryUtils.swapItemStack
|
||||
local swapItemInventory = inventoryUtils.swapItemInventory
|
||||
local topOffHand = inventoryUtils.topOffHand
|
||||
|
||||
local processWorld = worldProcessor.processWorld
|
||||
|
||||
local processMap = mapProcessor.processMap
|
||||
local processPlayers = mapProcessor.processPlayers
|
||||
local scanMap = mapProcessor.scanMap
|
||||
@@ -80,23 +59,22 @@ local squadsBeginAttack = squadAttack.squadsBeginAttack
|
||||
|
||||
local retreatUnits = squadDefense.retreatUnits
|
||||
|
||||
local addRemovePlayerEntity = entityUtils.addRemovePlayerEntity
|
||||
local unregisterEnemyBaseStructure = baseRegisterUtils.unregisterEnemyBaseStructure
|
||||
local registerEnemyBaseStructure = baseRegisterUtils.registerEnemyBaseStructure
|
||||
local makeImmortalEntity = entityUtils.makeImmortalEntity
|
||||
local addRemovePlayerEntity = chunkUtils.addRemovePlayerEntity
|
||||
local unregisterEnemyBaseStructure = chunkUtils.unregisterEnemyBaseStructure
|
||||
local registerEnemyBaseStructure = chunkUtils.registerEnemyBaseStructure
|
||||
local makeImmortalEntity = chunkUtils.makeImmortalEntity
|
||||
|
||||
local processBases = baseProcessor.processBases
|
||||
|
||||
local mRandom = math.random
|
||||
|
||||
local getPlayerInventory = playerUtils.getPlayerInventory
|
||||
local positionToChunkXY = mapUtils.positionToChunkXY
|
||||
|
||||
-- local references to global
|
||||
|
||||
local regionMap -- manages the chunks that make up the game world
|
||||
local natives -- manages the enemy units, structures, and ai
|
||||
local pendingChunks -- chunks that have yet to be processed by the mod
|
||||
local world -- manages the player built structures and any other events in the world
|
||||
|
||||
-- hook functions
|
||||
|
||||
@@ -110,13 +88,10 @@ local function onIonCannonFired(event)
|
||||
if (natives.points > AI_MAX_OVERFLOW_POINTS) then
|
||||
natives.points = AI_MAX_OVERFLOW_POINTS
|
||||
end
|
||||
local chunk = getChunkByPosition(regionMap, event.position.x, event.position.y)
|
||||
if chunk then
|
||||
rallyUnits(chunk,
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
event.tick)
|
||||
local chunkX, chunkY = positionToChunkXY(event.position)
|
||||
local chunk = getChunkByPosition(regionMap, chunkX, chunkY)
|
||||
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
rallyUnits(chunk, regionMap, surface, natives, event.tick)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -134,7 +109,6 @@ local function onLoad()
|
||||
regionMap = global.regionMap
|
||||
natives = global.natives
|
||||
pendingChunks = global.pendingChunks
|
||||
world = global.world
|
||||
|
||||
hookEvents()
|
||||
end
|
||||
@@ -158,9 +132,28 @@ local function rebuildRegionMap()
|
||||
regionMap.processQueue = {}
|
||||
regionMap.processIndex = 1
|
||||
regionMap.scanIndex = 1
|
||||
|
||||
regionMap.chunkToHives = {}
|
||||
regionMap.chunkToNests = {}
|
||||
regionMap.chunkToWorms = {}
|
||||
regionMap.chunkToRetreats = {}
|
||||
regionMap.chunkToRallys = {}
|
||||
regionMap.chunkToPlayerBase = {}
|
||||
regionMap.chunkToResource = {}
|
||||
|
||||
-- preallocating memory to be used in code, making it fast by reducing garbage generated.
|
||||
regionMap.neighbors = { nil, nil, nil, nil, nil, nil, nil, nil }
|
||||
regionMap.cardinalNeighbors = { nil, nil, nil, nil }
|
||||
regionMap.neighbors = { SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK }
|
||||
regionMap.cardinalNeighbors = { SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK,
|
||||
SENTINEL_IMPASSABLE_CHUNK }
|
||||
regionMap.chunkTiles = {}
|
||||
regionMap.position = {x=0,
|
||||
y=0}
|
||||
@@ -242,7 +235,7 @@ end
|
||||
|
||||
local function onConfigChanged()
|
||||
local upgraded
|
||||
upgraded, natives, world = upgrade.attempt(natives, world)
|
||||
upgraded, natives = upgrade.attempt(natives)
|
||||
if upgraded and onModSettingsChange(nil) then
|
||||
rebuildRegionMap()
|
||||
end
|
||||
@@ -271,8 +264,6 @@ local function onTick(event)
|
||||
cleanSquads(natives)
|
||||
regroupSquads(natives)
|
||||
|
||||
processWorld(surface, world, tick)
|
||||
|
||||
processPlayers(players, regionMap, surface, natives, tick)
|
||||
|
||||
if natives.useCustomAI then
|
||||
@@ -288,7 +279,7 @@ local function onTick(event)
|
||||
end
|
||||
|
||||
local function onBuild(event)
|
||||
local entity = buildComplexEntity(event.created_entity, world)
|
||||
local entity = event.created_entity
|
||||
addRemovePlayerEntity(regionMap, entity, natives, true, false)
|
||||
if natives.safeBuildings then
|
||||
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
|
||||
@@ -298,24 +289,20 @@ local function onBuild(event)
|
||||
end
|
||||
|
||||
local function onMine(event)
|
||||
mineComplexEntity(addRemovePlayerEntity(regionMap,
|
||||
event.entity,
|
||||
natives,
|
||||
false,
|
||||
false),
|
||||
world)
|
||||
addRemovePlayerEntity(regionMap, event.entity, natives, false, false)
|
||||
end
|
||||
|
||||
local function onDeath(event)
|
||||
local entity = event.entity
|
||||
local surface = entity.surface
|
||||
if (surface.index == 1) then
|
||||
local entityPosition = entity.position
|
||||
local chunkX, chunkY = positionToChunkXY(entityPosition)
|
||||
if (entity.force.name == "enemy") then
|
||||
if (entity.type == "unit") then
|
||||
local entityPosition = entity.position
|
||||
local deathChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y)
|
||||
local deathChunk = getChunkByPosition(regionMap, chunkX, chunkY)
|
||||
|
||||
if deathChunk then
|
||||
if (deathChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
-- drop death pheromone where unit died
|
||||
deathScent(deathChunk)
|
||||
|
||||
@@ -324,18 +311,14 @@ local function onDeath(event)
|
||||
|
||||
retreatUnits(deathChunk,
|
||||
entityPosition,
|
||||
convertUnitGroupToSquad(natives,
|
||||
entity.unit_group),
|
||||
convertUnitGroupToSquad(natives, entity.unit_group),
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
tick)
|
||||
|
||||
if (mRandom() < natives.rallyThreshold) and not surface.peaceful_mode then
|
||||
rallyUnits(deathChunk,
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
tick)
|
||||
rallyUnits(deathChunk, regionMap, surface, natives, tick)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -345,32 +328,24 @@ local function onDeath(event)
|
||||
end
|
||||
elseif (entity.force.name == "player") then
|
||||
local creditNatives = false
|
||||
local entityPosition = entity.position
|
||||
if (event.force ~= nil) and (event.force.name == "enemy") then
|
||||
creditNatives = true
|
||||
local victoryChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y)
|
||||
if victoryChunk then
|
||||
local victoryChunk = getChunkByPosition(regionMap, chunkX, chunkY)
|
||||
if (victoryChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
victoryScent(victoryChunk, entity.type)
|
||||
end
|
||||
end
|
||||
if creditNatives and natives.safeBuildings and (natives.safeEntities[entity.type] or natives.safeEntityName[entity.name]) then
|
||||
makeImmortalEntity(surface, entity)
|
||||
else
|
||||
mineComplexEntity(addRemovePlayerEntity(regionMap,
|
||||
entity,
|
||||
natives,
|
||||
false,
|
||||
creditNatives),
|
||||
world,
|
||||
true)
|
||||
addRemovePlayerEntity(regionMap, entity, natives, false, creditNatives)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onEnemyBaseBuild(event)
|
||||
local entity = event.entity
|
||||
registerEnemyBaseStructure(regionMap, entity, nil)
|
||||
registerEnemyBaseStructure(regionMap, event.entity, nil)
|
||||
end
|
||||
|
||||
local function onSurfaceTileChange(event)
|
||||
@@ -384,128 +359,30 @@ local function onInit()
|
||||
global.regionMap = {}
|
||||
global.pendingChunks = {}
|
||||
global.natives = {}
|
||||
global.world = {}
|
||||
|
||||
regionMap = global.regionMap
|
||||
natives = global.natives
|
||||
pendingChunks = global.pendingChunks
|
||||
world = global.world
|
||||
|
||||
onConfigChanged()
|
||||
hookEvents()
|
||||
end
|
||||
|
||||
-- local function onBuildingRotated(event)
|
||||
|
||||
-- end
|
||||
|
||||
local function onCursorChange(event)
|
||||
if settings.startup["rampant-enableBuildings"].value then
|
||||
local player = game.players[event.player_index]
|
||||
swapItemStack(getPlayerCursorStack(player),
|
||||
"item-collector-base-rampant",
|
||||
"item-collector-base-overlay-rampant")
|
||||
local inventory = getPlayerInventory(player,
|
||||
DEFINES_INVENTORY_PLAYER_QUICKBAR,
|
||||
DEFINES_INVENTORY_GOD_QUICKBAR)
|
||||
topOffHand(inventory,
|
||||
player.cursor_stack,
|
||||
"item-collector-base-rampant",
|
||||
"item-collector-base-overlay-rampant")
|
||||
inventory = getPlayerInventory(player,
|
||||
DEFINES_INVENTORY_PLAYER_MAIN,
|
||||
DEFINES_INVENTORY_GOD_MAIN)
|
||||
topOffHand(inventory,
|
||||
player.cursor_stack,
|
||||
"item-collector-base-rampant",
|
||||
"item-collector-base-overlay-rampant")
|
||||
end
|
||||
end
|
||||
|
||||
local function onPlayerDropped(event)
|
||||
if settings.startup["rampant-enableBuildings"].value then
|
||||
local item = event.entity
|
||||
if item.valid then
|
||||
swapItemStack(item.stack,
|
||||
"item-collector-base-overlay-rampant",
|
||||
"item-collector-base-rampant")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onMainInventoryChanged(event)
|
||||
if settings.startup["rampant-enableBuildings"].value then
|
||||
local player = game.players[event.player_index]
|
||||
local inventory = getPlayerInventory(player,
|
||||
DEFINES_INVENTORY_PLAYER_MAIN,
|
||||
DEFINES_INVENTORY_GOD_MAIN)
|
||||
swapItemInventory(inventory,
|
||||
"item-collector-base-overlay-rampant",
|
||||
"item-collector-base-rampant")
|
||||
end
|
||||
end
|
||||
|
||||
local function onQuickInventoryChanged(event)
|
||||
if settings.startup["rampant-enableBuildings"].value then
|
||||
local player = game.players[event.player_index]
|
||||
local inventory = getPlayerInventory(player,
|
||||
DEFINES_INVENTORY_PLAYER_QUICKBAR,
|
||||
DEFINES_INVENTORY_GOD_QUICKBAR)
|
||||
swapItemInventory(inventory,
|
||||
"item-collector-base-overlay-rampant",
|
||||
"item-collector-base-rampant")
|
||||
topOffHand(inventory,
|
||||
player.cursor_stack,
|
||||
"item-collector-base-rampant",
|
||||
"item-collector-base-overlay-rampant")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function onScannedSector(event)
|
||||
local radar = event.radar
|
||||
if (radar.name == "item-collector-base-rampant") then
|
||||
local count = #world.itemCollectorEvents
|
||||
if (count <= ITEM_COLLECTOR_MAX_QUEUE_SIZE) then
|
||||
world.itemCollectorEvents[count+1] = radar.unit_number
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- hooks
|
||||
|
||||
script.on_init(onInit)
|
||||
script.on_load(onLoad)
|
||||
script.on_event(defines.events.on_runtime_mod_setting_changed,
|
||||
onModSettingsChange)
|
||||
script.on_event(defines.events.on_runtime_mod_setting_changed, onModSettingsChange)
|
||||
script.on_configuration_changed(onConfigChanged)
|
||||
|
||||
-- script.on_event(defines.events.on_player_rotated_entity,
|
||||
-- onBuildingRotated)
|
||||
|
||||
script.on_event(defines.events.on_player_built_tile, onSurfaceTileChange)
|
||||
|
||||
script.on_event(defines.events.on_player_cursor_stack_changed,
|
||||
onCursorChange)
|
||||
|
||||
script.on_event(defines.events.on_player_main_inventory_changed,
|
||||
onMainInventoryChanged)
|
||||
script.on_event(defines.events.on_player_quickbar_inventory_changed,
|
||||
onQuickInventoryChanged)
|
||||
|
||||
script.on_event(defines.events.on_biter_base_built,
|
||||
onEnemyBaseBuild)
|
||||
script.on_event(defines.events.on_biter_base_built, onEnemyBaseBuild)
|
||||
script.on_event({defines.events.on_player_mined_entity,
|
||||
defines.events.on_robot_mined_entity},
|
||||
onMine)
|
||||
defines.events.on_robot_mined_entity}, onMine)
|
||||
script.on_event({defines.events.on_built_entity,
|
||||
defines.events.on_robot_built_entity},
|
||||
onBuild)
|
||||
script.on_event(defines.events.on_player_dropped_item,
|
||||
onPlayerDropped)
|
||||
defines.events.on_robot_built_entity}, onBuild)
|
||||
|
||||
script.on_event(defines.events.on_sector_scanned,
|
||||
onScannedSector)
|
||||
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)
|
||||
|
5
data.lua
5
data.lua
@@ -11,8 +11,3 @@ require("prototypes/enemies/UnitFireSpitters")
|
||||
require("prototypes/enemies/UnitTendril")
|
||||
|
||||
|
||||
if settings.startup["rampant-enableBuildings"].value then
|
||||
require("prototypes/buildings/ItemCollector")
|
||||
end
|
||||
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name" : "Rampant",
|
||||
"factorio_version" : "0.15",
|
||||
"version" : "0.15.22",
|
||||
"version" : "0.15.23",
|
||||
"title" : "Rampant",
|
||||
"author" : "Veden",
|
||||
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",
|
||||
|
@@ -4,8 +4,9 @@ local aiAttackWave = {}
|
||||
|
||||
local constants = require("Constants")
|
||||
local mapUtils = require("MapUtils")
|
||||
local chunkUtils = require("ChunkUtils")
|
||||
local unitGroupUtils = require("UnitGroupUtils")
|
||||
local neighborUtils = require("NeighborUtils")
|
||||
local movementUtils = require("MovementUtils")
|
||||
package.path = "../?.lua;" .. package.path
|
||||
local config = require("config")
|
||||
|
||||
@@ -18,19 +19,21 @@ local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local AI_SQUAD_COST = constants.AI_SQUAD_COST
|
||||
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
|
||||
|
||||
local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
|
||||
local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE
|
||||
local PASSABLE = constants.PASSABLE
|
||||
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
|
||||
local CHUNK_SIZE = constants.CHUNK_SIZE
|
||||
|
||||
local RALLY_CRY_DISTANCE = constants.RALLY_CRY_DISTANCE
|
||||
|
||||
local DEFINES_COMMAND_GROUP = defines.command.group
|
||||
local DEFINES_DISTRACTION_NONE = defines.distraction.none
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
-- imported functions
|
||||
|
||||
@@ -38,9 +41,13 @@ local mRandom = math.random
|
||||
|
||||
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
|
||||
|
||||
local getNestCount = chunkUtils.getNestCount
|
||||
local getRallyTick = chunkUtils.getRallyTick
|
||||
local setRallyTick = chunkUtils.setRallyTick
|
||||
|
||||
local getNeighborChunks = mapUtils.getNeighborChunks
|
||||
local getChunkByIndex = mapUtils.getChunkByIndex
|
||||
local scoreNeighborsForFormation = neighborUtils.scoreNeighborsForFormation
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
local scoreNeighborsForFormation = movementUtils.scoreNeighborsForFormation
|
||||
local createSquad = unitGroupUtils.createSquad
|
||||
local attackWaveScaling = config.attackWaveScaling
|
||||
|
||||
@@ -74,21 +81,21 @@ local function scoreUnitGroupLocation(neighborChunk)
|
||||
return neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE]
|
||||
end
|
||||
|
||||
local function validUnitGroupLocation(neighborChunk)
|
||||
return (neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS) and (neighborChunk[NEST_COUNT] == 0)
|
||||
local function validUnitGroupLocation(regionMap, neighborChunk)
|
||||
return neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS and (getNestCount(regionMap, neighborChunk) == 0)
|
||||
end
|
||||
|
||||
function aiAttackWave.rallyUnits(chunk, regionMap, surface, natives, tick)
|
||||
if ((tick - chunk[RALLY_TRIGGERED] > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST) and
|
||||
if ((tick - getRallyTick(regionMap, chunk) > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST) and
|
||||
(#natives.squads < natives.maxSquads)) then
|
||||
chunk[RALLY_TRIGGERED] = tick
|
||||
local cX = chunk.cX
|
||||
local cY = chunk.cY
|
||||
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
|
||||
setRallyTick(regionMap, chunk, tick)
|
||||
local cX = chunk.x
|
||||
local cY = chunk.y
|
||||
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE, 32 do
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do
|
||||
if (x ~= cX) and (y ~= cY) then
|
||||
local rallyChunk = getChunkByIndex(regionMap, x, y)
|
||||
if rallyChunk and (rallyChunk[NEST_COUNT] ~= 0) then
|
||||
local rallyChunk = getChunkByPosition(regionMap, x, y)
|
||||
if (rallyChunk ~= SENTINEL_IMPASSABLE_CHUNK) and (getNestCount(regionMap, rallyChunk) > 0) then
|
||||
aiAttackWave.formSquads(regionMap, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST)
|
||||
if (natives.points < AI_VENGENCE_SQUAD_COST) and (#natives.squads < natives.maxSquads) then
|
||||
return
|
||||
@@ -105,16 +112,17 @@ function aiAttackWave.formSquads(regionMap, surface, natives, chunk, cost)
|
||||
|
||||
if valid and (mRandom() < natives.formSquadThreshold) then
|
||||
|
||||
local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(regionMap, chunk.cX, chunk.cY),
|
||||
local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(regionMap, chunk.x, chunk.y),
|
||||
validUnitGroupLocation,
|
||||
scoreUnitGroupLocation)
|
||||
if squadPath then
|
||||
local squadPosition = surface.find_non_colliding_position("biter-spawner-hive",
|
||||
scoreUnitGroupLocation,
|
||||
regionMap)
|
||||
if (squadPath ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
local squadPosition = surface.find_non_colliding_position("biter-spawner-hive-rampant",
|
||||
positionFromDirectionAndChunk(squadDirection,
|
||||
chunk,
|
||||
regionMap.position,
|
||||
0.98),
|
||||
32,
|
||||
CHUNK_SIZE,
|
||||
4)
|
||||
if squadPosition then
|
||||
local squad = createSquad(squadPosition, surface, natives)
|
||||
|
@@ -3,21 +3,28 @@ local aiPredicates = {}
|
||||
-- imports
|
||||
|
||||
local constants = require("Constants")
|
||||
local nocturnalUtils = require("NocturnalUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
|
||||
local AI_STATE_NOCTURNAL = constants.AI_STATE_NOCTURNAL
|
||||
|
||||
-- imported functions
|
||||
|
||||
local canAttackNocturnal = nocturnalUtils.canAttack
|
||||
|
||||
-- module code
|
||||
|
||||
function aiPredicates.canAttack(natives, surface)
|
||||
return (((natives.state == AI_STATE_AGGRESSIVE) or canAttackNocturnal(natives, surface))
|
||||
return (((natives.state == AI_STATE_AGGRESSIVE) or aiPredicates.canAttackDark(natives, surface))
|
||||
and not surface.peaceful_mode and (#natives.squads < natives.maxSquads))
|
||||
end
|
||||
|
||||
function aiPredicates.isDark(surface)
|
||||
return surface.darkness > 0.65
|
||||
end
|
||||
|
||||
function aiPredicates.canAttackDark(natives, surface)
|
||||
return aiPredicates.isDark(surface) and natives.state == AI_STATE_NOCTURNAL
|
||||
end
|
||||
|
||||
|
||||
return aiPredicates
|
||||
|
@@ -1,118 +0,0 @@
|
||||
local baseRegisterUtils = {}
|
||||
|
||||
-- imports
|
||||
|
||||
local constants = require("Constants")
|
||||
|
||||
local entityUtils = require("EntityUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
local WORM_COUNT = constants.WORM_COUNT
|
||||
|
||||
local NEST_BASE = constants.NEST_BASE
|
||||
local WORM_BASE = constants.WORM_BASE
|
||||
|
||||
-- imported functions
|
||||
|
||||
local getEntityOverlapChunks = entityUtils.getEntityOverlapChunks
|
||||
|
||||
-- module code
|
||||
|
||||
function baseRegisterUtils.addEnemyStructureToChunk(chunk, entity, base)
|
||||
local indexChunk
|
||||
local indexBase
|
||||
local countChunk
|
||||
if (entity.type == "unit-spawner") then
|
||||
indexChunk = chunk[NEST_BASE]
|
||||
if base then
|
||||
if base.hives[entity.unit_number] then
|
||||
indexBase = base.hives
|
||||
else
|
||||
indexBase = base.nests
|
||||
end
|
||||
end
|
||||
countChunk = NEST_COUNT
|
||||
elseif (entity.type == "turret") then
|
||||
indexChunk = chunk[WORM_BASE]
|
||||
if base then
|
||||
indexBase = base.worms
|
||||
end
|
||||
countChunk = WORM_COUNT
|
||||
end
|
||||
chunk[countChunk] = chunk[countChunk] + 1
|
||||
if indexBase then
|
||||
indexChunk[entity.unit_number] = base
|
||||
indexBase[entity.unit_number] = entity
|
||||
end
|
||||
end
|
||||
|
||||
function baseRegisterUtils.removeEnemyStructureFromChunk(chunk, entity)
|
||||
local indexChunk
|
||||
local countChunk
|
||||
if (entity.type == "unit-spawner") then
|
||||
indexChunk = chunk[NEST_BASE]
|
||||
countChunk = NEST_COUNT
|
||||
elseif (entity.type == "turret") then
|
||||
indexChunk = chunk[WORM_BASE]
|
||||
countChunk = WORM_COUNT
|
||||
end
|
||||
local base = indexChunk[entity.unit_number]
|
||||
local indexBase
|
||||
if base then
|
||||
if (entity.type == "unit-spawner") then
|
||||
if base.hives[entity.unit_number] then
|
||||
indexBase = base.hives
|
||||
else
|
||||
indexBase = base.nests
|
||||
end
|
||||
elseif (entity.type == "turret") then
|
||||
indexBase = base.worms
|
||||
end
|
||||
indexBase[entity.unit_number] = nil
|
||||
end
|
||||
chunk[countChunk] = chunk[countChunk] - 1
|
||||
end
|
||||
|
||||
function baseRegisterUtils.registerEnemyBaseStructure(regionMap, entity, base)
|
||||
local entityType = entity.type
|
||||
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
|
||||
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity)
|
||||
|
||||
if leftTop then
|
||||
baseRegisterUtils.addEnemyStructureToChunk(leftTop, entity, base)
|
||||
end
|
||||
if rightTop then
|
||||
baseRegisterUtils.addEnemyStructureToChunk(rightTop, entity, base)
|
||||
end
|
||||
if leftBottom then
|
||||
baseRegisterUtils.addEnemyStructureToChunk(leftBottom, entity, base)
|
||||
end
|
||||
if rightBottom then
|
||||
baseRegisterUtils.addEnemyStructureToChunk(rightBottom, entity, base)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function baseRegisterUtils.unregisterEnemyBaseStructure(regionMap, entity)
|
||||
local entityType = entity.type
|
||||
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
|
||||
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity)
|
||||
|
||||
if leftTop then
|
||||
baseRegisterUtils.removeEnemyStructureFromChunk(leftTop, entity)
|
||||
end
|
||||
if rightTop then
|
||||
baseRegisterUtils.removeEnemyStructureFromChunk(rightTop, entity)
|
||||
end
|
||||
if leftBottom then
|
||||
baseRegisterUtils.removeEnemyStructureFromChunk(leftBottom, entity)
|
||||
end
|
||||
if rightBottom then
|
||||
baseRegisterUtils.removeEnemyStructureFromChunk(rightBottom, entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return baseRegisterUtils
|
@@ -5,7 +5,7 @@ local baseUtils = {}
|
||||
local mathUtils = require("MathUtils")
|
||||
local constants = require("Constants")
|
||||
|
||||
local tendrilUtils = require("TendrilUtils")
|
||||
-- local tendrilUtils = require("TendrilUtils")
|
||||
|
||||
local nestUtils = require("NestUtils")
|
||||
|
||||
@@ -26,7 +26,7 @@ local buildHive = nestUtils.buildHive
|
||||
|
||||
local mFloor = math.floor
|
||||
|
||||
local buildTendril = tendrilUtils.buildTendril
|
||||
-- local buildTendril = tendrilUtils.buildTendril
|
||||
|
||||
local mRandom = math.random
|
||||
|
||||
@@ -68,7 +68,7 @@ function baseUtils.createBase(regionMap, natives, position, surface, tick)
|
||||
if not buildHive(regionMap, base, surface) then
|
||||
return nil
|
||||
end
|
||||
buildTendril(regionMap, natives, base, surface, tick)
|
||||
-- buildTendril(regionMap, natives, base, surface, tick)
|
||||
bases[#bases+1] = base
|
||||
return base
|
||||
end
|
||||
|
@@ -1,78 +0,0 @@
|
||||
local buildUtils = {}
|
||||
|
||||
-- module code
|
||||
|
||||
function buildUtils.buildComplexEntity(entity, world)
|
||||
if (entity.name == "item-collector-base-overlay-rampant") or (entity.name == "item-collector-base-rampant") then
|
||||
local surface = entity.surface
|
||||
local x = entity.position.x
|
||||
local y = entity.position.y
|
||||
local chest
|
||||
local position = entity.position
|
||||
local force = entity.force
|
||||
if (entity.name == "item-collector-base-overlay-rampant") then
|
||||
entity.destroy()
|
||||
chest = surface.create_entity({name = "item-collector-chest-rampant",
|
||||
position = position,
|
||||
force = force})
|
||||
entity = surface.create_entity({name="item-collector-base-rampant",
|
||||
position = position,
|
||||
force = force})
|
||||
else
|
||||
local ghosts = surface.find_entities_filtered({name="entity-ghost",
|
||||
area={{x=x-1,
|
||||
y=y-1},
|
||||
{x=x+1,
|
||||
y=y+1}},
|
||||
limit=1})
|
||||
if (#ghosts > 0) then
|
||||
local ghost = ghosts[1]
|
||||
if (ghost.ghost_name == "item-collector-chest-rampant") then
|
||||
local conflicts
|
||||
conflicts, chest = ghost.revive()
|
||||
end
|
||||
else
|
||||
chest = surface.create_entity({name = "item-collector-chest-rampant",
|
||||
position = position,
|
||||
force = force})
|
||||
end
|
||||
end
|
||||
if chest and chest.valid then
|
||||
local pair = { chest, entity }
|
||||
world.itemCollectorLookup[chest.unit_number] = pair
|
||||
world.itemCollectorLookup[entity.unit_number] = pair
|
||||
entity.backer_name = ""
|
||||
end
|
||||
end
|
||||
return entity
|
||||
end
|
||||
|
||||
function buildUtils.mineComplexEntity(entity, world, destroyed)
|
||||
if (entity.name == "item-collector-chest-rampant") or (entity.name == "item-collector-base-rampant") then
|
||||
local pair = world.itemCollectorLookup[entity.unit_number]
|
||||
if pair then
|
||||
local chest = pair[1]
|
||||
local dish = pair[2]
|
||||
|
||||
if chest and chest.valid then
|
||||
world.itemCollectorLookup[chest.unit_number] = nil
|
||||
if destroyed and (entity == chest) then
|
||||
chest.die()
|
||||
elseif (entity ~= chest) then
|
||||
chest.destroy()
|
||||
end
|
||||
end
|
||||
if dish and dish.valid then
|
||||
world.itemCollectorLookup[dish.unit_number] = nil
|
||||
if destroyed and (entity ~= dish) then
|
||||
dish.die()
|
||||
elseif (entity ~= dish) then
|
||||
dish.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return entity
|
||||
end
|
||||
|
||||
return buildUtils
|
@@ -9,6 +9,8 @@ local constants = require("Constants")
|
||||
|
||||
local CHUNK_SIZE = constants.CHUNK_SIZE
|
||||
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
-- imported functions
|
||||
|
||||
local remakeChunk = chunkUtils.remakeChunk
|
||||
@@ -40,26 +42,31 @@ function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendin
|
||||
local y = topLeft.y
|
||||
local chunk = createChunk(x, y)
|
||||
|
||||
chunk = checkChunkPassability(chunkTiles, chunk, surface)
|
||||
|
||||
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
|
||||
areaBoundingBox[1] = chunk
|
||||
offset[1] = x + CHUNK_SIZE
|
||||
offset[2] = y + CHUNK_SIZE
|
||||
|
||||
local chunkX = chunk.cX
|
||||
if vanillaAI then
|
||||
registerChunkEnemies(regionMap, chunk, surface, query)
|
||||
else
|
||||
remakeChunk(regionMap, chunk, surface, natives, tick, query)
|
||||
end
|
||||
scoreChunk(regionMap, chunk, surface, natives, query)
|
||||
|
||||
local chunkX = chunk.x
|
||||
|
||||
if regionMap[chunkX] == nil then
|
||||
regionMap[chunkX] = {}
|
||||
end
|
||||
regionMap[chunkX][chunk.cY] = chunk
|
||||
regionMap[chunkX][chunk.y] = chunk
|
||||
|
||||
checkChunkPassability(chunkTiles, chunk, surface)
|
||||
if vanillaAI then
|
||||
registerChunkEnemies(chunk, surface, query)
|
||||
else
|
||||
remakeChunk(regionMap, chunk, surface, natives, tick, query)
|
||||
end
|
||||
scoreChunk(chunk, surface, natives, query)
|
||||
processQueue[#processQueue+1] = chunk
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return chunkProcessor
|
||||
|
@@ -3,31 +3,25 @@ local chunkUtils = {}
|
||||
-- imports
|
||||
|
||||
local constants = require("Constants")
|
||||
|
||||
local baseUtils = require("BaseUtils")
|
||||
|
||||
local baseRegisterUtils = require("BaseRegisterUtils")
|
||||
local mapUtils = require("MapUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local DEFINES_DIRECTION_EAST = defines.direction.east
|
||||
local DEFINES_WIRE_TYPE_RED = defines.wire_type.red
|
||||
local DEFINES_WIRE_TYPE_GREEN = defines.wire_type.green
|
||||
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
|
||||
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
|
||||
local NEST_BASE = constants.NEST_BASE
|
||||
local WORM_BASE = constants.WORM_BASE
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
local WORM_COUNT = constants.WORM_COUNT
|
||||
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
local RESOURCE_GENERATOR = constants.RESOURCE_GENERATOR
|
||||
|
||||
local CHUNK_NORTH_SOUTH = constants.CHUNK_NORTH_SOUTH
|
||||
local CHUNK_EAST_WEST = constants.CHUNK_EAST_WEST
|
||||
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
local CHUNK_IMPASSABLE = constants.CHUNK_IMPASSABLE
|
||||
|
||||
@@ -35,14 +29,13 @@ local CHUNK_TICK = constants.CHUNK_TICK
|
||||
|
||||
local PATH_RATING = constants.PATH_RATING
|
||||
|
||||
local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED
|
||||
local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
-- imported functions
|
||||
|
||||
local findNearbyBase = baseUtils.findNearbyBase
|
||||
local createBase = baseUtils.createBase
|
||||
local addEnemyStructureToChunk = baseRegisterUtils.addEnemyStructureToChunk
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
|
||||
local mFloor = math.floor
|
||||
|
||||
-- module code
|
||||
|
||||
@@ -109,6 +102,126 @@ local function spotCheck(x, y, get_tile)
|
||||
return valid
|
||||
end
|
||||
|
||||
local function addEnemyStructureToChunk(regionMap, chunk, entity, base)
|
||||
local lookup
|
||||
if (entity.type == "unit-spawner") then
|
||||
lookup = regionMap.chunkToNests
|
||||
elseif (entity.type == "turret") then
|
||||
lookup = regionMap.chunkToWorms
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
local entityCollection = lookup[chunk]
|
||||
if not entityCollection then
|
||||
entityCollection = {}
|
||||
lookup[chunk] = entityCollection
|
||||
end
|
||||
entityCollection[#entityCollection+1] = entity
|
||||
|
||||
-- if base then
|
||||
-- local baseCollection = regionMap.chunkToBases[chunk]
|
||||
-- if not baseCollection then
|
||||
-- baseCollection = {}
|
||||
-- regionMap.chunkToBases[chunk] = baseCollection
|
||||
-- end
|
||||
-- baseCollection[base.id] = chunk
|
||||
-- end
|
||||
end
|
||||
|
||||
local function removeEnemyStructureFromChunk(regionMap, chunk, entity)
|
||||
local lookup
|
||||
if (entity.type == "unit-spawner") then
|
||||
lookup = regionMap.chunkToNests
|
||||
elseif (entity.type == "turret") then
|
||||
lookup = regionMap.chunkToWorms
|
||||
else
|
||||
return
|
||||
end
|
||||
-- local base = indexChunk[entity.unit_number]
|
||||
-- local indexBase
|
||||
-- if base then
|
||||
-- if (entity.type == "unit-spawner") then
|
||||
-- if base.hives[entity.unit_number] then
|
||||
-- indexBase = base.hives
|
||||
-- else
|
||||
-- indexBase = base.nests
|
||||
-- end
|
||||
-- elseif (entity.type == "turret") then
|
||||
-- indexBase = base.worms
|
||||
-- end
|
||||
-- indexBase[entity.unit_number] = nil
|
||||
-- end
|
||||
local collection = lookup[chunk]
|
||||
if collection then
|
||||
for i=1,#collection do
|
||||
local e = collection[i]
|
||||
if e.valid and (e == entity) then
|
||||
table.remove(collection, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getEntityOverlapChunks(regionMap, entity)
|
||||
local boundingBox = entity.prototype.selection_box or entity.prototype.collision_box;
|
||||
|
||||
local leftTopChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
local rightTopChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
local leftBottomChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
local rightBottomChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
if (boundingBox ~= nil) then
|
||||
local center = entity.position
|
||||
local topXOffset
|
||||
local topYOffset
|
||||
|
||||
local bottomXOffset
|
||||
local bottomYOffset
|
||||
|
||||
if (entity.direction == DEFINES_DIRECTION_EAST) then
|
||||
topXOffset = boundingBox.left_top.y
|
||||
topYOffset = boundingBox.left_top.x
|
||||
bottomXOffset = boundingBox.right_bottom.y
|
||||
bottomYOffset = boundingBox.right_bottom.x
|
||||
else
|
||||
topXOffset = boundingBox.left_top.x
|
||||
topYOffset = boundingBox.left_top.y
|
||||
bottomXOffset = boundingBox.right_bottom.x
|
||||
bottomYOffset = boundingBox.right_bottom.y
|
||||
end
|
||||
|
||||
local leftTopChunkX = mFloor(center.x + topXOffset)
|
||||
local leftTopChunkY = mFloor(center.y + topYOffset)
|
||||
|
||||
-- used to force things on chunk boundary to not spill over 0.0001
|
||||
local rightTopChunkX = mFloor(center.x + bottomXOffset - 0.0001)
|
||||
local rightTopChunkY = leftTopChunkY
|
||||
|
||||
-- used to force things on chunk boundary to not spill over 0.0001
|
||||
local leftBottomChunkX = leftTopChunkX
|
||||
local leftBottomChunkY = mFloor(center.y + bottomYOffset - 0.0001)
|
||||
|
||||
local rightBottomChunkX = rightTopChunkX
|
||||
local rightBottomChunkY = leftBottomChunkY
|
||||
|
||||
leftTopChunk = getChunkByPosition(regionMap, leftTopChunkX, leftTopChunkY)
|
||||
if (leftTopChunkX ~= rightTopChunkX) then
|
||||
rightTopChunk = getChunkByPosition(regionMap, rightTopChunkX, rightTopChunkY)
|
||||
end
|
||||
if (leftTopChunkY ~= leftBottomChunkY) then
|
||||
leftBottomChunk = getChunkByPosition(regionMap, leftBottomChunkX, leftBottomChunkY)
|
||||
end
|
||||
if (leftTopChunkX ~= rightBottomChunkX) and (leftTopChunkY ~= rightBottomChunkY) then
|
||||
rightBottomChunk = getChunkByPosition(regionMap, rightBottomChunkX, rightBottomChunkY)
|
||||
end
|
||||
end
|
||||
return leftTopChunk, rightTopChunk, leftBottomChunk, rightBottomChunk
|
||||
end
|
||||
|
||||
-- external functions
|
||||
|
||||
function chunkUtils.checkChunkPassability(chunkTiles, chunk, surface)
|
||||
local x = chunk.x
|
||||
local y = chunk.y
|
||||
@@ -144,7 +257,12 @@ function chunkUtils.checkChunkPassability(chunkTiles, chunk, surface)
|
||||
else
|
||||
chunk[PATH_RATING] = 1
|
||||
end
|
||||
if (pass == CHUNK_IMPASSABLE) then
|
||||
return SENTINEL_IMPASSABLE_CHUNK
|
||||
else
|
||||
chunk[PASSABLE] = pass
|
||||
return chunk
|
||||
end
|
||||
end
|
||||
|
||||
function chunkUtils.remakeChunk(regionMap, chunk, surface, natives, tick, tempQuery)
|
||||
@@ -155,7 +273,7 @@ function chunkUtils.remakeChunk(regionMap, chunk, surface, natives, tick, tempQu
|
||||
for f=1, #enemies do
|
||||
local enemy = enemies[f]
|
||||
local entityType = enemies[f].type
|
||||
if not ((enemy.name == "small-tendril-biter-rampant") or (enemy.name == "biter-spawner-hive")) then
|
||||
if not ((enemy.name == "small-tendril-biter-rampant") or (enemy.name == "biter-spawner-hive-rampant")) then
|
||||
if (entityType == "unit-spawner") then
|
||||
points = points + 3
|
||||
elseif (entityType == "turret") then
|
||||
@@ -166,13 +284,13 @@ function chunkUtils.remakeChunk(regionMap, chunk, surface, natives, tick, tempQu
|
||||
enemy.destroy()
|
||||
end
|
||||
end
|
||||
local foundBase = findNearbyBase(natives, chunk) or createBase(regionMap, natives, chunk, surface, tick)
|
||||
if foundBase then
|
||||
foundBase.upgradePoints = foundBase.upgradePoints + points
|
||||
end
|
||||
-- local foundBase = findNearbyBase(natives, chunk) or createBase(regionMap, natives, chunk, surface, tick)
|
||||
-- if foundBase then
|
||||
-- foundBase.upgradePoints = foundBase.upgradePoints + points
|
||||
-- end
|
||||
end
|
||||
|
||||
function chunkUtils.registerChunkEnemies(chunk, surface, tempQuery)
|
||||
function chunkUtils.registerChunkEnemies(regionMap, chunk, surface, tempQuery)
|
||||
tempQuery.force = "enemy"
|
||||
local enemies = surface.find_entities_filtered(tempQuery)
|
||||
|
||||
@@ -180,15 +298,61 @@ function chunkUtils.registerChunkEnemies(chunk, surface, tempQuery)
|
||||
local enemy = enemies[i]
|
||||
local enemyType = enemy.type
|
||||
if (enemyType == "unit-spawner") or (enemyType == "turret") then
|
||||
addEnemyStructureToChunk(chunk, enemy, nil)
|
||||
addEnemyStructureToChunk(regionMap, chunk, enemy, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function chunkUtils.scoreChunk(chunk, surface, natives, tempQuery)
|
||||
function chunkUtils.getNestCount(regionMap, chunk)
|
||||
local nests = regionMap.chunkToNests[chunk]
|
||||
return (nests and #nests) or 0
|
||||
end
|
||||
|
||||
function chunkUtils.getWormCount(regionMap, chunk)
|
||||
local worms = regionMap.chunkToWorms[chunk]
|
||||
return (worms and #worms) or 0
|
||||
end
|
||||
|
||||
function chunkUtils.getRetreatTick(regionMap, chunk)
|
||||
return regionMap.chunkToRetreats[chunk] or 0
|
||||
end
|
||||
|
||||
function chunkUtils.getRallyTick(regionMap, chunk)
|
||||
return regionMap.chunkToRallys[chunk] or 0
|
||||
end
|
||||
|
||||
function chunkUtils.setRallyTick(regionMap, chunk, tick)
|
||||
regionMap.chunkToRallys[chunk] = tick
|
||||
end
|
||||
|
||||
function chunkUtils.setRetreatTick(regionMap, chunk, tick)
|
||||
regionMap.chunkToRetreats[chunk] = tick
|
||||
end
|
||||
|
||||
function chunkUtils.setResourceGenerator(regionMap, chunk, playerGenerator)
|
||||
regionMap.chunkToResource[chunk] = playerGenerator
|
||||
end
|
||||
|
||||
function chunkUtils.getResourceGenerator(regionMap, chunk)
|
||||
return regionMap.chunkToResource[chunk] or 0
|
||||
end
|
||||
|
||||
function chunkUtils.getPlayerBaseGenerator(regionMap, chunk)
|
||||
return regionMap.chunkToPlayerBase[chunk] or 0
|
||||
end
|
||||
|
||||
function chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerGenerator)
|
||||
regionMap.chunkToPlayerBase[chunk] = playerGenerator
|
||||
end
|
||||
|
||||
function chunkUtils.addPlayerBaseGenerator(regionMap, chunk, playerGenerator)
|
||||
regionMap.chunkToPlayerBase[chunk] = regionMap.chunkToPlayerBase[chunk] + playerGenerator
|
||||
end
|
||||
|
||||
function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tempQuery)
|
||||
tempQuery.force = nil
|
||||
tempQuery.type = "resource"
|
||||
chunk[RESOURCE_GENERATOR] = surface.count_entities_filtered(tempQuery) * 0.001
|
||||
chunkUtils.setResourceGenerator(regionMap, chunk, surface.count_entities_filtered(tempQuery) * 0.001)
|
||||
|
||||
tempQuery.type = nil
|
||||
tempQuery.force = "player"
|
||||
@@ -207,36 +371,27 @@ function chunkUtils.scoreChunk(chunk, surface, natives, tempQuery)
|
||||
end
|
||||
|
||||
local entityScore = BUILDING_PHEROMONES[entityType]
|
||||
if (entityScore ~= nil) then
|
||||
if entityScore then
|
||||
playerObjects = playerObjects + entityScore
|
||||
end
|
||||
end
|
||||
|
||||
chunk[PLAYER_BASE_GENERATOR] = playerObjects
|
||||
chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerObjects)
|
||||
end
|
||||
|
||||
function chunkUtils.createChunk(topX, topY)
|
||||
local chunk = {
|
||||
x = topX,
|
||||
y = topY,
|
||||
cX = topX * 0.03125,
|
||||
cY = topY * 0.03125
|
||||
y = topY
|
||||
}
|
||||
chunk[MOVEMENT_PHEROMONE] = 0
|
||||
chunk[BASE_PHEROMONE] = 0
|
||||
chunk[PLAYER_PHEROMONE] = 0
|
||||
chunk[RESOURCE_PHEROMONE] = 0
|
||||
chunk[PLAYER_BASE_GENERATOR] = 0
|
||||
chunk[RESOURCE_GENERATOR] = 0
|
||||
chunk[PASSABLE] = 0
|
||||
chunk[CHUNK_TICK] = 0
|
||||
chunk[RETREAT_TRIGGERED] = 0
|
||||
chunk[RALLY_TRIGGERED] = 0
|
||||
chunk[NEST_BASE] = {}
|
||||
chunk[WORM_BASE] = {}
|
||||
chunk[NEST_COUNT] = 0
|
||||
chunk[WORM_COUNT] = 0
|
||||
chunk[PATH_RATING] = 0
|
||||
|
||||
return chunk
|
||||
end
|
||||
|
||||
@@ -250,4 +405,109 @@ function chunkUtils.colorChunk(x, y, tileType, surface)
|
||||
surface.set_tiles(tiles, false)
|
||||
end
|
||||
|
||||
function chunkUtils.registerEnemyBaseStructure(regionMap, entity, base)
|
||||
local entityType = entity.type
|
||||
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
|
||||
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity)
|
||||
|
||||
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
addEnemyStructureToChunk(regionMap, leftTop, entity, base)
|
||||
end
|
||||
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
addEnemyStructureToChunk(regionMap, rightTop, entity, base)
|
||||
end
|
||||
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
addEnemyStructureToChunk(regionMap, leftBottom, entity, base)
|
||||
end
|
||||
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
addEnemyStructureToChunk(regionMap, rightBottom, entity, base)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function chunkUtils.unregisterEnemyBaseStructure(regionMap, entity)
|
||||
local entityType = entity.type
|
||||
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
|
||||
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity)
|
||||
|
||||
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
removeEnemyStructureFromChunk(regionMap, leftTop, entity)
|
||||
end
|
||||
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
removeEnemyStructureFromChunk(regionMap, rightTop, entity)
|
||||
end
|
||||
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
removeEnemyStructureFromChunk(regionMap, leftBottom, entity)
|
||||
end
|
||||
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
removeEnemyStructureFromChunk(regionMap, rightBottom, entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function chunkUtils.addRemovePlayerEntity(regionMap, entity, natives, addObject, creditNatives)
|
||||
local leftTop, rightTop, leftBottom, rightBottom
|
||||
local entityValue
|
||||
if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name == "player") then
|
||||
entityValue = BUILDING_PHEROMONES[entity.type]
|
||||
|
||||
leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity)
|
||||
if not addObject then
|
||||
if creditNatives then
|
||||
natives.points = natives.points + entityValue
|
||||
end
|
||||
entityValue = -entityValue
|
||||
end
|
||||
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
chunkUtils.addPlayerBaseGenerator(regionMap, leftTop, entityValue)
|
||||
end
|
||||
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
chunkUtils.addPlayerBaseGenerator(regionMap, rightTop, entityValue)
|
||||
end
|
||||
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
chunkUtils.addPlayerBaseGenerator(regionMap, leftBottom, entityValue)
|
||||
end
|
||||
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
chunkUtils.addPlayerBaseGenerator(regionMap, rightBottom, entityValue)
|
||||
end
|
||||
end
|
||||
return entity
|
||||
end
|
||||
|
||||
function chunkUtils.makeImmortalEntity(surface, entity)
|
||||
local repairPosition = entity.position
|
||||
local repairName = entity.name
|
||||
local repairForce = entity.force
|
||||
local repairDirection = entity.direction
|
||||
|
||||
local wires
|
||||
if (entity.type == "electric-pole") then
|
||||
wires = entity.neighbours
|
||||
end
|
||||
entity.destroy()
|
||||
local newEntity = surface.create_entity({position=repairPosition,
|
||||
name=repairName,
|
||||
direction=repairDirection,
|
||||
force=repairForce})
|
||||
if wires then
|
||||
for connectType,neighbourGroup in pairs(wires) do
|
||||
if connectType == "copper" then
|
||||
for _,v in pairs(neighbourGroup) do
|
||||
newEntity.connect_neighbour(v);
|
||||
end
|
||||
elseif connectType == "red" then
|
||||
for _,v in pairs(neighbourGroup) do
|
||||
newEntity.connect_neighbour({wire = DEFINES_WIRE_TYPE_RED, target_entity = v});
|
||||
end
|
||||
elseif connectType == "green" then
|
||||
for _,v in pairs(neighbourGroup) do
|
||||
newEntity.connect_neighbour({wire = DEFINES_WIRE_TYPE_GREEN, target_entity = v});
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newEntity.destructible = false
|
||||
end
|
||||
|
||||
return chunkUtils
|
||||
|
@@ -15,10 +15,11 @@ constants.VERSION_25 = 25
|
||||
constants.VERSION_26 = 26
|
||||
constants.VERSION_27 = 27
|
||||
constants.VERSION_28 = 28
|
||||
constants.VERSION_32 = 32
|
||||
constants.VERSION_33 = 33
|
||||
|
||||
-- misc
|
||||
|
||||
constants.CHUNK_SIZE_DIVIDER = 0.03125
|
||||
constants.MAGIC_MAXIMUM_NUMBER = 1e99 -- used in loops trying to find the lowest/highest score
|
||||
constants.MAGIC_MAXIMUM_BASE_NUMBER = 100000000
|
||||
constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL = 10000
|
||||
@@ -28,7 +29,7 @@ constants.SCAN_QUEUE_SIZE = 5
|
||||
constants.ITEM_COLLECTOR_QUEUE_SIZE = 6
|
||||
constants.BASE_QUEUE_SIZE = 1
|
||||
constants.SQUAD_QUEUE_SIZE = 2
|
||||
constants.PROCESS_PLAYER_BOUND = 4
|
||||
constants.PROCESS_PLAYER_BOUND = 128
|
||||
|
||||
constants.ITEM_COLLECTOR_MAX_QUEUE_SIZE = 20
|
||||
|
||||
@@ -42,6 +43,18 @@ constants.PLAYER_PHEROMONE_MULTIPLER = 100
|
||||
|
||||
constants.DEV_CUSTOM_AI = false
|
||||
|
||||
-- mask
|
||||
|
||||
constants.MASK_PASSABLE = 3
|
||||
constants.MASK_PASSABLE_SIZE = 2
|
||||
constants.MASK_NEST_COUNT = 511
|
||||
constants.MASK_NEST_COUNT_SIZE = 9
|
||||
constants.MASK_WORM_COUNT = 511
|
||||
constants.MASK_WORM_COUNT_SIZE = 9
|
||||
constants.MASK_PASSABLE_AND_NEST_COUNT = 2047
|
||||
constants.MASK_PASSABLE_AND_NEST_COUNT_SIZE = 11
|
||||
|
||||
|
||||
-- item collector
|
||||
|
||||
constants.ITEM_COLLECTOR_DISTANCE = 50
|
||||
@@ -127,19 +140,11 @@ constants.BASE_PHEROMONE = 2
|
||||
constants.PLAYER_PHEROMONE = 3
|
||||
constants.RESOURCE_PHEROMONE = 4
|
||||
|
||||
constants.PLAYER_BASE_GENERATOR = 5
|
||||
constants.RESOURCE_GENERATOR = 6
|
||||
constants.PASSABLE = 5
|
||||
|
||||
constants.PASSABLE = 7
|
||||
constants.CHUNK_TICK = 6
|
||||
|
||||
constants.CHUNK_TICK = 8
|
||||
constants.RETREAT_TRIGGERED = 9
|
||||
constants.RALLY_TRIGGERED = 10
|
||||
constants.NEST_BASE = 11
|
||||
constants.WORM_BASE = 12
|
||||
constants.NEST_COUNT = 13
|
||||
constants.WORM_COUNT = 14
|
||||
constants.PATH_RATING = 15
|
||||
constants.PATH_RATING = 7
|
||||
|
||||
-- Squad status
|
||||
|
||||
@@ -155,7 +160,7 @@ constants.RETREAT_GRAB_RADIUS = 24
|
||||
constants.BASE_RALLY_CHANCE = 0.02
|
||||
constants.BONUS_RALLY_CHANCE = 0.06
|
||||
|
||||
constants.RALLY_CRY_DISTANCE = 3
|
||||
constants.RALLY_CRY_DISTANCE = 96
|
||||
|
||||
constants.GROUP_MERGE_DISTANCE = 28
|
||||
|
||||
@@ -211,6 +216,20 @@ constants.UNIT_GROUP_MAX_SPEED_UP = 1.1
|
||||
constants.UNIT_GROUP_MAX_SLOWDOWN = 1.0
|
||||
constants.UNIT_GROUP_SLOWDOWN_FACTOR = 0.9
|
||||
|
||||
-- sentinels
|
||||
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK = {}
|
||||
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK[constants.MOVEMENT_PHEROMONE] = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK[constants.BASE_PHEROMONE] = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK[constants.PLAYER_PHEROMONE] = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK[constants.RESOURCE_PHEROMONE] = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK[constants.PASSABLE] = constants.CHUNK_IMPASSABLE
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK[constants.CHUNK_TICK] = 0
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK[constants.PATH_RATING] = 0
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK.x = 0
|
||||
constants.SENTINEL_IMPASSABLE_CHUNK.y = 0
|
||||
|
||||
return constants
|
||||
|
||||
--[[
|
||||
|
@@ -1,147 +0,0 @@
|
||||
local entityUtils = {}
|
||||
|
||||
-- imports
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
local constants = require("Constants")
|
||||
|
||||
-- constants
|
||||
|
||||
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
|
||||
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
|
||||
local DEFINES_DIRECTION_EAST = defines.direction.east
|
||||
local DEFINES_WIRE_TYPE_RED = defines.wire_type.red
|
||||
local DEFINES_WIRE_TYPE_GREEN = defines.wire_type.green
|
||||
|
||||
-- imported functions
|
||||
|
||||
local getChunkByIndex = mapUtils.getChunkByIndex
|
||||
|
||||
local mFloor = math.floor
|
||||
|
||||
-- module code
|
||||
|
||||
function entityUtils.getEntityOverlapChunks(regionMap, entity)
|
||||
local boundingBox = entity.prototype.selection_box or entity.prototype.collision_box;
|
||||
|
||||
local leftTopChunk
|
||||
local rightTopChunk
|
||||
local leftBottomChunk
|
||||
local rightBottomChunk
|
||||
|
||||
if (boundingBox ~= nil) then
|
||||
local center = entity.position
|
||||
local topXOffset
|
||||
local topYOffset
|
||||
|
||||
local bottomXOffset
|
||||
local bottomYOffset
|
||||
|
||||
if (entity.direction == DEFINES_DIRECTION_EAST) then
|
||||
topXOffset = boundingBox.left_top.y
|
||||
topYOffset = boundingBox.left_top.x
|
||||
bottomXOffset = boundingBox.right_bottom.y
|
||||
bottomYOffset = boundingBox.right_bottom.x
|
||||
else
|
||||
topXOffset = boundingBox.left_top.x
|
||||
topYOffset = boundingBox.left_top.y
|
||||
bottomXOffset = boundingBox.right_bottom.x
|
||||
bottomYOffset = boundingBox.right_bottom.y
|
||||
end
|
||||
|
||||
local leftTopChunkX = mFloor((center.x + topXOffset) * 0.03125)
|
||||
local leftTopChunkY = mFloor((center.y + topYOffset) * 0.03125)
|
||||
|
||||
-- used to force things on chunk boundary to not spill over 0.0001
|
||||
local rightTopChunkX = mFloor((center.x + bottomXOffset - 0.0001) * 0.03125)
|
||||
local rightTopChunkY = leftTopChunkY
|
||||
|
||||
-- used to force things on chunk boundary to not spill over 0.0001
|
||||
local leftBottomChunkX = leftTopChunkX
|
||||
local leftBottomChunkY = mFloor((center.y + bottomYOffset - 0.0001) * 0.03125)
|
||||
|
||||
local rightBottomChunkX = rightTopChunkX
|
||||
local rightBottomChunkY = leftBottomChunkY
|
||||
|
||||
leftTopChunk = getChunkByIndex(regionMap, leftTopChunkX, leftTopChunkY)
|
||||
if (leftTopChunkX ~= rightTopChunkX) then
|
||||
rightTopChunk = getChunkByIndex(regionMap, rightTopChunkX, rightTopChunkY)
|
||||
end
|
||||
if (leftTopChunkY ~= leftBottomChunkY) then
|
||||
leftBottomChunk = getChunkByIndex(regionMap, leftBottomChunkX, leftBottomChunkY)
|
||||
end
|
||||
if (leftTopChunkX ~= rightBottomChunkX) and (leftTopChunkY ~= rightBottomChunkY) then
|
||||
rightBottomChunk = getChunkByIndex(regionMap, rightBottomChunkX, rightBottomChunkY)
|
||||
end
|
||||
end
|
||||
return leftTopChunk, rightTopChunk, leftBottomChunk, rightBottomChunk
|
||||
end
|
||||
|
||||
function entityUtils.addRemovePlayerEntity(regionMap, entity, natives, addObject, creditNatives)
|
||||
local leftTop, rightTop, leftBottom, rightBottom
|
||||
local entityValue
|
||||
if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name == "player") then
|
||||
entityValue = BUILDING_PHEROMONES[entity.type]
|
||||
|
||||
leftTop, rightTop, leftBottom, rightBottom = entityUtils.getEntityOverlapChunks(regionMap, entity)
|
||||
if not addObject then
|
||||
if creditNatives then
|
||||
natives.points = natives.points + entityValue
|
||||
end
|
||||
entityValue = -entityValue
|
||||
end
|
||||
if leftTop then
|
||||
leftTop[PLAYER_BASE_GENERATOR] = leftTop[PLAYER_BASE_GENERATOR] + entityValue
|
||||
end
|
||||
if rightTop then
|
||||
rightTop[PLAYER_BASE_GENERATOR] = rightTop[PLAYER_BASE_GENERATOR] + entityValue
|
||||
end
|
||||
if leftBottom then
|
||||
leftBottom[PLAYER_BASE_GENERATOR] = leftBottom[PLAYER_BASE_GENERATOR] + entityValue
|
||||
end
|
||||
if rightBottom then
|
||||
rightBottom[PLAYER_BASE_GENERATOR] = rightBottom[PLAYER_BASE_GENERATOR] + entityValue
|
||||
end
|
||||
end
|
||||
return entity
|
||||
end
|
||||
|
||||
function entityUtils.makeImmortalEntity(surface, entity)
|
||||
local repairPosition = entity.position
|
||||
local repairName = entity.name
|
||||
local repairForce = entity.force
|
||||
local repairDirection = entity.direction
|
||||
|
||||
local wires
|
||||
if (entity.type == "electric-pole") then
|
||||
wires = entity.neighbours
|
||||
end
|
||||
entity.destroy()
|
||||
local newEntity = surface.create_entity({position=repairPosition,
|
||||
name=repairName,
|
||||
direction=repairDirection,
|
||||
force=repairForce})
|
||||
if wires then
|
||||
for connectType,neighbourGroup in pairs(wires) do
|
||||
if connectType == "copper" then
|
||||
for _,v in pairs(neighbourGroup) do
|
||||
newEntity.connect_neighbour(v);
|
||||
end
|
||||
elseif connectType == "red" then
|
||||
for _,v in pairs(neighbourGroup) do
|
||||
newEntity.connect_neighbour({wire = DEFINES_WIRE_TYPE_RED, target_entity = v});
|
||||
end
|
||||
elseif connectType == "green" then
|
||||
for _,v in pairs(neighbourGroup) do
|
||||
newEntity.connect_neighbour({wire = DEFINES_WIRE_TYPE_GREEN, target_entity = v});
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newEntity.destructible = false
|
||||
end
|
||||
|
||||
return entityUtils
|
@@ -1,46 +0,0 @@
|
||||
local inventoryUtils = {}
|
||||
|
||||
-- imported functions
|
||||
|
||||
local mMin = math.min
|
||||
|
||||
-- modules code
|
||||
|
||||
function inventoryUtils.swapItemInventory(inventory, src, dst)
|
||||
if inventory and inventory.valid then
|
||||
local itemCount = inventory.get_item_count(src)
|
||||
if (itemCount > 0) then
|
||||
inventory.remove({name = src, count = itemCount})
|
||||
inventory.insert({name = dst, count = itemCount})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function inventoryUtils.topOffHand(inventory, handStack, src, dst)
|
||||
if inventory and inventory.valid then
|
||||
local itemCount = inventory.get_item_count(src)
|
||||
if (itemCount > 0) then
|
||||
if handStack and handStack.valid and handStack.valid_for_read and (handStack.prototype.name == dst) then
|
||||
local remaining = mMin(itemCount, handStack.prototype.stack_size - handStack.count)
|
||||
if (remaining > 0) then
|
||||
local stack = { name = src, count = remaining + handStack.count }
|
||||
if (handStack.can_set_stack(stack)) and handStack.set_stack(stack) then
|
||||
inventory.remove({name = src, count = remaining})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function inventoryUtils.swapItemStack(stack, src, dst)
|
||||
if stack and stack.valid_for_read and (stack.name == src) then
|
||||
local item = { name = dst, count = stack.count }
|
||||
if stack.can_set_stack(item) then
|
||||
stack.set_stack(item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return inventoryUtils
|
@@ -3,14 +3,13 @@ local mapProcessor = {}
|
||||
-- imports
|
||||
|
||||
local unitGroupUtils = require("UnitGroupUtils")
|
||||
|
||||
local pheromoneUtils = require("PheromoneUtils")
|
||||
local aiAttackWave = require("AIAttackWave")
|
||||
local aiPredicates = require("AIPredicates")
|
||||
local constants = require("Constants")
|
||||
local mapUtils = require("MapUtils")
|
||||
local playerUtils = require("PlayerUtils")
|
||||
|
||||
local chunkUtils = require("ChunkUtils")
|
||||
local mathUtils = require("MathUtils")
|
||||
|
||||
-- constants
|
||||
@@ -26,30 +25,33 @@ local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE
|
||||
local PROCESS_PLAYER_BOUND = constants.PROCESS_PLAYER_BOUND
|
||||
local CHUNK_TICK = constants.CHUNK_TICK
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
local WORM_COUNT = constants.WORM_COUNT
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
local AI_SQUAD_COST = constants.AI_SQUAD_COST
|
||||
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
|
||||
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
local RESOURCE_GENERATOR = constants.RESOURCE_GENERATOR
|
||||
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
|
||||
|
||||
-- imported functions
|
||||
|
||||
local scents = pheromoneUtils.scents
|
||||
local processPheromone = pheromoneUtils.processPheromone
|
||||
local playerScent = pheromoneUtils.playerScent
|
||||
|
||||
local formSquads = aiAttackWave.formSquads
|
||||
|
||||
local getChunkByIndex = mapUtils.getChunkByIndex
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
local positionToChunkXY = mapUtils.positionToChunkXY
|
||||
|
||||
local recycleBiters = unitGroupUtils.recycleBiters
|
||||
|
||||
local playerScent = pheromoneUtils.playerScent
|
||||
local validPlayer = playerUtils.validPlayer
|
||||
|
||||
local setResourceGenerator = chunkUtils.setResourceGenerator
|
||||
local setPlayerBaseGenerator = chunkUtils.setPlayerBaseGenerator
|
||||
local getNestCount = chunkUtils.getNestCount
|
||||
local getWormCount = chunkUtils.getWormCount
|
||||
|
||||
local canAttack = aiPredicates.canAttack
|
||||
|
||||
@@ -57,8 +59,6 @@ local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
|
||||
|
||||
local mMin = math.min
|
||||
|
||||
local validPlayer = playerUtils.validPlayer
|
||||
|
||||
local mRandom = math.random
|
||||
|
||||
-- module code
|
||||
@@ -105,12 +105,12 @@ function mapProcessor.processMap(regionMap, surface, natives, tick)
|
||||
|
||||
processPheromone(regionMap, chunk)
|
||||
|
||||
if squads and (chunk[NEST_COUNT] ~= 0) then
|
||||
if squads and (getNestCount(regionMap, chunk) > 0) then
|
||||
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST)
|
||||
squads = (natives.points >= AI_SQUAD_COST) and (#natives.squads < natives.maxSquads)
|
||||
end
|
||||
|
||||
scents(chunk)
|
||||
scents(regionMap, chunk)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -141,10 +141,10 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick)
|
||||
for i=1,#playerOrdering do
|
||||
local player = players[playerOrdering[i]]
|
||||
if validPlayer(player) then
|
||||
local playerPosition = player.character.position
|
||||
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
|
||||
local chunkX, chunkY = positionToChunkXY(player.character.position)
|
||||
local playerChunk = getChunkByPosition(regionMap, chunkX, chunkY)
|
||||
|
||||
if playerChunk then
|
||||
if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
playerScent(playerChunk)
|
||||
end
|
||||
end
|
||||
@@ -152,21 +152,24 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick)
|
||||
for i=1,#playerOrdering do
|
||||
local player = players[playerOrdering[i]]
|
||||
if validPlayer(player) then
|
||||
local playerPosition = player.character.position
|
||||
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
|
||||
local chunkX, chunkY = positionToChunkXY(player.character.position)
|
||||
local playerChunk = getChunkByPosition(regionMap, chunkX, chunkY)
|
||||
|
||||
if playerChunk then
|
||||
local vengence = allowingAttacks and ((playerChunk[NEST_COUNT] ~= 0) or (playerChunk[WORM_COUNT] ~= 0) or (playerChunk[MOVEMENT_PHEROMONE] < natives.retreatThreshold)) and (natives.points >= AI_VENGENCE_SQUAD_COST)
|
||||
if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
local vengence = (allowingAttacks and
|
||||
(natives.points >= AI_VENGENCE_SQUAD_COST) and
|
||||
((getWormCount(regionMap, playerChunk) > 0) or (getNestCount(regionMap, playerChunk) > 0) or (playerChunk[MOVEMENT_PHEROMONE] < natives.retreatThreshold)))
|
||||
|
||||
for x=playerChunk.cX - PROCESS_PLAYER_BOUND, playerChunk.cX + PROCESS_PLAYER_BOUND do
|
||||
for y=playerChunk.cY - PROCESS_PLAYER_BOUND, playerChunk.cY + PROCESS_PLAYER_BOUND do
|
||||
local chunk = getChunkByIndex(regionMap, x, y)
|
||||
if chunk and (chunk[CHUNK_TICK] ~= tick) then
|
||||
for x=playerChunk.x - PROCESS_PLAYER_BOUND, playerChunk.x + PROCESS_PLAYER_BOUND, 32 do
|
||||
for y=playerChunk.y - PROCESS_PLAYER_BOUND, playerChunk.y + PROCESS_PLAYER_BOUND, 32 do
|
||||
local chunk = getChunkByPosition(regionMap, x, y)
|
||||
|
||||
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (chunk[CHUNK_TICK] ~= tick) then
|
||||
chunk[CHUNK_TICK] = tick
|
||||
|
||||
processPheromone(regionMap, chunk)
|
||||
|
||||
if (chunk[NEST_COUNT] ~= 0) then
|
||||
if (getNestCount(regionMap, chunk) > 0) then
|
||||
if squads then
|
||||
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST)
|
||||
squads = (natives.points >= AI_SQUAD_COST) and (#natives.squads < natives.maxSquads)
|
||||
@@ -177,7 +180,7 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick)
|
||||
end
|
||||
end
|
||||
|
||||
scents(chunk)
|
||||
scents(regionMap, chunk)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -232,7 +235,7 @@ function mapProcessor.scanMap(regionMap, surface, natives)
|
||||
end
|
||||
end
|
||||
|
||||
chunk[RESOURCE_GENERATOR] = surface.count_entities_filtered(resourceQuery) * 0.001
|
||||
setResourceGenerator(regionMap, chunk, surface.count_entities_filtered(resourceQuery) * 0.001)
|
||||
|
||||
local entities = surface.find_entities_filtered(playerQuery)
|
||||
local playerBaseGenerator = 0
|
||||
@@ -250,7 +253,7 @@ function mapProcessor.scanMap(regionMap, surface, natives)
|
||||
end
|
||||
end
|
||||
|
||||
chunk[PLAYER_BASE_GENERATOR] = playerBaseGenerator
|
||||
setPlayerBaseGenerator(regionMap, chunk, playerBaseGenerator)
|
||||
end
|
||||
|
||||
if (endIndex == #processQueue) then
|
||||
|
@@ -13,10 +13,12 @@ local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
local CHUNK_IMPASSABLE = constants.CHUNK_IMPASSABLE
|
||||
|
||||
local CHUNK_SIZE = constants.CHUNK_SIZE
|
||||
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
local CHUNK_SIZE_DIVIDER = constants.CHUNK_SIZE_DIVIDER
|
||||
|
||||
-- imported functions
|
||||
|
||||
local mFloor = math.floor
|
||||
@@ -24,19 +26,17 @@ local mFloor = math.floor
|
||||
-- module code
|
||||
|
||||
function mapUtils.getChunkByPosition(regionMap, x, y)
|
||||
local chunkX = regionMap[mFloor(x * 0.03125)]
|
||||
if chunkX then
|
||||
return chunkX[mFloor(y * 0.03125)]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function mapUtils.getChunkByIndex(regionMap, x, y)
|
||||
local chunkX = regionMap[x]
|
||||
if chunkX then
|
||||
return chunkX[y]
|
||||
return chunkX[y] or SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
return nil
|
||||
return SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
|
||||
function mapUtils.positionToChunkXY(position)
|
||||
local chunkX = mFloor(position.x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
|
||||
local chunkY = mFloor(position.y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
|
||||
return chunkX, chunkY
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -46,39 +46,39 @@ end
|
||||
/|\
|
||||
6 7 8
|
||||
]]--
|
||||
function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY)
|
||||
function mapUtils.getNeighborChunks(regionMap, x, y)
|
||||
local neighbors = regionMap.neighbors
|
||||
local chunkYRow1 = chunkY - 1
|
||||
local chunkYRow3 = chunkY + 1
|
||||
local xChunks = regionMap[chunkX-1]
|
||||
local chunkYRow1 = y - CHUNK_SIZE
|
||||
local chunkYRow3 = y + CHUNK_SIZE
|
||||
local xChunks = regionMap[x-CHUNK_SIZE]
|
||||
if xChunks then
|
||||
neighbors[1] = xChunks[chunkYRow1]
|
||||
neighbors[4] = xChunks[chunkY]
|
||||
neighbors[6] = xChunks[chunkYRow3]
|
||||
neighbors[1] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[4] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[6] = xChunks[chunkYRow3] or SENTINEL_IMPASSABLE_CHUNK
|
||||
else
|
||||
neighbors[1] = nil
|
||||
neighbors[4] = nil
|
||||
neighbors[6] = nil
|
||||
neighbors[1] = SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[4] = SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[6] = SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX+1]
|
||||
xChunks = regionMap[x+CHUNK_SIZE]
|
||||
if xChunks then
|
||||
neighbors[3] = xChunks[chunkYRow1]
|
||||
neighbors[5] = xChunks[chunkY]
|
||||
neighbors[8] = xChunks[chunkYRow3]
|
||||
neighbors[3] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[5] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[8] = xChunks[chunkYRow3] or SENTINEL_IMPASSABLE_CHUNK
|
||||
else
|
||||
neighbors[3] = nil
|
||||
neighbors[5] = nil
|
||||
neighbors[8] = nil
|
||||
neighbors[3] = SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[5] = SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[8] = SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX]
|
||||
xChunks = regionMap[x]
|
||||
if xChunks then
|
||||
neighbors[2] = xChunks[chunkYRow1]
|
||||
neighbors[7] = xChunks[chunkYRow3]
|
||||
neighbors[2] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[7] = xChunks[chunkYRow3] or SENTINEL_IMPASSABLE_CHUNK
|
||||
else
|
||||
neighbors[2] = nil
|
||||
neighbors[7] = nil
|
||||
neighbors[2] = SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[7] = SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
return neighbors
|
||||
end
|
||||
@@ -87,41 +87,41 @@ function mapUtils.canMoveChunkDirection(direction, startChunk, endChunk)
|
||||
local canMove = false
|
||||
local startPassable = startChunk[PASSABLE]
|
||||
local endPassable = endChunk[PASSABLE]
|
||||
if ((direction == 2) or (direction == 7)) and (startPassable == CHUNK_NORTH_SOUTH) and (endPassable == CHUNK_NORTH_SOUTH) then
|
||||
if (startPassable == CHUNK_ALL_DIRECTIONS) and (endPassable == CHUNK_ALL_DIRECTIONS) then
|
||||
canMove = true
|
||||
elseif ((direction == 2) or (direction == 7)) and (startPassable == CHUNK_NORTH_SOUTH) and (endPassable == CHUNK_NORTH_SOUTH) then
|
||||
canMove = true
|
||||
elseif ((direction == 4) or (direction == 5)) and (startPassable == CHUNK_EAST_WEST) and (endPassable == CHUNK_EAST_WEST) then
|
||||
canMove = true
|
||||
elseif (startPassable == CHUNK_ALL_DIRECTIONS) and (endPassable == CHUNK_ALL_DIRECTIONS) then
|
||||
canMove = true
|
||||
elseif (startPassable ~= CHUNK_IMPASSABLE) and (endPassable == CHUNK_ALL_DIRECTIONS) then
|
||||
elseif (startChunk ~= SENTINEL_IMPASSABLE_CHUNK) and (endPassable == CHUNK_ALL_DIRECTIONS) then
|
||||
canMove = true
|
||||
end
|
||||
return canMove
|
||||
end
|
||||
|
||||
function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY)
|
||||
function mapUtils.getCardinalChunks(regionMap, x, y)
|
||||
local neighbors = regionMap.cardinalNeighbors
|
||||
local xChunks = regionMap[chunkX]
|
||||
local xChunks = regionMap[x]
|
||||
if xChunks then
|
||||
neighbors[1] = xChunks[chunkY-1]
|
||||
neighbors[4] = xChunks[chunkY+1]
|
||||
neighbors[1] = xChunks[y-CHUNK_SIZE] or SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[4] = xChunks[y+CHUNK_SIZE] or SENTINEL_IMPASSABLE_CHUNK
|
||||
else
|
||||
neighbors[1] = nil
|
||||
neighbors[4] = nil
|
||||
neighbors[1] = SENTINEL_IMPASSABLE_CHUNK
|
||||
neighbors[4] = SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX-1]
|
||||
xChunks = regionMap[x-CHUNK_SIZE]
|
||||
if xChunks then
|
||||
neighbors[2] = xChunks[chunkY]
|
||||
neighbors[2] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
|
||||
else
|
||||
neighbors[2] = nil
|
||||
neighbors[2] = SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX+1]
|
||||
xChunks = regionMap[x+CHUNK_SIZE]
|
||||
if xChunks then
|
||||
neighbors[3] = xChunks[chunkY]
|
||||
neighbors[3] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
|
||||
else
|
||||
neighbors[3] = nil
|
||||
neighbors[3] = SENTINEL_IMPASSABLE_CHUNK
|
||||
end
|
||||
return neighbors
|
||||
end
|
||||
|
@@ -4,7 +4,7 @@ local movementUtils = {}
|
||||
|
||||
local constants = require("Constants")
|
||||
local unitGroupUtils = require("UnitGroupUtils")
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
local mathUtils = require("MathUtils")
|
||||
|
||||
-- constants
|
||||
@@ -12,8 +12,16 @@ local mathUtils = require("MathUtils")
|
||||
local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
|
||||
local MAX_PENALTY_BEFORE_PURGE = constants.MAX_PENALTY_BEFORE_PURGE
|
||||
|
||||
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
|
||||
|
||||
local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
|
||||
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
-- imported functions
|
||||
|
||||
local canMoveChunkDirection = mapUtils.canMoveChunkDirection
|
||||
|
||||
local recycleBiters = unitGroupUtils.recycleBiters
|
||||
|
||||
local tableRemove = table.remove
|
||||
@@ -31,11 +39,11 @@ function movementUtils.findMovementPosition(surface, position, distort)
|
||||
return (distort and distortPosition(pos)) or pos
|
||||
end
|
||||
|
||||
function movementUtils.addMovementPenalty(natives, units, chunkX, chunkY)
|
||||
function movementUtils.addMovementPenalty(natives, units, x, y)
|
||||
local penalties = units.penalties
|
||||
for i=1,#penalties do
|
||||
local penalty = penalties[i]
|
||||
if (penalty.x == chunkX) and (penalty.y == chunkY) then
|
||||
if (penalty.x == x) and (penalty.y == y) then
|
||||
penalty.v = penalty.v + MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
|
||||
if (penalty.v > MAX_PENALTY_BEFORE_PURGE) then
|
||||
local group = units.group
|
||||
@@ -53,15 +61,15 @@ function movementUtils.addMovementPenalty(natives, units, chunkX, chunkY)
|
||||
tableRemove(penalties, 7)
|
||||
end
|
||||
tableInsert(penalties, 1, { v = MOVEMENT_PHEROMONE_GENERATOR_AMOUNT,
|
||||
x = chunkX,
|
||||
y = chunkY })
|
||||
x = x,
|
||||
y = y })
|
||||
end
|
||||
|
||||
function movementUtils.lookupMovementPenalty(squad, chunkX, chunkY)
|
||||
function movementUtils.lookupMovementPenalty(squad, x, y)
|
||||
local penalties = squad.penalties
|
||||
for i=1,#penalties do
|
||||
local penalty = penalties[i]
|
||||
if (penalty.x == chunkX) and (penalty.y == chunkY) then
|
||||
if (penalty.x == x) and (penalty.y == y) then
|
||||
return penalty.v
|
||||
end
|
||||
end
|
||||
@@ -69,4 +77,101 @@ function movementUtils.lookupMovementPenalty(squad, chunkX, chunkY)
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function movementUtils.scoreNeighborsForAttack(chunk, neighborDirectionChunks, scoreFunction, squad)
|
||||
local highestChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and canMoveChunkDirection(x, chunk, neighborChunk) then
|
||||
local score = scoreFunction(squad, neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if scoreFunction(squad, chunk) > highestScore then
|
||||
return SENTINEL_IMPASSABLE_CHUNK, -1
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function movementUtils.scoreNeighborsForResource(chunk, neighborDirectionChunks, scoreFunction, squad, threshold)
|
||||
local highestChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and canMoveChunkDirection(x, chunk, neighborChunk) and (neighborChunk[RESOURCE_PHEROMONE] > (threshold or 1)) then
|
||||
local score = scoreFunction(squad, neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if scoreFunction(squad, chunk) > highestScore then
|
||||
return SENTINEL_IMPASSABLE_CHUNK, -1
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function movementUtils.scoreNeighborsForRetreat(chunk, neighborDirectionChunks, scoreFunction, regionMap)
|
||||
local highestChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and canMoveChunkDirection(x, chunk, neighborChunk) then
|
||||
local score = scoreFunction(regionMap, neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function movementUtils.scoreNeighborsForFormation(neighborChunks, validFunction, scoreFunction, regionMap)
|
||||
local highestChunk = SENTINEL_IMPASSABLE_CHUNK
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborChunks[x]
|
||||
if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and validFunction(regionMap, neighborChunk) then
|
||||
local score = scoreFunction(neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
return movementUtils
|
||||
|
@@ -1,119 +0,0 @@
|
||||
local neighborUtils = {}
|
||||
|
||||
-- imports
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
|
||||
local constants = require("Constants")
|
||||
|
||||
-- constants
|
||||
|
||||
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
|
||||
|
||||
local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
|
||||
|
||||
-- imported functions
|
||||
|
||||
local canMoveChunkDirection = mapUtils.canMoveChunkDirection
|
||||
|
||||
-- module code
|
||||
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function neighborUtils.scoreNeighborsForAttack(chunk, neighborDirectionChunks, scoreFunction, squad)
|
||||
local highestChunk
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
if neighborChunk and canMoveChunkDirection(x, chunk, neighborChunk) then
|
||||
local score = scoreFunction(squad, neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if scoreFunction(squad, chunk) > highestScore then
|
||||
return nil, -1
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function neighborUtils.scoreNeighborsForResource(chunk, neighborDirectionChunks, scoreFunction, squad, threshold)
|
||||
local highestChunk
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
if neighborChunk and canMoveChunkDirection(x, chunk, neighborChunk) and (neighborChunk[RESOURCE_PHEROMONE] > (threshold or 1)) then
|
||||
local score = scoreFunction(squad, neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if scoreFunction(squad, chunk) > highestScore then
|
||||
return nil, -1
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function neighborUtils.scoreNeighborsForRetreat(chunk, neighborDirectionChunks, scoreFunction)
|
||||
local highestChunk
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
if neighborChunk and canMoveChunkDirection(x, chunk, neighborChunk) then
|
||||
local score = scoreFunction(neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function neighborUtils.scoreNeighborsForFormation(neighborChunks, validFunction, scoreFunction)
|
||||
local highestChunk
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborChunks[x]
|
||||
if neighborChunk and validFunction(neighborChunk) then
|
||||
local score = scoreFunction(neighborChunk)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
return neighborUtils
|
@@ -4,10 +4,8 @@ local nestUtils = {}
|
||||
|
||||
local constants = require("Constants")
|
||||
local mathUtils = require("MathUtils")
|
||||
|
||||
local baseRegisterUtils = require("BaseRegisterUtils")
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
local chunkUtils = require("ChunkUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
@@ -20,9 +18,11 @@ local NEST_COUNT = constants.NEST_COUNT
|
||||
|
||||
local DOUBLE_CHUNK_SIZE = constants.DOUBLE_CHUNK_SIZE
|
||||
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
-- imported functions
|
||||
|
||||
local registerEnemyBaseStructure = baseRegisterUtils.registerEnemyBaseStructure
|
||||
local registerEnemyBaseStructure = chunkUtils.registerEnemyBaseStructure
|
||||
local gaussianRandomRange = mathUtils.gaussianRandomRange
|
||||
|
||||
local mRandom = math.random
|
||||
@@ -35,7 +35,7 @@ function nestUtils.buildNest(regionMap, base, surface, targetPosition, name)
|
||||
local position = surface.find_non_colliding_position(name, targetPosition, DOUBLE_CHUNK_SIZE, 2)
|
||||
local chunk = getChunkByPosition(regionMap, position.x, position.y)
|
||||
local nest = nil
|
||||
if position and chunk and (chunk[NEST_COUNT] < 3) then
|
||||
if position and (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (chunk[NEST_COUNT] < 3) then
|
||||
local biterSpawner = {name=name, position=position}
|
||||
nest = surface.create_entity(biterSpawner)
|
||||
registerEnemyBaseStructure(regionMap, nest, base)
|
||||
@@ -45,7 +45,7 @@ end
|
||||
|
||||
function nestUtils.buildHive(regionMap, base, surface)
|
||||
local valid = false
|
||||
local hive = nestUtils.buildNest(regionMap, base, surface, base, "biter-spawner-hive")
|
||||
local hive = nestUtils.buildNest(regionMap, base, surface, base, "biter-spawner-hive-rampant")
|
||||
if hive then
|
||||
if (#base.hives == 0) then
|
||||
base.x = hive.position.x
|
||||
@@ -101,7 +101,7 @@ function nestUtils.buildOutpost(regionMap, natives, base, surface, tendril)
|
||||
y = position.y + (distortion * math.sin(pos))}
|
||||
local biterSpawner = {name=thing, position=nestPosition}
|
||||
if surface.can_place_entity(biterSpawner) then
|
||||
registerEnemyBaseStructure(regionMap, surface.create_entity(biterSpawner), base)
|
||||
registerEnemyBaseStructure(natives, regionMap, surface.create_entity(biterSpawner), base)
|
||||
base.upgradePoints = base.upgradePoints - cost
|
||||
end
|
||||
pos = pos + slice
|
||||
@@ -149,7 +149,7 @@ function nestUtils.buildOrder(regionMap, natives, base, surface)
|
||||
y = base.y + (distortion * math.sin(pos))}
|
||||
local biterSpawner = {name=thing, position=nestPosition}
|
||||
if surface.can_place_entity(biterSpawner) then
|
||||
registerEnemyBaseStructure(regionMap, surface.create_entity(biterSpawner), base)
|
||||
registerEnemyBaseStructure(natives, regionMap, surface.create_entity(biterSpawner), base)
|
||||
base.upgradePoints = base.upgradePoints - cost
|
||||
end
|
||||
pos = pos + slice
|
||||
|
@@ -1,21 +0,0 @@
|
||||
local nocturnalUtils = {}
|
||||
|
||||
-- imports
|
||||
|
||||
local constants = require("Constants")
|
||||
|
||||
-- constants
|
||||
|
||||
local AI_STATE_NOCTURNAL = constants.AI_STATE_NOCTURNAL
|
||||
|
||||
-- module code
|
||||
|
||||
function nocturnalUtils.isDark(surface)
|
||||
return surface.darkness > 0.65
|
||||
end
|
||||
|
||||
function nocturnalUtils.canAttack(natives, surface)
|
||||
return nocturnalUtils.isDark(surface) and natives.state == AI_STATE_NOCTURNAL
|
||||
end
|
||||
|
||||
return nocturnalUtils
|
@@ -4,6 +4,7 @@ local pheromoneUtils = {}
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
local constants = require("Constants")
|
||||
local chunkUtils = require("ChunkUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
@@ -14,9 +15,6 @@ local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
|
||||
|
||||
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
|
||||
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
local RESOURCE_GENERATOR = constants.RESOURCE_GENERATOR
|
||||
|
||||
local PLAYER_PHEROMONE_GENERATOR_AMOUNT = constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
||||
local DEATH_PHEROMONE_GENERATOR_AMOUNT = constants.DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
|
||||
@@ -25,63 +23,45 @@ local BASE_PHEROMONE_PERSISTANCE = constants.BASE_PHEROMONE_PERSISTANCE
|
||||
local PLAYER_PHEROMONE_PERSISTANCE = constants.PLAYER_PHEROMONE_PERSISTANCE
|
||||
local RESOURCE_PHEROMONE_PERSISTANCE = constants.RESOURCE_PHEROMONE_PERSISTANCE
|
||||
|
||||
local CHUNK_IMPASSABLE = constants.CHUNK_IMPASSABLE
|
||||
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
|
||||
local PATH_RATING = constants.PATH_RATING
|
||||
|
||||
local IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
|
||||
|
||||
-- imported functions
|
||||
|
||||
local getCardinalChunks = mapUtils.getCardinalChunks
|
||||
|
||||
local mMax = math.max
|
||||
local getNestCount = chunkUtils.getNestCount
|
||||
local getWormCount = chunkUtils.getWormCount
|
||||
local getPlayerBaseGenerator = chunkUtils.getPlayerBaseGenerator
|
||||
local getResourceGenerator = chunkUtils.getResourceGenerator
|
||||
|
||||
-- module code
|
||||
|
||||
function pheromoneUtils.scents(chunk)
|
||||
|
||||
if (chunk[PASSABLE] == CHUNK_IMPASSABLE) then
|
||||
chunk[BASE_PHEROMONE] = IMPASSABLE_TERRAIN_GENERATOR_AMOUNT;
|
||||
else
|
||||
chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR]
|
||||
local resourceGenerator = chunk[RESOURCE_GENERATOR]
|
||||
if (resourceGenerator > 0) and (chunk[NEST_COUNT] == 0) then
|
||||
function pheromoneUtils.scents(regionMap, chunk)
|
||||
chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + getPlayerBaseGenerator(regionMap, chunk)
|
||||
local resourceGenerator = getResourceGenerator(regionMap, chunk)
|
||||
if (resourceGenerator > 0) and (getNestCount(regionMap, chunk) == 0) and (getWormCount(regionMap, chunk) == 0) then
|
||||
chunk[RESOURCE_PHEROMONE] = chunk[RESOURCE_PHEROMONE] + mMax(resourceGenerator * 100, 90)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function pheromoneUtils.victoryScent(chunk, entityType)
|
||||
local value = BUILDING_PHEROMONES[entityType]
|
||||
if value and (chunk[PASSABLE] ~= CHUNK_IMPASSABLE) then
|
||||
if value then
|
||||
chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] + (value * 100000)
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.deathScent(chunk)
|
||||
if (chunk[PASSABLE] ~= CHUNK_IMPASSABLE) then
|
||||
chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] - DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.playerScent(playerChunk)
|
||||
if (playerChunk[PASSABLE] ~= CHUNK_IMPASSABLE) then
|
||||
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.processPheromone(regionMap, chunk)
|
||||
|
||||
if (chunk[PASSABLE] == CHUNK_IMPASSABLE) then
|
||||
return
|
||||
end
|
||||
|
||||
local chunkMovement = chunk[MOVEMENT_PHEROMONE]
|
||||
local chunkBase = chunk[BASE_PHEROMONE]
|
||||
local chunkPlayer = chunk[PLAYER_PHEROMONE]
|
||||
@@ -93,17 +73,31 @@ function pheromoneUtils.processPheromone(regionMap, chunk)
|
||||
local totalPlayer = 0
|
||||
local totalResource = 0
|
||||
|
||||
local tempNeighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
|
||||
local tempNeighbors = getCardinalChunks(regionMap, chunk.x, chunk.y)
|
||||
|
||||
for i=1,4 do
|
||||
local neighborChunk = tempNeighbors[i]
|
||||
if neighborChunk then
|
||||
local neighborChunk = tempNeighbors[1]
|
||||
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunkBase)
|
||||
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
totalResource = totalResource + (neighborChunk[RESOURCE_PHEROMONE] - chunkResource)
|
||||
|
||||
neighborChunk = tempNeighbors[2]
|
||||
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunkBase)
|
||||
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
totalResource = totalResource + (neighborChunk[RESOURCE_PHEROMONE] - chunkResource)
|
||||
|
||||
neighborChunk = tempNeighbors[3]
|
||||
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunkBase)
|
||||
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
totalResource = totalResource + (neighborChunk[RESOURCE_PHEROMONE] - chunkResource)
|
||||
|
||||
neighborChunk = tempNeighbors[4]
|
||||
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunkBase)
|
||||
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
totalResource = totalResource + (neighborChunk[RESOURCE_PHEROMONE] - chunkResource)
|
||||
end
|
||||
end
|
||||
|
||||
chunk[MOVEMENT_PHEROMONE] = (chunkMovement + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
chunk[BASE_PHEROMONE] = (chunkBase + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
|
@@ -25,24 +25,4 @@ function playerUtils.playersWithinProximityToPosition(players, position, distanc
|
||||
return false
|
||||
end
|
||||
|
||||
function playerUtils.getPlayerInventory(player, withChar, withoutChar)
|
||||
local inventory = nil
|
||||
if player and player.valid and player.connected then
|
||||
if player.character and player.character.valid then
|
||||
inventory = player.character.get_inventory(withChar)
|
||||
else
|
||||
inventory = player.get_inventory(withoutChar)
|
||||
end
|
||||
end
|
||||
return inventory
|
||||
end
|
||||
|
||||
function playerUtils.getPlayerCursorStack(player)
|
||||
local result = nil
|
||||
if player and player.valid then
|
||||
result = player.cursor_stack
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
return playerUtils
|
||||
|
@@ -6,9 +6,9 @@ local constants = require("Constants")
|
||||
local mapUtils = require("MapUtils")
|
||||
local unitGroupUtils = require("UnitGroupUtils")
|
||||
local playerUtils = require("PlayerUtils")
|
||||
local neighborUtils = require("NeighborUtils")
|
||||
local movementUtils = require("MovementUtils")
|
||||
local mathUtils = require("MathUtils")
|
||||
local chunkUtils = require("ChunkUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
@@ -19,7 +19,7 @@ local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
local SQUAD_RAIDING = constants.SQUAD_RAIDING
|
||||
local SQUAD_GUARDING = constants.SQUAD_GUARDING
|
||||
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
local CHUNK_SIZE = constants.CHUNK_SIZE
|
||||
|
||||
local PLAYER_PHEROMONE_MULTIPLER = constants.PLAYER_PHEROMONE_MULTIPLER
|
||||
|
||||
@@ -32,6 +32,8 @@ local DEFINES_GROUP_ATTACKING_TARGET = defines.group_state.attacking_target
|
||||
local DEFINES_DISTRACTION_BY_ENEMY = defines.distraction.by_enemy
|
||||
local DEFINES_DISTRACTION_BY_ANYTHING = defines.distraction.by_anything
|
||||
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
-- imported functions
|
||||
|
||||
local mRandom = math.random
|
||||
@@ -48,14 +50,17 @@ local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
|
||||
local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
|
||||
|
||||
local playersWithinProximityToPosition = playerUtils.playersWithinProximityToPosition
|
||||
local getPlayerBaseGenerator = chunkUtils.getPlayerBaseGenerator
|
||||
|
||||
local scoreNeighborsForAttack = neighborUtils.scoreNeighborsForAttack
|
||||
local positionToChunkXY = mapUtils.positionToChunkXY
|
||||
|
||||
local scoreNeighborsForAttack = movementUtils.scoreNeighborsForAttack
|
||||
|
||||
-- module code
|
||||
|
||||
local function scoreAttackLocation(squad, neighborChunk)
|
||||
local damage = (2*neighborChunk[MOVEMENT_PHEROMONE]) + neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
|
||||
return damage - lookupMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
|
||||
return damage - lookupMovementPenalty(squad, neighborChunk.x, neighborChunk.y)
|
||||
end
|
||||
|
||||
function squadAttack.squadsAttack(regionMap, surface, natives)
|
||||
@@ -67,7 +72,7 @@ function squadAttack.squadsAttack(regionMap, surface, natives)
|
||||
attackPosition = regionMap.position
|
||||
attackCmd = { type = DEFINES_COMMAND_ATTACK_AREA,
|
||||
destination = attackPosition,
|
||||
radius = 32,
|
||||
radius = CHUNK_SIZE,
|
||||
distraction = DEFINES_DISTRACTION_BY_ENEMY }
|
||||
end
|
||||
|
||||
@@ -78,18 +83,17 @@ function squadAttack.squadsAttack(regionMap, surface, natives)
|
||||
local groupState = group.state
|
||||
if (groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING) or ((groupState == DEFINES_GROUP_MOVING) and (squad.cycles == 0)) then
|
||||
local groupPosition = group.position
|
||||
local chunk = getChunkByPosition(regionMap, groupPosition.x, groupPosition.y)
|
||||
if chunk then
|
||||
local chunkX, chunkY = positionToChunkXY(groupPosition)
|
||||
local chunk = getChunkByPosition(regionMap, chunkX, chunkY)
|
||||
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
local attackChunk, attackDirection = scoreNeighborsForAttack(chunk,
|
||||
getNeighborChunks(regionMap,
|
||||
chunk.cX,
|
||||
chunk.cY),
|
||||
getNeighborChunks(regionMap, chunkX, chunkY),
|
||||
scoreAttackLocation,
|
||||
squad)
|
||||
addMovementPenalty(natives, squad, chunk.cX, chunk.cY)
|
||||
if group.valid and attackChunk then
|
||||
if (attackChunk[PLAYER_BASE_GENERATOR] == 0) or
|
||||
((groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING)) then
|
||||
addMovementPenalty(natives, squad, chunkX, chunkY)
|
||||
if group.valid and (attackChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
local playerBaseGenerator = getPlayerBaseGenerator(regionMap, attackChunk)
|
||||
if (playerBaseGenerator == 0) or ((groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING)) then
|
||||
|
||||
squad.cycles = ((#squad.group.members > 80) and 6) or 4
|
||||
|
||||
@@ -102,22 +106,18 @@ function squadAttack.squadsAttack(regionMap, surface, natives)
|
||||
attackCmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
|
||||
end
|
||||
|
||||
local position = findMovementPosition(surface,
|
||||
positionFromDirectionAndChunk(attackDirection,
|
||||
groupPosition,
|
||||
attackPosition,
|
||||
1.35))
|
||||
local position = findMovementPosition(surface, positionFromDirectionAndChunk(attackDirection, groupPosition, attackPosition, 1.35))
|
||||
if position then
|
||||
attackPosition.x = position.x
|
||||
attackPosition.y = position.y
|
||||
group.set_command(attackCmd)
|
||||
group.start_moving()
|
||||
else
|
||||
addMovementPenalty(natives, squad, attackChunk.cX, attackChunk.cY)
|
||||
addMovementPenalty(natives, squad, attackChunk.x, attackChunk.y)
|
||||
end
|
||||
elseif not squad.frenzy and not squad.rabid and
|
||||
((groupState == DEFINES_GROUP_ATTACKING_DISTRACTION) or (groupState == DEFINES_GROUP_ATTACKING_TARGET) or
|
||||
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then
|
||||
(playerBaseGenerator ~= 0)) then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = groupPosition.x
|
||||
squad.frenzyPosition.y = groupPosition.y
|
||||
|
@@ -5,14 +5,13 @@ local aiDefense = {}
|
||||
local constants = require("Constants")
|
||||
local mapUtils = require("MapUtils")
|
||||
local unitGroupUtils = require("UnitGroupUtils")
|
||||
local neighborUtils = require("NeighborUtils")
|
||||
local movementUtils = require("MovementUtils")
|
||||
local chunkUtils = require("ChunkUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local RETREAT_GRAB_RADIUS = constants.RETREAT_GRAB_RADIUS
|
||||
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
@@ -23,12 +22,9 @@ local SQUAD_RETREATING = constants.SQUAD_RETREATING
|
||||
|
||||
local RETREAT_FILTER = constants.RETREAT_FILTER
|
||||
|
||||
local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED
|
||||
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
local WORM_COUNT = constants.WORM_COUNT
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
-- imported functions
|
||||
|
||||
@@ -38,43 +34,44 @@ local findNearBySquad = unitGroupUtils.findNearBySquad
|
||||
local addMovementPenalty = movementUtils.addMovementPenalty
|
||||
local createSquad = unitGroupUtils.createSquad
|
||||
local membersToSquad = unitGroupUtils.membersToSquad
|
||||
local scoreNeighborsForRetreat = neighborUtils.scoreNeighborsForRetreat
|
||||
local scoreNeighborsForRetreat = movementUtils.scoreNeighborsForRetreat
|
||||
local findMovementPosition = movementUtils.findMovementPosition
|
||||
|
||||
local getRetreatTick = chunkUtils.getRetreatTick
|
||||
local getPlayerBaseGenerator = chunkUtils.getPlayerBaseGenerator
|
||||
local setRetreatTick = chunkUtils.setRetreatTick
|
||||
local getNestCount = chunkUtils.getNestCount
|
||||
local getWormCount = chunkUtils.getWormCount
|
||||
|
||||
-- module code
|
||||
|
||||
local function scoreRetreatLocation(neighborChunk)
|
||||
return -(neighborChunk[BASE_PHEROMONE] + -neighborChunk[MOVEMENT_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 100) + (neighborChunk[PLAYER_BASE_GENERATOR] * 20))
|
||||
local function scoreRetreatLocation(regionMap, neighborChunk)
|
||||
return -(neighborChunk[BASE_PHEROMONE] + -neighborChunk[MOVEMENT_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 100) + (getPlayerBaseGenerator(regionMap, neighborChunk) * 20))
|
||||
end
|
||||
|
||||
function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, natives, tick)
|
||||
if (tick - chunk[RETREAT_TRIGGERED] > INTERVAL_LOGIC) and (chunk[NEST_COUNT] == 0) and (chunk[WORM_COUNT] == 0) then
|
||||
if (tick - getRetreatTick(regionMap, chunk) > INTERVAL_LOGIC) and (getNestCount(regionMap, chunk) == 0) and (getWormCount(regionMap, chunk) == 0) then
|
||||
local performRetreat = false
|
||||
local enemiesToSquad = nil
|
||||
|
||||
if not squad then
|
||||
enemiesToSquad = surface.find_enemy_units(chunk, RETREAT_GRAB_RADIUS)
|
||||
enemiesToSquad = surface.find_enemy_units(position, RETREAT_GRAB_RADIUS)
|
||||
performRetreat = #enemiesToSquad > 0
|
||||
elseif squad.group.valid and (squad.status ~= SQUAD_RETREATING) and not squad.kamikaze then
|
||||
performRetreat = #squad.group.members > 1
|
||||
end
|
||||
|
||||
if performRetreat then
|
||||
chunk[RETREAT_TRIGGERED] = tick
|
||||
setRetreatTick(regionMap, chunk, tick)
|
||||
local exitPath,exitDirection = scoreNeighborsForRetreat(chunk,
|
||||
getNeighborChunks(regionMap,
|
||||
chunk.cX,
|
||||
chunk.cY),
|
||||
scoreRetreatLocation)
|
||||
if exitPath then
|
||||
getNeighborChunks(regionMap, chunk.x, chunk.y),
|
||||
scoreRetreatLocation,
|
||||
regionMap)
|
||||
if (exitPath ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
local retreatPosition = findMovementPosition(surface,
|
||||
positionFromDirectionAndChunk(exitDirection,
|
||||
position,
|
||||
regionMap.position,
|
||||
0.98),
|
||||
positionFromDirectionAndChunk(exitDirection, position, regionMap.position, 0.98),
|
||||
false)
|
||||
|
||||
|
||||
if not retreatPosition then
|
||||
return
|
||||
end
|
||||
@@ -100,7 +97,7 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
|
||||
newSquad.rabid = true
|
||||
end
|
||||
end
|
||||
addMovementPenalty(natives, newSquad, chunk.cX, chunk.cY)
|
||||
addMovementPenalty(natives, newSquad, chunk.x, chunk.y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -4,24 +4,18 @@ local tendrilUtils = {}
|
||||
|
||||
local constants = require("Constants")
|
||||
local mapUtils = require("MapUtils")
|
||||
local baseRegisterUtils = require("BaseRegisterUtils")
|
||||
local neighborsUtils = require("NeighborUtils")
|
||||
local mathUtils = require("MathUtils")
|
||||
|
||||
local nestUtils = require("NestUtils")
|
||||
local mathUtils = require("MathUtils")
|
||||
local movementUtils = require("MovementUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
|
||||
|
||||
local RESOURCE_GENERATOR = constants.RESOURCE_GENERATOR
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
||||
|
||||
-- imported functions
|
||||
|
||||
local scoreNeighborsForResource = neighborsUtils.scoreNeighborsForResource
|
||||
local scoreNeighborsForResource = movementUtils.scoreNeighborsForResource
|
||||
|
||||
local getNeighborChunks = mapUtils.getNeighborChunks
|
||||
|
||||
@@ -74,11 +68,9 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives
|
||||
end
|
||||
local tendrilPosition = tendrilUnit.position
|
||||
local chunk = getChunkByPosition(regionMap, tendrilPosition.x, tendrilPosition.y)
|
||||
if chunk then
|
||||
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
|
||||
local tendrilPath,tendrilDirection = scoreNeighborsForResource(chunk,
|
||||
getNeighborChunks(regionMap,
|
||||
chunk.cX,
|
||||
chunk.cY),
|
||||
getNeighborChunks(regionMap, chunk.x, chunk.y),
|
||||
scoreTendrilChunk,
|
||||
nil)
|
||||
if (tendrilDirection == -1) then
|
||||
|
@@ -1,83 +0,0 @@
|
||||
local worldProcessor = {}
|
||||
|
||||
-- imports
|
||||
|
||||
local constants = require("Constants")
|
||||
|
||||
-- constants
|
||||
|
||||
local ITEM_COLLECTOR_DISTANCE = constants.ITEM_COLLECTOR_DISTANCE
|
||||
|
||||
local ITEM_COLLECTOR_QUEUE_SIZE = constants.ITEM_COLLECTOR_QUEUE_SIZE
|
||||
|
||||
-- imported functions
|
||||
|
||||
-- module code
|
||||
|
||||
function worldProcessor.processWorld(surface, world, tick)
|
||||
local collectors = world.itemCollectorEvents
|
||||
if (#collectors > 0) then
|
||||
local collectorLookup = world.itemCollectorLookup
|
||||
|
||||
local inserter = {name="", count=0}
|
||||
local topLeftPosition = {x = 0, y = 0}
|
||||
local bottomRightPosition = {x = 0, y = 0}
|
||||
local boundingArea = {topLeftPosition,
|
||||
bottomRightPosition}
|
||||
|
||||
local count = 0
|
||||
for index = #collectors, 1, -1 do
|
||||
count = count + 1
|
||||
local itemCollectorPair = collectorLookup[collectors[index]]
|
||||
collectors[index] = nil
|
||||
|
||||
if itemCollectorPair then
|
||||
local chest = itemCollectorPair[1]
|
||||
local dish = itemCollectorPair[2]
|
||||
|
||||
if chest.valid and dish.valid then
|
||||
|
||||
local collectorPosition = dish.position
|
||||
|
||||
topLeftPosition.x = collectorPosition.x - ITEM_COLLECTOR_DISTANCE
|
||||
topLeftPosition.y = collectorPosition.y - ITEM_COLLECTOR_DISTANCE
|
||||
|
||||
bottomRightPosition.x = collectorPosition.x + ITEM_COLLECTOR_DISTANCE
|
||||
bottomRightPosition.y = collectorPosition.y + ITEM_COLLECTOR_DISTANCE
|
||||
|
||||
local items = surface.find_entities_filtered({area = boundingArea,
|
||||
name = "item-on-ground"})
|
||||
|
||||
local counts = {}
|
||||
if (#items > 0) then
|
||||
for x=1,#items do
|
||||
local item = items[x]
|
||||
local itemName = item.stack.name
|
||||
if not counts[itemName] then
|
||||
counts[itemName] = {item}
|
||||
else
|
||||
counts[itemName][#counts[itemName]+1] = item
|
||||
end
|
||||
end
|
||||
for k,a in pairs(counts) do
|
||||
inserter.name = k
|
||||
inserter.count = #a
|
||||
local stored = chest.insert(inserter)
|
||||
for i=1,stored do
|
||||
a[i].destroy()
|
||||
end
|
||||
end
|
||||
-- dish.surface.create_entity({name="item-collector-base-particle-rampant",
|
||||
-- position=dish.position})
|
||||
end
|
||||
end
|
||||
end
|
||||
if (count >= ITEM_COLLECTOR_QUEUE_SIZE) then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return worldProcessor
|
@@ -1,6 +1,6 @@
|
||||
|
||||
[entity-name]
|
||||
tunnel-entrance=Tunnel Entrance
|
||||
tunnel-entrance-rampant=Tunnel Entrance
|
||||
|
||||
small-suicide-biter=Small Suicide Biter
|
||||
medium-suicide-biter=Medium Suicide Biter
|
||||
@@ -9,7 +9,7 @@ behemoth-suicide-biter=Behemoth Suicide Biter
|
||||
|
||||
small-fire-spitter=Small Fire Spitter
|
||||
|
||||
biter-spawner-hive=Small Hive
|
||||
biter-spawner-hive-rampant=Small Hive
|
||||
|
||||
small-tendril-biter-rampant=Small Tendril
|
||||
item-collector-base-rampant=Item Collector
|
||||
@@ -32,7 +32,7 @@ short-range-electrodynamics-1-rampant=Short-range Electrodynamics
|
||||
short-range-electrodynamics-1-rampant=Buildings that generate strong electromagnetic fields
|
||||
|
||||
[entity-description]
|
||||
tunnel-entrance=This tunnel is used by the biters to bypass player defenses. Fill the hole using landfill.
|
||||
tunnel-entrance-rampant=This tunnel is used by the biters to bypass player defenses. Fill the hole using landfill.
|
||||
|
||||
small-suicide-biter=These biters will explode at close range
|
||||
medium-suicide-biter=These biters will explode at close range
|
||||
@@ -41,7 +41,7 @@ behemoth-suicide-biter=These biters will explode at close range
|
||||
|
||||
small-fire-spitter=These biters will spit fire
|
||||
|
||||
biter-spawner-hive=Small Hive
|
||||
biter-spawner-hive-rampant=Small Hive
|
||||
|
||||
small-tendril-biter-rampant=Small Tendril
|
||||
item-collector-base-rampant=Scans the surrounding area for items on the ground, if any items are found they are pulled into the storage chest when the sector is finished scanning.
|
||||
|
6
make.rkt
6
make.rkt
@@ -36,6 +36,7 @@
|
||||
(string->path "README.md")
|
||||
(string->path "NOTICE")
|
||||
(string->path "libs")
|
||||
(string->path "sounds")
|
||||
(string->path "locale")
|
||||
(string->path "graphics")
|
||||
(string->path "prototypes")))
|
||||
@@ -72,12 +73,13 @@
|
||||
(copyFile "tests.lua" modFolder)
|
||||
(copyDirectory "libs" modFolder)
|
||||
(copyDirectory "locale" modFolder)
|
||||
(copyDirectory "sounds" modFolder)
|
||||
(copyDirectory "graphics" modFolder)
|
||||
(copyDirectory "prototypes" modFolder)))
|
||||
|
||||
(define (run)
|
||||
;;(copyFiles modFolder)
|
||||
(copyFiles modFolder)
|
||||
;;(copyFiles zipModFolder)
|
||||
(makeZip modFolder)
|
||||
;;(makeZip modFolder)
|
||||
)
|
||||
)
|
||||
|
@@ -1,197 +0,0 @@
|
||||
-- overlays
|
||||
|
||||
local radar = util.table.deepcopy(data.raw["radar"]["radar"])
|
||||
radar.name = "item-collector-base-rampant"
|
||||
radar.icon = "__Rampant__/graphics/icon/itemCollectorIcon.png"
|
||||
radar.collision_box = {{-0.35, -0.35}, {0.35, 0.35}}
|
||||
radar.selection_box = {{-0.485, -0.7}, {0.465, -0.1}}
|
||||
radar.energy_per_sector = "27MJ"
|
||||
radar.max_distance_of_nearby_sector_revealed = 1
|
||||
radar.max_distance_of_sector_revealed = 0
|
||||
radar.energy_per_nearby_scan = "27MJ"
|
||||
radar.energy_usage = "450KW"
|
||||
radar.flags[#radar.flags+1] = "not-deconstructable"
|
||||
radar.pictures = {
|
||||
filename = "__Rampant__/graphics/entities/chest/itemCollector.png",
|
||||
priority = "low",
|
||||
width = 46,
|
||||
height = 49,
|
||||
apply_projection = false,
|
||||
direction_count = 64,
|
||||
line_length = 8,
|
||||
shift = {0.1875, -0.24}
|
||||
}
|
||||
radar.minable = nil
|
||||
|
||||
-- local particle = {
|
||||
-- type = "explosion",
|
||||
-- name = "item-collector-base-particle-rampant",
|
||||
-- flags = {"not-on-map"},
|
||||
-- animations =
|
||||
-- {
|
||||
-- {
|
||||
-- filename = "__Rampant__/graphics/entities/chest/itemCollectorParticle.png",
|
||||
-- priority = "extra-high",
|
||||
-- width = 46,
|
||||
-- height = 49,
|
||||
-- frame_count = 16,
|
||||
-- line_length = 8,
|
||||
-- animation_speed = 0.2
|
||||
-- }
|
||||
-- },
|
||||
-- light = {intensity = 1, size = 20, color = {r=1.0, g=1.0, b=1.0}},
|
||||
-- smoke = "smoke-fast",
|
||||
-- smoke_count = 0,
|
||||
-- smoke_slow_down_factor = 1,
|
||||
-- sound =
|
||||
-- {
|
||||
-- aggregation =
|
||||
-- {
|
||||
-- max_count = 1,
|
||||
-- remove = true
|
||||
-- },
|
||||
-- variations =
|
||||
-- {
|
||||
-- {
|
||||
-- filename = "__base__/sound/fight/small-explosion-1.ogg",
|
||||
-- volume = 0.75
|
||||
-- }
|
||||
-- }
|
||||
-- }
|
||||
-- }
|
||||
|
||||
local radarOverlay = util.table.deepcopy(radar)
|
||||
radarOverlay.name = "item-collector-base-overlay-rampant"
|
||||
radarOverlay.pictures.filename = "__Rampant__/graphics/entities/chest/itemCollectorOverlay2.png"
|
||||
radarOverlay.pictures.width = 2048
|
||||
radarOverlay.pictures.height = 2048
|
||||
radarOverlay.pictures.direction_count = 1
|
||||
radarOverlay.pictures.line_length = 1
|
||||
radarOverlay.pictures.shift[2] = 0.07
|
||||
radarOverlay.pictures.hr_version = {
|
||||
filename = "__Rampant__/graphics/entities/chest/itemCollectorOverlay2.5.png",
|
||||
priority = "low",
|
||||
width = 3200,
|
||||
height = 3200,
|
||||
apply_projection = false,
|
||||
direction_count = 1,
|
||||
line_length = 1,
|
||||
shift = {0.1875, -0.24}
|
||||
}
|
||||
|
||||
local chest = util.table.deepcopy(data.raw["container"]["steel-chest"])
|
||||
chest.name = "item-collector-chest-rampant"
|
||||
chest.picture = {
|
||||
filename = "__core__/graphics/empty.png",
|
||||
priority = "low",
|
||||
width = 46,
|
||||
height = 49,
|
||||
line_length = 1,
|
||||
shift = {0.1875, -0.2}
|
||||
}
|
||||
chest.selection_box = {{-0.485, -0.1}, {0.465, 0.6}}
|
||||
chest.collision_mask = {}
|
||||
chest.minable.result = "item-collector-base-rampant"
|
||||
|
||||
|
||||
data:extend({
|
||||
radar,
|
||||
radarOverlay,
|
||||
chest-- ,
|
||||
-- particle
|
||||
})
|
||||
|
||||
data:extend({
|
||||
|
||||
{
|
||||
type = "recipe",
|
||||
name = "item-collector-base-rampant",
|
||||
normal = {
|
||||
enabled = false,
|
||||
energy_required = 10,
|
||||
ingredients = {
|
||||
{"steel-chest", 1},
|
||||
{"accumulator", 1},
|
||||
{"radar", 1}
|
||||
},
|
||||
result = "item-collector-base-rampant",
|
||||
requester_paste_multiplier = 4
|
||||
},
|
||||
expensive = {
|
||||
enabled = false,
|
||||
energy_required = 10,
|
||||
ingredients = {
|
||||
{"steel-chest", 2},
|
||||
{"accumulator", 2},
|
||||
{"radar", 2}
|
||||
},
|
||||
result = "item-collector-base-rampant",
|
||||
requester_paste_multiplier = 4
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type = "item",
|
||||
name = "item-collector-base-rampant",
|
||||
icon = "__Rampant__/graphics/icon/itemCollectorIcon.png",
|
||||
flags = {"goes-to-quickbar"},
|
||||
subgroup = "storage",
|
||||
order = "a[items]-c[steel-collector]",
|
||||
place_result = "item-collector-base-rampant",
|
||||
stack_size = 50
|
||||
},
|
||||
|
||||
{
|
||||
type = "item",
|
||||
name = "item-collector-base-overlay-rampant",
|
||||
icon = "__Rampant__/graphics/icon/itemCollectorIcon.png",
|
||||
flags = {"goes-to-quickbar"},
|
||||
subgroup = "storage",
|
||||
order = "a[items]-c[steel-collector]",
|
||||
place_result = "item-collector-base-overlay-rampant",
|
||||
stack_size = 50
|
||||
},
|
||||
|
||||
{
|
||||
type = "item",
|
||||
name = "item-collector-chest-rampant",
|
||||
icon = "__Rampant__/graphics/icon/itemCollectorIcon.png",
|
||||
flags = {"goes-to-quickbar"},
|
||||
subgroup = "storage",
|
||||
order = "a[items]-c[steel-collector]",
|
||||
place_result = "item-collector-chest-rampant",
|
||||
stack_size = 50
|
||||
}
|
||||
})
|
||||
|
||||
-- technology insertions
|
||||
|
||||
data:extend({
|
||||
{
|
||||
type = "technology",
|
||||
name = "short-range-electrodynamics-1-rampant",
|
||||
icon = "__Rampant__/graphics/technology/itemCollectorTech.png",
|
||||
icon_size = 128,
|
||||
localised_name = {"technology-name.short-range-electrodynamics-1-rampant"},
|
||||
effects =
|
||||
{
|
||||
{
|
||||
type = "unlock-recipe",
|
||||
recipe = "item-collector-base-rampant"
|
||||
}
|
||||
},
|
||||
prerequisites = {"electric-energy-accumulators-1"},
|
||||
unit =
|
||||
{
|
||||
count = 200,
|
||||
ingredients =
|
||||
{
|
||||
{"science-pack-1", 1},
|
||||
{"science-pack-2", 1}
|
||||
},
|
||||
time = 22
|
||||
},
|
||||
order = "c-e-a",
|
||||
},
|
||||
})
|
||||
|
@@ -102,7 +102,7 @@ data:extend({
|
||||
|
||||
{
|
||||
type = "unit-spawner",
|
||||
name = "biter-spawner-hive",
|
||||
name = "biter-spawner-hive-rampant",
|
||||
icon = "__base__/graphics/icons/biter-spawner.png",
|
||||
flags = {"placeable-player", "placeable-enemy", "not-repairable"},
|
||||
max_health = 350,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
data:extend({
|
||||
{
|
||||
type = "simple-entity",
|
||||
name = "tunnel-entrance",
|
||||
name = "tunnel-entrance-rampant",
|
||||
flags = {"placeable-neutral", "placeable-off-grid", "not-on-map"},
|
||||
icon = "__base__/graphics/icons/small-scorchmark.png",
|
||||
subgroup = "grass",
|
||||
|
@@ -10,278 +10,95 @@ local makeColor = colorUtils.makeColor
|
||||
|
||||
-- dumb acid projectiles
|
||||
|
||||
makeStream({
|
||||
local templateDamage = { amount = 4, type = "acid" }
|
||||
local templateArea = {
|
||||
type = "area",
|
||||
perimeter = 1.2,
|
||||
action_delivery =
|
||||
{
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = templateDamage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local templateActions = {
|
||||
templateArea,
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
local template = {
|
||||
name = "acid-ball",
|
||||
particleTint = {r=0, g=1, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=1, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 1.5,
|
||||
action_delivery =
|
||||
{
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 15, type = "acid" }
|
||||
actions = templateActions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
makeStream(template)
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "acid-ball-1",
|
||||
particleTint = {r=0, g=1, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=1, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 1.5,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 22, type = "acid" }
|
||||
},
|
||||
{
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
template.name = "acid-ball-1"
|
||||
templateDamage.amount = 9
|
||||
templateArea.perimeter = 1.3
|
||||
makeStream(template)
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "acid-ball-2",
|
||||
particleTint = {r=0, g=1, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=1, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 1.5,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 32, type = "acid" }
|
||||
},
|
||||
{
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
template.name = "acid-ball-2"
|
||||
templateDamage.amount = 14
|
||||
templateArea.perimeter = 1.4
|
||||
makeStream(template)
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "acid-ball-3",
|
||||
particleTint = {r=0, g=1, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=1, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 1.5,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 45, type = "acid" }
|
||||
},
|
||||
{
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
template.name = "acid-ball-3"
|
||||
templateDamage.amount = 23
|
||||
templateArea.perimeter = 1.5
|
||||
makeStream(template)
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "wide-acid-ball",
|
||||
particleTint = {r=0, g=1, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=1, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 3,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 35, type = "acid" }
|
||||
},
|
||||
{
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
template.name = "wide-acid-ball"
|
||||
templateDamage.amount = 18
|
||||
templateArea.perimeter = 3
|
||||
makeStream(template)
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "acid-ball-4",
|
||||
particleTint = {r=0, g=1, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=1, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 2,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 95, type = "acid" }
|
||||
},
|
||||
{
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
template.name = "acid-ball-4"
|
||||
templateDamage.amount = 25
|
||||
templateArea.perimeter = 1.75
|
||||
makeStream(template)
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "acid-ball-5",
|
||||
particleTint = {r=0, g=1, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=1, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 2,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 145, type = "acid" }
|
||||
},
|
||||
{
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery = {
|
||||
type = "instant",
|
||||
target_effects = {
|
||||
type= "create-entity",
|
||||
entity_name = "acid-splash-purple"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
template.name = "acid-ball-5"
|
||||
templateDamage.amount = 50
|
||||
templateArea.perimeter = 2
|
||||
makeStream(template)
|
||||
|
||||
--
|
||||
|
||||
template.name = "acid-ball-6"
|
||||
templateDamage.amount = 70
|
||||
templateArea.perimeter = 2.5
|
||||
makeStream(template)
|
||||
|
@@ -57,57 +57,7 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 35, type = "explosion" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "bob-explosive-ball-1",
|
||||
particleTint = {r=1, g=0.97, b=0.34, a=0.5},
|
||||
spineAnimationTint = {r=1, g=0.97, b=0.34, a=0.5},
|
||||
softSmokeTint = makeColor(0.3, 0.75, 0.3, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "create-entity",
|
||||
entity_name = "small-scorchmark",
|
||||
check_buildability = true
|
||||
},
|
||||
{
|
||||
type = "create-entity",
|
||||
entity_name = "big-explosion",
|
||||
check_buildability = true
|
||||
},
|
||||
{
|
||||
type = "create-entity",
|
||||
entity_name = "small-fire-cloud"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 3,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 55, type = "explosion" }
|
||||
damage = { amount = 25, type = "explosion" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,7 +116,7 @@ makeStream({
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 43, type = "fire" }
|
||||
damage = { amount = 20, type = "fire" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,47 +164,6 @@ makeStream({
|
||||
}
|
||||
})
|
||||
|
||||
--
|
||||
|
||||
|
||||
makeStream({
|
||||
name = "bob-poison-ball-1",
|
||||
particleTint = {r=0.1, g=0.5, b=1, a=0.5},
|
||||
spineAnimationTint = {r=0, g=0, b=1, a=0.5},
|
||||
softSmokeTint = makeColor(0.7, 0.4, 0.2, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "create-entity",
|
||||
entity_name = "small-poison-cloud"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 2,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 43, type = "poison" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
-- piercing
|
||||
|
||||
data:extend({
|
||||
@@ -318,7 +227,7 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 43, type = "bob-pierce" }
|
||||
damage = { amount = 30, type = "bob-pierce" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -400,47 +309,7 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 10, type = "electric" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
--
|
||||
|
||||
makeStream({
|
||||
name = "bob-electric-ball-1",
|
||||
particleTint = {r=0, g=0.1, b=1, a=1},
|
||||
spineAnimationTint = {r=0, g=0.1, b=1, a=1},
|
||||
softSmokeTint = makeColor(0.7, 0.4, 0.2, 0.1),
|
||||
actions = {
|
||||
{
|
||||
type = "cluster",
|
||||
cluster_count = 10,
|
||||
distance = 4,
|
||||
distance_deviation = 3,
|
||||
action_delivery =
|
||||
{
|
||||
type = "projectile",
|
||||
projectile = "electric-spike-rampant",
|
||||
direction_deviation = 0.6,
|
||||
starting_speed = 0.65,
|
||||
starting_speed_deviation = 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "area",
|
||||
perimeter = 3,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 55, type = "electric" }
|
||||
damage = { amount = 25, type = "electric" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,7 +334,7 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "create-entity",
|
||||
entity_name = "small-poison-cloud"
|
||||
entity_name = "small-fire-cloud"
|
||||
},
|
||||
{
|
||||
type = "create-entity",
|
||||
@@ -484,19 +353,15 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 15, type = "electric" }
|
||||
damage = { amount = 10, type = "electric" }
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 15, type = "explosion" }
|
||||
damage = { amount = 10, type = "explosion" }
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 15, type = "fire" }
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 15, type = "poison" }
|
||||
damage = { amount = 10, type = "fire" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -615,7 +480,7 @@ makeStream({
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 20, type = "explosion" }
|
||||
damage = { amount = 15, type = "explosion" }
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
@@ -631,7 +496,7 @@ makeStream({
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 20, type = "acid" }
|
||||
damage = { amount = 15, type = "acid" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ makeStream({
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = {amount = 25, type = "poison"}
|
||||
damage = {amount = 24, type = "poison"}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,11 +91,11 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 5, type = "explosion" }
|
||||
damage = { amount = 8, type = "explosion" }
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 15, type = "acid" }
|
||||
damage = { amount = 18, type = "acid" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,11 +135,11 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 3, type = "explosion" }
|
||||
damage = { amount = 5, type = "explosion" }
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 7, type = "poison" }
|
||||
damage = { amount = 12, type = "poison" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,11 +183,11 @@ makeStream({
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 7, type = "explosion" }
|
||||
damage = { amount = 5, type = "explosion" }
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 14, type = "acid" }
|
||||
damage = { amount = 12, type = "acid" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -218,22 +218,50 @@ function biterFunctions.createFireAttack(attributes, fireAttack)
|
||||
begin_sound =
|
||||
{
|
||||
{
|
||||
filename = "__base__/sound/fight/flamethrower-start.ogg",
|
||||
filename = "__base__/sound/creatures/spitter-1.ogg",
|
||||
volume = 0.7
|
||||
},
|
||||
{
|
||||
filename = "__base__/sound/creatures/spitter-2.ogg",
|
||||
volume = 0.7
|
||||
},
|
||||
{
|
||||
filename = "__base__/sound/creatures/spitter-3.ogg",
|
||||
volume = 0.7
|
||||
},
|
||||
{
|
||||
filename = "__base__/sound/creatures/spitter-4.ogg",
|
||||
volume = 0.7
|
||||
},
|
||||
{
|
||||
filename = "__base__/sound/creatures/spitter-5.ogg",
|
||||
volume = 0.7
|
||||
},
|
||||
{
|
||||
filename = "__base__/sound/creatures/spitter-6.ogg",
|
||||
volume = 0.7
|
||||
},
|
||||
{
|
||||
filename = "__base__/sound/creatures/spitter-7.ogg",
|
||||
volume = 0.7
|
||||
},
|
||||
{
|
||||
filename = "__base__/sound/creatures/spitter-8.ogg",
|
||||
volume = 0.7
|
||||
}
|
||||
},
|
||||
middle_sound =
|
||||
{
|
||||
{
|
||||
filename = "__base__/sound/fight/flamethrower-mid.ogg",
|
||||
volume = 0.7
|
||||
filename = attributes.midSound or "__Rampant__/sounds/attacks/acid-mid.ogg",
|
||||
volume = 0.5
|
||||
}
|
||||
},
|
||||
end_sound =
|
||||
{
|
||||
{
|
||||
filename = "__base__/sound/fight/flamethrower-end.ogg",
|
||||
volume = 0.7
|
||||
filename = attributes.endSound or "__Rampant__/sounds/attacks/acid-end.ogg",
|
||||
volume = 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,8 @@ local makeSmokeSoft = smokeUtils.makeSmokeSoft
|
||||
|
||||
-- module code
|
||||
|
||||
function streamUtils.makeStream(attributes)
|
||||
function streamUtils.makeStream(info)
|
||||
local attributes = util.table.deepcopy(info)
|
||||
local softSmokeName = attributes.softSmokeName or makeSmokeSoft(attributes)
|
||||
data:extend(
|
||||
{
|
||||
@@ -79,7 +80,7 @@ function streamUtils.makeStream(attributes)
|
||||
height = 64,
|
||||
frame_count = 32,
|
||||
line_length = 8
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@@ -7,19 +7,19 @@ function bobsUpdates.useDumbProjectiles()
|
||||
|
||||
turrets["bob-big-explosive-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 25,
|
||||
cooldown = 60,
|
||||
range = 26,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
scale = 1.2
|
||||
},
|
||||
"bob-explosive-ball-1-stream-rampant")
|
||||
"bob-explosive-ball-stream-rampant")
|
||||
|
||||
turrets["bob-big-fire-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 25,
|
||||
cooldown = 60,
|
||||
range = 26,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
@@ -29,19 +29,19 @@ function bobsUpdates.useDumbProjectiles()
|
||||
|
||||
turrets["bob-big-poison-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 25,
|
||||
cooldown = 60,
|
||||
range = 26,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
scale = 1.2
|
||||
},
|
||||
"bob-poison-ball-1-stream-rampant")
|
||||
"bob-poison-ball-stream-rampant")
|
||||
|
||||
turrets["bob-big-piercing-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 25,
|
||||
cooldown = 60,
|
||||
range = 26,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
@@ -51,44 +51,44 @@ function bobsUpdates.useDumbProjectiles()
|
||||
|
||||
turrets["bob-big-electric-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 25,
|
||||
cooldown = 60,
|
||||
range = 26,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
scale = 1.2
|
||||
},
|
||||
"bob-electric-ball-1-stream-rampant")
|
||||
"bob-electric-ball-stream-rampant")
|
||||
|
||||
turrets["bob-giant-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
cooldown = 60,
|
||||
range = 28,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
scale = 1.6
|
||||
},
|
||||
"acid-ball-4-stream-rampant")
|
||||
"acid-ball-5-stream-rampant")
|
||||
|
||||
turrets["bob-behemoth-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
cooldown = 60,
|
||||
range = 30,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
scale = 2
|
||||
},
|
||||
"acid-ball-5-stream-rampant")
|
||||
"acid-ball-6-stream-rampant")
|
||||
|
||||
local units = data.raw["unit"]
|
||||
|
||||
local unit = units["behemoth-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
warmup = 30,
|
||||
@@ -102,10 +102,11 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-big-electric-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
cooldown = 90,
|
||||
range = 15,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
damageModifier = 0.6,
|
||||
warmup = 30,
|
||||
fire_penalty = 0,
|
||||
scale = biterUtils.findRunScale(unit),
|
||||
@@ -117,11 +118,12 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-huge-explosive-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
warmup = 30,
|
||||
turn_range = 1,
|
||||
damageModifier = 0.8,
|
||||
fire_penalty = 15,
|
||||
scale = biterUtils.findRunScale(unit),
|
||||
tint1 = biterUtils.findTint(unit),
|
||||
@@ -132,8 +134,8 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-huge-acid-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
warmup = 30,
|
||||
@@ -147,8 +149,8 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-giant-fire-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
warmup = 30,
|
||||
@@ -162,8 +164,8 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-giant-poison-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
warmup = 30,
|
||||
@@ -177,8 +179,8 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-titan-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
warmup = 30,
|
||||
@@ -192,8 +194,8 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-behemoth-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
warmup = 30,
|
||||
@@ -208,8 +210,8 @@ function bobsUpdates.useDumbProjectiles()
|
||||
unit = units["bob-leviathan-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 17,
|
||||
min_range = 3,
|
||||
warmup = 30,
|
||||
turn_range = 1,
|
||||
|
@@ -7,8 +7,8 @@ function NEUpdates.useNEUnitLaunchers ()
|
||||
|
||||
turrets["medium-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 22,
|
||||
cooldown = 60,
|
||||
range = 25,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
@@ -19,8 +19,8 @@ function NEUpdates.useNEUnitLaunchers ()
|
||||
|
||||
turrets["big-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 27,
|
||||
cooldown = 60,
|
||||
range = 30,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
@@ -40,13 +40,13 @@ function NEUpdates.useDumbProjectiles()
|
||||
turret["attack_parameters"].range = 22
|
||||
turret["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 22,
|
||||
cooldown = 60,
|
||||
range = 25,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
damageModifier = 4.5,
|
||||
scale = 1.0
|
||||
scale = 1.2
|
||||
},
|
||||
"ne-infected-ball-stream-rampant")
|
||||
|
||||
@@ -54,13 +54,13 @@ function NEUpdates.useDumbProjectiles()
|
||||
turret["attack_parameters"].range = 27
|
||||
turret["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 27,
|
||||
cooldown = 60,
|
||||
range = 30,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
damageModifier = 5.5,
|
||||
scale = 1.2
|
||||
scale = 1.6
|
||||
},
|
||||
"ne-mutated-ball-stream-rampant")
|
||||
|
||||
@@ -69,7 +69,7 @@ function NEUpdates.useDumbProjectiles()
|
||||
local unit = units["small-spitter-Mk2"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 150,
|
||||
cooldown = 100,
|
||||
range = 13,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
@@ -85,7 +85,7 @@ function NEUpdates.useDumbProjectiles()
|
||||
unit = units["small-spitter-Mk3"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 150,
|
||||
cooldown = 100,
|
||||
range = 13,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
@@ -102,7 +102,7 @@ function NEUpdates.useDumbProjectiles()
|
||||
unit = units["medium-spitter-Mk2"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 150,
|
||||
cooldown = 100,
|
||||
range = 14,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
@@ -118,7 +118,7 @@ function NEUpdates.useDumbProjectiles()
|
||||
unit = units["medium-spitter-Mk3"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 150,
|
||||
cooldown = 100,
|
||||
range = 14,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
@@ -134,7 +134,7 @@ function NEUpdates.useDumbProjectiles()
|
||||
unit = units["big-spitter-Mk2"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 150,
|
||||
cooldown = 100,
|
||||
range = 15,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
@@ -151,7 +151,7 @@ function NEUpdates.useDumbProjectiles()
|
||||
unit = units["big-spitter-Mk3"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 150,
|
||||
cooldown = 100,
|
||||
range = 15,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
|
@@ -7,44 +7,46 @@ function vanillaUpdates.useDumbProjectiles()
|
||||
|
||||
turrets["small-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 50,
|
||||
range = 18,
|
||||
cooldown = 60,
|
||||
range = 21,
|
||||
min_range = 5,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
damageModifier = 0.9,
|
||||
scale = 0.8
|
||||
},
|
||||
"acid-ball-stream-rampant")
|
||||
"acid-ball-2-stream-rampant")
|
||||
|
||||
turrets["medium-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 20,
|
||||
cooldown = 60,
|
||||
range = 25,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
damageModifier = 0.87,
|
||||
scale = 1
|
||||
},
|
||||
"acid-ball-1-stream-rampant")
|
||||
"acid-ball-3-stream-rampant")
|
||||
|
||||
|
||||
turrets["big-worm-turret"]["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 25,
|
||||
cooldown = 60,
|
||||
range = 26,
|
||||
min_range = 3,
|
||||
turn_range = 1,
|
||||
fire_penalty = 0,
|
||||
scale = 1.2
|
||||
},
|
||||
"acid-ball-2-stream-rampant")
|
||||
"acid-ball-4-stream-rampant")
|
||||
|
||||
local units = data.raw["unit"];
|
||||
|
||||
local unit = units["small-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
cooldown = 100,
|
||||
range = 13,
|
||||
warmup = 30,
|
||||
min_range = 3,
|
||||
@@ -59,7 +61,7 @@ function vanillaUpdates.useDumbProjectiles()
|
||||
unit = units["medium-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
cooldown = 95,
|
||||
range = 14,
|
||||
min_range = 3,
|
||||
warmup = 30,
|
||||
@@ -74,7 +76,7 @@ function vanillaUpdates.useDumbProjectiles()
|
||||
unit = units["big-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
cooldown = 90,
|
||||
range = 15,
|
||||
min_range = 3,
|
||||
warmup = 30,
|
||||
@@ -89,8 +91,8 @@ function vanillaUpdates.useDumbProjectiles()
|
||||
unit = units["behemoth-spitter"]
|
||||
unit["attack_parameters"] = biterUtils.createFireAttack(
|
||||
{
|
||||
cooldown = 80,
|
||||
range = 15,
|
||||
cooldown = 90,
|
||||
range = 16,
|
||||
min_range = 3,
|
||||
warmup = 30,
|
||||
turn_range = 1,
|
||||
|
11
settings.lua
11
settings.lua
@@ -194,17 +194,6 @@ data:extend({
|
||||
per_user = false
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
type = "bool-setting",
|
||||
name = "rampant-enableBuildings",
|
||||
description = "rampant-enableBuildings",
|
||||
setting_type = "startup",
|
||||
default_value = true,
|
||||
order = "i[modifier]-a[buildings]",
|
||||
per_user = false
|
||||
},
|
||||
|
||||
{
|
||||
type = "bool-setting",
|
||||
name = "rampant-attack-warning",
|
||||
|
BIN
sounds/attacks/acid-end.ogg
Executable file
BIN
sounds/attacks/acid-end.ogg
Executable file
Binary file not shown.
BIN
sounds/attacks/acid-mid.ogg
Executable file
BIN
sounds/attacks/acid-mid.ogg
Executable file
Binary file not shown.
31
tests.lua
31
tests.lua
@@ -5,22 +5,23 @@ local mathUtils = require("libs/MathUtils")
|
||||
local chunkUtils = require("libs/ChunkUtils")
|
||||
local mapUtils = require("libs/MapUtils")
|
||||
local baseUtils = require("libs/BaseUtils")
|
||||
local baseRegisterUtils = require("libs/BaseRegisterUtils")
|
||||
local tendrilUtils = require("libs/TendrilUtils")
|
||||
-- local tendrilUtils = require("libs/TendrilUtils")
|
||||
|
||||
function tests.pheromoneLevels(size)
|
||||
local player = game.player.character
|
||||
local playerChunkX = math.floor(player.position.x / 32)
|
||||
local playerChunkY = math.floor(player.position.y / 32)
|
||||
local playerChunkX = math.floor(player.position.x / 32) * constants.CHUNK_SIZE
|
||||
local playerChunkY = math.floor(player.position.y / 32) * constants.CHUNK_SIZE
|
||||
if not size then
|
||||
size = 3
|
||||
size = 3 * constants.CHUNK_SIZE
|
||||
else
|
||||
size = size * constants.CHUNK_SIZE
|
||||
end
|
||||
print("------")
|
||||
print(#global.regionMap.processQueue)
|
||||
print(playerChunkX .. ", " .. playerChunkY)
|
||||
print("--")
|
||||
for y=playerChunkY-size, playerChunkY+size do
|
||||
for x=playerChunkX-size, playerChunkX+size do
|
||||
for y=playerChunkY-size, playerChunkY+size,32 do
|
||||
for x=playerChunkX-size, playerChunkX+size,32 do
|
||||
if (global.regionMap[x] ~= nil) then
|
||||
local chunk = global.regionMap[x][y]
|
||||
if (chunk ~= nil) then
|
||||
@@ -29,12 +30,12 @@ function tests.pheromoneLevels(size)
|
||||
str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i])
|
||||
end
|
||||
str = str .. " " .. "p/" .. game.surfaces[1].get_pollution(chunk)
|
||||
if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then
|
||||
if (chunk.x == playerChunkX) and (chunk.y == playerChunkY) then
|
||||
print("=============")
|
||||
print(chunk.cX, chunk.cY, str)
|
||||
print(chunk.x, chunk.y, str)
|
||||
print("=============")
|
||||
else
|
||||
print(chunk.cX, chunk.cY, str)
|
||||
print(chunk.x, chunk.y, str)
|
||||
end
|
||||
-- print(str)
|
||||
print("----")
|
||||
@@ -109,7 +110,7 @@ function tests.tunnelTest()
|
||||
local playerPosition = game.players[1].position
|
||||
local chunkX = math.floor(playerPosition.x * 0.03125) * 32
|
||||
local chunkY = math.floor(playerPosition.y * 0.03125) * 32
|
||||
game.surfaces[1].create_entity({name="tunnel-entrance", position={chunkX, chunkY}})
|
||||
game.surfaces[1].create_entity({name="tunnel-entrance-rampant", position={chunkX, chunkY}})
|
||||
end
|
||||
|
||||
function tests.createEnemy(x)
|
||||
@@ -121,7 +122,7 @@ end
|
||||
|
||||
function tests.registeredNest(x)
|
||||
local entity = tests.createEnemy(x)
|
||||
baseRegisterUtils.registerEnemyBaseStructure(global.regionMap,
|
||||
chunk.registerEnemyBaseStructure(global.regionMap,
|
||||
entity,
|
||||
nil)
|
||||
end
|
||||
@@ -280,9 +281,9 @@ function tests.showMovementGrid()
|
||||
end
|
||||
|
||||
function tests.stepAdvanceTendrils()
|
||||
for _, base in pairs(global.natives.bases) do
|
||||
tendrilUtils.advanceTendrils(global.regionMap, base, game.surfaces[1], {nil,nil,nil,nil,nil,nil,nil,nil})
|
||||
end
|
||||
-- for _, base in pairs(global.natives.bases) do
|
||||
-- tendrilUtils.advanceTendrils(global.regionMap, base, game.surfaces[1], {nil,nil,nil,nil,nil,nil,nil,nil})
|
||||
-- end
|
||||
end
|
||||
|
||||
return tests
|
||||
|
Reference in New Issue
Block a user