1
0
mirror of https://github.com/veden/Rampant.git synced 2025-09-16 09:16:43 +02:00

Stable merged with ai toggle

This commit is contained in:
Aaron Veden
2017-05-27 21:50:37 -07:00
parent 2b3fa0ca0e
commit afe7cacb0f
21 changed files with 367 additions and 300 deletions

View File

@@ -55,6 +55,11 @@ Configure Options not in game menu:
# Version History # Version History
0.15.11 -
- Tweak: Increased rally cry chance from 0.02(@100 evo) to 0.08(@100 evo) compensate for the once per logic cycle per chunk
- Improvement: Added negative score contribution to nest causing biters to move around nests instead of through
- Improvement: Increased player pheromone for weight multipler from 25 to 50 for hunting parties
0.15.10 - 0.15.10 -
- Fix: nil chunk in pheromone utils(https://mods.factorio.com/mods/Veden/Rampant/discussion/13806) - Fix: nil chunk in pheromone utils(https://mods.factorio.com/mods/Veden/Rampant/discussion/13806)
- Tweak: Increased failed behaviors before dispanding from 3 to 6 - Tweak: Increased failed behaviors before dispanding from 3 to 6

View File

@@ -10,8 +10,6 @@ local mathUtils = require("libs/MathUtils")
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
local MAX_RALLY_CRIES = constants.MAX_RALLY_CRIES
-- imported functions -- imported functions
local roundToNearest = mathUtils.roundToNearest local roundToNearest = mathUtils.roundToNearest
@@ -80,7 +78,6 @@ function upgrade.attempt(natives, regionMap)
global.version = constants.VERSION_16 global.version = constants.VERSION_16
end end
if (global.version < constants.VERSION_18) then if (global.version < constants.VERSION_18) then
print(global.version)
natives.safeEntities = {} natives.safeEntities = {}
natives.safeEntityName = {} natives.safeEntityName = {}
@@ -132,20 +129,18 @@ function upgrade.attempt(natives, regionMap)
game.surfaces[1].print("Rampant - Version 0.15.10") game.surfaces[1].print("Rampant - Version 0.15.10")
global.version = constants.VERSION_22 global.version = constants.VERSION_22
end end
if (global.version < constants.VERSION_22) then if (global.version < constants.VERSION_23) then
natives.bases = {}
natives.baseDistanceMin = 0
natives.baseIndex = 1
natives.randomGenerator = game.create_random_generator()
game.forces.enemy.ai_controllable = false game.forces.enemy.ai_controllable = false
game.surfaces[1].print("Rampant - Version 0.15.10") natives.useCustomAI = settings.startup["rampant-useCustomAI"].value
global.version = constants.VERSION_22 natives.bases = {}
natives.baseDistanceMin = 0
natives.baseIndex = 1
natives.randomGenerator = game.create_random_generator()
game.surfaces[1].print("Rampant - Version 0.15.11")
global.version = constants.VERSION_23
end end
return starting ~= global.version return starting ~= global.version
end end

View File

@@ -15,6 +15,7 @@ local aiPlanning = require("libs/AIPlanning")
local interop = require("libs/Interop") local interop = require("libs/Interop")
local tests = require("tests") local tests = require("tests")
local upgrade = require("Upgrade") local upgrade = require("Upgrade")
local baseUtils = require("libs/BaseUtils")
-- constants -- constants
@@ -55,8 +56,8 @@ local squadBeginAttack = aiAttack.squadBeginAttack
local retreatUnits = aiDefense.retreatUnits local retreatUnits = aiDefense.retreatUnits
local addRemovePlayerEntity = entityUtils.addRemovePlayerEntity local addRemovePlayerEntity = entityUtils.addRemovePlayerEntity
local removeEnemyBase = entityUtils.removeEnemyBase local unregisterEnemyBaseStructure = baseUtils.unregisterEnemyBaseStructure
--local makeImmortalEntity = entityUtils.makeImmortalEntity local makeImmortalEntity = entityUtils.makeImmortalEntity
local processBases = baseProcessor.processBases local processBases = baseProcessor.processBases
@@ -82,10 +83,31 @@ local function onChunkGenerated(event)
end end
end end
local function reprocessChunks()
game.surfaces[1].print("Rampant - Reindexing chunks, please wait")
-- clear old regionMap processing Queue
-- prevents queue adding duplicate chunks
-- chunks are by key, so should overwrite old
regionMap.processQueue = {}
regionMap.processPointer = 1
regionMap.scanPointer = 1
-- clear pending chunks, will be added when loop runs below
pendingChunks = {}
-- queue all current chunks that wont be generated during play
local surface = game.surfaces[1]
for chunk in surface.get_chunks() do
onChunkGenerated({ tick = game.tick,
surface = surface,
area = { left_top = { x = chunk.x * 32,
y = chunk.y * 32 }}})
end
end
local function onModSettingsChange(event) local function onModSettingsChange(event)
if event and (string.sub(event.setting, 1, 7) ~= "rampant") then if event and (string.sub(event.setting, 1, 7) ~= "rampant") then
return return false
end end
natives.safeBuildings = settings.global["rampant-safeBuildings"].value natives.safeBuildings = settings.global["rampant-safeBuildings"].value
@@ -112,31 +134,21 @@ local function onModSettingsChange(event)
natives.attackPlayerThreshold = settings.global["rampant-attackPlayerThreshold"].value natives.attackPlayerThreshold = settings.global["rampant-attackPlayerThreshold"].value
natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value
natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value
local useCustomAI = natives.useCustomAI
natives.useCustomAI = settings.startup["rampant-useCustomAI"].value
if not useCustomAI and natives.useCustomAI then
reprocessChunks()
return false
end
return true
end end
local function onConfigChanged() local function onConfigChanged()
if upgrade.attempt(natives, regionMap) and onModSettingsChange(nil) then
if upgrade.attempt(natives, regionMap) then reprocessChunks()
onModSettingsChange(nil)
game.surfaces[1].print("Rampant - Reindexing chunks, please wait")
-- clear old regionMap processing Queue
-- prevents queue adding duplicate chunks
-- chunks are by key, so should overwrite old
regionMap.processQueue = {}
regionMap.processPointer = 1
regionMap.scanPointer = 1
-- clear pending chunks, will be added when loop runs below
pendingChunks = {}
-- queue all current chunks that wont be generated during play
local surface = game.surfaces[1]
for chunk in surface.get_chunks() do
onChunkGenerated({ tick = game.tick,
surface = surface,
area = { left_top = { x = chunk.x * 32,
y = chunk.y * 32 }}})
end
end end
end end
@@ -161,7 +173,9 @@ local function onTick(event)
processPlayers(players, regionMap, surface, natives, evolutionFactor, tick) processPlayers(players, regionMap, surface, natives, evolutionFactor, tick)
processBases(regionMap, surface, natives, tick) if (natives.useCustomAI) then
processBases(regionMap, surface, natives, tick)
end
squadBeginAttack(natives, players, evolutionFactor) squadBeginAttack(natives, players, evolutionFactor)
squadAttack(regionMap, surface, natives) squadAttack(regionMap, surface, natives)
@@ -173,7 +187,7 @@ end
local function onBuild(event) local function onBuild(event)
local entity = event.created_entity local entity = event.created_entity
addRemoveEntity(regionMap, entity, natives, true, false) addRemovePlayerEntity(regionMap, entity, natives, true, false)
if natives.safeBuildings then if natives.safeBuildings then
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
entity.destructible = false entity.destructible = false
@@ -198,7 +212,7 @@ local function onDeath(event)
-- drop death pheromone where unit died -- drop death pheromone where unit died
deathScent(deathChunk) deathScent(deathChunk)
if ((event.force ~= nil) and (event.force.name == "player")) then if event.force and (event.force.name == "player") then
local evolutionFactor = entity.force.evolution_factor local evolutionFactor = entity.force.evolution_factor
local tick = event.tick local tick = event.tick
@@ -224,7 +238,7 @@ local function onDeath(event)
end end
elseif (entity.type == "unit-spawner") or (entity.type == "turret") then elseif (entity.type == "unit-spawner") or (entity.type == "turret") then
removeEnemyBase(regionMap, entity) unregisterEnemyBaseStructure(regionMap, entity)
end end
elseif (entity.force.name == "player") then elseif (entity.force.name == "player") then
local creditNatives = false local creditNatives = false
@@ -247,7 +261,7 @@ end
local function onSurfaceTileChange(event) local function onSurfaceTileChange(event)
local player = game.players[event.player_index] local player = game.players[event.player_index]
if (player.surface.index==1) then if (player.surface.index == 1) then
aiBuilding.fillTunnel(regionMap, player.surface, natives, event.positions) aiBuilding.fillTunnel(regionMap, player.surface, natives, event.positions)
end end
end end
@@ -303,7 +317,9 @@ remote.add_interface("rampantTests",
baseStats = tests.baseStats, baseStats = tests.baseStats,
baseTiles = tests.baseTiles, baseTiles = tests.baseTiles,
mergeBases = tests.mergeBases, mergeBases = tests.mergeBases,
clearBases = tests.clearBases clearBases = tests.clearBases,
getOffsetChunk = tests.getOffsetChunk,
registeredNest = tests.registeredNest
} }
) )

