Skip to content

Commit

Permalink
see readme, base work not done
Browse files Browse the repository at this point in the history
  • Loading branch information
veden committed Jun 10, 2017
1 parent 41fb7d6 commit 75eb3a2
Show file tree
Hide file tree
Showing 17 changed files with 196 additions and 166 deletions.
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 0 additions & 2 deletions Upgrade.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 4 additions & 6 deletions control.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
35 changes: 21 additions & 14 deletions libs/AIAttack.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down
26 changes: 17 additions & 9 deletions libs/AIBuilding.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -47,28 +47,36 @@ 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)
return surface.get_pollution(neighborChunk) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE]
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
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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)
Expand Down
18 changes: 13 additions & 5 deletions libs/AIDefense.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,28 @@ 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,
surface,
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

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion libs/AIPlanning.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions libs/BaseProcessor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 25 additions & 27 deletions libs/ChunkUtils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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
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
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
-- chunk[EAST_WEST_PASSABLE] = passableEastWest
-- chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth
chunk[PASSABLE] = pass
end

function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tick, tempQuery)
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 75eb3a2

Please sign in to comment.