diff --git a/README.md b/README.md index 9e222a1..b579f60 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ https://forums.factorio.com/viewtopic.php?f=94&t=31445 There will be a slight pause the first time this is started up due to indexing all the chunks that have been generated. MP should be working +If experiencing desyncs, after an update, please due the following: + 1) let me know + 2) Load save with Rampant enabled + 3) Save the map after Rampant has been updated + 4) Load save in step 3 Configure Options not in game menu: - Ramp up to max biter wave size @@ -50,6 +55,20 @@ Configure Options not in game menu: # Version History +0.15.10 - +- 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 +- Improvement: Switched to untargetable indestructible safe buildings +- Improvement: Changed the "ground shake" message to be displayed at a more appropriate time +- Improvement: Recycling biter groups now has a lower threshold and checks for active nearby squads before purging the clusters +- Optimization: Adjusted factorio pathfinder parameters to favor short paths for performance +- Optimization: Moved invariants out of inner loop in pheromone dispersion +- Optimization: Reduced garbage generated when doing passive map scan +- Optimization: Switched rally cries to a once per logic cycle per chunk +- Optimization: Locallized global defines in files that use them +- Optimization: Preallocating tables of falses for chunk neighbors +- Framework: Split squad regrouping and squad cleanup + 0.15.9 - - Improvement: Added bobs higher tier big electric poles to be included with make safe toggle for big electric poles - Improvement: Added logic to reconnect wires when big electric poles are made safe and get destroyed (Thanks Jeroen D Stout, https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=140#p275663) diff --git a/Upgrade.lua b/Upgrade.lua index 4275fc6..65a0c24 100644 --- a/Upgrade.lua +++ b/Upgrade.lua @@ -42,63 +42,46 @@ function upgrade.attempt(natives, regionMap) regionMap.pP = nil regionMap.pR = nil - global.version = constants.VERSION_9 + global.version = constants.VERSION_9 end if (global.version < constants.VERSION_10) then - for _,squad in pairs(natives.squads) do - squad.frenzy = false - squad.frenzyPosition = {x=0,y=0} - squad.rabid = false - end + for _,squad in pairs(natives.squads) do + squad.frenzy = false + squad.frenzyPosition = {x=0,y=0} + squad.rabid = false + end - global.version = constants.VERSION_10 + global.version = constants.VERSION_10 end if (global.version < constants.VERSION_11) then - natives.state = constants.AI_STATE_AGGRESSIVE - natives.temperament = 0 + natives.state = constants.AI_STATE_AGGRESSIVE + natives.temperament = 0 - global.version = constants.VERSION_11 + global.version = constants.VERSION_11 end if (global.version < constants.VERSION_12) then - for _,squad in pairs(natives.squads) do - squad.status = constants.SQUAD_GUARDING - squad.kamikaze = false - end + for _,squad in pairs(natives.squads) do + squad.status = constants.SQUAD_GUARDING + squad.kamikaze = false + end - -- reset ai build points due to error in earning points - natives.points = 0 + -- reset ai build points due to error in earning points + natives.points = 0 - global.version = constants.VERSION_12 - end - if (global.version < constants.VERSION_13) then - - -- used to rate limit the number of rally cries during a period of time - natives.rallyCries = MAX_RALLY_CRIES - - global.version = constants.VERSION_13 - end - if (global.version < constants.VERSION_14) then - game.map_settings.unit_group.member_disown_distance = 5 - game.map_settings.unit_group.max_member_speedup_when_behind = 1.1 - game.map_settings.unit_group.max_member_slowdown_when_ahead = 1.0 - game.map_settings.unit_group.max_group_slowdown_factor = 0.9 - - game.surfaces[1].print("Rampant - Version 0.14.11") - global.version = constants.VERSION_14 + global.version = constants.VERSION_12 end if (global.version < constants.VERSION_16) then - natives.lastShakeMessage = 0 - --remove version 14 retreat limit, it has been made redundant - natives.retreats = nil + natives.lastShakeMessage = 0 + --remove version 14 retreat limit, it has been made redundant + natives.retreats = nil - game.map_settings.unit_group.max_group_radius = 20 - - game.surfaces[1].print("Rampant - Version 0.14.13") - global.version = constants.VERSION_16 + game.surfaces[1].print("Rampant - Version 0.14.13") + global.version = constants.VERSION_16 end if (global.version < constants.VERSION_18) then - + print(global.version) + natives.safeEntities = {} natives.safeEntityName = {} @@ -106,37 +89,46 @@ function upgrade.attempt(natives, regionMap) global.version = constants.VERSION_18 end if (global.version < constants.VERSION_20) then - + natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value game.surfaces[1].print("Rampant - Version 0.15.8") global.version = constants.VERSION_20 end - if (global.version < constants.VERSION_21) then - - game.surfaces[1].print("Rampant - Version 0.15.9") - global.version = constants.VERSION_21 - end if (global.version < constants.VERSION_22) then -- been made redundant natives.rallyCries = nil - + -- switched over to tick event regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC) regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS) -- needs to be on inner logic tick loop interval natives.stateTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC) natives.temperamentTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC) - - game.map_settings.path_finder.short_request_ratio = 0.8 - game.map_settings.path_finder.short_cache_size = 25 - game.map_settings.path_finder.long_cache_size = 5 - game.map_settings.path_finder.min_steps_to_check_path_find_termination = 300 - game.map_settings.max_failed_behavior_count = 6 + --[[ + For making changes to maps that haven't had Rampant loaded and aren't starting from a brand new map + Was causing desyncs when client connected before having the below settings saved into the map + --]] + local mapSettings = game.map_settings + mapSettings.path_finder.short_request_ratio = constants.PATH_FINDER_SHORT_REQUEST_RATIO + mapSettings.path_finder.short_cache_size = constants.PATH_FINDER_SHORT_CACHE_SIZE + mapSettings.path_finder.long_cache_size = constants.PATH_FINDER_LONG_REQUEST_RATIO + mapSettings.path_finder.min_steps_to_check_path_find_termination = constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH + + mapSettings.max_failed_behavior_count = constants.MAX_FAILED_BEHAVIORS + + mapSettings.unit_group.member_disown_distance = constants.UNIT_GROUP_DISOWN_DISTANCE + mapSettings.unit_group.tick_tolerance_when_member_arrives = constants.UNIT_GROUP_TICK_TOLERANCE + + mapSettings.unit_group.max_group_radius = constants.UNIT_GROUP_MAX_RADIUS + mapSettings.unit_group.max_member_speedup_when_behind = constants.UNIT_GROUP_MAX_SPEED_UP + mapSettings.unit_group.max_member_slowdown_when_ahead = constants.UNIT_GROUP_MAX_SLOWDOWN + mapSettings.unit_group.max_group_slowdown_factor = constants.UNIT_GROUP_SLOWDOWN_FACTOR + game.surfaces[1].print("Rampant - Version 0.15.10") global.version = constants.VERSION_22 end diff --git a/control.lua b/control.lua index c5afd7e..0cc1623 100644 --- a/control.lua +++ b/control.lua @@ -53,7 +53,6 @@ local squadBeginAttack = aiAttack.squadBeginAttack local retreatUnits = aiDefense.retreatUnits --- local regenerateEntity = entityUtils.regenerateEntity local addRemoveEntity = entityUtils.addRemoveEntity local makeImmortalEntity = entityUtils.makeImmortalEntity @@ -80,7 +79,7 @@ local function onChunkGenerated(event) end local function onModSettingsChange(event) - + if event and (string.sub(event.setting, 1, 7) ~= "rampant") then return end @@ -112,6 +111,7 @@ local function onModSettingsChange(event) end local function onConfigChanged() + if upgrade.attempt(natives, regionMap) then onModSettingsChange(nil) @@ -132,7 +132,7 @@ local function onConfigChanged() area = { left_top = { x = chunk.x * 32, y = chunk.y * 32 }}}) end - end + end end local function onTick(event) @@ -142,7 +142,7 @@ local function onTick(event) local surface = game.surfaces[1] local evolutionFactor = game.forces.enemy.evolution_factor local players = game.players - + processPendingChunks(natives, regionMap, surface, pendingChunks) scanMap(regionMap, surface, natives, evolutionFactor) @@ -150,17 +150,16 @@ local function onTick(event) regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC planning(natives, evolutionFactor, tick, surface) - + cleanSquads(natives, evolutionFactor) - -- regroupSquads(natives, evolutionFactor) + regroupSquads(natives, evolutionFactor) processPlayers(players, regionMap, surface, natives, evolutionFactor, tick) - squadBeginAttack(natives, players, evolutionFactor) squadAttack(regionMap, surface, natives) end - processMap(regionMap, surface, natives, evolutionFactor) + processMap(regionMap, surface, natives, evolutionFactor) end end @@ -187,12 +186,12 @@ local function onDeath(event) local entityPosition = entity.position local deathChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y) - if (deathChunk ~= nil) then + if deathChunk then -- drop death pheromone where unit died deathScent(deathChunk) if ((event.force ~= nil) and (event.force.name == "player")) then - local evolutionFactor = game.forces.enemy.evolution_factor + local evolutionFactor = entity.force.evolution_factor local tick = event.tick if (deathChunk[MOVEMENT_PHEROMONE] < -(evolutionFactor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) then @@ -216,7 +215,6 @@ local function onDeath(event) end end - -- removeScout(entity, natives) elseif (entity.type == "unit-spawner") or (entity.type == "turret") then addRemoveEntity(regionMap, entity, natives, false, false) end @@ -226,7 +224,9 @@ local function onDeath(event) if (event.force ~= nil) and (event.force.name == "enemy") then creditNatives = true local victoryChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y) - victoryScent(victoryChunk, entity.type) + if victoryChunk 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) diff --git a/data-updates.lua b/data-updates.lua index cd54a99..b32d0e0 100644 --- a/data-updates.lua +++ b/data-updates.lua @@ -1,6 +1,7 @@ local vanillaUpdates = require("prototypes/enemies/UpdatesVanilla") local bobsUpdates = require("prototypes/enemies/UpdatesBobs") local NEUpdates = require("prototypes/enemies/UpdatesNE") +local constants = require("libs/Constants") local function bobsDetected() return data.raw["turret"]["bob-big-explosive-worm-turret"] ~= nil @@ -25,6 +26,26 @@ if settings.startup["rampant-useDumbProjectiles"].value then end end +--[[ + try to make sure new maps use the correct map settings without having to completely load the mod. + done because seeing desync issues with dynamic map-settings changes before re-saving the map. +--]] +local mapSettings = data.raw["map-settings"]["map-settings"] + +mapSettings.path_finder.short_request_ratio = constants.PATH_FINDER_SHORT_REQUEST_RATIO +mapSettings.path_finder.short_cache_size = constants.PATH_FINDER_SHORT_CACHE_SIZE +mapSettings.path_finder.long_cache_size = constants.PATH_FINDER_LONG_REQUEST_RATIO +mapSettings.path_finder.min_steps_to_check_path_find_termination = constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH + +mapSettings.max_failed_behavior_count = constants.MAX_FAILED_BEHAVIORS + +mapSettings.unit_group.member_disown_distance = constants.UNIT_GROUP_DISOWN_DISTANCE +mapSettings.unit_group.tick_tolerance_when_member_arrives = constants.UNIT_GROUP_TICK_TOLERANCE + +mapSettings.unit_group.max_group_radius = constants.UNIT_GROUP_MAX_RADIUS +mapSettings.unit_group.max_member_speedup_when_behind = constants.UNIT_GROUP_MAX_SPEED_UP +mapSettings.unit_group.max_member_slowdown_when_ahead = constants.UNIT_GROUP_MAX_SLOWDOWN +mapSettings.unit_group.max_group_slowdown_factor = constants.UNIT_GROUP_SLOWDOWN_FACTOR diff --git a/libs/AIAttack.lua b/libs/AIAttack.lua index 21ea416..9ae3dbe 100644 --- a/libs/AIAttack.lua +++ b/libs/AIAttack.lua @@ -20,6 +20,14 @@ local SQUAD_GUARDING = constants.SQUAD_GUARDING local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR +local DEFINES_GROUP_FINISHED = defines.group_state.finished +local DEFINES_GROUP_GATHERING = defines.group_state.gathering +local DEFINES_GROUP_MOVING = defines.group_state.moving +local DEFINES_GROUP_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction +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 + -- imported functions local getNeighborChunksWithDirection = mapUtils.getNeighborChunksWithDirection @@ -52,21 +60,43 @@ function aiAttack.squadAttack(regionMap, surface, natives) local squads = natives.squads local attackPosition 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 + -- 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} attackCmd = { type = defines.command.attack_area, destination = attackPosition, radius = 28, - distraction = defines.distraction.by_enemy } + distraction = DEFINES_DISTRACTION_BY_ENEMY } end for i=1,#squads do local squad = squads[i] local group = squad.group if group.valid and (squad.status == SQUAD_RAIDING) then local groupState = group.state - if (groupState == defines.group_state.finished) or (groupState == defines.group_state.gathering) or ((groupState == defines.group_state.moving) and (squad.cycles == 0)) then - local chunk = getChunkByPosition(regionMap, group.position.x, group.position.y) - if (chunk ~= nil) then + 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 attackChunk, attackDirection = scoreNeighborsWithDirection(chunk, getNeighborChunksWithDirection(regionMap, chunk.cX, chunk.cY), validLocation, @@ -78,9 +108,9 @@ function aiAttack.squadAttack(regionMap, surface, natives) addSquadMovementPenalty(squad, chunk.cX, chunk.cY) if attackChunk then if (attackChunk[PLAYER_BASE_GENERATOR] == 0) or - ((groupState == defines.group_state.finished) or (groupState == defines.group_state.gathering)) then + ((groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING)) then - positionFromDirectionAndChunk(attackDirection, squad.group.position, attackPosition) + positionFromDirectionAndChunk(attackDirection, groupPosition, attackPosition) if (#squad.group.members > 80) then squad.cycles = 6 @@ -88,24 +118,24 @@ function aiAttack.squadAttack(regionMap, surface, natives) squad.cycles = 4 end - if not squad.rabid and squad.frenzy and (euclideanDistanceNamed(squad.group.position, squad.frenzyPosition) > 100) then + if not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) > 100) then squad.frenzy = false end if squad.rabid or squad.frenzy then - attackCmd.distraction = defines.distraction.by_anything + attackCmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING else - attackCmd.distraction = defines.distraction.by_enemy + attackCmd.distraction = DEFINES_DISTRACTION_BY_ENEMY end group.set_command(attackCmd) group.start_moving() elseif not squad.frenzy and not squad.rabid and - ((groupState == defines.group_state.attacking_distraction) or (groupState == defines.group_state.attacking_target) or + ((groupState == DEFINES_GROUP_ATTACKING_DISTRACTION) or (groupState == DEFINES_GROUP_ATTACKING_TARGET) or (attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then squad.frenzy = true - squad.frenzyPosition.x = squad.group.position.x - squad.frenzyPosition.y = squad.group.position.y + squad.frenzyPosition.x = groupPosition.x + squad.frenzyPosition.y = groupPosition.y end end end diff --git a/libs/AIBuilding.lua b/libs/AIBuilding.lua index 937e17c..4469e78 100644 --- a/libs/AIBuilding.lua +++ b/libs/AIBuilding.lua @@ -6,7 +6,6 @@ local constants = require("Constants") local mapUtils = require("MapUtils") local unitGroupUtils = require("UnitGroupUtils") local neighborUtils = require("NeighborUtils") -local nocturnalUtils = require("NocturnalUtils") package.path = "../?.lua;" .. package.path local config = require("config") @@ -31,7 +30,10 @@ local CHUNK_SIZE = constants.CHUNK_SIZE local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE -local RALLY_CRY_DISTANCE = 3 +local RALLY_CRY_DISTANCE = constants.RALLY_CRY_DISTANCE + +local DEFINES_COMMAND_GROUP = defines.command.group +local DEFINES_DISTRACTION_NONE = defines.distraction.none -- imported functions @@ -41,8 +43,6 @@ local scoreNeighbors = neighborUtils.scoreNeighbors local createSquad = unitGroupUtils.createSquad local attackWaveScaling = config.attackWaveScaling -local canAttackNocturnal = nocturnalUtils.canAttack - local mMax = math.max -- module code @@ -52,7 +52,7 @@ local function attackWaveValidCandidate(chunk, natives, surface, evolutionFactor if natives.attackUsePlayer then local playerPheromone = chunk[PLAYER_PHEROMONE] - if (playerPheromone > natives.attackPlayerThreshold) then + if (playerPheromone > natives.attackPlayerThreshold) and (playerPheromone > 0) then total = total + chunk[PLAYER_PHEROMONE] end end @@ -78,52 +78,6 @@ local function validUnitGroupLocation(x, chunk, neighborChunk) return neighborChunk[NORTH_SOUTH_PASSABLE] and neighborChunk[EAST_WEST_PASSABLE] and neighborChunk[ENEMY_BASE_GENERATOR] == 0 end --- function aiBuilding.removeScout(entity, natives) --- --[[ --- local scouts = natives.scouts --- for i=1, #scouts do --- local scout = scouts[i] --- if (scout == entity) then --- tableRemove(scouts, i) --- return --- end --- end --- --]] --- end - --- function aiBuilding.makeScouts(surface, natives, chunk, evolution_factor) --- --[[ --- if (natives.points > AI_SCOUT_COST) then --- if (#global.natives.scouts < 5) and (math.random() < 0.05) then -- TODO scaled with evolution factor --- local enemy = surface.find_nearest_enemy({ position = { x = chunk.pX + HALF_CHUNK_SIZE, --- y = chunk.pY + HALF_CHUNK_SIZE }, --- max_distance = 100}) - --- if (enemy ~= nil) and enemy.valid and (enemy.type == "unit") then --- natives.points = natives.points - AI_SCOUT_COST --- global.natives.scouts[#global.natives.scouts+1] = enemy --- -- print(enemy, enemy.unit_number) --- end --- end --- end --- --]] --- end - --- function aiBuilding.scouting(regionMap, natives) --- --[[ --- local scouts = natives.scouts --- for i=1,#scouts do --- local scout = scouts[i] --- if scout.valid then --- scout.set_command({type=defines.command.attack_area, --- destination={0,0}, --- radius=32, --- distraction=defines.distraction.none}) --- end --- end --- --]] --- end - function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor, tick) if (tick - chunk[RALLY_TRIGGERED] > INTERVAL_LOGIC) then chunk[RALLY_TRIGGERED] = tick @@ -132,7 +86,7 @@ function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFact for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do local rallyChunk = getChunkByIndex(regionMap, x, y) - if (rallyChunk ~= nil) and (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then + if rallyChunk and (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST) end end @@ -171,9 +125,9 @@ function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_fac end local scaledWaveSize = attackWaveScaling(evolution_factor, natives) - local foundUnits = surface.set_multi_command({ command = { type = defines.command.group, + local foundUnits = surface.set_multi_command({ command = { type = DEFINES_COMMAND_GROUP, group = squad.group, - distraction = defines.distraction.none }, + distraction = DEFINES_DISTRACTION_NONE }, unit_count = scaledWaveSize, unit_search_distance = (CHUNK_SIZE * 3)}) if (foundUnits > 0) then diff --git a/libs/AIPlanning.lua b/libs/AIPlanning.lua index 9996ead..fc3c9ae 100644 --- a/libs/AIPlanning.lua +++ b/libs/AIPlanning.lua @@ -20,6 +20,8 @@ local AI_MIN_TEMPERAMENT_DURATION = constants.AI_MIN_TEMPERAMENT_DURATION local AI_MAX_STATE_DURATION = constants.AI_MAX_STATE_DURATION local AI_MAX_TEMPERAMENT_DURATION = constants.AI_MAX_TEMPERAMENT_DURATION +local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT + local TICKS_A_MINUTE = constants.TICKS_A_MINUTE -- imported functions @@ -38,12 +40,6 @@ function aiPlanning.planning(natives, evolution_factor, tick, surface) maxPoints = maxPoints * 0.85 end if (natives.points < maxPoints) then - --[[ check for ai points scaler being nil, potential race condition with mod config being run - discovered 0.15.8 - --]] - -- if not natives.aiPointsScaler then - -- natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value - -- end 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 @@ -64,7 +60,7 @@ function aiPlanning.planning(natives, evolution_factor, tick, surface) natives.stateTick = randomTickEvent(tick, AI_MIN_STATE_DURATION, AI_MAX_STATE_DURATION) end - if ((natives.state == AI_STATE_AGGRESSIVE) or canAttackNocturnal(natives, surface)) and (tick - natives.lastShakeMessage > TICKS_A_MINUTE * 5) and (natives.points > AI_MAX_POINTS) then + 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 natives.lastShakeMessage = tick surface.print("Rampant: The ground begins to shake") end diff --git a/libs/Constants.lua b/libs/Constants.lua index feb981a..2d2ff6b 100644 --- a/libs/Constants.lua +++ b/libs/Constants.lua @@ -154,6 +154,23 @@ constants.BUILDING_PHEROMONES["turret"] = 2.5 constants.retreatFilter = {} constants.retreatFilter[constants.SQUAD_RETREATING] = true +-- map settings tweaks + +constants.PATH_FINDER_SHORT_REQUEST_RATIO = 0.8 +constants.PATH_FINDER_SHORT_CACHE_SIZE = 25 +constants.PATH_FINDER_LONG_REQUEST_RATIO = 5 +constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH = 300 + +constants.MAX_FAILED_BEHAVIORS = 6 + +constants.UNIT_GROUP_DISOWN_DISTANCE = 5 +constants.UNIT_GROUP_TICK_TOLERANCE = 80 + +constants.UNIT_GROUP_MAX_RADIUS = 20 +constants.UNIT_GROUP_MAX_SPEED_UP = 1.1 +constants.UNIT_GROUP_MAX_SLOWDOWN = 1.0 +constants.UNIT_GROUP_SLOWDOWN_FACTOR = 0.9 + return constants --[[ diff --git a/libs/EntityUtils.lua b/libs/EntityUtils.lua index ac09abe..bd0dfea 100644 --- a/libs/EntityUtils.lua +++ b/libs/EntityUtils.lua @@ -14,7 +14,9 @@ local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT -local CHUNK_SIZE = constants.CHUNK_SIZE +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 @@ -40,7 +42,7 @@ local function getEntityOverlapChunks(regionMap, entity) local bottomXOffset local bottomYOffset - if (entity.direction == defines.direction.east) then + if (entity.direction == DEFINES_DIRECTION_EAST) then topXOffset = boundingBox.left_top.y topYOffset = boundingBox.left_top.x bottomXOffset = boundingBox.right_bottom.y @@ -140,11 +142,11 @@ function entityUtils.makeImmortalEntity(surface, entity) end elseif connectType == "red" then for _,v in pairs(neighbourGroup) do - newEntity.connect_neighbour({wire = defines.wire_type.red, target_entity = v}); + 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}); + newEntity.connect_neighbour({wire = DEFINES_WIRE_TYPE_GREEN, target_entity = v}); end end end diff --git a/libs/MapProcessor.lua b/libs/MapProcessor.lua index 1584985..25c697c 100644 --- a/libs/MapProcessor.lua +++ b/libs/MapProcessor.lua @@ -21,7 +21,6 @@ local AI_UNIT_REFUND = constants.AI_UNIT_REFUND local CHUNK_SIZE = constants.CHUNK_SIZE local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE -local AI_STATE_NOCTURNAL = constants.AI_STATE_NOCTURNAL local PROCESS_PLAYER_BOUND = constants.PROCESS_PLAYER_BOUND local CHUNK_TICK = constants.CHUNK_TICK @@ -78,16 +77,13 @@ end function mapProcessor.processMap(regionMap, surface, natives, evolution_factor) local roll = regionMap.processRoll local index = regionMap.processPointer - local squads = false if (index == 1) then roll = math.random() regionMap.processRoll = roll end - if ((natives.state == AI_STATE_AGGRESSIVE) or canAttackNocturnal(natives, surface)) and (0.11 <= roll) and (roll <= 0.35) then - squads = true - end + local squads = ((natives.state == AI_STATE_AGGRESSIVE) or canAttackNocturnal(natives, surface)) and (0.11 <= roll) and (roll <= 0.35) local processQueue = regionMap.processQueue local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue) @@ -121,13 +117,10 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, evolu -- randomize player order to ensure a single player isn't singled out local playerOrdering = nonRepeatingRandom(players) - local squads = false local vengenceThreshold = -(evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL) local roll = math.random() - if ((natives.state == AI_STATE_AGGRESSIVE) or canAttackNocturnal(natives, surface)) and (0.11 <= roll) and (roll <= 0.20) then - squads = true - end + local squads = ((natives.state == AI_STATE_AGGRESSIVE) or canAttackNocturnal(natives, surface)) and (0.11 <= roll) and (roll <= 0.20) for i=1,#playerOrdering do local player = players[playerOrdering[i]] @@ -135,7 +128,7 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, evolu local playerPosition = player.character.position local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y) - if (playerChunk ~= nil) then + if playerChunk then playerScent(playerChunk) end end @@ -146,17 +139,14 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, evolu local playerPosition = player.character.position local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y) - if (playerChunk ~= nil) then - local vengence = false - if ((playerChunk[ENEMY_BASE_GENERATOR] ~= 0) or (playerChunk[MOVEMENT_PHEROMONE] < vengenceThreshold)) and - (natives.state == AI_STATE_AGGRESSIVE or canAttackNocturnal(natives, surface)) then - vengence = true - end + if playerChunk then + local vengence = ((playerChunk[ENEMY_BASE_GENERATOR] ~= 0) or (playerChunk[MOVEMENT_PHEROMONE] < vengenceThreshold)) and + (natives.state == AI_STATE_AGGRESSIVE or canAttackNocturnal(natives, surface)) 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 ~= nil) and (chunk[CHUNK_TICK] ~= tick) then + if chunk and (chunk[CHUNK_TICK] ~= tick) then chunk[CHUNK_TICK] = tick processPheromone(regionMap, chunk) @@ -223,7 +213,7 @@ function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor) if (unitCount > 300) then for i=1,#natives.squads do local squadGroup = natives.squads[i].group - if (euclideanDistanceNamed(squadGroup.position, chunkPosition) < CHUNK_SIZE * 2) then + if squadGroup.valid and (euclideanDistanceNamed(squadGroup.position, chunkPosition) < CHUNK_SIZE * 2) then closeBy = true end end diff --git a/libs/UnitGroupUtils.lua b/libs/UnitGroupUtils.lua index 8b5dd0e..4854ba5 100644 --- a/libs/UnitGroupUtils.lua +++ b/libs/UnitGroupUtils.lua @@ -9,9 +9,9 @@ local constants = require("Constants") local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT -local GROUP_STATE_FINISHED = defines.group_state.finished -local GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target -local GROUP_STATE_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction +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_DISTRACTION = defines.group_state.attacking_distraction local SQUAD_RETREATING = constants.SQUAD_RETREATING local SQUAD_GUARDING = constants.SQUAD_GUARDING @@ -142,7 +142,7 @@ end local function isAttacking(group) local state = group.state - return (state == GROUP_STATE_ATTACKING_TARGET) or (state == GROUP_STATE_ATTACKING_DISTRACTION) + return (state == DEFINES_GROUP_STATE_ATTACKING_TARGET) or (state == DEFINES_GROUP_STATE_ATTACKING_DISTRACTION) end function unitGroupUtils.cleanSquads(natives, evolution_factor) @@ -180,7 +180,7 @@ function unitGroupUtils.cleanSquads(natives, evolution_factor) squad.frenzy = true squad.frenzyPosition.x = squadPosition.x squad.frenzyPosition.y = squadPosition.y - elseif (group.state == GROUP_STATE_FINISHED) then + elseif (group.state == DEFINES_GROUP_STATE_FINISHED) then squad.status = SQUAD_GUARDING elseif (cycles > 0) then squad.cycles = cycles - 1 diff --git a/make.rkt b/make.rkt index 5dfcf00..e91b0c1 100644 --- a/make.rkt +++ b/make.rkt @@ -5,7 +5,7 @@ (require json) (define modFolder "/home/veden/.factorio/mods/") - ;; (define zipModFolder "/data/games/factorio14.18/mods/") + (define zipModFolder "/data/games/factorio15.15/mods/") (define configuration (call-with-input-file "info.json" (lambda (port) (string->jsexpr (port->string port))))) @@ -77,7 +77,8 @@ (copyDirectory "prototypes" modFolder))) (define (run) - (copyFiles modFolder) - ;;(makeZip modFolder) + ;; (copyFiles modFolder) + ;; (copyFiles zipModFolder) + (makeZip modFolder) ) )