View File

@@ -1,7 +1,7 @@
{ {
"name" : "Rampant", "name" : "Rampant",
"factorio_version" : "0.15", "factorio_version" : "0.15",
"version" : "0.15.10", "version" : "0.15.11",
"title" : "Rampant", "title" : "Rampant",
"author" : "Veden", "author" : "Veden",
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445", "homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",

View File

@@ -19,6 +19,9 @@ local SQUAD_GUARDING = constants.SQUAD_GUARDING
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local NEST_COUNT = constants.NEST_COUNT
local DEFINES_COMMAND_ATTACK_AREA = defines.command.attack_area
local DEFINES_GROUP_FINISHED = defines.group_state.finished local DEFINES_GROUP_FINISHED = defines.group_state.finished
local DEFINES_GROUP_GATHERING = defines.group_state.gathering local DEFINES_GROUP_GATHERING = defines.group_state.gathering
local DEFINES_GROUP_MOVING = defines.group_state.moving local DEFINES_GROUP_MOVING = defines.group_state.moving
@@ -49,40 +52,20 @@ local function validLocation(x, chunk, neighborChunk)
return canMoveChunkDirection(x, chunk, neighborChunk) return canMoveChunkDirection(x, chunk, neighborChunk)
end end
local function scoreAttackLocation(position, squad, neighborChunk, surface) local function scoreAttackLocation(squad, neighborChunk, surface)
local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY) local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
local r = surface.get_pollution(position) + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 25) --- neighborChunk[ENEMY_BASE_GENERATOR] local r = surface.get_pollution(neighborChunk) + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 50)
return r - squadMovementPenalty return r - squadMovementPenalty - (neighborChunk[NEST_COUNT] * 30)
end end
function aiAttack.squadAttack(regionMap, surface, natives) function aiAttack.squadAttack(regionMap, surface, natives)
local squads = natives.squads local squads = natives.squads
local attackPosition local attackPosition
local attackCmd local attackCmd
--[[
Constants populated by the factorio runtime
--]]
-- local DEFINES_GROUP_FINISHED
-- local DEFINES_GROUP_GATHERING
-- local DEFINES_GROUP_MOVING
-- local DEFINES_GROUP_ATTACKING_DISTRACTION
-- local DEFINES_GROUP_ATTACKING_TARGET
-- local DEFINES_DISTRACTION_BY_ENEMY
-- local DEFINES_DISTRACTION_BY_ANYTHING
if (#squads > 0) then if (#squads > 0) then
-- DEFINES_GROUP_FINISHED = defines.group_state.finished
-- DEFINES_GROUP_GATHERING = defines.group_state.gathering
-- DEFINES_GROUP_MOVING = defines.group_state.moving
-- DEFINES_GROUP_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction
-- DEFINES_GROUP_ATTACKING_TARGET = defines.group_state.attacking_target
-- DEFINES_DISTRACTION_BY_ENEMY = defines.distraction.by_enemy
-- DEFINES_DISTRACTION_BY_ANYTHING = defines.distraction.by_anything
attackPosition = {x=0, y=0} attackPosition = {x=0, y=0}
attackCmd = { type = defines.command.attack_area, attackCmd = { type = DEFINES_COMMAND_ATTACK_AREA,
destination = attackPosition, destination = attackPosition,
radius = 28, radius = 28,
distraction = DEFINES_DISTRACTION_BY_ENEMY } distraction = DEFINES_DISTRACTION_BY_ENEMY }
@@ -102,7 +85,6 @@ function aiAttack.squadAttack(regionMap, surface, natives)
scoreAttackLocation, scoreAttackLocation,
squad, squad,
surface, surface,
attackPosition,
true) true)
addSquadMovementPenalty(squad, chunk.cX, chunk.cY) addSquadMovementPenalty(squad, chunk.cX, chunk.cY)
if attackChunk then if attackChunk then
@@ -117,8 +99,8 @@ function aiAttack.squadAttack(regionMap, surface, natives)
squad.cycles = 4 squad.cycles = 4
end end
local outsideFrenzyRadius = not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) > 100) local moreFrenzy = not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100)
squad.frenzy = not outsideFrenzyRadius squad.frenzy = moreFrenzy
if squad.rabid or squad.frenzy then if squad.rabid or squad.frenzy then
attackCmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING attackCmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING

View File

