diff --git a/README.md b/README.md index 00f52a0a..6321dec6 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,15 @@ Configure Options not in game menu: # Version History +0.15.5 - +- Tweak: Increased ai refund from 2 to 3 +- Fix: Signals, Chain Signals, and Train stops now correctly rebuild when the corresponding make safe is toggled +- Feature: Remote interfaces for adjusting wave size, thresholds, ai build points, ai state, player thresholds, and attack triggers +- Improvement: Added reactor, programmable speaker, radars, lights, and rocket silo to biter targets +- Improvement: Switched all configs to global runtime except Dumb projectiles and NE Unit Launcher Options + 0.15.4 - -- Fixed: Changed setting name from "make buildings safe from biters" to "Enable building safety." This is to clarify what the setting does. +- Fix: Changed setting name from "make buildings safe from biters" to "Enable building safety." This is to clarify what the setting does. 0.15.3 - - Improvement: Added configuration for safe buildings. This will be improved after a bug fix in factorio diff --git a/config.lua b/config.lua index ac9fa19c..5004d016 100644 --- a/config.lua +++ b/config.lua @@ -3,23 +3,13 @@ local config = {} local mathUtils = require("libs/MathUtils") local gaussianRandomRange = mathUtils.gaussianRandomRange ---[[ - Causes buildings to regenerate and become untargetable after they are destroyed by biters ---]] -config.safeBuildings = settings.startup["rampant-safeBuildings"].value -config.safeEntities = {} -config.safeEntityName = {} -config.safeEntities["curved-rail"] = settings.startup["rampant-safeBuildings-curvedRail"].value -config.safeEntities["straight-rail"] = settings.startup["rampant-safeBuildings-straightRail"].value -config.safeEntityName["big-electric-pole"] = settings.startup["rampant-safeBuildings-bigElectricPole"].value - --[[ attackWaveScaling is used to calculate the attack wave size from the evolutionFactor - default is config.attackWaveMaxSize * (evolutionFactor ^ 1.666667) + default is natives.attackWaveMaxSize * (evolutionFactor ^ 1.666667) DOES NOT affect vanilla biters waves --]] -config.attackWaveScaling = function (evolutionFactor) - local attackWaveMaxSize = settings.startup["rampant-attackWaveMaxSize"].value +config.attackWaveScaling = function (evolutionFactor, natives) + local attackWaveMaxSize = natives.attackWaveMaxSize return math.ceil(gaussianRandomRange(attackWaveMaxSize * (evolutionFactor ^ 1.66667), (attackWaveMaxSize * 0.5) * 0.333, 1, diff --git a/control.lua b/control.lua index e8fe72d8..223c8190 100644 --- a/control.lua +++ b/control.lua @@ -12,8 +12,8 @@ local aiAttack = require("libs/AIAttack") local aiBuilding = require("libs/AIBuilding") local aiPlanning = require("libs/AIPlanning") local mathUtils = require("libs/MathUtils") +local interop = require("libs/Interop") local tests = require("tests") -local config = require("config") -- constants @@ -21,7 +21,6 @@ local INTERVAL_LOGIC = constants.INTERVAL_LOGIC local INTERVAL_PROCESS = constants.INTERVAL_PROCESS local MAX_RALLY_CRIES = constants.MAX_RALLY_CRIES -local MAX_RETREATS = constants.MAX_RETREATS local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE @@ -43,8 +42,6 @@ local processPlayers = mapProcessor.processPlayers local scanMap = mapProcessor.scanMap local planning = aiPlanning.planning --- local removeScout = aiBuilding.removeScout --- local scouting = aiBuilding.scouting local rallyUnits = aiBuilding.rallyUnits @@ -60,7 +57,7 @@ local squadBeginAttack = aiAttack.squadBeginAttack local retreatUnits = aiDefense.retreatUnits local addRemoveEntity = entityUtils.addRemoveEntity -local makeImmortalEntity = entityUtils.makeImmortalEntity +--local makeImmortalEntity = entityUtils.makeImmortalEntity local roundToNearest = mathUtils.roundToNearest @@ -86,6 +83,32 @@ local function onChunkGenerated(event) end end +local function onModSettingsChange(event) + + if event and (string.sub(event.setting, 1, 7) ~= "rampant") then + return + end + + natives.safeBuildings = settings.global["rampant-safeBuildings"].value + + natives.safeEntities["curved-rail"] = settings.global["rampant-safeBuildings-curvedRail"].value + natives.safeEntities["straight-rail"] = settings.global["rampant-safeBuildings-straightRail"].value + natives.safeEntities["rail-signal"] = settings.global["rampant-safeBuildings-railSignals"].value + natives.safeEntities["rail-chain-signal"] = settings.global["rampant-safeBuildings-railChainSignals"].value + natives.safeEntities["train-stop"] = settings.global["rampant-safeBuildings-trainStops"].value + + natives.safeEntityName["big-electric-pole"] = settings.global["rampant-safeBuildings-bigElectricPole"].value + + natives.attackUsePlayer = settings.global["rampant-attackWaveGenerationUsePlayerProximity"].value + natives.attackUsePollution = settings.global["rampant-attackWaveGenerationUsePollution"].value + + natives.attackThresholdMin = settings.global["rampant-attackWaveGenerationThresholdMin"].value + natives.attackThresholdMax = settings.global["rampant-attackWaveGenerationThresholdMax"].value + natives.attackThresholdRange = natives.attackThresholdMax - natives.attackThresholdMin + natives.attackWaveMaxSize = settings.global["rampant-attackWaveMaxSize"].value + natives.attackPlayerThreshold = settings.global["rampant-attackPlayerThreshold"].value +end + local function onConfigChanged() if (global.version == nil) then @@ -171,7 +194,12 @@ local function onConfigChanged() game.surfaces[1].print("Rampant - Version 0.14.13") global.version = constants.VERSION_16 end - if (global.version < constants.VERSION_17) then + if (global.version < constants.VERSION_18) then + + natives.safeEntities = {} + natives.safeEntityName = {} + + onModSettingsChange(nil) -- clear old regionMap processing Queue -- prevents queue adding duplicate chunks @@ -182,7 +210,6 @@ local function onConfigChanged() -- 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 @@ -191,8 +218,8 @@ local function onConfigChanged() y = chunk.y * 32 }}}) end - game.surfaces[1].print("Rampant - Version 0.15.1") - global.version = constants.VERSION_17 + game.surfaces[1].print("Rampant - Version 0.15.5") + global.version = constants.VERSION_18 end end @@ -212,16 +239,12 @@ local function onTick(event) natives.rallyCries = MAX_RALLY_CRIES - natives.retreats = MAX_RETREATS - planning(natives, evolutionFactor, tick, surface) regroupSquads(natives, evolutionFactor) processPlayers(players, regionMap, surface, natives, evolutionFactor, tick) - -- scouting(regionMap, natives) - squadBeginAttack(natives, players, evolutionFactor) squadAttack(regionMap, surface, natives) end @@ -287,7 +310,7 @@ local function onDeath(event) local victoryChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y) victoryScent(victoryChunk, entity.type) end - if creditNatives and config.safeBuildings and (config.safeEntities[entity.type] or config.safeEntityName[entity.name]) then + if creditNatives and natives.safeBuildings and (natives.safeEntities[entity.type] or natives.safeEntityName[entity.name]) then -- makeImmortalEntity(surface, entity) -- patch (Needs to be removed) @@ -337,6 +360,8 @@ end script.on_init(onInit) script.on_load(onLoad) +script.on_event(defines.events.on_runtime_mod_setting_changed, + onModSettingsChange) script.on_configuration_changed(onConfigChanged) script.on_event(defines.events.on_player_built_tile, onSurfaceTileChange) @@ -352,7 +377,7 @@ script.on_event(defines.events.on_entity_died, onDeath) script.on_event(defines.events.on_tick, onTick) script.on_event(defines.events.on_chunk_generated, onChunkGenerated) -remote.add_interface("rampant", { +remote.add_interface("rampantTests", { test1 = tests.test1, test2 = tests.test2, test3 = tests.test3, @@ -363,5 +388,7 @@ remote.add_interface("rampant", { test8 = tests.test8, test9 = tests.test9, test10 = tests.test10, - test11 = tests.test11 + test11 = tests.test11 }) + +remote.add_interface("rampant", interop) diff --git a/data.lua b/data.lua index 07fb982b..4653af8c 100644 --- a/data.lua +++ b/data.lua @@ -7,4 +7,3 @@ require("prototypes/tile/fillableDirt") require("prototypes/enemies/UnitSuicideBiters") require("prototypes/enemies/UnitFireSpitters") - diff --git a/info.json b/info.json index 6439e807..990c53c2 100644 --- a/info.json +++ b/info.json @@ -1,7 +1,7 @@ { "name" : "Rampant", "factorio_version" : "0.15", - "version" : "0.15.4", + "version" : "0.15.5", "title" : "Rampant AI", "author" : "Veden", "homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445", diff --git a/libs/AIAttack.lua b/libs/AIAttack.lua index ecfe0a7a..d413a02f 100644 --- a/libs/AIAttack.lua +++ b/libs/AIAttack.lua @@ -118,7 +118,7 @@ function aiAttack.squadBeginAttack(natives, players, evolution_factor) for i=1,#squads do local squad = squads[i] if (squad.status == SQUAD_GUARDING) and squad.group.valid then - local kamikazeThreshold = calculateKamikazeThreshold(squad, evolution_factor) + local kamikazeThreshold = calculateKamikazeThreshold(squad, natives, evolution_factor) local playerNearby = playersWithinProximityToPosition(players, squad.group.position, 100) if playerNearby then diff --git a/libs/AIBuilding.lua b/libs/AIBuilding.lua index 6f146fc7..8e2d5858 100644 --- a/libs/AIBuilding.lua +++ b/libs/AIBuilding.lua @@ -27,20 +27,11 @@ local CHUNK_SIZE = constants.CHUNK_SIZE local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE -local CONFIG_USE_PLAYER_PROXIMITY = settings.startup["rampant-attackWaveGenerationUsePlayerProximity"].value -local CONFIG_USE_POLLUTION_PROXIMITY = settings.startup["rampant-attackWaveGenerationUsePollution"].value -local CONFIG_USE_THRESHOLD_MIN = settings.startup["rampant-attackWaveGenerationThresholdMin"].value -local CONFIG_USE_THRESHOLD_MAX = settings.startup["rampant-attackWaveGenerationThresholdMax"].value -local CONFIG_USE_THRESHOLD_RANGE = CONFIG_USE_THRESHOLD_MAX - CONFIG_USE_THRESHOLD_MIN - -local RETREAT_MOVEMENT_PHEROMONE_LEVEL = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL - local RALLY_CRY_DISTANCE = 3 -- imported functions local getNeighborChunks = mapUtils.getNeighborChunks -local getChunkByPosition = mapUtils.getChunkByPosition local getChunkByIndex = mapUtils.getChunkByIndex local scoreNeighbors = neighborUtils.scoreNeighbors local createSquad = unitGroupUtils.createSquad @@ -50,22 +41,23 @@ local mMax = math.max -- module code -local function attackWaveValidCandidate(chunk, surface, evolutionFactor) +local function attackWaveValidCandidate(chunk, natives, surface, evolutionFactor) local total = 0; - if CONFIG_USE_PLAYER_PROXIMITY then + if natives.attackUsePlayer then local playerPheromone = chunk[PLAYER_PHEROMONE] - if (playerPheromone > 7) then + if (playerPheromone > natives.attackPlayerThreshold) then total = total + chunk[PLAYER_PHEROMONE] end end - if CONFIG_USE_POLLUTION_PROXIMITY then + if natives.attackUsePollution then total = total + surface.get_pollution({chunk.pX, chunk.pY}) end - local delta = CONFIG_USE_THRESHOLD_RANGE * evolutionFactor + local threshold = natives.attackThresholdRange + local delta = threshold * evolutionFactor - if (total > (CONFIG_USE_THRESHOLD_MAX - delta)) then + if (total > ((threshold - delta) + natives.attackThresholdMin)) then return true else return false @@ -80,51 +72,51 @@ 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}) +-- 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 +-- 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) local cX = chunk.cX @@ -146,19 +138,19 @@ function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_fac if (cost == AI_VENGENCE_SQUAD_COST) then valid = true elseif (cost == AI_SQUAD_COST) then - valid = attackWaveValidCandidate(chunk, surface, evolution_factor) + valid = attackWaveValidCandidate(chunk, natives, surface, evolution_factor) end end if valid and (math.random() < mMax((0.25 * evolution_factor), 0.10)) then local squadPosition = {x=0, y=0} - local squadPath, squadScore = scoreNeighbors(chunk, - getNeighborChunks(regionMap, chunk.cX, chunk.cY), - validUnitGroupLocation, - scoreUnitGroupLocation, - nil, - surface, - squadPosition, - false) + local squadPath, _ = scoreNeighbors(chunk, + getNeighborChunks(regionMap, chunk.cX, chunk.cY), + validUnitGroupLocation, + scoreUnitGroupLocation, + nil, + surface, + squadPosition, + false) if (squadPath ~= nil) then squadPosition.x = squadPath.pX + HALF_CHUNK_SIZE squadPosition.y = squadPath.pY + HALF_CHUNK_SIZE @@ -169,7 +161,7 @@ function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_fac squad.rabid = true end - local scaledWaveSize = attackWaveScaling(evolution_factor) + local scaledWaveSize = attackWaveScaling(evolution_factor, natives) local foundUnits = surface.set_multi_command({ command = { type = defines.command.group, group = squad.group, distraction = defines.distraction.none }, diff --git a/libs/ChunkUtils.lua b/libs/ChunkUtils.lua index 6d4b44b4..aa0a178a 100644 --- a/libs/ChunkUtils.lua +++ b/libs/ChunkUtils.lua @@ -27,7 +27,7 @@ local CHUNK_TICK = constants.CHUNK_TICK local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED -- module code - + function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, surface) local get_tile = surface.get_tile @@ -72,17 +72,19 @@ function chunkUtils.scoreChunk(chunk, surface) local x = chunk.pX local y = chunk.pY - local areaBoundingBox = {{x, y}, - {x + 32, y + 32}} + local areaBoundingBox = { + {x, y}, + {x + 32, y + 32} + } local enemyChunkQuery = {area=areaBoundingBox, type="unit-spawner", force="enemy"} local enemyWormChunkQuery = {area=areaBoundingBox, - type="turret", - force="enemy"} + type="turret", + force="enemy"} local playerChunkQuery = {area=areaBoundingBox, force="player"} - + local entities = surface.count_entities_filtered(enemyChunkQuery) local worms = surface.count_entities_filtered(enemyWormChunkQuery) local playerObjects = 0 @@ -122,14 +124,14 @@ function chunkUtils.createChunk(topX, topY) return chunk end --- function chunkUtils.colorChunk(x, y, tileType, surface) --- local tiles = {} --- for xi=x+5, x + 27 do --- for yi=y+5, y + 27 do --- tiles[#tiles+1] = {name=tileType, position={xi, yi}} --- end --- end --- surface.set_tiles(tiles, false) --- end +function chunkUtils.colorChunk(x, y, tileType, surface) + local tiles = {} + for xi=x+5, x + 27 do + for yi=y+5, y + 27 do + tiles[#tiles+1] = {name=tileType, position={xi, yi}} + end + end + surface.set_tiles(tiles, false) +end return chunkUtils diff --git a/libs/Constants.lua b/libs/Constants.lua index b5a61cc4..4f3f395d 100644 --- a/libs/Constants.lua +++ b/libs/Constants.lua @@ -12,6 +12,7 @@ constants.VERSION_14 = 14 constants.VERSION_15 = 15 constants.VERSION_16 = 16 constants.VERSION_17 = 17 +constants.VERSION_18 = 18 -- misc @@ -39,7 +40,7 @@ constants.AI_BASE_BUILDING_COST = 500 constants.AI_TUNNEL_COST = 100 constants.AI_MAX_POINTS = 10000 -constants.AI_UNIT_REFUND = 2 +constants.AI_UNIT_REFUND = 3 constants.AI_MAX_SQUAD_COUNT = 40 constants.AI_MAX_BITER_GROUP_SIZE = 450 @@ -110,18 +111,17 @@ constants.RETREAT_GRAB_RADIUS = 24 constants.BASE_RALLY_CHANCE = 0.01 constants.BONUS_RALLY_CHANCE = 0.01 -constants.MAX_RETREATS = 7 - constants.MAX_RALLY_CRIES = 2 constants.RALLY_CRY_DISTANCE = 3 constants.GROUP_MERGE_DISTANCE = 28 - + -- player building pheromones constants.BUILDING_PHEROMONES = {} constants.BUILDING_PHEROMONES["generator"] = 8 constants.BUILDING_PHEROMONES["pump"] = 2 +constants.BUILDING_PHEROMONES["reactor"] = 16 constants.BUILDING_PHEROMONES["offshore-pump"] = 2 constants.BUILDING_PHEROMONES["transport-belt"] = 1 constants.BUILDING_PHEROMONES["accumulator"] = 10 @@ -131,7 +131,11 @@ constants.BUILDING_PHEROMONES["assembling-machine"] = 10 constants.BUILDING_PHEROMONES["roboport"] = 10 constants.BUILDING_PHEROMONES["beacon"] = 10 constants.BUILDING_PHEROMONES["furnace"] = 12 +constants.BUILDING_PHEROMONES["programmable-speaker"] = 8 constants.BUILDING_PHEROMONES["mining-drill"] = 15 +constants.BUILDING_PHEROMONES["rocket-silo"] = 18 +constants.BUILDING_PHEROMONES["lamp"] = 4 +constants.BUILDING_PHEROMONES["radar"] = 10 -- player defense pheromones @@ -146,69 +150,176 @@ constants.retreatFilter[constants.SQUAD_RETREATING] = true return constants ---[[ types - inserter - loader - - offshore-pump - accumulator - power-switch - generator - pump - boiler - solar-panel +--[[ - constant-combinator - arithmetic-combinator - decider-combinator - player-port - rocket-silo - roboport - assembling-machine - mining-drill - lab - beacon - radar + player furnace - unit-spawner - + transport-belt + fish + boiler + container + electric-pole + generator + offshore-pump + inserter + pipe + radar lamp - - land-mine - ammo-turret + pipe-to-ground + assembling-machine wall - gate - electric-turret - fluid-turret - turret - + mining-drill + projectile resource - - logistic-robot - construction-robot + turret + ammo-turret unit - player - combat-robot - - locomotive - cargo-wagon - car - + unit-spawner + tree smart-container - logistic-container - container - storage-tank - - transport-belt underground-belt + loader splitter - pipe-to-ground - electric-pole - curved-rail + car + solar-panel + locomotive + cargo-wagon + fluid-wagon + gate + player-port straight-rail + curved-rail + land-mine train-stop rail-signal rail-chain-signal - pipe -]]-- + lab + logistic-robot + construction-robot + logistic-container + rocket-silo + roboport + storage-tank + pump + market + accumulator + beacon + combat-robot + arithmetic-combinator + decider-combinator + constant-combinator + power-switch + programmable-speaker + electric-energy-interface + reactor + heat-pipe + + electric-turret + fluid-turret + + night-vision-equipment + energy-shield-equipment + battery-equipment + solar-panel-equipment + generator-equipment + active-defense-equipment + movement-bonus-equipment + roboport-equipment + belt-immunity-equipment + + tutorial + + rocket-defense + + item-with-entity-data + rail-planner + tool + blueprint + deconstruction-item + blueprint-book + selection-tool + item-with-tags + module + technology + + custom-input + sprite + font + noise-layer + gui-style + utility-constants + utility-sounds + utility-sprites + ambient-sound + character-corpse + explosion + smoke + item-entity + arrow + flying-text + corpse + entity-ghost + tile-ghost + deconstructible-tile-proxy + item-request-proxy + particle + particle-source + leaf-particle + rail-remnants + simple-entity + decorative + ammo + armor + gun + item + capsule + repair-tool + mining-tool + item-group + item-subgroup + recipe + fluid + virtual-signal + autoplace-control + map-settings + map-gen-presets + tile + optimized-decorative + simple-entity-with-force + simple-entity-with-owner + beam + fire + stream + damage-type + ammo-category + rail-category + fuel-category + recipe-category + resource-category + module-category + equipment-grid + equipment-category + build-entity-achievement + research-achievement + finish-the-game-achievement + group-attack-achievement + construct-with-robots-achievement + deconstruct-with-robots-achievement + deliver-by-robots-achievement + train-path-achievement + player-damaged-achievement + produce-achievement + produce-per-hour-achievement + dont-use-entity-in-energy-production-achievement + kill-achievement + combat-robot-count + dont-craft-manually-achievement + dont-build-entity-achievement + achievement + rocket-silo-rocket + rocket-silo-rocket-shadow + smoke-with-trigger + sticker + +--]]-- diff --git a/libs/EntityUtils.lua b/libs/EntityUtils.lua index 36ac7e13..53d8edbf 100644 --- a/libs/EntityUtils.lua +++ b/libs/EntityUtils.lua @@ -14,8 +14,6 @@ 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 - -- imported functions local getChunkByIndex = mapUtils.getChunkByIndex diff --git a/libs/Interop.lua b/libs/Interop.lua new file mode 100644 index 00000000..6de4177c --- /dev/null +++ b/libs/Interop.lua @@ -0,0 +1,65 @@ +local interop = {} + +function interop.addAIPoints(value) + global.natives.points = global.natives.points + value +end + +function interop.getAIPoints() + return global.natives.points +end + +function interop.changeState(aiState) + global.natives.state = aiState +end + +function interop.getState() + return global.natives.state +end + +function interop.getNextStateTick() + return global.natives.stateTick +end + +function interop.getMaxWaveSize() + return global.natives.attackMaxWaveSize +end + +function interop.getThresholds() + return global.natives.attackThresholdMin, global.natives.attackThresholdMax +end + +function interop.changeMaxWaveSize(waveSize) + global.natives.attackMaxWaveSize = waveSize +end + +function interop.changeThreshold(min, max) + global.natives.attackThresholdMin = min + global.natives.attackThresholdMax = max + global.natives.attackThresholdRange = max - min +end + +function interop.changePlayerThreshold(value) + global.natives.attackPlayerThreshold = value +end + +function interop.getPlayerThreshold() + return global.natives.attackPlayerThreshold +end + +function interop.changeAttackUsePollution(bool) + global.natives.attackUsePollution = bool +end + +function interop.changeAttackUsePlayer(bool) + global.natives.attackUsePlayer = bool +end + +function interop.getAttackUsePollution() + return global.natives.attackUsePollution +end + +function interop.getAttackUsePlayer() + return global.natives.attackUsePlayer +end + +return interop diff --git a/libs/MapProcessor.lua b/libs/MapProcessor.lua index 21a18a18..a2132e9b 100644 --- a/libs/MapProcessor.lua +++ b/libs/MapProcessor.lua @@ -37,7 +37,6 @@ local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES local scents = pheromoneUtils.scents local processPheromone = pheromoneUtils.processPheromone -local makeScouts = aiBuilding.makeScouts local formSquads = aiBuilding.formSquads local getChunkByIndex = mapUtils.getChunkByIndex @@ -73,18 +72,13 @@ end function mapProcessor.processMap(regionMap, surface, natives, evolution_factor) local roll = regionMap.processRoll local index = regionMap.processPointer - local scouts = false local squads = false if (index == 1) then roll = math.random() regionMap.processRoll = roll end - - if (0.05 <= roll) and (roll <= 0.10) then - scouts = true - end - + if (natives.state == AI_STATE_AGGRESSIVE) and (0.11 <= roll) and (roll <= 0.35) then squads = true end @@ -96,9 +90,6 @@ function mapProcessor.processMap(regionMap, surface, natives, evolution_factor) processPheromone(regionMap, chunk) - if scouts then - makeScouts(surface, natives, chunk, evolution_factor) - end if squads then formSquads(regionMap, surface, natives, chunk, evolution_factor, AI_SQUAD_COST) end @@ -124,15 +115,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 scouts = false local squads = false local vengenceThreshold = -(evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL) local roll = math.random() - if (0.05 <= roll) and (roll <= 0.7) then - scouts = true - end - if (natives.state == AI_STATE_AGGRESSIVE) and (0.11 <= roll) and (roll <= 0.20) then squads = true end @@ -168,9 +154,6 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, evolu processPheromone(regionMap, chunk) - if scouts then - makeScouts(surface, natives, chunk, evolution_factor) - end if squads then formSquads(regionMap, surface, natives, chunk, evolution_factor, AI_SQUAD_COST) end diff --git a/libs/MapUtils.lua b/libs/MapUtils.lua index c1b7d842..e949fca3 100644 --- a/libs/MapUtils.lua +++ b/libs/MapUtils.lua @@ -9,7 +9,6 @@ local constants = require("Constants") local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE -local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE local CHUNK_SIZE = constants.CHUNK_SIZE -- imported functions @@ -38,7 +37,6 @@ function mapUtils.positionToChunkOffset(position) return mFloor(position.x * 0.03125), mFloor(position.y * 0.03125) end - --[[ 1 2 3 \|/ @@ -121,7 +119,7 @@ end --[[ 1 | - 2- -3 + 2- -3 | 4 ]]-- @@ -187,7 +185,7 @@ end --[[ 1 | - 2- -3 + 2- -3 | 4 ]]-- diff --git a/libs/PheromoneUtils.lua b/libs/PheromoneUtils.lua index 5b2ef271..08e6f451 100644 --- a/libs/PheromoneUtils.lua +++ b/libs/PheromoneUtils.lua @@ -38,7 +38,7 @@ function pheromoneUtils.scents(chunk) if not chunk[NORTH_SOUTH_PASSABLE] and not chunk[EAST_WEST_PASSABLE] then chunk[BASE_PHEROMONE] = IMPASSABLE_TERRAIN_GENERATOR_AMOUNT; else - chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR] -- chunk[ENEMY_BASE_GENERATOR] + chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR] end end diff --git a/libs/UnitGroupUtils.lua b/libs/UnitGroupUtils.lua index 854c4d3a..24b91999 100644 --- a/libs/UnitGroupUtils.lua +++ b/libs/UnitGroupUtils.lua @@ -21,8 +21,6 @@ local NO_RETREAT_BASE_PERCENT = constants.NO_RETREAT_BASE_PERCENT local NO_RETREAT_EVOLUTION_BONUS_MAX = constants.NO_RETREAT_EVOLUTION_BONUS_MAX local NO_RETREAT_SQUAD_SIZE_BONUS_MAX = constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX -local CONFIG_ATTACK_WAVE_MAX_SIZE = settings.startup["rampant-attackWaveMaxSize"].value - local AI_MAX_BITER_GROUP_SIZE = constants.AI_MAX_BITER_GROUP_SIZE -- imported functions @@ -131,9 +129,10 @@ function unitGroupUtils.lookupSquadMovementPenalty(squad, chunkX, chunkY) return 0 end -function unitGroupUtils.calculateKamikazeThreshold(squad, evolution_factor) +function unitGroupUtils.calculateKamikazeThreshold(squad, natives, evolution_factor) + local maxSize = natives.attackWaveMaxSize local kamikazeThreshold = NO_RETREAT_BASE_PERCENT + (evolution_factor * NO_RETREAT_EVOLUTION_BONUS_MAX) - local squadSizeBonus = mLog((#squad.group.members / CONFIG_ATTACK_WAVE_MAX_SIZE) + 0.1) + 1 + local squadSizeBonus = mLog((#squad.group.members / maxSize) + 0.1) + 1 return kamikazeThreshold + (NO_RETREAT_SQUAD_SIZE_BONUS_MAX * squadSizeBonus) end @@ -192,7 +191,7 @@ function unitGroupUtils.regroupSquads(natives, evolution_factor) end end if mergedSquads and not squad.kamikaze then - local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, evolution_factor) + local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives, evolution_factor) if (math.random() < kamikazeThreshold) then squad.kamikaze = true end diff --git a/locale/en/locale.cfg b/locale/en/locale.cfg index 3a0908b1..babaf8e9 100644 --- a/locale/en/locale.cfg +++ b/locale/en/locale.cfg @@ -35,14 +35,15 @@ rampant-safeBuildings-bigElectricPole=Make big electric poles safe from biters rampant-safeBuildings-railChainSignals=Make rail chain signals safe from biters rampant-safeBuildings-railSignals=Make rail signals safe from biters rampant-safeBuildings-trainStops=Make train stops safe from biters +rampant-attackPlayerThreshold=Player score contribution threshold [mod-setting-description] rampant-useDumbProjectiles=Turns off homing projectiles for worms and spitters rampant-useNEUnitLaunchers=ONLY FOR USE WITH NATURAL EVOLUTION ENEMIES use the NE unit launchers with medium and big worms. if set to false this will still allow the dumb projectiles but without the unit spawning. A side effect of the dumb projectiles cause the units to be spawned as if two shots were fired rampant-attackWaveGenerationUsePollution=Include pollution amount for threshold on chunks with biter nests that will generate a Rampant attack wave. DOES NOT affect vanilla biters waves rampant-attackWaveGenerationUsePlayerProximity=Include player pheromones amount for threshold on chunks with biter nests that will generate a Rampant attack wave. DOES NOT affect vanilla biters waves -rampant-attackWaveGenerationThresholdMax=The score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (starting threshold @ 0.0 evolution) -rampant-attackWaveGenerationThresholdMin=The score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (ending threshold @ 100.0 evolution) +rampant-attackWaveGenerationThresholdMax=The total score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (starting threshold @ 0.0 evolution) +rampant-attackWaveGenerationThresholdMin=The total score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (ending threshold @ 100.0 evolution) rampant-attackWaveMaxSize=If you wish to change how the attack wave scales with evolution you will need to modify the config.lua in the zip file. rampant-safeBuildings=This needs to be toggle for the safe building toggles to work. Understand this can cause weird behavior due to the fact that this is a stopgap until a bug is fixed in factorio. rampant-safeBuildings-curvedRail=Make curved rails safe from biters @@ -50,4 +51,5 @@ rampant-safeBuildings-straightRail=Make straight rails safe from biters rampant-safeBuildings-bigElectricPole=Make big electric poles safe from biters rampant-safeBuildings-railChainSignals=Make rail chain signals safe from biters rampant-safeBuildings-railSignals=Make rail signals safe from biters -rampant-safeBuildings-trainStops=Make train stops safe from biters \ No newline at end of file +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. diff --git a/settings.lua b/settings.lua index 78dde71f..f90a776e 100644 --- a/settings.lua +++ b/settings.lua @@ -22,7 +22,7 @@ data:extend({ { type = "bool-setting", name = "rampant-attackWaveGenerationUsePollution", - setting_type = "startup", + setting_type = "runtime-global", default_value = true, order = "b[modifier]-a[trigger]", per_user = false @@ -31,16 +31,26 @@ data:extend({ { type = "bool-setting", name = "rampant-attackWaveGenerationUsePlayerProximity", - setting_type = "startup", + setting_type = "runtime-global", default_value = true, order = "b[modifier]-b[trigger]", per_user = false }, + { + type = "double-setting", + name = "rampant-attackPlayerThreshold", + setting_type = "runtime-global", + minimum_value = 0, + default_value = 7, + order = "c[modifier]-b[threshold]", + per_user = false + }, + { type = "double-setting", name = "rampant-attackWaveGenerationThresholdMax", - setting_type = "startup", + setting_type = "runtime-global", minimum_value = 0, default_value = 20, order = "c[modifier]-b[threshold]", @@ -50,7 +60,7 @@ data:extend({ { type = "double-setting", name = "rampant-attackWaveGenerationThresholdMin", - setting_type = "startup", + setting_type = "runtime-global", minimum_value = 0, default_value = 0, order = "c[modifier]-a[threshold]", @@ -60,9 +70,9 @@ data:extend({ { type = "int-setting", name = "rampant-attackWaveMaxSize", - setting_type = "startup", + setting_type = "runtime-global", minimum_value = 20, - maximum_value = 250, + maximum_value = 400, default_value = 150, order = "d[modifier]-a[wave]", per_user = false @@ -71,7 +81,7 @@ data:extend({ { type = "bool-setting", name = "rampant-safeBuildings", - setting_type = "startup", + setting_type = "runtime-global", default_value = false, order = "e[modifier]-a[safe]", per_user = false @@ -80,7 +90,7 @@ data:extend({ { type = "bool-setting", name = "rampant-safeBuildings-curvedRail", - setting_type = "startup", + setting_type = "runtime-global", default_value = false, order = "e[modifier]-b[safe]", per_user = false @@ -90,7 +100,7 @@ data:extend({ { type = "bool-setting", name = "rampant-safeBuildings-straightRail", - setting_type = "startup", + setting_type = "runtime-global", default_value = false, order = "e[modifier]-c[safe]", per_user = false @@ -99,7 +109,7 @@ data:extend({ { type = "bool-setting", name = "rampant-safeBuildings-bigElectricPole", - setting_type = "startup", + setting_type = "runtime-global", default_value = false, order = "e[modifier]-d[safe]", per_user = false @@ -108,7 +118,7 @@ data:extend({ { type = "bool-setting", name = "rampant-safeBuildings-railSignals", - setting_type = "startup", + setting_type = "runtime-global", default_value = false, order = "e[modifier]-e[safe]", per_user = false @@ -117,7 +127,7 @@ data:extend({ { type = "bool-setting", name = "rampant-safeBuildings-railChainSignals", - setting_type = "startup", + setting_type = "runtime-global", default_value = false, order = "e[modifier]-f[safe]", per_user = false @@ -126,7 +136,7 @@ data:extend({ { type = "bool-setting", name = "rampant-safeBuildings-trainStops", - setting_type = "startup", + setting_type = "runtime-global", default_value = false, order = "e[modifier]-g[safe]", per_user = false