mirror of
https://github.com/veden/Rampant.git
synced 2024-12-26 20:54:12 +02:00
RC3 build
This commit is contained in:
parent
7e837d8529
commit
9aa81d20d4
@ -1,5 +1,5 @@
|
||||
# Rampant Tactics
|
||||
Factorio Mod - Improves the enemies tactics by using potential fields/pheromones allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses nonhoming blockable biter projectiles. Adds new Enemies (disabled by default). Can completely replace the vanilla AI. Difficulty setting in mod options menu.
|
||||
Factorio Mod - Improves the enemies tactics by using potential fields/pheromones allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses nonhoming blockable biter projectiles. Adds new Enemies (disabled by default). Difficulty setting in mod options menu.
|
||||
|
||||
# Forum Post
|
||||
|
||||
@ -35,7 +35,6 @@ Configure Options not in game menu:
|
||||
- Frenzy squads - When a unit group gets close to a player or start combat they switch to attacking everything in there path for a set radius or until there is nothing left
|
||||
- Rabid squads - Is in a permanent frenzied state as soon as the group is formed
|
||||
- Tactical Retreats - These will take place when a unit group is in a chunk that has reached a death threshold
|
||||
- Unit Group Merging - If two squads occupy roughly the same area and are doing the same task then they will merge
|
||||
- Unit Group Forming - Any chunks with spawners in it that is covered by a pollution or player clouds will form groups based on the evolution factor
|
||||
- Probing Behavior Against Defenses - unit groups will attempt to avoid chunks that are soaked in death
|
||||
- Player Hunting - Unit groups will track the player based on there emitted pheromone cloud
|
||||
|
@ -7,7 +7,9 @@ Date: 16. 4 2020
|
||||
- Integrated vanilla AI into Rampant for pollution management
|
||||
- Map processing sweep now does and forward and reverse pass
|
||||
- Better handling of death pheromone and squad coordination
|
||||
- Added support for script_raised_set_tiles
|
||||
Tweaks:
|
||||
- Reduced active raid nest contribution to AI state to 0.002
|
||||
- Changed ai credits per rocket launched to 5000
|
||||
- Refactored calculateKamikazeThreshold based on member count and current evolution
|
||||
- Reduced enemy unit lost contribution to AI state to 0.001
|
||||
|
92
control.lua
92
control.lua
@ -41,11 +41,10 @@ local INTERVAL_PASS_SCAN = constants.INTERVAL_PASS_SCAN
|
||||
local INTERVAL_NEST = constants.INTERVAL_NEST
|
||||
local INTERVAL_CLEANUP = constants.INTERVAL_CLEANUP
|
||||
local INTERVAL_MAP_STATIC_PROCESS = constants.INTERVAL_MAP_STATIC_PROCESS
|
||||
local INTERVAL_VICTORY = constants.INTERVAL_VICTORY
|
||||
|
||||
local HIVE_BUILDINGS = constants.HIVE_BUILDINGS
|
||||
|
||||
local AI_MAX_BUILDER_COUNT = constants.AI_MAX_BUILDER_COUNT
|
||||
local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT
|
||||
local AI_SQUAD_COST = constants.AI_SQUAD_COST
|
||||
local AI_SETTLER_COST = constants.AI_SETTLER_COST
|
||||
|
||||
@ -113,6 +112,8 @@ local processStaticMap = mapProcessor.processStaticMap
|
||||
|
||||
local getPlayerBaseGenerator = chunkPropertyUtils.getPlayerBaseGenerator
|
||||
|
||||
local disperseVictoryScent = pheromoneUtils.disperseVictoryScent
|
||||
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
|
||||
local entityForPassScan = chunkUtils.entityForPassScan
|
||||
@ -259,6 +260,7 @@ local function rebuildMap()
|
||||
map.chunkToPathRating = {}
|
||||
map.chunkToDeathGenerator = {}
|
||||
map.chunkToDrained = {}
|
||||
map.chunkToVictory = {}
|
||||
map.chunkToActiveNest = {}
|
||||
map.chunkToActiveRaidNest = {}
|
||||
|
||||
@ -273,6 +275,7 @@ local function rebuildMap()
|
||||
map.processActiveRaidSpawnerIterator = nil
|
||||
map.processMigrationIterator = nil
|
||||
map.processNestIterator = nil
|
||||
map.victoryScentIterator = nil
|
||||
|
||||
-- preallocating memory to be used in code, making it fast by reducing garbage generated.
|
||||
map.neighbors = {
|
||||
@ -442,8 +445,7 @@ local function rebuildMap()
|
||||
map.moveCommand = {
|
||||
type = DEFINES_COMMAND_GO_TO_LOCATION,
|
||||
destination = map.position,
|
||||
radius = 2,
|
||||
pathfind_flags = { prefer_straight_paths = true, cache = true },
|
||||
pathfind_flags = { cache = false },
|
||||
distraction = DEFINES_DISTRACTION_BY_ENEMY
|
||||
}
|
||||
|
||||
@ -539,11 +541,11 @@ local function rebuildMap()
|
||||
unit_search_distance = TRIPLE_CHUNK_SIZE }
|
||||
|
||||
map.formLocalCommand = { command = map.formLocalGroupCommand,
|
||||
unit_count = AI_MAX_BITER_GROUP_SIZE,
|
||||
unit_count = natives.attackWaveMaxSize,
|
||||
unit_search_distance = CHUNK_SIZE }
|
||||
|
||||
map.formRetreatCommand = { command = map.compoundRetreatGroupCommand,
|
||||
unit_count = AI_MAX_BITER_GROUP_SIZE,
|
||||
unit_count = natives.attackWaveMaxSize,
|
||||
unit_search_distance = CHUNK_SIZE }
|
||||
end
|
||||
|
||||
@ -597,6 +599,8 @@ local function onModSettingsChange(event)
|
||||
natives.enabledMigration = natives.expansion and settings.global["rampant-enableMigration"].value
|
||||
|
||||
upgrade.compareTable(natives, "ENEMY_VARIATIONS", settings.startup["rampant-newEnemyVariations"].value)
|
||||
upgrade.compareTable(natives, "AI_MAX_SQUAD_COUNT", settings.global["rampant-maxNumberOfSquads"].value)
|
||||
upgrade.compareTable(natives, "AI_MAX_BUILDER_COUNT", settings.global["rampant-maxNumberOfBuilders"].value)
|
||||
|
||||
return true
|
||||
end
|
||||
@ -864,7 +868,7 @@ local function onSurfaceTileChange(event)
|
||||
if (surface.index == surfaceIndex) then
|
||||
local chunks = {}
|
||||
local tiles = event.tiles
|
||||
if (event.tile.name == "landfill") or sFind(event.tile.name, "water") then
|
||||
if event.tile and ((event.tile.name == "landfill") or sFind(event.tile.name, "water")) then
|
||||
for i=1,#tiles do
|
||||
local position = tiles[i].position
|
||||
local chunk = getChunkByPosition(map, position)
|
||||
@ -889,6 +893,34 @@ local function onSurfaceTileChange(event)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
for i=1,#tiles do
|
||||
local tile = tiles[i]
|
||||
if (tile.name == "landfill") or sFind(tile.name, "water") then
|
||||
local position = tile.position
|
||||
local chunk = getChunkByPosition(map, position)
|
||||
|
||||
if (chunk ~= -1) then
|
||||
map.chunkToPassScan[chunk] = true
|
||||
else
|
||||
local x,y = positionToChunkXY(position)
|
||||
local addMe = true
|
||||
for ci=1,#chunks do
|
||||
local c = chunks[ci]
|
||||
if (c.x == x) and (c.y == y) then
|
||||
addMe = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if addMe then
|
||||
local chunkXY = {x=x,y=y}
|
||||
chunks[#chunks+1] = chunkXY
|
||||
onChunkGenerated({area = { left_top = chunkXY },
|
||||
surface = surface})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -994,11 +1026,18 @@ local function onUnitGroupCreated(event)
|
||||
local group = event.group
|
||||
local surface = group.surface
|
||||
if (surface.name == natives.activeSurface) and (group.force.name == "enemy") then
|
||||
print("fuck", event.tick, natives.squadCount, natives.squadCount > natives.AI_MAX_SQUAD_COUNT, natives.builderCount, natives.builderCount > natives.AI_MAX_BUILDER_COUNT)
|
||||
if not group.is_script_driven then
|
||||
if not natives.aiNocturnalMode then
|
||||
local settler = mRandom() < 0.25 and
|
||||
canMigrate(natives, group.surface) and
|
||||
(natives.builderCount < AI_MAX_BUILDER_COUNT)
|
||||
(natives.builderCount < natives.AI_MAX_BUILDER_COUNT)
|
||||
|
||||
if not settler and natives.squadCount > natives.AI_MAX_SQUAD_COUNT then
|
||||
group.destroy()
|
||||
natives.points = natives.points + AI_SQUAD_COST
|
||||
return
|
||||
end
|
||||
|
||||
squad = createSquad(nil, nil, group, settler)
|
||||
natives.groupNumberToSquad[group.group_number] = squad
|
||||
@ -1008,13 +1047,22 @@ local function onUnitGroupCreated(event)
|
||||
else
|
||||
natives.squadCount = natives.squadCount + 1
|
||||
end
|
||||
elseif not (surface.darkness > 0.65) then
|
||||
natives.points = natives.points + AI_SQUAD_COST
|
||||
group.destroy()
|
||||
else
|
||||
if not (surface.darkness > 0.65) then
|
||||
natives.points = natives.points + AI_SQUAD_COST
|
||||
group.destroy()
|
||||
return
|
||||
end
|
||||
|
||||
local settler = mRandom() < 0.25 and
|
||||
canMigrate(natives, group.surface) and
|
||||
(natives.builderCount < AI_MAX_BUILDER_COUNT)
|
||||
(natives.builderCount < natives.AI_MAX_BUILDER_COUNT)
|
||||
|
||||
if not settler and natives.squadCount > natives.AI_MAX_SQUAD_COUNT then
|
||||
group.destroy()
|
||||
natives.points = natives.points + AI_SQUAD_COST
|
||||
return
|
||||
end
|
||||
|
||||
squad = createSquad(nil, nil, group, settler)
|
||||
natives.groupNumberToSquad[group.group_number] = squad
|
||||
@ -1055,21 +1103,17 @@ local function onGroupFinishedGathering(event)
|
||||
if (group.surface.name == natives.activeSurface) then
|
||||
local squad = natives.groupNumberToSquad[unitNumber]
|
||||
if squad.settler then
|
||||
if (natives.builderCount < AI_MAX_BUILDER_COUNT) then
|
||||
if (natives.builderCount < natives.AI_MAX_BUILDER_COUNT) then
|
||||
squadDispatch(map, group.surface, squad, unitNumber)
|
||||
else
|
||||
-- game.players[1].teleport(group.position, game.surfaces[1])
|
||||
group.destroy()
|
||||
-- print("destroying settlers", event.tick)
|
||||
natives.points = natives.points + AI_SETTLER_COST
|
||||
end
|
||||
else
|
||||
if (natives.squadCount < AI_MAX_SQUAD_COUNT) then
|
||||
if (natives.squadCount < natives.AI_MAX_SQUAD_COUNT) then
|
||||
squadDispatch(map, group.surface, squad, unitNumber)
|
||||
else
|
||||
-- game.players[1].teleport(group.position, game.surfaces[1])
|
||||
group.destroy()
|
||||
-- print("destroying squad", event.tick)
|
||||
natives.points = natives.points + AI_SQUAD_COST
|
||||
end
|
||||
end
|
||||
@ -1157,8 +1201,6 @@ script.on_nth_tick(INTERVAL_LOGIC,
|
||||
game.forces.enemy.evolution_factor,
|
||||
tick)
|
||||
|
||||
cleanSquads(natives, map.squadIterator)
|
||||
|
||||
if natives.newEnemies then
|
||||
recycleBases(natives, tick)
|
||||
end
|
||||
@ -1185,6 +1227,11 @@ script.on_nth_tick(INTERVAL_SPAWNER,
|
||||
event.tick)
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_VICTORY,
|
||||
function (event)
|
||||
disperseVictoryScent(map)
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_SQUAD,
|
||||
function (event)
|
||||
processVengence(map,
|
||||
@ -1222,7 +1269,7 @@ script.on_event(defines.events.on_tick,
|
||||
scanPlayerMap(map, surface, tick)
|
||||
end
|
||||
|
||||
|
||||
cleanSquads(natives, map.squadIterator)
|
||||
processActiveNests(map, surface, tick)
|
||||
end)
|
||||
|
||||
@ -1237,7 +1284,8 @@ script.on_configuration_changed(onConfigChanged)
|
||||
|
||||
script.on_event(defines.events.on_resource_depleted, onResourceDepleted)
|
||||
script.on_event({defines.events.on_player_built_tile,
|
||||
defines.events.on_robot_built_tile}, onSurfaceTileChange)
|
||||
defines.events.on_robot_built_tile,
|
||||
defines.events.script_raised_set_tiles}, onSurfaceTileChange)
|
||||
|
||||
script.on_event(defines.events.on_player_used_capsule, onUsedCapsule)
|
||||
|
||||
|
@ -6,5 +6,5 @@
|
||||
"author" : "Veden",
|
||||
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",
|
||||
"description" : "Improves the enemies tactics by using potential fields/pheromones allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses blockable biter projectiles. Adds new Enemies (disabled by default). Difficulty setting in mod options menu.",
|
||||
"dependencies" : ["base >= 0.18.22", "? bobenemies", "? Natural_Evolution_Enemies >= 0.17.0", "? Clockwork", "? Orbital Ion Cannon", "? RampantArsenal", "? RampantResources", "? ArmouredBiters"]
|
||||
"dependencies" : ["base >= 0.18.26", "? bobenemies", "? Natural_Evolution_Enemies >= 0.17.0", "? Clockwork", "? Orbital Ion Cannon", "? RampantArsenal", "? RampantResources", "? ArmouredBiters"]
|
||||
}
|
||||
|
@ -23,11 +23,8 @@ local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
|
||||
local AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION
|
||||
local AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION
|
||||
|
||||
local AI_MAX_BUILDER_COUNT = constants.AI_MAX_BUILDER_COUNT
|
||||
|
||||
local AI_SQUAD_COST = constants.AI_SQUAD_COST
|
||||
local AI_SETTLER_COST = constants.AI_SETTLER_COST
|
||||
local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT
|
||||
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
|
||||
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
|
||||
|
||||
@ -189,7 +186,7 @@ end
|
||||
function aiAttackWave.formSettlers(map, surface, chunk, tick)
|
||||
|
||||
local natives = map.natives
|
||||
if (natives.builderCount < AI_MAX_BUILDER_COUNT) and
|
||||
if (natives.builderCount < natives.AI_MAX_BUILDER_COUNT) and
|
||||
(mRandom() < natives.formSquadThreshold) and
|
||||
((natives.points - AI_SETTLER_COST) > 0)
|
||||
then
|
||||
@ -247,7 +244,7 @@ end
|
||||
|
||||
function aiAttackWave.formVengenceSquad(map, surface, chunk)
|
||||
local natives = map.natives
|
||||
if (natives.squadCount < AI_MAX_SQUAD_COUNT) and
|
||||
if (natives.squadCount < natives.AI_MAX_SQUAD_COUNT) and
|
||||
(mRandom() < natives.formSquadThreshold) and
|
||||
((natives.points - AI_VENGENCE_SQUAD_COST) > 0)
|
||||
then
|
||||
@ -277,6 +274,7 @@ function aiAttackWave.formVengenceSquad(map, surface, chunk)
|
||||
if (foundUnits > 0) then
|
||||
squad.kamikaze = mRandom() < calculateKamikazeThreshold(foundUnits, natives)
|
||||
natives.groupNumberToSquad[squad.groupNumber] = squad
|
||||
natives.squadCount = natives.squadCount + 1
|
||||
natives.points = natives.points - AI_VENGENCE_SQUAD_COST
|
||||
else
|
||||
if (squad.group.valid) then
|
||||
@ -290,7 +288,7 @@ end
|
||||
|
||||
function aiAttackWave.formSquads(map, surface, chunk, tick)
|
||||
local natives = map.natives
|
||||
if (natives.squadCount < AI_MAX_SQUAD_COUNT) and
|
||||
if (natives.squadCount < natives.AI_MAX_SQUAD_COUNT) and
|
||||
attackWaveValidCandidate(chunk, natives, map) and
|
||||
(mRandom() < natives.formSquadThreshold) and
|
||||
((natives.points - AI_SQUAD_COST) > 0)
|
||||
|
@ -290,7 +290,7 @@ function aiPlanning.temperamentPlanner(natives)
|
||||
end
|
||||
|
||||
if activeRaidNests > 0 then
|
||||
local val = (0.008 * activeRaidNests)
|
||||
local val = (0.002 * activeRaidNests)
|
||||
delta = delta - val
|
||||
else
|
||||
delta = delta - 0.5
|
||||
|
@ -226,6 +226,10 @@ function chunkPropertyUtils.addDeathGenerator(map, chunk, value)
|
||||
map.chunkToDeathGenerator[chunk] = (map.chunkToDeathGenerator[chunk] or 0) + value
|
||||
end
|
||||
|
||||
function chunkPropertyUtils.addVictoryGenerator(map, chunk, value)
|
||||
map.chunkToVictory[chunk] = (map.chunkToVictory[chunk] or 0) + value
|
||||
end
|
||||
|
||||
function chunkPropertyUtils.decayDeathGenerator(map, chunk)
|
||||
local gen = map.chunkToDeathGenerator[chunk]
|
||||
if gen then
|
||||
|
@ -53,24 +53,26 @@ constants.ATTACK_QUEUE_SIZE = 18
|
||||
constants.BASE_QUEUE_SIZE = 1
|
||||
constants.PROCESS_STATIC_QUEUE_SIZE = 20
|
||||
constants.PROCESS_PLAYER_BOUND = 128
|
||||
constants.VICTORY_SCENT_BOUND = 128
|
||||
|
||||
constants.TICKS_A_SECOND = 60
|
||||
constants.TICKS_A_MINUTE = constants.TICKS_A_SECOND * 60
|
||||
|
||||
constants.CHUNK_PASS_THRESHOLD = 0.25
|
||||
|
||||
constants.INTERVAL_PLAYER_PROCESS = 63
|
||||
constants.INTERVAL_MAP_PROCESS = 5
|
||||
constants.INTERVAL_MAP_STATIC_PROCESS = 11
|
||||
constants.INTERVAL_SCAN = 19
|
||||
-- constants.INTERVAL_PLAYER_PROCESS = 63
|
||||
-- constants.INTERVAL_MAP_PROCESS = 5
|
||||
-- constants.INTERVAL_MAP_STATIC_PROCESS = 11
|
||||
-- constants.INTERVAL_SCAN = 19
|
||||
constants.INTERVAL_CHUNK_PROCESS = 23
|
||||
constants.INTERVAL_LOGIC = 59
|
||||
constants.INTERVAL_TEMPERAMENT = 121
|
||||
constants.INTERVAL_SQUAD = 14
|
||||
constants.INTERVAL_NEST = 16
|
||||
constants.INTERVAL_PASS_SCAN = 29
|
||||
constants.INTERVAL_RESQUAD = 101
|
||||
-- constants.INTERVAL_RESQUAD = 101
|
||||
constants.INTERVAL_SPAWNER = 19
|
||||
constants.INTERVAL_VICTORY = 10
|
||||
constants.INTERVAL_CLEANUP = 34
|
||||
|
||||
constants.COOLDOWN_RALLY = constants.TICKS_A_SECOND * 10
|
||||
@ -129,8 +131,6 @@ constants.RAIDING_MINIMUM_BASE_THRESHOLD = 550
|
||||
|
||||
constants.AI_UNIT_REFUND = 3
|
||||
|
||||
constants.AI_MAX_BUILDER_COUNT = 60
|
||||
constants.AI_MAX_SQUAD_COUNT = 100
|
||||
constants.AI_MAX_BITER_GROUP_SIZE = 600
|
||||
|
||||
constants.AI_SQUAD_MERGE_THRESHOLD = constants.AI_MAX_BITER_GROUP_SIZE * 0.75
|
||||
@ -139,7 +139,6 @@ constants.AI_MAX_SQUADS_PER_CYCLE = 7
|
||||
|
||||
constants.AI_STATE_PEACEFUL = 1
|
||||
constants.AI_STATE_AGGRESSIVE = 2
|
||||
-- constants.AI_STATE_NOCTURNAL = 3
|
||||
constants.AI_STATE_RAIDING = 4
|
||||
constants.AI_STATE_MIGRATING = 5
|
||||
constants.AI_STATE_SIEGE = 6
|
||||
@ -147,8 +146,6 @@ constants.AI_STATE_ONSLAUGHT = 7
|
||||
|
||||
constants.BASE_AI_STATE_DORMANT = 0
|
||||
constants.BASE_AI_STATE_ACTIVE = 1
|
||||
-- constants.BASE_AI_STATE_WORMS = 2
|
||||
-- constants.BASE_AI_STATE_NESTS = 3
|
||||
constants.BASE_AI_STATE_OVERDRIVE = 2
|
||||
constants.BASE_AI_STATE_MUTATE = 3
|
||||
|
||||
@ -158,8 +155,6 @@ constants.AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION = 3
|
||||
|
||||
constants.AI_MIN_STATE_DURATION = 7
|
||||
constants.AI_MAX_STATE_DURATION = 17
|
||||
-- constants.AI_MIN_STATE_DURATION = 0.2
|
||||
-- constants.AI_MAX_STATE_DURATION = 0.2
|
||||
|
||||
constants.AI_MIN_TEMPERAMENT_DURATION = 25
|
||||
constants.AI_MAX_TEMPERAMENT_DURATION = 32
|
||||
@ -1190,7 +1185,7 @@ if settings.startup["rampant-poisonEnemy"].value then
|
||||
majorResistances = {"poison"},
|
||||
minorWeaknesses = {"electric", "explosion", "laser"},
|
||||
attributes = {"poisonDeathCloud"},
|
||||
acceptRate = {1, 10, 0.4, 0.6},
|
||||
acceptRate = {1, 10, 0.4, 0.6},
|
||||
drops = {"greenArtifact"},
|
||||
buildSets = {
|
||||
{"biter", 1, 10}
|
||||
@ -1217,7 +1212,7 @@ if settings.startup["rampant-poisonEnemy"].value then
|
||||
acceptRate = {2, 10, 0.001, 0.0175},
|
||||
drops = {"greenArtifact"},
|
||||
buildSets = {
|
||||
{"biter-spawner", 1, 10, 0.15, 0.3},
|
||||
{"biter-spawner", 1, 10, 0.15, 0.3},
|
||||
{"turret", 1, 10, 0.8, 0.57},
|
||||
{"hive", 2, 10, 0.002, 0.02}
|
||||
}
|
||||
@ -1491,6 +1486,29 @@ constants.HIVE_BUILDINGS_TYPES = {
|
||||
"hive"
|
||||
}
|
||||
|
||||
constants.VICTORY_SCENT_MULTIPLER = {}
|
||||
for x=1,9 do
|
||||
for y=1,9 do
|
||||
local adjV
|
||||
local v
|
||||
if x <= 5 and y <= 5 then
|
||||
v = math.min(x, y)
|
||||
elseif x > 5 and y < 5 then
|
||||
v = math.min((10-x), y)
|
||||
elseif x < 5 and y > 5 then
|
||||
v = math.min(x, (10-y))
|
||||
else
|
||||
v = math.min((10-x), (10-y))
|
||||
end
|
||||
if v < 5 then
|
||||
adjV = v / 5
|
||||
else
|
||||
adjV = 1
|
||||
end
|
||||
constants.VICTORY_SCENT_MULTIPLER[#constants.VICTORY_SCENT_MULTIPLER+1] = adjV
|
||||
end
|
||||
end
|
||||
|
||||
constants.HIVE_BUILDINGS_COST = {}
|
||||
constants.HIVE_BUILDINGS_COST["trap"] = constants.BASE_WORM_UPGRADE * 0.5
|
||||
constants.HIVE_BUILDINGS_COST["turret"] = constants.BASE_WORM_UPGRADE
|
||||
|
@ -55,7 +55,7 @@ function movementUtils.addMovementPenalty(map, squad, chunk)
|
||||
if (penalty.c == chunk) then
|
||||
penalty.v = ((penaltyCount > 1) and penalty.v + 1) or penalty.v
|
||||
if (penalty.v > 2) then
|
||||
-- print("movementThreshold", #penalties, squad.group.group_number, penalty.v, squad.settlers, squad.kamikaze, squad.status)
|
||||
print("movementThreshold", #penalties, squad.group.group_number, penalty.v, squad.settlers, squad.kamikaze, squad.status)
|
||||
-- game.players[1].teleport(chunk, game.surfaces[1])
|
||||
squad.kamikaze = true
|
||||
end
|
||||
|
@ -11,6 +11,9 @@ local chunkPropertyUtils = require("ChunkPropertyUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local VICTORY_SCENT_MULTIPLER = constants.VICTORY_SCENT_MULTIPLER
|
||||
local VICTORY_SCENT_BOUND = constants.VICTORY_SCENT_BOUND
|
||||
|
||||
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
|
||||
|
||||
local CHUNK_TICK = constants.CHUNK_TICK
|
||||
@ -36,6 +39,8 @@ local DEATH_PHEROMONE_GENERATOR_AMOUNT = constants.DEATH_PHEROMONE_GENERATOR_AMO
|
||||
|
||||
-- imported functions
|
||||
|
||||
local addVictoryGenerator = chunkPropertyUtils.addVictoryGenerator
|
||||
|
||||
local getPlayersOnChunk = chunkPropertyUtils.getPlayersOnChunk
|
||||
|
||||
local getNeighborChunks = mapUtils.getNeighborChunks
|
||||
@ -52,17 +57,48 @@ local decayDeathGenerator = chunkPropertyUtils.decayDeathGenerator
|
||||
|
||||
local linearInterpolation = mathUtils.linearInterpolation
|
||||
|
||||
local getChunkByXY = mapUtils.getChunkByXY
|
||||
|
||||
local mAbs = math.abs
|
||||
|
||||
local next = next
|
||||
|
||||
-- module code
|
||||
|
||||
function pheromoneUtils.victoryScent(map, chunk, entityType)
|
||||
local value = VICTORY_SCENT[entityType]
|
||||
if value then
|
||||
addDeathGenerator(map, chunk, -value)
|
||||
addVictoryGenerator(map, chunk, value)
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.disperseVictoryScent(map)
|
||||
local iterator = map.victoryScentIterator
|
||||
local chunkToVictory = map.chunkToVictory
|
||||
|
||||
local chunk,pheromone = next(chunkToVictory, iterator)
|
||||
if chunk then
|
||||
local chunkX = chunk.x
|
||||
local chunkY = chunk.y
|
||||
local i = 1
|
||||
for x=chunkX - VICTORY_SCENT_BOUND, chunkX + VICTORY_SCENT_BOUND do
|
||||
for y = chunkY - VICTORY_SCENT_BOUND, chunkY + VICTORY_SCENT_BOUND do
|
||||
local c = getChunkByXY(map, x, y)
|
||||
if (c ~= -1) then
|
||||
addDeathGenerator(map, c, -pheromone * VICTORY_SCENT_MULTIPLER[i])
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
local newChunk = next(chunkToVictory, chunk)
|
||||
chunkToVictory[chunk] = nil
|
||||
chunk = newChunk
|
||||
end
|
||||
|
||||
map.victoryScentIterator = chunk
|
||||
end
|
||||
|
||||
function pheromoneUtils.deathScent(map, chunk)
|
||||
addDeathGenerator(map, chunk, DEATH_PHEROMONE_GENERATOR_AMOUNT)
|
||||
end
|
||||
|
@ -93,10 +93,16 @@ function aiDefense.retreatUnits(chunk, cause, map, surface, tick, radius)
|
||||
|
||||
local newSquad = findNearbyRetreatingSquad(map, exitPath)
|
||||
local created = false
|
||||
|
||||
local natives = map.natives
|
||||
|
||||
if not newSquad then
|
||||
created = true
|
||||
newSquad = createSquad(position, surface)
|
||||
if (natives.squadCount < natives.AI_MAX_SQUAD_COUNT) then
|
||||
created = true
|
||||
newSquad = createSquad(position, surface)
|
||||
else
|
||||
print("cancelling retreat")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
map.fleeCommand.from = cause
|
||||
@ -113,8 +119,7 @@ function aiDefense.retreatUnits(chunk, cause, map, surface, tick, radius)
|
||||
return
|
||||
end
|
||||
|
||||
if created then
|
||||
local natives = map.natives
|
||||
if created then
|
||||
natives.groupNumberToSquad[newSquad.groupNumber] = newSquad
|
||||
natives.squadCount = natives.squadCount + 1
|
||||
end
|
||||
|
@ -134,13 +134,10 @@ function unitGroupUtils.createSquad(position, surface, group, settlers)
|
||||
end
|
||||
|
||||
function unitGroupUtils.cleanSquads(natives, iterator)
|
||||
-- local profiler = game.create_profiler()
|
||||
local squads = natives.groupNumberToSquad
|
||||
local map = natives.map
|
||||
|
||||
local k, squad = next(squads, iterator)
|
||||
local nextK
|
||||
-- for i=1,2 do
|
||||
if not k then
|
||||
if (table_size(squads) == 0) then
|
||||
-- this is needed as the next command remembers the max length a table has been
|
||||
@ -159,53 +156,15 @@ function unitGroupUtils.cleanSquads(natives, iterator)
|
||||
else
|
||||
natives.squadCount = natives.squadCount - 1
|
||||
end
|
||||
local nextK
|
||||
nextK,squad = next(squads, k)
|
||||
squads[k] = nil
|
||||
k = nextK
|
||||
-- else
|
||||
-- game.print({"", "3b", profiler})
|
||||
-- profiler.restart()
|
||||
-- local members = group.members
|
||||
-- local memberCount = #members
|
||||
-- if (memberCount == 0) then
|
||||
-- game.print({"", "4a", profiler})
|
||||
-- profiler.restart()
|
||||
-- local deathGen = getDeathGenerator(map, squad.chunk)
|
||||
-- local penalties = squad.penalties
|
||||
-- for xc=1,mMin(#squad.penalties,5) do
|
||||
-- addDeathGenerator(map,
|
||||
-- penalties[xc].c,
|
||||
-- deathGen * DIVISOR_DEATH_TRAIL_TABLE[xc])
|
||||
-- end
|
||||
-- removeSquadFromChunk(map, squad)
|
||||
-- group.destroy()
|
||||
-- game.print({"", "4ea", profiler})
|
||||
-- profiler.restart()
|
||||
-- elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then
|
||||
-- game.print({"", "4b", profiler})
|
||||
-- profiler.restart()
|
||||
-- unitGroupUtils.recycleBiters(natives, members)
|
||||
-- removeSquadFromChunk(map, squad)
|
||||
-- group.destroy()
|
||||
-- game.print({"", "4eb", profiler})
|
||||
-- profiler.restart()
|
||||
-- end
|
||||
-- game.print({"", "3be", profiler})
|
||||
end
|
||||
end
|
||||
-- end
|
||||
map.squadIterator = k
|
||||
end
|
||||
|
||||
-- function unitGroupUtils.membersToSquad(cmd, size, members, overwriteGroup)
|
||||
-- for i=1,size do
|
||||
-- local member = members[i]
|
||||
-- if member.valid and (overwriteGroup or (not overwriteGroup and not member.unit_group)) then
|
||||
-- member.set_command(cmd)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
function unitGroupUtils.calculateKamikazeThreshold(memberCount, natives)
|
||||
local threshold = (memberCount / natives.attackWaveMaxSize) * 0.2 + (natives.evolutionLevel * 0.2)
|
||||
return threshold
|
||||
|
@ -18687,6 +18687,8 @@ rampant-useDumbProjectiles=Projectiles: Use blockable projectiles
|
||||
rampant-attackWaveGenerationThresholdMax=Attack Wave: Starting chunk attack threshold
|
||||
rampant-attackWaveGenerationThresholdMin=Attack Wave: Ending chunk attack threshold
|
||||
rampant-attackWaveMaxSize=Attack Wave: Max biter group size that can be directly formed
|
||||
rampant-maxNumberOfSquads=Attack Wave: Max number of attack groups that can be active at once
|
||||
rampant-maxNumberOfBuilders=Attack Wave: Max number of building groups that can be active at once
|
||||
rampant-safeBuildings=Safety: Enable building safety.
|
||||
rampant-safeBuildings-curvedRail=Safety: Make curved rails safe from biters
|
||||
rampant-safeBuildings-straightRail=Safety: Make straight rails safe from biters
|
||||
@ -18870,6 +18872,9 @@ rampant-enableFullMapScan=This setting causes the game map to slowly be scanned
|
||||
|
||||
rampant-suppress-surface-change-warnings=Turn off the warnings you get when you change surfaces, warnings should only appear the first time you visit a new surface.
|
||||
|
||||
rampant-maxNumberOfBuilders=If you are not using many other script mods, I recommend putting this to 60.
|
||||
rampant-maxNumberOfSquads=If you are not using many other script mods, I recommend putting this to 70.
|
||||
|
||||
[description]
|
||||
rampant-set-surface=You are setting the Rampant AI active surface to\n__1__
|
||||
rampant-error-set-surface=If you wish to change Rampants active surface run, \n/SetRampantAISurface SurfaceName\nwhere SurfaceName is the name of the surface you want to switch to.
|
||||
|
@ -39,7 +39,8 @@
|
||||
baseCreated
|
||||
hives
|
||||
traps
|
||||
utility)
|
||||
utility
|
||||
vg)
|
||||
#:transparent)
|
||||
|
||||
(struct Chunk (kamikazeScore
|
||||
@ -70,7 +71,8 @@
|
||||
baseCreated
|
||||
hives
|
||||
traps
|
||||
utility)
|
||||
utility
|
||||
vg)
|
||||
#:transparent)
|
||||
|
||||
(require threading)
|
||||
@ -83,7 +85,7 @@
|
||||
(define (stringToChunk str)
|
||||
(match-let (((list movement base player resource passable tick rating x y nest
|
||||
worms rally retreat resourceGen playerGen deathGen pollution aNe aRNe squads
|
||||
baseCreated hives traps utility) (string-split str ",")))
|
||||
baseCreated hives traps utility vg) (string-split str ",")))
|
||||
(apply Chunk
|
||||
(cons (+ (string->number base)
|
||||
(* (string->number player) 100))
|
||||
@ -103,7 +105,7 @@
|
||||
(map string->number
|
||||
(list x y movement base player resource passable tick rating nest
|
||||
worms rally retreat resourceGen playerGen deathGen pollution aNe
|
||||
aRNe squads baseCreated hives traps utility))))))))))
|
||||
aRNe squads baseCreated hives traps utility vg))))))))))
|
||||
|
||||
(define (chunk->string chunk)
|
||||
(string-append "x: " (~v (Chunk-x chunk)) "\n"
|
||||
@ -135,7 +137,8 @@
|
||||
"bC: " (~v (Chunk-baseCreated chunk)) "\n"
|
||||
"H: " (~v (Chunk-hives chunk)) "\n"
|
||||
"T: " (~v (Chunk-traps chunk)) "\n"
|
||||
"U: " (~v (Chunk-utility chunk)) "\n"))
|
||||
"U: " (~v (Chunk-utility chunk)) "\n"
|
||||
"vg: " (~v (Chunk-vg chunk)) "\n"))
|
||||
|
||||
(define (normalizeRange xs)
|
||||
(let* ((sDev (stddev xs))
|
||||
@ -176,7 +179,8 @@
|
||||
(bC (map Chunk-baseCreated chunks))
|
||||
(H (map Chunk-hives chunks))
|
||||
(T (map Chunk-traps chunks))
|
||||
(U (map Chunk-utility chunks)))
|
||||
(U (map Chunk-utility chunks))
|
||||
(vg (map Chunk-vg chunks)))
|
||||
|
||||
(ChunkRange (MinMax (apply min xs) (apply max xs))
|
||||
(MinMax (apply min ys) (apply max ys))
|
||||
@ -206,7 +210,8 @@
|
||||
(MinMax (apply min bC) (apply max bC))
|
||||
(MinMax (apply min H) (apply max H))
|
||||
(MinMax (apply min T) (apply max T))
|
||||
(MinMax (apply min U) (apply max U)))
|
||||
(MinMax (apply min U) (apply max U))
|
||||
(MinMax (apply min vg) (apply max vg)))
|
||||
))
|
||||
|
||||
(define (readState filePath)
|
||||
|
24
settings.lua
24
settings.lua
@ -42,12 +42,34 @@ data:extend({
|
||||
name = "rampant-attackWaveMaxSize",
|
||||
setting_type = "runtime-global",
|
||||
minimum_value = 20,
|
||||
maximum_value = 400,
|
||||
maximum_value = 600,
|
||||
default_value = 150,
|
||||
order = "b[modifier]-f[wave]",
|
||||
per_user = false
|
||||
},
|
||||
|
||||
{
|
||||
type = "int-setting",
|
||||
name = "rampant-maxNumberOfSquads",
|
||||
setting_type = "runtime-global",
|
||||
minimum_value = 1,
|
||||
maximum_value = 300,
|
||||
default_value = 50,
|
||||
order = "b[modifier]-f[wave]",
|
||||
per_user = false
|
||||
},
|
||||
|
||||
{
|
||||
type = "int-setting",
|
||||
name = "rampant-maxNumberOfBuilders",
|
||||
setting_type = "runtime-global",
|
||||
minimum_value = 1,
|
||||
maximum_value = 120,
|
||||
default_value = 50,
|
||||
order = "b[modifier]-f[wave]",
|
||||
per_user = false
|
||||
},
|
||||
|
||||
{
|
||||
type = "bool-setting",
|
||||
name = "rampant-permanentNocturnal",
|
||||
|
@ -435,7 +435,9 @@ function tests.exportAiState()
|
||||
alignmentCount,
|
||||
chunkPropertyUtils.getHiveCount(global.map, chunk),
|
||||
chunkPropertyUtils.getTrapCount(global.map, chunk),
|
||||
chunkPropertyUtils.getUtilityCount(global.map, chunk)}, ",") .. "\n"
|
||||
chunkPropertyUtils.getUtilityCount(global.map, chunk),
|
||||
global.map.chunkToVictory[chunk] or 0
|
||||
}, ",") .. "\n"
|
||||
end
|
||||
game.write_file("rampantState.txt", s, false)
|
||||
end
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
(define CHUNK_SIZE 32)
|
||||
|
||||
(define INVALID_CHUNK (Chunk -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
|
||||
(define INVALID_CHUNK (Chunk -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
|
||||
|
||||
(define windowX 500)
|
||||
(define windowY 0)
|
||||
@ -278,7 +278,7 @@
|
||||
|
||||
(new radio-box%
|
||||
[label "Show Layer"]
|
||||
[choices (list "movement" "base" "player" "resource" "passable" "tick" "rating" "nests" "worms" "rally" "retreat" "resourceGen" "playerGen" "deathGen" "attackScore" "settleScore" "siegeScore" "retreatScore" "kamikazeScore" "pollution" "aNe" "aRNe" "squads" "baseCreated" "hives" "traps" "utility")]
|
||||
[choices (list "movement" "base" "player" "resource" "passable" "tick" "rating" "nests" "worms" "rally" "retreat" "resourceGen" "playerGen" "deathGen" "attackScore" "settleScore" "siegeScore" "retreatScore" "kamikazeScore" "pollution" "aNe" "aRNe" "squads" "baseCreated" "hives" "traps" "utility" "vg")]
|
||||
[selection 0]
|
||||
[parent mainFrame]
|
||||
(callback (lambda (radioButton event)
|
||||
|
Loading…
Reference in New Issue
Block a user