@@ -33,7 +33,7 @@ local RALLY_CRY_DISTANCE = constants.RALLY_CRY_DISTANCE
local DEFINES_COMMAND_GROUP = defines.command.group local DEFINES_COMMAND_GROUP = defines.command.group
local DEFINES_DISTRACTION_NONE = defines.distraction.none local DEFINES_DISTRACTION_NONE = defines.distraction.none
local CHUNK_BASE = constants.CHUNK_BASE local NEST_COUNT = constants.NEST_COUNT
-- imported functions -- imported functions
@@ -57,7 +57,7 @@ local function attackWaveValidCandidate(chunk, natives, surface, evolutionFactor
end end
end end
if natives.attackUsePollution then if natives.attackUsePollution then
total = total + surface.get_pollution({chunk.pX, chunk.pY}) total = total + surface.get_pollution(chunk)
end end
local threshold = natives.attackThresholdRange local threshold = natives.attackThresholdRange
@@ -66,12 +66,12 @@ local function attackWaveValidCandidate(chunk, natives, surface, evolutionFactor
return total > ((threshold - delta) + natives.attackThresholdMin) return total > ((threshold - delta) + natives.attackThresholdMin)
end end
local function scoreUnitGroupLocation(position, squad, neighborChunk, surface) local function scoreUnitGroupLocation(squad, neighborChunk, surface)
return surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] return surface.get_pollution(neighborChunk) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE]
end end
local function validUnitGroupLocation(x, chunk, neighborChunk) local function validUnitGroupLocation(x, chunk, neighborChunk)
return neighborChunk[NORTH_SOUTH_PASSABLE] and neighborChunk[EAST_WEST_PASSABLE] and neighborChunk[CHUNK_BASE] ~= nil return neighborChunk[NORTH_SOUTH_PASSABLE] and neighborChunk[EAST_WEST_PASSABLE] and neighborChunk[NEST_COUNT] ~= 0
end end
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor, tick) function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor, tick)
@@ -82,7 +82,7 @@ function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFact
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
local rallyChunk = getChunkByIndex(regionMap, x, y) local rallyChunk = getChunkByIndex(regionMap, x, y)
if rallyChunk and (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then if rallyChunk and (x ~= cX) and (y ~= cY) and (rallyChunk[NEST_COUNT] ~= 0) then
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST) aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST)
end end
end end
@@ -91,24 +91,23 @@ function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFact
end end
function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_factor, cost) function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_factor, cost)
if (natives.points > cost) and (chunk[CHUNK_BASE] ~= nil) and (#natives.squads < (AI_MAX_SQUAD_COUNT * evolution_factor)) then if (natives.points > cost) and (chunk[NEST_COUNT] ~= 0) and (#natives.squads < (AI_MAX_SQUAD_COUNT * evolution_factor)) then
local valid = not surface.peaceful_mode and local valid = not surface.peaceful_mode and
((cost == AI_VENGENCE_SQUAD_COST) or ((cost == AI_VENGENCE_SQUAD_COST) or
((cost == AI_SQUAD_COST) and attackWaveValidCandidate(chunk, natives, surface, evolution_factor))) ((cost == AI_SQUAD_COST) and attackWaveValidCandidate(chunk, natives, surface, evolution_factor)))
if valid and (math.random() < mMax((0.25 * evolution_factor), 0.10)) then if valid and (math.random() < mMax((0.25 * evolution_factor), 0.10)) then
local squadPosition = {x=0, y=0}
local squadPath, _ = scoreNeighbors(chunk, local squadPath, _ = scoreNeighbors(chunk,
getNeighborChunks(regionMap, chunk.cX, chunk.cY), getNeighborChunks(regionMap, chunk.cX, chunk.cY),
validUnitGroupLocation, validUnitGroupLocation,
scoreUnitGroupLocation, scoreUnitGroupLocation,
nil, nil,
surface, surface,
squadPosition,
false) false)
if (squadPath ~= nil) then if squadPath then
squadPosition.x = squadPath.pX + HALF_CHUNK_SIZE local squadPosition = { x = squadPath.x + HALF_CHUNK_SIZE,
squadPosition.y = squadPath.pY + HALF_CHUNK_SIZE y = squadPath.y + HALF_CHUNK_SIZE }
local squad = createSquad(squadPosition, surface, natives) local squad = createSquad(squadPosition, surface, natives)

View File

@@ -25,7 +25,8 @@ local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local NEST_BASE = constants.NEST_BASE local NEST_COUNT = constants.NEST_COUNT
local WORM_COUNT = constants.WORM_COUNT
-- imported functions -- imported functions
@@ -43,20 +44,19 @@ local function validRetreatLocation(x, chunk, neighborChunk)
return canMoveChunkDirection(x, chunk, neighborChunk) return canMoveChunkDirection(x, chunk, neighborChunk)
end end
local function scoreRetreatLocation(position, squad, neighborChunk, surface) local function scoreRetreatLocation(squad, neighborChunk, surface)
local safeScore = -neighborChunk[BASE_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] local safeScore = -neighborChunk[BASE_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE]
local dangerScore = surface.get_pollution(position) + (neighborChunk[PLAYER_PHEROMONE] * 100) --+ (neighborChunk[ENEMY_BASE_GENERATOR] * 50) local dangerScore = surface.get_pollution(neighborChunk) + (neighborChunk[PLAYER_PHEROMONE] * 100) --+ (neighborChunk[ENEMY_BASE_GENERATOR] * 50)
return safeScore - dangerScore return safeScore - dangerScore
end end
function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick) function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
if (tick - chunk[RETREAT_TRIGGERED] > INTERVAL_LOGIC) and (#chunk[NEST_BASE] == 0) then if (tick - chunk[RETREAT_TRIGGERED] > INTERVAL_LOGIC) and (chunk[NEST_COUNT] == 0) and (chunk[WORM_COUNT] == 0) then
local performRetreat = false local performRetreat = false
local enemiesToSquad local enemiesToSquad = nil
if (squad == nil) then if not squad then
enemiesToSquad = surface.find_enemy_units({x=chunk.pX, enemiesToSquad = surface.find_enemy_units(chunk, RETREAT_GRAB_RADIUS)
y=chunk.pY}, RETREAT_GRAB_RADIUS)
performRetreat = #enemiesToSquad > 0 performRetreat = #enemiesToSquad > 0
elseif squad.group.valid and (squad.status ~= SQUAD_RETREATING) and not squad.kamikaze then elseif squad.group.valid and (squad.status ~= SQUAD_RETREATING) and not squad.kamikaze then
performRetreat = #squad.group.members > 1 performRetreat = #squad.group.members > 1
@@ -64,31 +64,29 @@ function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
if performRetreat then if performRetreat then
chunk[RETREAT_TRIGGERED] = tick chunk[RETREAT_TRIGGERED] = tick
local retreatPosition = {x=0, y=0}
local exitPath,_ = scoreNeighborsWithDirection(chunk, local exitPath,_ = scoreNeighborsWithDirection(chunk,
getNeighborChunksWithDirection(regionMap, chunk.cX, chunk.cY), getNeighborChunksWithDirection(regionMap, chunk.cX, chunk.cY),
validRetreatLocation, validRetreatLocation,
scoreRetreatLocation, scoreRetreatLocation,
nil, nil,
surface, surface,
retreatPosition,
false) false)
if exitPath then if exitPath then
retreatPosition.x = exitPath.pX + HALF_CHUNK_SIZE local retreatPosition = { x = exitPath.x + HALF_CHUNK_SIZE,
retreatPosition.y = exitPath.pY + HALF_CHUNK_SIZE y = exitPath.y + HALF_CHUNK_SIZE }
-- in order for units in a group attacking to retreat, we have to create a new group and give the command to join -- in order for units in a group attacking to retreat, we have to create a new group and give the command to join
-- to each unit, this is the only way I have found to have snappy mid battle retreats even after 0.14.4 -- to each unit, this is the only way I have found to have snappy mid battle retreats even after 0.14.4
local newSquad = findNearBySquad(natives, retreatPosition, HALF_CHUNK_SIZE, RETREAT_FILTER) local newSquad = findNearBySquad(natives, retreatPosition, HALF_CHUNK_SIZE, RETREAT_FILTER)
if (newSquad == nil) then if not newSquad then
newSquad = createSquad(retreatPosition, surface, natives) newSquad = createSquad(retreatPosition, surface, natives)
newSquad.status = SQUAD_RETREATING newSquad.status = SQUAD_RETREATING
newSquad.cycles = 4 newSquad.cycles = 4
end end
if (enemiesToSquad ~= nil) then if enemiesToSquad then
membersToSquad(newSquad, enemiesToSquad, false) membersToSquad(newSquad, enemiesToSquad, false)
else else
membersToSquad(newSquad, squad.group.members, true) membersToSquad(newSquad, squad.group.members, true)

View File

@@ -4,8 +4,8 @@ local aiPlanning = {}
local constants = require("Constants") local constants = require("Constants")
local mathUtils = require("MathUtils") local mathUtils = require("MathUtils")
local nocturnalUtils = require("NocturnalUtils") local aiPredicates = require("AIPredicates")
-- constants -- constants
local AI_STATE_PEACEFUL = constants.AI_STATE_PEACEFUL local AI_STATE_PEACEFUL = constants.AI_STATE_PEACEFUL
@@ -26,7 +26,7 @@ local TICKS_A_MINUTE = constants.TICKS_A_MINUTE
-- imported functions -- imported functions
local canAttackNocturnal = nocturnalUtils.canAttack local canAttack = aiPredicates.canAttack
local randomTickEvent = mathUtils.randomTickEvent local randomTickEvent = mathUtils.randomTickEvent
@@ -34,13 +34,22 @@ local mMax = math.max
-- module code -- module code
local function isShockwaveReady(evolution_factor, natives, surface, tick, maxPoints)
return canAttack(natives, surface) and
(tick - natives.lastShakeMessage > TICKS_A_MINUTE * 5) and
((evolution_factor > 0.7) and
(natives.points > maxPoints * 0.85) and
(#natives.squads > AI_MAX_SQUAD_COUNT * 0.35))
end
function aiPlanning.planning(natives, evolution_factor, tick, surface) function aiPlanning.planning(natives, evolution_factor, tick, surface)
local maxPoints = AI_MAX_POINTS * evolution_factor local maxPoints = AI_MAX_POINTS * evolution_factor
if natives.aiNocturnalMode then if natives.aiNocturnalMode then
maxPoints = maxPoints * 0.85 maxPoints = maxPoints * 0.85
end end
if (natives.points < maxPoints) then if (natives.points < maxPoints) then
natives.points = natives.points + math.floor((AI_POINT_GENERATOR_AMOUNT * math.random()) + ((AI_POINT_GENERATOR_AMOUNT * 0.7) * (evolution_factor ^ 2.5)) * natives.aiPointsScaler) natives.points = natives.points + math.floor((AI_POINT_GENERATOR_AMOUNT * math.random()) +
((AI_POINT_GENERATOR_AMOUNT * 0.7) * (evolution_factor ^ 2.5)) * natives.aiPointsScaler)
end end
if (natives.temperamentTick == tick) then if (natives.temperamentTick == tick) then
@@ -60,7 +69,7 @@ function aiPlanning.planning(natives, evolution_factor, tick, surface)
natives.stateTick = randomTickEvent(tick, AI_MIN_STATE_DURATION, AI_MAX_STATE_DURATION) natives.stateTick = randomTickEvent(tick, AI_MIN_STATE_DURATION, AI_MAX_STATE_DURATION)
end end
if ((natives.state == AI_STATE_AGGRESSIVE) or canAttackNocturnal(natives, surface)) and (tick - natives.lastShakeMessage > TICKS_A_MINUTE * 5) and ((evolution_factor > 0.7) and (natives.points > maxPoints * 0.85) and (#natives.squads > AI_MAX_SQUAD_COUNT * 0.35)) then if isShockwaveReady(evolution_factor, natives, surface, tick, maxPoints) then
natives.lastShakeMessage = tick natives.lastShakeMessage = tick
surface.print("Rampant: The ground begins to shake") surface.print("Rampant: The ground begins to shake")
end end

View File

@@ -5,6 +5,7 @@ local baseUtils = {}
local mapUtils = require("MapUtils") local mapUtils = require("MapUtils")
local constants = require("Constants") local constants = require("Constants")
local mathUtils = require("MathUtils") local mathUtils = require("MathUtils")
local entityUtils = require("EntityUtils") local entityUtils = require("EntityUtils")
-- constants -- constants
@@ -13,6 +14,12 @@ local BASE_DISTANCE_THRESHOLD = constants.BASE_DISTANCE_THRESHOLD
local BASE_ALIGNMENT_NEUTRAL = constants.BASE_ALIGNMENT_NEUTRAL local BASE_ALIGNMENT_NEUTRAL = constants.BASE_ALIGNMENT_NEUTRAL
local NEST_COUNT = constants.NEST_COUNT
local WORM_COUNT = constants.WORM_COUNT
local NEST_BASE = constants.NEST_BASE
local WORM_BASE = constants.WORM_BASE
local AI_NEST_COST = constants.AI_NEST_COST local AI_NEST_COST = constants.AI_NEST_COST
local AI_WORM_COST = constants.AI_WORM_COST local AI_WORM_COST = constants.AI_WORM_COST
@@ -25,34 +32,34 @@ local MAGIC_MAXIMUM_BASE_NUMBER = constants.MAGIC_MAXIMUM_BASE_NUMBER
local euclideanDistancePoints = mapUtils.euclideanDistancePoints local euclideanDistancePoints = mapUtils.euclideanDistancePoints
local gaussianRandomRange = mathUtils.gaussianRandomRange local getEntityOverlapChunks = entityUtils.getEntityOverlapChunks
local addEnemyBase = entityUtils.addEnemyBase local gaussianRandomRange = mathUtils.gaussianRandomRange
-- module code -- module code
function baseUtils.annexNest(natives, position) function baseUtils.findNearbyBase(natives, position)
local bases = natives.bases local bases = natives.bases
local annex = nil local foundBase
local closest = MAGIC_MAXIMUM_NUMBER local closest = MAGIC_MAXIMUM_NUMBER
for i=1,#bases do for i=1,#bases do
local base = bases[i] local base = bases[i]
local distance = euclideanDistancePoints(base.x, base.y, position.x, position.y) local distance = euclideanDistancePoints(base.x, base.y, position.x, position.y)
if (distance <= BASE_DISTANCE_THRESHOLD) and (distance < closest) then if (distance <= BASE_DISTANCE_THRESHOLD) and (distance < closest) then
closest = distance closest = distance
annex = base foundBase = base
end end
end end
return annex return foundBase
end end
function baseUtils.buildHive(regionMap, base, surface) function baseUtils.buildHive(regionMap, base, surface)
local valid = false local valid = false
local position = surface.find_non_colliding_position("biter-spawner", {x=base.x, y=base.y}, 2*CHUNK_SIZE, 10) local position = surface.find_non_colliding_position("biter-spawner-hive", {x=base.x, y=base.y}, 2*CHUNK_SIZE, 2)
if position then if position then
local biterSpawner = {name="biter-spawner", position=position} local biterSpawner = {name="biter-spawner-hive", position=position}
base.hive = surface.create_entity(biterSpawner) base.hives[#base.hives+1] = surface.create_entity(biterSpawner)
addEnemyBase(regionMap, base.hive, base) baseUtils.registerEnemyBaseStructure(regionMap, base.hive, base)
valid = true valid = true
end end
return valid return valid
@@ -67,7 +74,7 @@ function baseUtils.buildTendril(natives, base, surface, tick, startPosition, end
end end
function baseUtils.buildOrder(regionMap, natives, base, surface, tick) function baseUtils.buildOrder(regionMap, natives, base, surface, tick)
if not base.hive or (base.upgradePoints < 10) then if (#base.hives == 0) or (base.upgradePoints < 10) then
return return
end end
@@ -100,7 +107,7 @@ function baseUtils.buildOrder(regionMap, natives, base, surface, tick)
y = base.y + (distortion * math.sin(pos))} y = base.y + (distortion * math.sin(pos))}
local biterSpawner = {name=thing, position=nestPosition} local biterSpawner = {name=thing, position=nestPosition}
if surface.can_place_entity(biterSpawner) then if surface.can_place_entity(biterSpawner) then
addEnemyBase(regionMap, surface.create_entity(biterSpawner), base) baseUtils.registerEnemyBaseStructure(regionMap, surface.create_entity(biterSpawner), base)
base.upgradePoints = base.upgradePoints - cost base.upgradePoints = base.upgradePoints - cost
end end
pos = pos + slice pos = pos + slice
@@ -115,7 +122,7 @@ function baseUtils.createBase(regionMap, natives, position, surface, tick)
y = position.y, y = position.y,
created = tick, created = tick,
alignment = { BASE_ALIGNMENT_NEUTRAL }, alignment = { BASE_ALIGNMENT_NEUTRAL },
hive = nil, hives = {},
nests = {}, nests = {},
worms = {}, worms = {},
eggs = {}, eggs = {},
@@ -131,5 +138,93 @@ function baseUtils.createBase(regionMap, natives, position, surface, tick)
return base return base
end end
function baseUtils.addEnemyStructureToChunk(chunk, entity, base)
local indexChunk
local indexBase
local countChunk
if (entity.type == "unit-spawner") then
indexChunk = chunk[NEST_BASE]
if base then
indexBase = base.nests
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 baseUtils.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
indexBase = base.nests
elseif (entity.type == "turret") then
indexBase = base.worms
end
indexBase[entity.unit_number] = nil
end
chunk[countChunk] = chunk[countChunk] - 1
end
function baseUtils.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
baseUtils.addEnemyStructureToChunk(leftTop, entity, base)
end
if rightTop then
baseUtils.addEnemyStructureToChunk(rightTop, entity, base)
end
if leftBottom then
baseUtils.addEnemyStructureToChunk(leftBottom, entity, base)
end
if rightBottom then
baseUtils.addEnemyStructureToChunk(rightBottom, entity, base)
end
end
end
function baseUtils.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
baseUtils.removeEnemyStructureFromChunk(leftTop, entity)
end
if rightTop then
baseUtils.removeEnemyStructureFromChunk(rightTop, entity)
end
if leftBottom then
baseUtils.removeEnemyStructureFromChunk(leftBottom, entity)
end
if rightBottom then
baseUtils.removeEnemyStructureFromChunk(rightBottom, entity)
end
end
end
return baseUtils return baseUtils

View File

@@ -14,6 +14,8 @@ local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
local NEST_BASE = constants.NEST_BASE local NEST_BASE = constants.NEST_BASE
local WORM_BASE = constants.WORM_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 PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
@@ -30,13 +32,13 @@ local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
-- imported functions -- imported functions
local annexNest = baseUtils.annexNest local findNearbyBase = baseUtils.findNearbyBase
local createBase = baseUtils.createBase local createBase = baseUtils.createBase
local addEnemyStructureToChunk = baseUtils.addEnemyStructureToChunk
-- module code -- module code
local function checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, surface) local function checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, get_tile)
local get_tile = surface.get_tile
for x=iteratingCoordinate, iteratingCoordinate + 31 do for x=iteratingCoordinate, iteratingCoordinate + 31 do
local tile local tile
@@ -53,19 +55,20 @@ local function checkForDeadendTiles(constantCoordinate, iteratingCoordinate, dir
end end
function chunkUtils.checkChunkPassability(chunk, surface) function chunkUtils.checkChunkPassability(chunk, surface)
local x = chunk.pX local x = chunk.x
local y = chunk.pY local y = chunk.y
local get_tile = surface.get_tile
local passableNorthSouth = false local passableNorthSouth = false
local passableEastWest = false local passableEastWest = false
for xi=x, x + 31 do for xi=x, x + 31 do
if (not checkForDeadendTiles(xi, y, NORTH_SOUTH, surface)) then if (not checkForDeadendTiles(xi, y, NORTH_SOUTH, get_tile)) then
passableNorthSouth = true passableNorthSouth = true
break break
end end
end end
for yi=y, y + 31 do for yi=y, y + 31 do
if (not checkForDeadendTiles(yi, x, EAST_WEST, surface)) then if (not checkForDeadendTiles(yi, x, EAST_WEST, get_tile)) then
passableEastWest = true passableEastWest = true
break break
end end
@@ -76,77 +79,83 @@ function chunkUtils.checkChunkPassability(chunk, surface)
end end
function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tick) function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tick)
local x = chunk.pX local x = chunk.x
local y = chunk.pY local y = chunk.y
local chunkPosition = {x=x, y=y}
local areaBoundingBox = { local areaBoundingBox = {
chunkPosition, chunk,
{x + 32, y + 32} {x + 32, y + 32}
} }
local enemyChunkQuery = {area=areaBoundingBox, local enemyChunkQuery = {area=areaBoundingBox,
force="enemy"} force="enemy"}
local playerChunkQuery = {area=areaBoundingBox, local playerChunkQuery = {area=areaBoundingBox,
force="player"} force="player"}
local useCustomAI = natives.useCustomAI
local enemies = surface.find_entities_filtered(enemyChunkQuery) local enemies = surface.find_entities_filtered(enemyChunkQuery)
local nestsRemoved = 0 local nests = 0
local wormsRemoved = 0 local worms = 0
local bitersRemoved = 0 local biters = 0
for i=1, #enemies do for i=1, #enemies do
local entityType = enemies[i].type local entityType = enemies[i].type
if (entityType == "unit-spawner") then if (entityType == "unit-spawner") then
nestsRemoved = nestsRemoved + 3 nests = nests + 1
elseif (entityType == "turret") then elseif (entityType == "turret") then
wormsRemoved = wormsRemoved + 2 worms = worms + 1
elseif (entityType == "unit") then elseif useCustomAI and (entityType == "unit") then
bitersRemoved = bitersRemoved + 1 biters = biters + 1
end end
end end
entities = surface.find_entities_filtered(playerChunkQuery) if useCustomAI then
if (nests > 0) or (worms > 0) or (biters > 0) then
for f=1, #enemies do
enemies[f].destroy()
end
local foundBase = findNearbyBase(natives, chunk) or createBase(regionMap, natives, chunk, surface, tick)
if foundBase then
foundBase.upgradePoints = foundBase.upgradePoints + (nests*3) + (worms*2) + biters
end
end
else
for i=1, #enemies do
local enemy = enemies[i]
local enemyType = enemy.type
if (enemyType == "unit-spawner") or (enemyType == "turret") then
addEnemyStructureToChunk(chunk, enemy, nil)
end
end
end
local safeBuildings = natives.safeBuildings local entities = surface.find_entities_filtered(playerChunkQuery)
local playerObjects = 0
local safeBuildings = natives.safeBuildings
for i=1, #entities do for i=1, #entities do
local entity = entities[i] local entity = entities[i]
local entityType = entity.type local entityType = entity.type
if safeBuildings then if safeBuildings then
if natives.safeEntities[entityType] or natives.safeEntityName[entity.name] then if natives.safeEntities[entityType] or natives.safeEntityName[entity.name] then
entity.destructible = false entity.destructible = false
end end
end end
if (nestsRemoved > 0) or (wormsRemoved > 0) or (bitersRemoved > 0) then local entityScore = BUILDING_PHEROMONES[entityType]
for i=1, #enemies do
enemies[i].destroy()
end
local foundBase = annexNest(natives, chunkPosition) or createBase(regionMap, natives, chunkPosition, surface, tick)
if foundBase then
foundBase.upgradePoints = foundBase.upgradePoints + nestsRemoved + wormsRemoved + bitersRemoved
end
end
end
local playerObjects = 0
local entities = surface.find_entities_filtered(playerChunkQuery)
for i=1, #entities do
local entityScore = BUILDING_PHEROMONES[entities[i].type]
if (entityScore ~= nil) then if (entityScore ~= nil) then
playerObjects = playerObjects + entityScore playerObjects = playerObjects + entityScore
end end
end end
chunk[PLAYER_BASE_GENERATOR] = playerObjects chunk[PLAYER_BASE_GENERATOR] = playerObjects
end end
function chunkUtils.createChunk(topX, topY) function chunkUtils.createChunk(topX, topY)
local chunk = { local chunk = {
pX = topX, x = topX,
pY = topY, y = topY,
cX = topX * 0.03125, cX = topX * 0.03125,
cY = topY * 0.03125 cY = topY * 0.03125
} }
@@ -161,6 +170,8 @@ function chunkUtils.createChunk(topX, topY)
chunk[RALLY_TRIGGERED] = 0 chunk[RALLY_TRIGGERED] = 0
chunk[NEST_BASE] = {} chunk[NEST_BASE] = {}
chunk[WORM_BASE] = {} chunk[WORM_BASE] = {}
chunk[NEST_COUNT] = 0
chunk[WORM_COUNT] = 0
return chunk return chunk
end end

View File

@@ -17,6 +17,7 @@ constants.VERSION_19 = 19
constants.VERSION_20 = 20 constants.VERSION_20 = 20
constants.VERSION_21 = 21 constants.VERSION_21 = 21
constants.VERSION_22 = 22 constants.VERSION_22 = 22
constants.VERSION_23 = 23
-- misc -- misc
@@ -91,7 +92,7 @@ constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX = 0.40
-- pheromone amounts -- pheromone amounts
constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 500 constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 500
constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = 30 --constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = 30
constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 500 constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 500
constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 150 constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 150
@@ -120,6 +121,8 @@ constants.RETREAT_TRIGGERED = 9
constants.RALLY_TRIGGERED = 10 constants.RALLY_TRIGGERED = 10
constants.NEST_BASE = 11 constants.NEST_BASE = 11
constants.WORM_BASE = 12 constants.WORM_BASE = 12
constants.NEST_COUNT = 13
constants.WORM_COUNT = 14
-- Squad status -- Squad status
@@ -132,8 +135,8 @@ constants.SQUAD_RAIDING = 4 -- used when player stuff is close
constants.RETREAT_GRAB_RADIUS = 24 constants.RETREAT_GRAB_RADIUS = 24
constants.BASE_RALLY_CHANCE = 0.01 constants.BASE_RALLY_CHANCE = 0.02
constants.BONUS_RALLY_CHANCE = 0.01 constants.BONUS_RALLY_CHANCE = 0.06
constants.MAX_RALLY_CRIES = 2 constants.MAX_RALLY_CRIES = 2
constants.RALLY_CRY_DISTANCE = 3 constants.RALLY_CRY_DISTANCE = 3

View File

@@ -11,9 +11,6 @@ local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local NEST_BASE = constants.NEST_BASE
local WORM_BASE = constants.WORM_BASE
local DEFINES_DIRECTION_EAST = defines.direction.east local DEFINES_DIRECTION_EAST = defines.direction.east
local DEFINES_WIRE_TYPE_RED = defines.wire_type.red local DEFINES_WIRE_TYPE_RED = defines.wire_type.red
local DEFINES_WIRE_TYPE_GREEN = defines.wire_type.green local DEFINES_WIRE_TYPE_GREEN = defines.wire_type.green
@@ -26,8 +23,8 @@ local mFloor = math.floor
-- module code -- module code
local function getEntityOverlapChunks(regionMap, entity) function entityUtils.getEntityOverlapChunks(regionMap, entity)
local boundingBox = entity.prototype.selection_box; local boundingBox = entity.prototype.selection_box or entity.prototype.collision_box;
local leftTopChunk local leftTopChunk
local rightTopChunk local rightTopChunk
@@ -88,102 +85,28 @@ function entityUtils.addRemovePlayerEntity(regionMap, entity, natives, addObject
if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name == "player") then if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name == "player") then
entityValue = BUILDING_PHEROMONES[entity.type] entityValue = BUILDING_PHEROMONES[entity.type]
leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) leftTop, rightTop, leftBottom, rightBottom = entityUtils.getEntityOverlapChunks(regionMap, entity)
if not addObject then if not addObject then
if creditNatives then if creditNatives then
natives.points = natives.points + entityValue natives.points = natives.points + entityValue
end end
entityValue = -entityValue entityValue = -entityValue
end end
if (leftTop ~= nil) then if leftTop then
leftTop[PLAYER_BASE_GENERATOR] = leftTop[PLAYER_BASE_GENERATOR] + entityValue leftTop[PLAYER_BASE_GENERATOR] = leftTop[PLAYER_BASE_GENERATOR] + entityValue
end end
if (rightTop ~= nil) then if rightTop then
rightTop[PLAYER_BASE_GENERATOR] = rightTop[PLAYER_BASE_GENERATOR] + entityValue rightTop[PLAYER_BASE_GENERATOR] = rightTop[PLAYER_BASE_GENERATOR] + entityValue
end end
if (leftBottom ~= nil) then if leftBottom then
leftBottom[PLAYER_BASE_GENERATOR] = leftBottom[PLAYER_BASE_GENERATOR] + entityValue leftBottom[PLAYER_BASE_GENERATOR] = leftBottom[PLAYER_BASE_GENERATOR] + entityValue
end end
if (rightBottom ~= nil) then if rightBottom then
rightBottom[PLAYER_BASE_GENERATOR] = rightBottom[PLAYER_BASE_GENERATOR] + entityValue rightBottom[PLAYER_BASE_GENERATOR] = rightBottom[PLAYER_BASE_GENERATOR] + entityValue
end end
end end
end end
local function addBaseToChunk(chunk, entity, base)
local indexChunk
local indexBase
if (entity.type == "unit-spawner") then
indexChunk = chunk[NEST_BASE]
indexBase = base.nests
elseif (entity.type == "turret") then
indexChunk = chunk[WORM_BASE]
indexBase = base.worms
end
indexChunk[entity.unit_number] = base
indexBase[entity.unit_number] = entity
end
local function removeBaseFromChunk(chunk, entity)
local indexChunk
if (entity.type == "unit-spawner") then
indexChunk = chunk[NEST_BASE]
elseif (entity.type == "turret") then
indexChunk = chunk[WORM_BASE]
end
local base = indexChunk[entity.unit_number]
local indexBase
if base then
if (entity.type == "unit-spawner") then
indexBase = base.nests
elseif (entity.type == "turret") then
indexBase = base.worms
end
indexBase[entity.unit_number] = nil
end
end
function entityUtils.addEnemyBase(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 ~= nil) then
addBaseToChunk(leftTop, entity, base)
end
if (rightTop ~= nil) then
addBaseToChunk(rightTop, entity, base)
end
if (leftBottom ~= nil) then
addBaseToChunk(leftBottom, entity, base)
end
if (rightBottom ~= nil) then
addBaseToChunk(rightBottom, entity, base)
end
end
end
function entityUtils.removeEnemyBase(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 ~= nil) then
removeBaseFromChunk(leftTop, entity)
end
if (rightTop ~= nil) then
removeBaseFromChunk(rightTop, entity)
end
if (leftBottom ~= nil) then
removeBaseFromChunk(leftBottom, entity)
end
if (rightBottom ~= nil) then
removeBaseFromChunk(rightBottom, entity)
end
end
end
function entityUtils.makeImmortalEntity(surface, entity) function entityUtils.makeImmortalEntity(surface, entity)
local repairPosition = entity.position local repairPosition = entity.position
local repairName = entity.name local repairName = entity.name

View File

@@ -23,7 +23,8 @@ local CHUNK_SIZE = constants.CHUNK_SIZE
local PROCESS_PLAYER_BOUND = constants.PROCESS_PLAYER_BOUND local PROCESS_PLAYER_BOUND = constants.PROCESS_PLAYER_BOUND
local CHUNK_TICK = constants.CHUNK_TICK local CHUNK_TICK = constants.CHUNK_TICK
local NEST_BASE = constants.NEST_BASE local NEST_COUNT = constants.NEST_COUNT
local WORM_COUNT = constants.WORM_COUNT
local AI_MAX_POINTS = constants.AI_MAX_POINTS local AI_MAX_POINTS = constants.AI_MAX_POINTS
local AI_SQUAD_COST = constants.AI_SQUAD_COST local AI_SQUAD_COST = constants.AI_SQUAD_COST
@@ -47,6 +48,8 @@ local playerScent = pheromoneUtils.playerScent
local canAttack = aiPredicates.canAttack local canAttack = aiPredicates.canAttack
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
local mMin = math.min local mMin = math.min
local validPlayer = playerUtils.validPlayer local validPlayer = playerUtils.validPlayer
@@ -140,12 +143,11 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, evolu
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y) local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
if playerChunk then if playerChunk then
local vengence = canAttack(natives, surface) and ((#playerChunk[NEST_BASE] ~= 0) or (playerChunk[MOVEMENT_PHEROMONE] < vengenceThreshold)) local vengence = canAttack(natives, surface) and ((playerChunk[NEST_COUNT] ~= 0) or (playerChunk[WORM_COUNT] ~= 0) or (playerChunk[MOVEMENT_PHEROMONE] < vengenceThreshold))
for x=playerChunk.cX - PROCESS_PLAYER_BOUND, playerChunk.cX + PROCESS_PLAYER_BOUND do 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 for y=playerChunk.cY - PROCESS_PLAYER_BOUND, playerChunk.cY + PROCESS_PLAYER_BOUND do
local chunk = getChunkByIndex(regionMap, x, y) local chunk = getChunkByIndex(regionMap, x, y)
if chunk and (chunk[CHUNK_TICK] ~= tick) then if chunk and (chunk[CHUNK_TICK] ~= tick) then
chunk[CHUNK_TICK] = tick chunk[CHUNK_TICK] = tick
@@ -172,11 +174,11 @@ end
Passive scan to find entities that have been generated outside the factorio event system Passive scan to find entities that have been generated outside the factorio event system
--]] --]]
function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor) function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
-- local index = regionMap.scanPointer local index = regionMap.scanPointer
local chunkPosition = {x=0,y=0} local chunkBox = {false,
local chunkBox = {chunkPosition, {x=0,
{x=chunkPosition.x + CHUNK_SIZE, y=chunkPosition.y + CHUNK_SIZE}} y=0}}
local playerQuery = {area = chunkBox, local playerQuery = {area = chunkBox,
force = "player"} force = "player"}
local spawnerQuery = {area = chunkBox, local spawnerQuery = {area = chunkBox,
@@ -195,11 +197,10 @@ function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
for x=index,endIndex do for x=index,endIndex do
local chunk = processQueue[x] local chunk = processQueue[x]
chunkPosition.x = chunk.pX chunkBox[1] = chunk
chunkPosition.y = chunk.pY
chunkBox[2].x = chunk.x + CHUNK_SIZE
chunkBox[2].x = chunkPosition.x + CHUNK_SIZE chunkBox[2].y = chunk.y + CHUNK_SIZE
chunkBox[2].y = chunkPosition.y + CHUNK_SIZE
local entities = surface.find_entities_filtered(playerQuery) local entities = surface.find_entities_filtered(playerQuery)
@@ -213,7 +214,7 @@ function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
if (unitCount > 300) then if (unitCount > 300) then
for i=1,#natives.squads do for i=1,#natives.squads do
local squadGroup = natives.squads[i].group local squadGroup = natives.squads[i].group
if squadGroup.valid and (euclideanDistanceNamed(squadGroup.position, chunkPosition) < CHUNK_SIZE * 2) then if squadGroup.valid and (euclideanDistanceNamed(squadGroup.position, chunk) < CHUNK_SIZE * 2) then
closeBy = true closeBy = true
end end
end end
@@ -221,7 +222,7 @@ function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
if (unitCount > 300) and not closeBy then if (unitCount > 300) and not closeBy then
local weight = AI_UNIT_REFUND * evolution_factor local weight = AI_UNIT_REFUND * evolution_factor
local units = surface.find_enemy_units(chunkPosition, CHUNK_SIZE * 3) local units = surface.find_enemy_units(chunk, CHUNK_SIZE * 3)
for i=1,#units do for i=1,#units do
units[i].destroy() units[i].destroy()
@@ -248,7 +249,8 @@ function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
end end
end end
chunk[ENEMY_BASE_GENERATOR] = (spawners * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT) + worms chunk[NEST_COUNT] = spawners
chunk[WORM_COUNT] = worms
chunk[PLAYER_BASE_GENERATOR] = playerBaseGenerator chunk[PLAYER_BASE_GENERATOR] = playerBaseGenerator
end end

View File

@@ -49,21 +49,21 @@ function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY)
local chunkYRow1 = chunkY - 1 local chunkYRow1 = chunkY - 1
local chunkYRow3 = chunkY + 1 local chunkYRow3 = chunkY + 1
local xChunks = regionMap[chunkX-1] local xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then if xChunks then
neighbors[1] = xChunks[chunkYRow1] neighbors[1] = xChunks[chunkYRow1]
neighbors[4] = xChunks[chunkY] neighbors[4] = xChunks[chunkY]
neighbors[6] = xChunks[chunkYRow3] neighbors[6] = xChunks[chunkYRow3]
end end
xChunks = regionMap[chunkX+1] xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then if xChunks then
neighbors[3] = xChunks[chunkYRow1] neighbors[3] = xChunks[chunkYRow1]
neighbors[5] = xChunks[chunkY] neighbors[5] = xChunks[chunkY]
neighbors[8] = xChunks[chunkYRow3] neighbors[8] = xChunks[chunkYRow3]
end end
xChunks = regionMap[chunkX] xChunks = regionMap[chunkX]
if (xChunks ~= nil) then if xChunks then
neighbors[2] = xChunks[chunkYRow1] neighbors[2] = xChunks[chunkYRow1]
neighbors[7] = xChunks[chunkYRow3] neighbors[7] = xChunks[chunkYRow3]
end end
@@ -89,21 +89,21 @@ function mapUtils.getNeighborChunksWithDirection(regionMap, chunkX, chunkY)
local chunkYRow3 = chunkY + 1 local chunkYRow3 = chunkY + 1
local xChunks = regionMap[chunkX-1] local xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then if xChunks then
neighbors[1] = xChunks[chunkYRow1] neighbors[1] = xChunks[chunkYRow1]
neighbors[4] = xChunks[chunkY] neighbors[4] = xChunks[chunkY]
neighbors[6] = xChunks[chunkYRow3] neighbors[6] = xChunks[chunkYRow3]
end end
xChunks = regionMap[chunkX+1] xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then if xChunks then
neighbors[3] = xChunks[chunkYRow1] neighbors[3] = xChunks[chunkYRow1]
neighbors[5] = xChunks[chunkY] neighbors[5] = xChunks[chunkY]
neighbors[8] = xChunks[chunkYRow3] neighbors[8] = xChunks[chunkYRow3]
end end
xChunks = regionMap[chunkX] xChunks = regionMap[chunkX]
if (xChunks ~= nil) then if xChunks then
neighbors[2] = xChunks[chunkYRow1] neighbors[2] = xChunks[chunkYRow1]
neighbors[7] = xChunks[chunkYRow3] neighbors[7] = xChunks[chunkYRow3]
end end
@@ -120,18 +120,18 @@ end
function mapUtils.getCardinalChunksWithDirection(regionMap, chunkX, chunkY) function mapUtils.getCardinalChunksWithDirection(regionMap, chunkX, chunkY)
local neighbors = {false, false, false, false} local neighbors = {false, false, false, false}
local xChunks = regionMap[chunkX] local xChunks = regionMap[chunkX]
if (xChunks ~= nil) then if xChunks then
neighbors[1] = xChunks[chunkY-1] neighbors[1] = xChunks[chunkY-1]
neighbors[4] = xChunks[chunkY+1] neighbors[4] = xChunks[chunkY+1]
end end
xChunks = regionMap[chunkX-1] xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then if xChunks then
neighbors[2] = xChunks[chunkY] neighbors[2] = xChunks[chunkY]
end end
xChunks = regionMap[chunkX+1] xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then if xChunks then
neighbors[3] = xChunks[chunkY] neighbors[3] = xChunks[chunkY]
end end
return neighbors return neighbors
@@ -140,18 +140,18 @@ end
function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY) function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY)
local neighbors = {false,false,false,false} local neighbors = {false,false,false,false}
local xChunks = regionMap[chunkX] local xChunks = regionMap[chunkX]
if (xChunks ~= nil) then if xChunks then
neighbors[1] = xChunks[chunkY-1] neighbors[1] = xChunks[chunkY-1]
neighbors[4] = xChunks[chunkY+1] neighbors[4] = xChunks[chunkY+1]
end end
xChunks = regionMap[chunkX-1] xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then if xChunks then
neighbors[2] = xChunks[chunkY] neighbors[2] = xChunks[chunkY]
end end
xChunks = regionMap[chunkX+1] xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then if xChunks then
neighbors[3] = xChunks[chunkY] neighbors[3] = xChunks[chunkY]
end end
return neighbors return neighbors

