mirror of
https://github.com/veden/Rampant.git
synced 2025-03-17 20:58:35 +02:00
see readme, base work not done
This commit is contained in:
parent
41fb7d6db4
commit
75eb3a29d4
23
README.md
23
README.md
@ -57,8 +57,29 @@ Configure Options not in game menu:
|
||||
# Version History
|
||||
|
||||
0.15.14 -
|
||||
- Improvement: Made form squads aware of orientation changes when building squads
|
||||
- Tweak: Increased pheromone output of:
|
||||
- ammo-turret 2.5 -> 10
|
||||
- wall 0.25 -> 0.5
|
||||
- electric-turret 7 -> 20
|
||||
- fluid-turret 9 -> 28
|
||||
- turret 2.5 -> 10
|
||||
- mining-drill 15 -> 35
|
||||
- Tweak: Increased attack radius of squads from 28 to 32 tiles
|
||||
- Tweak: Decreased movement(death) pheromone persistance from 0.98 to 0.9
|
||||
- Tweak: Increased impassable terrain generator pheromone amount from -30 to -0.1
|
||||
- Tweak: Reduced number of remembered past chunks for a squad from 10 to 7
|
||||
- Tweak: Increased unit group count for "ground shake" message from 11 to 14
|
||||
- Fixed: Pheromone is no longer placed on impassable chunks
|
||||
- Improvement: Removed pollution from ai attack chunk scoring, pollution travels over water and creates weird pockets groups get stuck in
|
||||
- Improvement: Made create squads aware of orientation changes when building squads
|
||||
- Improvement: Recycling unit groups that are stuck
|
||||
- Improvement: Allow movement from an impassable chunk to a all cardinals passable chunk
|
||||
- Improvement: When creating squads base pheromone or player pheromone must be present. Prevents squad spawns when they can't reach the player(s) or player(s) structures.
|
||||
- Improvement: Made retreats aware of orientation changes with retreating squads
|
||||
- Improvement: Path finding check for invalid destination before making command
|
||||
- Improvement: Added path rating to each chunk to reduce the scores on chunks that may be passable but are easy to invalidate the unit group by making a command to an invalid location(water, entity)
|
||||
- Optimization: Collapsed chunk attributes *_PASSABLE into single attribute PASSABLE
|
||||
- Optimization: Preallocated neighbors and cardinal neighbors array
|
||||
|
||||
0.15.13 -
|
||||
- Improvement: Added lamps to make safe options (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=160#p284736)
|
||||
|
@ -143,8 +143,6 @@ function upgrade.attempt(natives, regionMap)
|
||||
global.version = constants.VERSION_23
|
||||
end
|
||||
if (global.version < constants.VERSION_24) then
|
||||
|
||||
|
||||
|
||||
game.surfaces[1].print("Rampant - Version 0.15.14")
|
||||
global.version = constants.VERSION_24
|
||||
|
10
control.lua
10
control.lua
@ -98,6 +98,8 @@ local function rebuildRegionMap()
|
||||
regionMap.processQueue = {}
|
||||
regionMap.processPointer = 1
|
||||
regionMap.scanPointer = 1
|
||||
regionMap.neighbors = { nil, nil, nil, nil, nil, nil, nil, nil }
|
||||
regionMap.cardinalNeighbors = { nil, nil, nil, nil }
|
||||
|
||||
-- switched over to tick event
|
||||
regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
@ -234,13 +236,11 @@ local function onIonCannonFired(event)
|
||||
end
|
||||
local chunk = getChunkByPosition(regionMap, event.position.x, event.position.y)
|
||||
if chunk then
|
||||
local tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
rallyUnits(chunk,
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
event.tick,
|
||||
tempNeighbors)
|
||||
event.tick)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -270,13 +270,11 @@ local function onDeath(event)
|
||||
natives,
|
||||
tick)
|
||||
if (math.random() < natives.rallyThreshold) and not surface.peaceful_mode then
|
||||
local tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
rallyUnits(deathChunk,
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
tick,
|
||||
tempNeighbors)
|
||||
tick)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -19,8 +19,6 @@ local SQUAD_GUARDING = constants.SQUAD_GUARDING
|
||||
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
|
||||
local DEFINES_COMMAND_ATTACK_AREA = defines.command.attack_area
|
||||
local DEFINES_GROUP_FINISHED = defines.group_state.finished
|
||||
local DEFINES_GROUP_GATHERING = defines.group_state.gathering
|
||||
@ -63,14 +61,12 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
local squads = natives.squads
|
||||
local attackPosition
|
||||
local attackCmd
|
||||
local tempNeighbors
|
||||
|
||||
if (#squads > 0) then
|
||||
tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
attackPosition = {x=0, y=0}
|
||||
attackCmd = { type = DEFINES_COMMAND_ATTACK_AREA,
|
||||
destination = attackPosition,
|
||||
radius = 28,
|
||||
radius = 32,
|
||||
distraction = DEFINES_DISTRACTION_BY_ENEMY }
|
||||
end
|
||||
|
||||
@ -86,19 +82,18 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
local attackChunk, attackDirection = scoreNeighborsWithDirection(chunk,
|
||||
getNeighborChunks(regionMap,
|
||||
chunk.cX,
|
||||
chunk.cY,
|
||||
tempNeighbors),
|
||||
chunk.cY),
|
||||
validLocation,
|
||||
scoreAttackLocation,
|
||||
squad,
|
||||
surface,
|
||||
true)
|
||||
addSquadMovementPenalty(squad, chunk.cX, chunk.cY)
|
||||
if attackChunk then
|
||||
addSquadMovementPenalty(natives, squad, chunk.cX, chunk.cY)
|
||||
if group.valid and attackChunk then
|
||||
if (attackChunk[PLAYER_BASE_GENERATOR] == 0) or
|
||||
((groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING)) then
|
||||
|
||||
positionFromDirectionAndChunk(attackDirection, groupPosition, attackPosition, 1.25)
|
||||
|
||||
positionFromDirectionAndChunk(attackDirection, groupPosition, attackPosition, 1.35)
|
||||
|
||||
if (#squad.group.members > 80) then
|
||||
squad.cycles = 6
|
||||
@ -114,9 +109,21 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
else
|
||||
attackCmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
|
||||
end
|
||||
|
||||
group.set_command(attackCmd)
|
||||
group.start_moving()
|
||||
|
||||
if surface.can_place_entity({name="behemoth-biter", position=attackPosition}) then
|
||||
group.set_command(attackCmd)
|
||||
group.start_moving()
|
||||
else
|
||||
local newAttackPosition = surface.find_non_colliding_position("behemoth-biter", attackPosition, 5, 2)
|
||||
if newAttackPosition then
|
||||
attackPosition.x = newAttackPosition.x
|
||||
attackPosition.y = newAttackPosition.y
|
||||
group.set_command(attackCmd)
|
||||
group.start_moving()
|
||||
else
|
||||
addSquadMovementPenalty(natives, squad, attackChunk.cX, attackChunk.cY)
|
||||
end
|
||||
end
|
||||
elseif not squad.frenzy and not squad.rabid and
|
||||
((groupState == DEFINES_GROUP_ATTACKING_DISTRACTION) or (groupState == DEFINES_GROUP_ATTACKING_TARGET) or
|
||||
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then
|
||||
|
@ -22,8 +22,8 @@ local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
|
||||
local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE
|
||||
local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
|
||||
local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE
|
||||
local PASSABLE = constants.PASSABLE
|
||||
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
|
||||
local RALLY_CRY_DISTANCE = constants.RALLY_CRY_DISTANCE
|
||||
|
||||
@ -47,17 +47,25 @@ local attackWaveScaling = config.attackWaveScaling
|
||||
local function attackWaveValidCandidate(chunk, natives, surface)
|
||||
local total = 0;
|
||||
|
||||
local hasPlayerPheromone = false
|
||||
if natives.attackUsePlayer then
|
||||
local playerPheromone = chunk[PLAYER_PHEROMONE]
|
||||
if (playerPheromone > natives.attackPlayerThreshold) then
|
||||
total = total + chunk[PLAYER_PHEROMONE]
|
||||
hasPlayerPheromone = true
|
||||
elseif (playerPheromone > 0) then
|
||||
hasPlayerPheromone = true
|
||||
end
|
||||
end
|
||||
local hasBasePheromone = false
|
||||
if (chunk[BASE_PHEROMONE] > 0) then
|
||||
hasBasePheromone = true
|
||||
end
|
||||
if natives.attackUsePollution then
|
||||
total = total + surface.get_pollution(chunk)
|
||||
end
|
||||
|
||||
return total > natives.attackWaveThreshold
|
||||
return (total > natives.attackWaveThreshold) and hasBasePheromone and hasPlayerPheromone
|
||||
end
|
||||
|
||||
local function scoreUnitGroupLocation(squad, neighborChunk, surface)
|
||||
@ -65,10 +73,10 @@ local function scoreUnitGroupLocation(squad, neighborChunk, surface)
|
||||
end
|
||||
|
||||
local function validUnitGroupLocation(x, chunk, neighborChunk)
|
||||
return neighborChunk[NORTH_SOUTH_PASSABLE] and neighborChunk[EAST_WEST_PASSABLE] and (neighborChunk[NEST_COUNT] ~= 0)
|
||||
return (neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS) and (neighborChunk[NEST_COUNT] ~= 0)
|
||||
end
|
||||
|
||||
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, tick, tempNeighbors)
|
||||
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, tick)
|
||||
if (tick - chunk[RALLY_TRIGGERED] > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST) then
|
||||
chunk[RALLY_TRIGGERED] = tick
|
||||
local cX = chunk.cX
|
||||
@ -77,7 +85,7 @@ function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, tick, tempNei
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
|
||||
local rallyChunk = getChunkByIndex(regionMap, x, y)
|
||||
if rallyChunk and (rallyChunk[NEST_COUNT] ~= 0) and (x ~= cX) and (y ~= cY) then
|
||||
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST, tempNeighbors)
|
||||
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST)
|
||||
if (natives.points < AI_VENGENCE_SQUAD_COST) then
|
||||
return
|
||||
end
|
||||
@ -87,14 +95,14 @@ function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, tick, tempNei
|
||||
end
|
||||
end
|
||||
|
||||
function aiBuilding.formSquads(regionMap, surface, natives, chunk, cost, tempNeighbors)
|
||||
function aiBuilding.formSquads(regionMap, surface, natives, chunk, cost)
|
||||
local valid = ((cost == AI_VENGENCE_SQUAD_COST) or
|
||||
((cost == AI_SQUAD_COST) and attackWaveValidCandidate(chunk, natives, surface)))
|
||||
|
||||
if valid and (math.random() < natives.formSquadThreshold) then
|
||||
|
||||
local squadPath, squadDirection = scoreNeighborsWithDirection(chunk,
|
||||
getNeighborChunks(regionMap, chunk.cX, chunk.cY, tempNeighbors),
|
||||
getNeighborChunks(regionMap, chunk.cX, chunk.cY),
|
||||
validUnitGroupLocation,
|
||||
scoreUnitGroupLocation,
|
||||
nil,
|
||||
@ -103,7 +111,7 @@ function aiBuilding.formSquads(regionMap, surface, natives, chunk, cost, tempNei
|
||||
if squadPath then
|
||||
local squadPosition = positionFromDirectionAndChunk(squadDirection, chunk, {x=0,y=0}, 0.98)
|
||||
|
||||
squadPosition = surface.find_non_colliding_position("biter-spawner",
|
||||
squadPosition = surface.find_non_colliding_position("biter-spawner-hive",
|
||||
squadPosition,
|
||||
32,
|
||||
4)
|
||||
|
@ -65,12 +65,10 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
|
||||
|
||||
if performRetreat then
|
||||
chunk[RETREAT_TRIGGERED] = tick
|
||||
local tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
local exitPath,exitDirection = scoreNeighborsWithDirection(chunk,
|
||||
getNeighborChunks(regionMap,
|
||||
chunk.cX,
|
||||
chunk.cY,
|
||||
tempNeighbors),
|
||||
chunk.cY),
|
||||
validRetreatLocation,
|
||||
scoreRetreatLocation,
|
||||
nil,
|
||||
@ -78,7 +76,17 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
|
||||
false)
|
||||
if exitPath then
|
||||
local retreatPosition = positionFromDirectionAndChunk(exitDirection, position, {x=0,y=0}, 0.98)
|
||||
|
||||
|
||||
if not surface.can_place_entity({name="behemoth-biter", position=retreatPosition}) then
|
||||
local newRetreatPosition = surface.find_non_colliding_position("behemoth-biter", retreatPosition, 5, 2)
|
||||
if newRetreatPosition then
|
||||
retreatPosition.x = newRetreatPosition.x
|
||||
retreatPosition.y = newRetreatPosition.y
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- in order for units in a group attacking to retreat, we have to create a new group and give the command to join
|
||||
-- to each unit, this is the only way I have found to have snappy mid battle retreats even after 0.14.4
|
||||
|
||||
@ -99,7 +107,7 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
|
||||
newSquad.rabid = true
|
||||
end
|
||||
end
|
||||
addSquadMovementPenalty(newSquad, chunk.cX, chunk.cY)
|
||||
addSquadMovementPenalty(natives, newSquad, chunk.cX, chunk.cY)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -49,7 +49,7 @@ local function isShockwaveReady(evolution_factor, natives, surface, tick, maxPoi
|
||||
(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))
|
||||
(#natives.squads > AI_MAX_SQUAD_COUNT * 0.45))
|
||||
end
|
||||
|
||||
function aiPlanning.planning(natives, evolution_factor, tick, surface)
|
||||
|
@ -23,14 +23,12 @@ function baseProcessor.processBases(regionMap, surface, natives, tick)
|
||||
local baseIndex = natives.baseIndex
|
||||
local bases = natives.bases
|
||||
|
||||
local tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
|
||||
local endIndex = mMin(baseIndex+BASE_QUEUE_SIZE, #bases)
|
||||
for index = baseIndex, endIndex do
|
||||
local base = bases[index]
|
||||
|
||||
buildOrder(regionMap, natives, base, surface, tick)
|
||||
advanceTendrils(regionMap, base, surface, tempNeighbors)
|
||||
advanceTendrils(regionMap, base, surface, tick)
|
||||
end
|
||||
|
||||
if (endIndex == #bases) then
|
||||
|
@ -23,11 +23,13 @@ local WORM_COUNT = constants.WORM_COUNT
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
local RESOURCE_GENERATOR = constants.RESOURCE_GENERATOR
|
||||
|
||||
local NORTH_SOUTH = constants.NORTH_SOUTH
|
||||
local EAST_WEST = constants.EAST_WEST
|
||||
local CHUNK_NORTH_SOUTH = constants.CHUNK_NORTH_SOUTH
|
||||
local CHUNK_EAST_WEST = constants.CHUNK_EAST_WEST
|
||||
|
||||
local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE
|
||||
local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
local CHUNK_IMPASSABLE = constants.CHUNK_IMPASSABLE
|
||||
|
||||
local CHUNK_TICK = constants.CHUNK_TICK
|
||||
|
||||
@ -48,7 +50,7 @@ local function checkForDeadendTiles(constantCoordinate, iteratingCoordinate, dir
|
||||
local tile
|
||||
|
||||
for x=iteratingCoordinate, iteratingCoordinate + 31 do
|
||||
if (direction == NORTH_SOUTH) then
|
||||
if (direction == CHUNK_NORTH_SOUTH) then
|
||||
tile = get_tile(constantCoordinate, x)
|
||||
else
|
||||
tile = get_tile(x, constantCoordinate)
|
||||
@ -80,37 +82,33 @@ function chunkUtils.checkChunkPassability(chunk, surface)
|
||||
local passableNorthSouth = false
|
||||
local passableEastWest = false
|
||||
for xi=x, x + 31 do
|
||||
if not checkForDeadendTiles(xi, y, NORTH_SOUTH, get_tile) then
|
||||
if not checkForDeadendTiles(xi, y, CHUNK_NORTH_SOUTH, get_tile) then
|
||||
passableNorthSouth = true
|
||||
break
|
||||
end
|
||||
end
|
||||
for yi=y, y + 31 do
|
||||
if not checkForDeadendTiles(yi, x, EAST_WEST, get_tile) then
|
||||
if not checkForDeadendTiles(yi, x, CHUNK_EAST_WEST, get_tile) then
|
||||
passableEastWest = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if passableEastWest or passableNorthSouth then
|
||||
if (checkForValidTiles(x, y, get_tile) < 0.6) then
|
||||
passableEastWest = false
|
||||
passableNorthSouth = false
|
||||
|
||||
local pass = CHUNK_IMPASSABLE
|
||||
if passableEastWest and passableNorthSouth then
|
||||
pass = CHUNK_ALL_DIRECTIONS
|
||||
elseif passableEastWest then
|
||||
pass = CHUNK_EAST_WEST
|
||||
elseif passableNorthSouth then
|
||||
pass = CHUNK_NORTH_SOUTH
|
||||
end
|
||||
if (pass ~= CHUNK_IMPASSABLE) then
|
||||
chunk[PATH_RATING] = checkForValidTiles(x, y, get_tile)
|
||||
if (chunk[PATH_RATING] < 0.6) then
|
||||
pass = CHUNK_IMPASSABLE
|
||||
end
|
||||
end
|
||||
|
||||
-- if passableEastWest or passableNorthSouth then
|
||||
-- chunk[PATH_RATING] = checkForValidTiles(x, y, get_tile)
|
||||
-- end
|
||||
chunk[PATH_RATING] = checkForValidTiles(x, y, get_tile)
|
||||
if (chunk[PATH_RATING] < 0.99) then
|
||||
chunk[EAST_WEST_PASSABLE] = false
|
||||
chunk[NORTH_SOUTH_PASSABLE] = false
|
||||
else
|
||||
chunk[EAST_WEST_PASSABLE] = true
|
||||
chunk[NORTH_SOUTH_PASSABLE] = true
|
||||
end
|
||||
-- chunk[EAST_WEST_PASSABLE] = passableEastWest
|
||||
-- chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth
|
||||
chunk[PASSABLE] = pass
|
||||
end
|
||||
|
||||
function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tick, tempQuery)
|
||||
@ -201,8 +199,8 @@ function chunkUtils.createChunk(topX, topY)
|
||||
chunk[PLAYER_PHEROMONE] = 0
|
||||
chunk[RESOURCE_PHEROMONE] = 0
|
||||
chunk[PLAYER_BASE_GENERATOR] = 0
|
||||
chunk[NORTH_SOUTH_PASSABLE] = false
|
||||
chunk[EAST_WEST_PASSABLE] = false
|
||||
chunk[RESOURCE_GENERATOR] = 0
|
||||
chunk[PASSABLE] = 0
|
||||
chunk[CHUNK_TICK] = 0
|
||||
chunk[RETREAT_TRIGGERED] = 0
|
||||
chunk[RALLY_TRIGGERED] = 0
|
||||
|
@ -39,8 +39,10 @@ constants.TRIPLE_CHUNK_SIZE = constants.CHUNK_SIZE * 3
|
||||
constants.HALF_CHUNK_SIZE = constants.CHUNK_SIZE / 2
|
||||
constants.QUARTER_CHUNK_SIZE = constants.HALF_CHUNK_SIZE / 2
|
||||
|
||||
constants.NORTH_SOUTH = 1
|
||||
constants.EAST_WEST = 2
|
||||
constants.CHUNK_IMPASSABLE = 0
|
||||
constants.CHUNK_NORTH_SOUTH = 1
|
||||
constants.CHUNK_EAST_WEST = 2
|
||||
constants.CHUNK_ALL_DIRECTIONS = 3
|
||||
|
||||
-- ai
|
||||
|
||||
@ -93,15 +95,14 @@ constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX = 0.40
|
||||
-- pheromone amounts
|
||||
|
||||
constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 500
|
||||
--constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = 30
|
||||
constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 500
|
||||
constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 150
|
||||
|
||||
constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = -1
|
||||
constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = -0.1
|
||||
|
||||
-- pheromone diffusion amounts
|
||||
|
||||
constants.MOVEMENT_PHEROMONE_PERSISTANCE = 0.98
|
||||
constants.MOVEMENT_PHEROMONE_PERSISTANCE = 0.9
|
||||
constants.BASE_PHEROMONE_PERSISTANCE = 0.99
|
||||
constants.PLAYER_PHEROMONE_PERSISTANCE = 0.98
|
||||
constants.RESOURCE_PHEROMONE_PERSISTANCE = 0.85
|
||||
@ -116,17 +117,16 @@ constants.RESOURCE_PHEROMONE = 4
|
||||
constants.PLAYER_BASE_GENERATOR = 5
|
||||
constants.RESOURCE_GENERATOR = 6
|
||||
|
||||
constants.NORTH_SOUTH_PASSABLE = 7
|
||||
constants.EAST_WEST_PASSABLE = 8
|
||||
constants.PASSABLE = 7
|
||||
|
||||
constants.CHUNK_TICK = 9
|
||||
constants.RETREAT_TRIGGERED = 10
|
||||
constants.RALLY_TRIGGERED = 11
|
||||
constants.NEST_BASE = 12
|
||||
constants.WORM_BASE = 13
|
||||
constants.NEST_COUNT = 14
|
||||
constants.WORM_COUNT = 15
|
||||
constants.PATH_RATING = 16
|
||||
constants.CHUNK_TICK = 8
|
||||
constants.RETREAT_TRIGGERED = 9
|
||||
constants.RALLY_TRIGGERED = 10
|
||||
constants.NEST_BASE = 11
|
||||
constants.WORM_BASE = 12
|
||||
constants.NEST_COUNT = 13
|
||||
constants.WORM_COUNT = 14
|
||||
constants.PATH_RATING = 15
|
||||
|
||||
-- Squad status
|
||||
|
||||
@ -142,11 +142,12 @@ constants.RETREAT_GRAB_RADIUS = 24
|
||||
constants.BASE_RALLY_CHANCE = 0.02
|
||||
constants.BONUS_RALLY_CHANCE = 0.06
|
||||
|
||||
constants.MAX_RALLY_CRIES = 2
|
||||
constants.RALLY_CRY_DISTANCE = 3
|
||||
|
||||
constants.GROUP_MERGE_DISTANCE = 28
|
||||
|
||||
constants.MAX_PENALTY_BEFORE_PURGE = 8000
|
||||
|
||||
-- player building pheromones
|
||||
|
||||
constants.BUILDING_PHEROMONES = {}
|
||||
@ -163,18 +164,18 @@ 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["mining-drill"] = 35
|
||||
constants.BUILDING_PHEROMONES["rocket-silo"] = 18
|
||||
constants.BUILDING_PHEROMONES["lamp"] = 4
|
||||
constants.BUILDING_PHEROMONES["radar"] = 10
|
||||
constants.BUILDING_PHEROMONES["radar"] = 20
|
||||
|
||||
-- player defense pheromones
|
||||
|
||||
constants.BUILDING_PHEROMONES["ammo-turret"] = 2.5
|
||||
constants.BUILDING_PHEROMONES["wall"] = 0.25
|
||||
constants.BUILDING_PHEROMONES["electric-turret"] = 7
|
||||
constants.BUILDING_PHEROMONES["fluid-turret"] = 9
|
||||
constants.BUILDING_PHEROMONES["turret"] = 2.5
|
||||
constants.BUILDING_PHEROMONES["ammo-turret"] = 10
|
||||
constants.BUILDING_PHEROMONES["wall"] = 0.5
|
||||
constants.BUILDING_PHEROMONES["electric-turret"] = 20
|
||||
constants.BUILDING_PHEROMONES["fluid-turret"] = 28
|
||||
constants.BUILDING_PHEROMONES["turret"] = 10
|
||||
|
||||
constants.retreatFilter = {}
|
||||
constants.retreatFilter[constants.SQUAD_RETREATING] = true
|
||||
@ -184,14 +185,14 @@ constants.retreatFilter[constants.SQUAD_RETREATING] = true
|
||||
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 = 500
|
||||
constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH = 100
|
||||
|
||||
constants.MAX_FAILED_BEHAVIORS = 100
|
||||
constants.MAX_FAILED_BEHAVIORS = 6
|
||||
|
||||
constants.UNIT_GROUP_DISOWN_DISTANCE = 10
|
||||
constants.UNIT_GROUP_TICK_TOLERANCE = 360
|
||||
|
||||
constants.UNIT_GROUP_MAX_RADIUS = 12
|
||||
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
|
||||
|
@ -85,9 +85,6 @@ function mapProcessor.processMap(regionMap, surface, natives, tick)
|
||||
roll = math.random()
|
||||
regionMap.processRoll = roll
|
||||
end
|
||||
|
||||
local tempNeighbors = {nil, nil, nil, nil}
|
||||
local tempNeighborsAll = {nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
|
||||
local squads = canAttack(natives, surface) and (0.11 <= roll) and (roll <= 0.35) and (natives.points >= AI_SQUAD_COST)
|
||||
|
||||
@ -99,10 +96,10 @@ function mapProcessor.processMap(regionMap, surface, natives, tick)
|
||||
if (chunk[CHUNK_TICK] ~= tick) then
|
||||
chunk[CHUNK_TICK] = tick
|
||||
|
||||
processPheromone(regionMap, chunk, tempNeighbors)
|
||||
processPheromone(regionMap, chunk)
|
||||
|
||||
if squads and (chunk[NEST_COUNT] ~= 0) then
|
||||
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST, tempNeighborsAll)
|
||||
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST)
|
||||
squads = natives.points >= AI_SQUAD_COST
|
||||
end
|
||||
|
||||
@ -134,9 +131,6 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick)
|
||||
|
||||
local squads = allowingAttacks and (0.11 <= roll) and (roll <= 0.20) and (natives.points >= AI_SQUAD_COST)
|
||||
|
||||
local tempNeighbors = {nil, nil, nil, nil}
|
||||
local tempNeighborsAll = {nil, nil, nil, nil, nil, nil, nil, nil}
|
||||
|
||||
for i=1,#playerOrdering do
|
||||
local player = players[playerOrdering[i]]
|
||||
if validPlayer(player) then
|
||||
@ -163,14 +157,14 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick)
|
||||
if chunk and (chunk[CHUNK_TICK] ~= tick) then
|
||||
chunk[CHUNK_TICK] = tick
|
||||
|
||||
processPheromone(regionMap, chunk, tempNeighbors)
|
||||
processPheromone(regionMap, chunk)
|
||||
|
||||
if squads then
|
||||
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST, tempNeighborsAll)
|
||||
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST)
|
||||
squads = natives.points >= AI_SQUAD_COST
|
||||
end
|
||||
if vengence then
|
||||
formSquads(regionMap, surface, natives, chunk, AI_VENGENCE_SQUAD_COST, tempNeighborsAll)
|
||||
formSquads(regionMap, surface, natives, chunk, AI_VENGENCE_SQUAD_COST)
|
||||
vengence = natives.points >= AI_VENGENCE_SQUAD_COST
|
||||
end
|
||||
|
||||
|
@ -8,8 +8,14 @@ local mathUtils = require("MathUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
|
||||
local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE
|
||||
local CHUNK_NORTH_SOUTH = constants.CHUNK_NORTH_SOUTH
|
||||
local CHUNK_EAST_WEST = constants.CHUNK_EAST_WEST
|
||||
|
||||
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
local CHUNK_IMPASSABLE = constants.CHUNK_IMPASSABLE
|
||||
|
||||
local CHUNK_SIZE = constants.CHUNK_SIZE
|
||||
|
||||
@ -48,9 +54,10 @@ end
|
||||
/|\
|
||||
6 7 8
|
||||
]]--
|
||||
function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY, neighbors)
|
||||
function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY)
|
||||
local chunkYRow1 = chunkY - 1
|
||||
local chunkYRow3 = chunkY + 1
|
||||
local neighbors = regionMap.neighbors
|
||||
local xChunks = regionMap[chunkX-1]
|
||||
if xChunks then
|
||||
neighbors[1] = xChunks[chunkYRow1]
|
||||
@ -75,19 +82,23 @@ end
|
||||
|
||||
function mapUtils.canMoveChunkDirection(direction, startChunk, endChunk)
|
||||
local canMove = false
|
||||
if ((direction == 2) or (direction == 7)) and startChunk[NORTH_SOUTH_PASSABLE] and endChunk[NORTH_SOUTH_PASSABLE] then
|
||||
local startPassable = startChunk[PASSABLE]
|
||||
local endPassable = endChunk[PASSABLE]
|
||||
if ((direction == 2) or (direction == 7)) and (startPassable == CHUNK_NORTH_SOUTH) and (endPassable == CHUNK_NORTH_SOUTH) then
|
||||
canMove = true
|
||||
elseif ((direction == 4) or (direction == 5)) and startChunk[EAST_WEST_PASSABLE] and endChunk[EAST_WEST_PASSABLE] then
|
||||
elseif ((direction == 4) or (direction == 5)) and (startPassable == CHUNK_EAST_WEST) and (endPassable == CHUNK_EAST_WEST) then
|
||||
canMove = true
|
||||
elseif (startChunk[NORTH_SOUTH_PASSABLE] and startChunk[EAST_WEST_PASSABLE] and endChunk[NORTH_SOUTH_PASSABLE] and
|
||||
endChunk[EAST_WEST_PASSABLE]) then
|
||||
elseif (startPassable == CHUNK_ALL_DIRECTIONS) and (endPassable == CHUNK_ALL_DIRECTIONS) then
|
||||
canMove = true
|
||||
elseif (startPassable ~= CHUNK_IMPASSABLE) and (endPassable == CHUNK_ALL_DIRECTIONS) then
|
||||
canMove = true
|
||||
end
|
||||
return canMove
|
||||
end
|
||||
|
||||
function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY, neighbors)
|
||||
function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY)
|
||||
local xChunks = regionMap[chunkX]
|
||||
local neighbors = regionMap.cardinalNeighbors
|
||||
if xChunks then
|
||||
neighbors[1] = xChunks[chunkY-1]
|
||||
neighbors[4] = xChunks[chunkY+1]
|
||||
@ -123,41 +134,6 @@ function mapUtils.euclideanDistanceArray(p1, p2)
|
||||
return ((xs * xs) + (ys * ys)) ^ 0.5
|
||||
end
|
||||
|
||||
--[[
|
||||
1
|
||||
|
|
||||
2- -3
|
||||
|
|
||||
4
|
||||
]]--
|
||||
function mapUtils.canMoveChunkDirectionCardinal(direction, startChunk, endChunk)
|
||||
local canMove = false
|
||||
if ((direction == 1) or (direction == 4)) and startChunk[NORTH_SOUTH_PASSABLE] and endChunk[NORTH_SOUTH_PASSABLE] then
|
||||
canMove = true
|
||||
elseif ((direction == 2) or (direction == 3)) and startChunk[EAST_WEST_PASSABLE] and endChunk[EAST_WEST_PASSABLE] then
|
||||
canMove = true
|
||||
end
|
||||
return canMove
|
||||
end
|
||||
|
||||
function mapUtils.positionFromDirectionAndChunkCardinal(direction, startPosition, position)
|
||||
-- local position = {x=0,y=0}
|
||||
if (direction == 1) then
|
||||
position.x = startPosition.x
|
||||
position.y = startPosition.y - CHUNK_SIZE
|
||||
elseif (direction == 2) then
|
||||
position.x = startPosition.x - CHUNK_SIZE
|
||||
position.y = startPosition.y
|
||||
elseif (direction == 3) then
|
||||
position.x = startPosition.x + CHUNK_SIZE
|
||||
position.y = startPosition.y
|
||||
elseif (direction == 4) then
|
||||
position.x = startPosition.x
|
||||
position.y = startPosition.y + CHUNK_SIZE
|
||||
end
|
||||
-- return position
|
||||
end
|
||||
|
||||
function mapUtils.distortPosition(position)
|
||||
local xDistort = gaussianRandomRange(1, 0.5, 0, 2) - 1
|
||||
local yDistort = gaussianRandomRange(1, 0.5, 0, 2) - 1
|
||||
|
@ -27,6 +27,10 @@ local RESOURCE_PHEROMONE_PERSISTANCE = constants.RESOURCE_PHEROMONE_PERSISTANCE
|
||||
|
||||
local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
|
||||
local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE
|
||||
local CHUNK_IMPASSABLE = constants.CHUNK_IMPASSABLE
|
||||
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
|
||||
local PASSABLE = constants.PASSABLE
|
||||
|
||||
local NEST_COUNT = constants.NEST_COUNT
|
||||
|
||||
@ -42,7 +46,7 @@ local getCardinalChunks = mapUtils.getCardinalChunks
|
||||
|
||||
function pheromoneUtils.scents(chunk)
|
||||
|
||||
if not chunk[NORTH_SOUTH_PASSABLE] and not chunk[EAST_WEST_PASSABLE] then
|
||||
if (chunk[PASSABLE] == CHUNK_IMPASSABLE) then
|
||||
chunk[BASE_PHEROMONE] = IMPASSABLE_TERRAIN_GENERATOR_AMOUNT;
|
||||
else
|
||||
chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR]
|
||||
@ -55,26 +59,30 @@ end
|
||||
|
||||
function pheromoneUtils.victoryScent(chunk, entityType)
|
||||
local value = BUILDING_PHEROMONES[entityType]
|
||||
if (value ~= nil) then
|
||||
if (value ~= nil) and (chunk[PASSABLE] ~= CHUNK_IMPASSABLE) then
|
||||
chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] + (value * 10000)
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.deathScent(chunk)
|
||||
chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] - DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
if (chunk[PASSABLE] ~= CHUNK_IMPASSABLE) then
|
||||
chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] - DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.playerScent(playerChunk)
|
||||
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
||||
if (playerChunk[PASSABLE] ~= CHUNK_IMPASSABLE) then
|
||||
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.processPheromone(regionMap, chunk, tempNeighbors)
|
||||
function pheromoneUtils.processPheromone(regionMap, chunk)
|
||||
|
||||
if not chunk[NORTH_SOUTH_PASSABLE] and not chunk[EAST_WEST_PASSABLE] then
|
||||
if (chunk[PASSABLE] == CHUNK_IMPASSABLE) then
|
||||
return
|
||||
end
|
||||
|
||||
getCardinalChunks(regionMap, chunk.cX, chunk.cY, tempNeighbors)
|
||||
local tempNeighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
|
||||
|
||||
local chunkMovement = chunk[MOVEMENT_PHEROMONE]
|
||||
local chunkBase = chunk[BASE_PHEROMONE]
|
||||
|
@ -58,14 +58,13 @@ local function removeTendril(base, tendril)
|
||||
end
|
||||
end
|
||||
|
||||
local function buildTendrilPath(regionMap, tendril, surface, base, tempNeighbors)
|
||||
local function buildTendrilPath(regionMap, tendril, surface, base, tick)
|
||||
local chunk = getChunkByPosition(regionMap, tendril.x, tendril.y)
|
||||
if chunk then
|
||||
local tendrilPath,tendrilDirection = scoreNeighborsWithDirection(chunk,
|
||||
getNeighborChunks(regionMap,
|
||||
chunk.cX,
|
||||
chunk.cY,
|
||||
tempNeighbors),
|
||||
chunk.cY),
|
||||
validTendrilChunk,
|
||||
scoreTendrilChunk,
|
||||
nil,
|
||||
@ -98,9 +97,9 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tempNeighbors
|
||||
end
|
||||
end
|
||||
|
||||
function tendrilUtils.advanceTendrils(regionMap, base, surface, tempNeighbors)
|
||||
function tendrilUtils.advanceTendrils(regionMap, base, surface, tick)
|
||||
for i=1, #base.tendrils do
|
||||
buildTendrilPath(regionMap, base.tendrils[i], surface, base, tempNeighbors)
|
||||
buildTendrilPath(regionMap, base.tendrils[i], surface, base, tick)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -17,6 +17,8 @@ local DEFINES_GROUP_STATE_ATTACKING_DISTRACTION = defines.group_state.attacking_
|
||||
local DEFINES_COMMAND_GROUP = defines.command.group
|
||||
local DEFINES_DISTRACTION_NONE = defines.distraction.none
|
||||
|
||||
local MAX_PENALTY_BEFORE_PURGE = constants.MAX_PENALTY_BEFORE_PURGE
|
||||
|
||||
local SQUAD_RETREATING = constants.SQUAD_RETREATING
|
||||
local SQUAD_GUARDING = constants.SQUAD_GUARDING
|
||||
local GROUP_MERGE_DISTANCE = constants.GROUP_MERGE_DISTANCE
|
||||
@ -108,17 +110,31 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup)
|
||||
return returnSquad
|
||||
end
|
||||
|
||||
function unitGroupUtils.addSquadMovementPenalty(squad, chunkX, chunkY)
|
||||
function unitGroupUtils.addSquadMovementPenalty(natives, squad, chunkX, chunkY)
|
||||
local penalties = squad.penalties
|
||||
for i=1,#penalties do
|
||||
local penalty = penalties[i]
|
||||
if (penalty.x == chunkX) and (penalty.y == chunkY) then
|
||||
penalty.v = penalty.v + MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
|
||||
if (penalty.v > MAX_PENALTY_BEFORE_PURGE) then
|
||||
local group = squad.group
|
||||
local members = group.members
|
||||
for x=1,#members do
|
||||
members[x].destroy()
|
||||
end
|
||||
natives.points = natives.points + (#members * natives.unitRefundAmount)
|
||||
|
||||
if (natives.points > AI_MAX_OVERFLOW_POINTS) then
|
||||
natives.points = AI_MAX_OVERFLOW_POINTS
|
||||
end
|
||||
|
||||
group.destroy()
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
if (#penalties == 10) then
|
||||
tableRemove(penalties, 10)
|
||||
if (#penalties == 7) then
|
||||
tableRemove(penalties, 7)
|
||||
end
|
||||
tableInsert(penalties, 1, { v = MOVEMENT_PHEROMONE_GENERATOR_AMOUNT,
|
||||
x = chunkX,
|
||||
|
4
make.rkt
4
make.rkt
@ -77,8 +77,8 @@
|
||||
(copyDirectory "prototypes" modFolder)))
|
||||
|
||||
(define (run)
|
||||
(copyFiles modFolder)
|
||||
;; (copyFiles modFolder)
|
||||
;; (copyFiles zipModFolder)
|
||||
;; (makeZip modFolder)
|
||||
(makeZip modFolder)
|
||||
)
|
||||
)
|
||||
|
@ -188,7 +188,7 @@ data:extend({
|
||||
name = "rampant-useCustomAI",
|
||||
description = "rampant-useCustomAI",
|
||||
setting_type = 'startup',
|
||||
default_value = true,
|
||||
default_value = false,
|
||||
order = "h[total]-a[ai]",
|
||||
per_user = false
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user