View File

@@ -14,17 +14,14 @@ local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
--[[ --[[
Expects all neighbors adjacent to a chunk Expects all neighbors adjacent to a chunk
--]] --]]
function neighborUtils.scoreNeighborsWithDirection(chunk, neighborDirectionChunks, validFunction, scoreFunction, squad, surface, position, scoreSelf) function neighborUtils.scoreNeighborsWithDirection(chunk, neighborDirectionChunks, validFunction, scoreFunction, squad, surface, scoreSelf)
local highestChunk local highestChunk
local highestScore = -MAGIC_MAXIMUM_NUMBER local highestScore = -MAGIC_MAXIMUM_NUMBER
local highestDirection local highestDirection
for x=1,8 do for x=1,8 do
local neighborChunk = neighborDirectionChunks[x] local neighborChunk = neighborDirectionChunks[x]
if neighborChunk and validFunction(x, chunk, neighborChunk) then if neighborChunk and validFunction(x, chunk, neighborChunk) then
position.x = neighborChunk.pX local score = scoreFunction(squad, neighborChunk, surface)
position.y = neighborChunk.pY
local score = scoreFunction(position, squad, neighborChunk, surface)
if (score > highestScore) then if (score > highestScore) then
highestScore = score highestScore = score
highestChunk = neighborChunk highestChunk = neighborChunk
@@ -33,7 +30,7 @@ function neighborUtils.scoreNeighborsWithDirection(chunk, neighborDirectionChunk
end end
end end
if scoreSelf and scoreFunction(position, squad, chunk, surface) > highestScore then if scoreSelf and scoreFunction(squad, chunk, surface) > highestScore then
return nil, -1 return nil, -1
end end
@@ -44,15 +41,13 @@ end
--[[ --[[
Expects all neighbors adjacent to a chunk Expects all neighbors adjacent to a chunk
--]] --]]
function neighborUtils.scoreNeighbors(chunk, neighborChunks, validFunction, scoreFunction, squad, surface, position, scoreSelf) function neighborUtils.scoreNeighbors(chunk, neighborChunks, validFunction, scoreFunction, squad, surface, scoreSelf)
local highestChunk local highestChunk
local highestScore = -MAGIC_MAXIMUM_NUMBER local highestScore = -MAGIC_MAXIMUM_NUMBER
for x=1,8 do for x=1,8 do
local neighborChunk = neighborChunks[x] local neighborChunk = neighborChunks[x]
if neighborChunk and validFunction(x, chunk, neighborChunk) then if neighborChunk and validFunction(x, chunk, neighborChunk) then
position.x = neighborChunk.pX local score = scoreFunction(squad, neighborChunk, surface)
position.y = neighborChunk.pY
local score = scoreFunction(position, squad, neighborChunk, surface)
if (score > highestScore) then if (score > highestScore) then
highestScore = score highestScore = score
highestChunk = neighborChunk highestChunk = neighborChunk
@@ -60,7 +55,7 @@ function neighborUtils.scoreNeighbors(chunk, neighborChunks, validFunction, scor
end end
end end
if scoreSelf and scoreFunction(position, squad, chunk, surface) > highestScore then if scoreSelf and scoreFunction(squad, chunk, surface) > highestScore then
return nil, -1 return nil, -1
end end

View File

@@ -12,6 +12,8 @@ local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERAT
local DEFINES_GROUP_STATE_FINISHED = defines.group_state.finished local DEFINES_GROUP_STATE_FINISHED = defines.group_state.finished
local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target
local DEFINES_GROUP_STATE_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction local DEFINES_GROUP_STATE_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction
local DEFINES_COMMAND_GROUP = defines.command.group
local DEFINES_DISTRACTION_NONE = defines.distraction.none
local SQUAD_RETREATING = constants.SQUAD_RETREATING local SQUAD_RETREATING = constants.SQUAD_RETREATING
local SQUAD_GUARDING = constants.SQUAD_GUARDING local SQUAD_GUARDING = constants.SQUAD_GUARDING
@@ -42,7 +44,7 @@ function unitGroupUtils.findNearBySquad(natives, position, distance, filter)
for i=1,#squads do for i=1,#squads do
local squad = squads[i] local squad = squads[i]
local unitGroup = squad.group local unitGroup = squad.group
if unitGroup.valid and ((filter == nil) or (filter ~= nil and filter[squad.status])) then if unitGroup.valid and (not filter or (filter and filter[squad.status])) then
if (euclideanDistanceNamed(unitGroup.position, position) <= distance) then if (euclideanDistanceNamed(unitGroup.position, position) <= distance) then
return squad return squad
end end
@@ -68,12 +70,12 @@ end
function unitGroupUtils.membersToSquad(squad, members, overwriteGroup) function unitGroupUtils.membersToSquad(squad, members, overwriteGroup)
if (members ~= nil) then if (members ~= nil) then
local cmd = { type = defines.command.group, local cmd = { type = DEFINES_COMMAND_GROUP,
group = squad.group, group = squad.group,
distraction = defines.distraction.none } distraction = DEFINES_DISTRACTION_NONE }
for i=1,#members do for i=1,#members do
local member = members[i] local member = members[i]
if member.valid and (overwriteGroup or (not overwriteGroup and (member.unit_group == nil))) then if member.valid and (overwriteGroup or (not overwriteGroup and not member.unit_group)) then
member.set_command(cmd) member.set_command(cmd)
end end
end end

View File

@@ -9,6 +9,8 @@ behemoth-suicide-biter=Behemoth Suicide Biter
small-fire-spitter=Small Fire Spitter small-fire-spitter=Small Fire Spitter
biter-spawner-hive=Small Hive
[entity-description] [entity-description]
tunnel-entrance=This tunnel is used by the biters to bypass player defenses. Fill the hole using landfill. tunnel-entrance=This tunnel is used by the biters to bypass player defenses. Fill the hole using landfill.
@@ -19,6 +21,8 @@ behemoth-suicide-biter=These biters will explode at close range
small-fire-spitter=These biters will spit fire small-fire-spitter=These biters will spit fire
biter-spawner-hive=Small Hive
[mod-setting-name] [mod-setting-name]
rampant-useDumbProjectiles=Use Dumb Projectiles rampant-useDumbProjectiles=Use Dumb Projectiles
rampant-useNEUnitLaunchers=Use Natural Evolution Unit Launchers (Needs NE) rampant-useNEUnitLaunchers=Use Natural Evolution Unit Launchers (Needs NE)
@@ -38,6 +42,7 @@ rampant-attackPlayerThreshold=Player score contribution threshold
rampant-permanentNocturnal=Permanent Nocturnal Mode rampant-permanentNocturnal=Permanent Nocturnal Mode
rampant-aiPointsScaler=Difficulty Scaling rampant-aiPointsScaler=Difficulty Scaling
rampant-addWallResistanceAcid=Increase wall resistance to spitters rampant-addWallResistanceAcid=Increase wall resistance to spitters
rampant-useCustomAI=Use Custom AI
[mod-setting-description] [mod-setting-description]
rampant-useDumbProjectiles=Turns off homing projectiles for worms and spitters rampant-useDumbProjectiles=Turns off homing projectiles for worms and spitters
@@ -57,4 +62,5 @@ rampant-safeBuildings-trainStops=Make train stops safe from biters
rampant-attackPlayerThreshold=The score that a chunk must reach for it to contribute to the attack threshold. Increasing reduces player pheromone cloud impact. rampant-attackPlayerThreshold=The score that a chunk must reach for it to contribute to the attack threshold. Increasing reduces player pheromone cloud impact.
rampant-permanentNocturnal=Toggling this will cause Rampant attack waves to spawn at night. DOES NOT turn off vanilla attack groups yet. Works better with Day/Night extender mod. rampant-permanentNocturnal=Toggling this will cause Rampant attack waves to spawn at night. DOES NOT turn off vanilla attack groups yet. Works better with Day/Night extender mod.
rampant-aiPointsScaler=Between 0.0 and 5.0. This scales how many action points the ai gets per logic cycle to perform actions like making attack waves. 0.3 - very easy, 0.75 - easy, 1.0 - medium, 1.25+ - hard rampant-aiPointsScaler=Between 0.0 and 5.0. This scales how many action points the ai gets per logic cycle to perform actions like making attack waves. 0.3 - very easy, 0.75 - easy, 1.0 - medium, 1.25+ - hard
rampant-addWallResistanceAcid=Toggling this will cause a %60 acid resistance to be added to all wall entities to reduce the damage done by spitters to walls back to vanilla levels. rampant-addWallResistanceAcid=Toggling this will cause a %60 acid resistance to be added to all wall entities to reduce the damage done by spitters to walls back to vanilla levels.
rampant-useCustomAI=Having this enabled will completely remove the vanilla ai and change how biters build, produce units, and attack.

View File

@@ -77,8 +77,8 @@
(copyDirectory "prototypes" modFolder))) (copyDirectory "prototypes" modFolder)))
(define (run) (define (run)
;; (copyFiles modFolder) (copyFiles modFolder)
;; (copyFiles zipModFolder) (copyFiles zipModFolder)
(makeZip modFolder) ;;(makeZip modFolder)
) )
) )

View File

@@ -95,14 +95,14 @@ function spawner_die_animation(variation, tint)
end end
local biter_spawner_powered_tint = {r=1.0, g=1.0, b=1.0, a=1.0} local biter_spawner_powered_tint = {r=1.0, g=0, b=0, a=1.0}
data:extend({ data:extend({
{ {
type = "unit-spawner", type = "unit-spawner",
name = "biter-spawner-powered", name = "biter-spawner-hive",
icon = "__base__/graphics/icons/biter-spawner.png", icon = "__base__/graphics/icons/biter-spawner.png",
flags = {"placeable-player", "placeable-enemy", "not-repairable"}, flags = {"placeable-player", "placeable-enemy", "not-repairable"},
max_health = 350, max_health = 350,
@@ -148,8 +148,8 @@ data:extend({
} }
}, },
healing_per_tick = 0.02, healing_per_tick = 0.02,
collision_box = {{-3.2, -2.2}, {2.2, 2.2}}, collision_box = {{-6, -6}, {6, 6}},
selection_box = {{-3.5, -2.5}, {2.5, 2.5}}, selection_box = {{-6, -6}, {6, 6}},
-- in ticks per 1 pu -- in ticks per 1 pu
pollution_absorbtion_absolute = 20, pollution_absorbtion_absolute = 20,
pollution_absorbtion_proportional = 0.01, pollution_absorbtion_proportional = 0.01,

View File

@@ -172,6 +172,16 @@ data:extend({
default_value = false, default_value = false,
order = "g[modifier]-a[damage]", order = "g[modifier]-a[damage]",
per_user = false per_user = false
},
{
type = "bool-setting",
name = "rampant-useCustomAI",
description = "rampant-useCustomAI",
setting_type = 'startup',
default_value = false,
order = "h[total]-a[ai]",
per_user = false
} }
}) })

View File

@@ -3,6 +3,7 @@ local tests = {}
local constants = require("libs/Constants") local constants = require("libs/Constants")
local mathUtils = require("libs/MathUtils") local mathUtils = require("libs/MathUtils")
local chunkUtils = require("libs/ChunkUtils") local chunkUtils = require("libs/ChunkUtils")
local mapUtils = require("libs/MapUtils")
local baseUtils = require("libs/BaseUtils") local baseUtils = require("libs/BaseUtils")
function tests.pheromoneLevels() function tests.pheromoneLevels()
@@ -22,7 +23,7 @@ function tests.pheromoneLevels()
for i=1,#chunk do for i=1,#chunk do
str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i]) str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i])
end end
str = str .. " " .. "p/" .. game.surfaces[1].get_pollution({x=chunk.pX, y=chunk.pY}) str = str .. " " .. "p/" .. game.surfaces[1].get_pollution(chunk)
if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then
print("*", chunk.cX, chunk.cY, str) print("*", chunk.cX, chunk.cY, str)
else else
@@ -73,6 +74,14 @@ function tests.findNearestPlayerEnemy()
print("--") print("--")
end end
function tests.getOffsetChunk(x, y)
local playerPosition = game.players[1].position
local chunkX = math.floor(playerPosition.x * 0.03125)
local chunkY = math.floor(playerPosition.y * 0.03125)
local chunk = mapUtils.getChunkByIndex(global.regionMap, chunkX + x, chunkY + y)
print(serpent.dump(chunk))
end
function tests.aiStats() function tests.aiStats()
print(global.natives.points, game.tick, global.natives.state, global.natives.temperament, global.natives.stateTick, global.natives.temperamentTick) print(global.natives.points, game.tick, global.natives.state, global.natives.temperament, global.natives.stateTick, global.natives.temperamentTick)
end end
@@ -99,7 +108,14 @@ function tests.createEnemy(x)
local playerPosition = game.players[1].position local playerPosition = game.players[1].position
local chunkX = math.floor(playerPosition.x * 0.03125) * 32 local chunkX = math.floor(playerPosition.x * 0.03125) * 32
local chunkY = math.floor(playerPosition.y * 0.03125) * 32 local chunkY = math.floor(playerPosition.y * 0.03125) * 32
game.surfaces[1].create_entity({name=x, position={chunkX, chunkY}}) return game.surfaces[1].create_entity({name=x, position={chunkX, chunkY}})
end
function tests.registeredNest(x)
local entity = tests.createEnemy(x)
baseUtils.registerEnemyBaseStructure(global.regionMap,
entity,
nil)
end end
function tests.attackOrigin() function tests.attackOrigin()