1
0
mirror of https://github.com/veden/Rampant.git synced 2025-09-16 09:16:43 +02:00

basic working implemention

This commit is contained in:
Aaron Veden
2017-06-08 22:18:59 -07:00
parent 73e9dfd7f6
commit 41fb7d6db4
12 changed files with 168 additions and 67 deletions

View File

@@ -262,6 +262,7 @@ local function onDeath(event)
local tick = event.tick
retreatUnits(deathChunk,
entityPosition,
convertUnitGroupToSquad(natives,
entity.unit_group),
regionMap,
@@ -377,7 +378,8 @@ remote.add_interface("rampantTests",
clearBases = tests.clearBases,
getOffsetChunk = tests.getOffsetChunk,
registeredNest = tests.registeredNest,
colorResourcePoints = tests.colorResourcePoints
colorResourcePoints = tests.colorResourcePoints,
stepAdvanceTendrils = tests.stepAdvanceTendrils
}
)

View File

@@ -54,8 +54,9 @@ end
local function scoreAttackLocation(squad, neighborChunk, surface)
local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
local r = surface.get_pollution(neighborChunk) + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 50)
return r - squadMovementPenalty - (neighborChunk[NEST_COUNT] * 30)
local r = -- (surface.get_pollution(neighborChunk) * 0.01) +
neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 50)
return r - squadMovementPenalty -- - (neighborChunk[NEST_COUNT] * 30)
end
function aiAttack.squadAttack(regionMap, surface, natives)

View File

@@ -101,20 +101,26 @@ function aiBuilding.formSquads(regionMap, surface, natives, chunk, cost, tempNei
surface,
false)
if squadPath then
local squadPosition = positionFromDirectionAndChunk(squadDirection, chunk, {x=0,y=0}, 0.95)
local squadPosition = positionFromDirectionAndChunk(squadDirection, chunk, {x=0,y=0}, 0.98)
local squad = createSquad(squadPosition, surface, natives)
squadPosition = surface.find_non_colliding_position("biter-spawner",
squadPosition,
32,
4)
if squadPosition then
local squad = createSquad(squadPosition, surface, natives)
squad.rabid = math.random() < 0.03
squad.rabid = math.random() < 0.03
local scaledWaveSize = attackWaveScaling(natives)
local foundUnits = surface.set_multi_command({ command = { type = DEFINES_COMMAND_GROUP,
group = squad.group,
distraction = DEFINES_DISTRACTION_NONE },
unit_count = scaledWaveSize,
unit_search_distance = TRIPLE_CHUNK_SIZE })
if (foundUnits > 0) then
natives.points = natives.points - cost
local scaledWaveSize = attackWaveScaling(natives)
local foundUnits = surface.set_multi_command({ command = { type = DEFINES_COMMAND_GROUP,
group = squad.group,
distraction = DEFINES_DISTRACTION_NONE },
unit_count = scaledWaveSize,
unit_search_distance = TRIPLE_CHUNK_SIZE })
if (foundUnits > 0) then
natives.points = natives.points - cost
end
end
end
end

View File

@@ -51,7 +51,7 @@ local function scoreRetreatLocation(squad, neighborChunk, surface)
return safeScore - dangerScore
end
function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, natives, tick)
if (tick - chunk[RETREAT_TRIGGERED] > INTERVAL_LOGIC) and (chunk[NEST_COUNT] == 0) and (chunk[WORM_COUNT] == 0) then
local performRetreat = false
local enemiesToSquad = nil
@@ -77,7 +77,7 @@ function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
surface,
false)
if exitPath then
local retreatPosition = positionFromDirectionAndChunk(exitDirection, chunk, {x=0,y=0}, 1.25)
local retreatPosition = positionFromDirectionAndChunk(exitDirection, position, {x=0,y=0}, 0.98)
-- 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

View File

@@ -29,7 +29,7 @@ function baseProcessor.processBases(regionMap, surface, natives, tick)
for index = baseIndex, endIndex do
local base = bases[index]
-- buildOrder(regionMap, natives, base, surface, tick)
buildOrder(regionMap, natives, base, surface, tick)
advanceTendrils(regionMap, base, surface, tempNeighbors)
end

View File

@@ -50,11 +50,11 @@ function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendin
checkChunkPassability(chunk, surface)
scoreChunk(regionMap, chunk, surface, natives, tick, query)
processQueue[#processQueue+1] = chunk
if (count >= 3500) then
if (count >= 1000) then
break
end
end
if (count >= 3500) and (start > 0) then
if (count >= 1000) and (start > 0) then
surface.print("Rampant - " .. (start - count) .. " Remaining chunks to process")
end
end

View File

@@ -31,6 +31,8 @@ local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
local CHUNK_TICK = constants.CHUNK_TICK
local PATH_RATING = constants.PATH_RATING
local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED
local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
@@ -58,6 +60,18 @@ local function checkForDeadendTiles(constantCoordinate, iteratingCoordinate, dir
return false
end
local function checkForValidTiles(x, y, get_tile)
local count = 0
for xi=x,x+31 do
for yi=y,y+31 do
if not get_tile(xi, yi).collides_with("player-layer") then
count = count + 1
end
end
end
return count / 1024
end
function chunkUtils.checkChunkPassability(chunk, surface)
local x = chunk.x
local y = chunk.y
@@ -77,9 +91,26 @@ function chunkUtils.checkChunkPassability(chunk, surface)
break
end
end
if passableEastWest or passableNorthSouth then
if (checkForValidTiles(x, y, get_tile) < 0.6) then
passableEastWest = false
passableNorthSouth = false
end
end
chunk[EAST_WEST_PASSABLE] = passableEastWest
chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth
-- 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
end
function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tick, tempQuery)
@@ -179,6 +210,7 @@ function chunkUtils.createChunk(topX, topY)
chunk[WORM_BASE] = {}
chunk[NEST_COUNT] = 0
chunk[WORM_COUNT] = 0
chunk[PATH_RATING] = 0
return chunk
end

View File

@@ -97,14 +97,14 @@ constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 500
constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 500
constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 150
constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = -30
constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = -1
-- pheromone diffusion amounts
constants.MOVEMENT_PHEROMONE_PERSISTANCE = 0.98
constants.BASE_PHEROMONE_PERSISTANCE = 0.99
constants.PLAYER_PHEROMONE_PERSISTANCE = 0.98
constants.RESOURCE_PHEROMONE_PERSISTANCE = 0.98
constants.RESOURCE_PHEROMONE_PERSISTANCE = 0.85
-- chunk attributes
@@ -126,6 +126,7 @@ constants.NEST_BASE = 12
constants.WORM_BASE = 13
constants.NEST_COUNT = 14
constants.WORM_COUNT = 15
constants.PATH_RATING = 16
-- Squad status
@@ -183,14 +184,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 = 300
constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH = 500
constants.MAX_FAILED_BEHAVIORS = 6
constants.MAX_FAILED_BEHAVIORS = 100
constants.UNIT_GROUP_DISOWN_DISTANCE = 10
constants.UNIT_GROUP_TICK_TOLERANCE = 360
constants.UNIT_GROUP_MAX_RADIUS = 20
constants.UNIT_GROUP_MAX_RADIUS = 12
constants.UNIT_GROUP_MAX_SPEED_UP = 1.1
constants.UNIT_GROUP_MAX_SLOWDOWN = 1.0
constants.UNIT_GROUP_SLOWDOWN_FACTOR = 0.9

View File

@@ -4,6 +4,8 @@ local mapUtils = {}
local constants = require("Constants")
local mathUtils = require("MathUtils")
-- constants
local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
@@ -13,6 +15,8 @@ local CHUNK_SIZE = constants.CHUNK_SIZE
-- imported functions
local gaussianRandomRange = mathUtils.gaussianRandomRange
local mFloor = math.floor
-- module code
@@ -39,9 +43,9 @@ end
--[[
1 2 3
\|/
\|/
4- -5
/|\
/|\
6 7 8
]]--
function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY, neighbors)
@@ -122,7 +126,7 @@ end
--[[
1
|
2- -3
2- -3
|
4
]]--
@@ -154,6 +158,13 @@ function mapUtils.positionFromDirectionAndChunkCardinal(direction, startPosition
-- 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
position.x = position.x + (xDistort * 48)
position.y = position.y + (yDistort * 48)
end
function mapUtils.positionFromDirectionAndChunk(direction, startPosition, position, scaling)
-- local position = {x=0, y=0}
if (direction == 1) then

View File

@@ -30,6 +30,8 @@ local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE
local NEST_COUNT = constants.NEST_COUNT
local PATH_RATING = constants.PATH_RATING
local IMPASSABLE_TERRAIN_GENERATOR_AMOUNT = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
-- imported functions
@@ -44,7 +46,7 @@ function pheromoneUtils.scents(chunk)
chunk[BASE_PHEROMONE] = IMPASSABLE_TERRAIN_GENERATOR_AMOUNT;
else
chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR]
if (chunk[NEST_COUNT] ~= 0) then
if (chunk[NEST_COUNT] == 0) then
chunk[RESOURCE_PHEROMONE] = chunk[RESOURCE_PHEROMONE] + chunk[RESOURCE_GENERATOR]
end
end
@@ -78,6 +80,7 @@ function pheromoneUtils.processPheromone(regionMap, chunk, tempNeighbors)
local chunkBase = chunk[BASE_PHEROMONE]
local chunkPlayer = chunk[PLAYER_PHEROMONE]
local chunkResource = chunk[RESOURCE_PHEROMONE]
local chunkPathRating = chunk[PATH_RATING]
local totalMovement = 0
local totalBase = 0
@@ -93,10 +96,10 @@ function pheromoneUtils.processPheromone(regionMap, chunk, tempNeighbors)
totalResource = totalResource + (neighborChunk[RESOURCE_PHEROMONE] - chunkResource)
end
end
chunk[MOVEMENT_PHEROMONE] = (chunkMovement + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE
chunk[BASE_PHEROMONE] = (chunkBase + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE
chunk[PLAYER_PHEROMONE] = (chunkPlayer + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE
chunk[RESOURCE_PHEROMONE] = (chunkResource + (0.25 * totalResource)) * RESOURCE_PHEROMONE_PERSISTANCE
chunk[MOVEMENT_PHEROMONE] = (chunkMovement + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE * chunkPathRating
chunk[BASE_PHEROMONE] = (chunkBase + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE * chunkPathRating
chunk[PLAYER_PHEROMONE] = (chunkPlayer + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE * chunkPathRating
chunk[RESOURCE_PHEROMONE] = (chunkResource + (0.25 * totalResource)) * RESOURCE_PHEROMONE_PERSISTANCE * chunkPathRating
end
return pheromoneUtils

View File

@@ -27,6 +27,8 @@ local registerEnemyBaseStructure = baseRegisterUtils.registerEnemyBaseStructure
local canMoveChunkDirection = mapUtils.canMoveChunkDirection
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
-- module code
local function scoreTendrilChunk(squad, chunk, surface)
@@ -37,6 +39,25 @@ local function validTendrilChunk(x, chunk, neighborChunk)
return canMoveChunkDirection(x, chunk, neighborChunk)
end
-- local function 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
local function removeTendril(base, tendril)
for i=1,#base.tendrils do
if (base.tendrils[i] == tendril) then
table.remove(base.tendrils,i)
break
end
end
end
local function buildTendrilPath(regionMap, tendril, surface, base, tempNeighbors)
local chunk = getChunkByPosition(regionMap, tendril.x, tendril.y)
if chunk then
@@ -51,25 +72,29 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tempNeighbors
surface,
true)
if (tendrilDirection == -1) then
tendril.path[#tendril.path] = chunk
local biterSpawner = {name="spitter-spawner", position={x=chunk.x,y=chunk.y}}
local hive = surface.create_entity(biterSpawner)
registerEnemyBaseStructure(regionMap, hive, base)
for i=1,#base.tendrils do
if (base.tendrils[i] == tendril) then
table.remove(base.tendrils,i)
break
end
end
removeTendril(base, tendril)
tendrilUtils.buildTendril(regionMap, nil, base, surface, tick)
-- colorChunk(chunk.x, chunk.y, "hazard-concrete-left", surface)
return
elseif tendrilPath then
positionFromDirectionAndChunk(tendrilDirection, chunk, tendril, 0.95)
positionFromDirectionAndChunk(tendrilDirection, tendril, tendril, 0.5)
mapUtils.distortPosition(tendril)
tendril.path[#tendril.path] = chunk
local biterSpawner = {name="spitter-spawner", position={x=tendril.x,y=tendril.y}}
local hive = surface.create_entity(biterSpawner)
registerEnemyBaseStructure(regionMap, hive, base)
local position = surface.find_non_colliding_position("spitter-spawner",
{x=tendril.x,y=tendril.y},
32,
4)
if position and (tendrilPath[NEST_COUNT] <= 3)then
tendril.x = position.x
tendril.y = position.y
local biterSpawner = {name="spitter-spawner", position=position}
local hive = surface.create_entity(biterSpawner)
registerEnemyBaseStructure(regionMap, hive, base)
elseif not position then
removeTendril(base, tendril)
end
end
-- colorChunk(chunk.x, chunk.y, "concrete", surface)
end
end

View File

@@ -5,17 +5,22 @@ local mathUtils = require("libs/MathUtils")
local chunkUtils = require("libs/ChunkUtils")
local mapUtils = require("libs/MapUtils")
local baseUtils = require("libs/BaseUtils")
local baseRegisterUtils = require("libs/BaseRegisterUtils")
local tendrilUtils = require("libs/TendrilUtils")
function tests.pheromoneLevels()
function tests.pheromoneLevels(size)
local player = game.player.character
local playerChunkX = math.floor(player.position.x / 32)
local playerChunkY = math.floor(player.position.y / 32)
if not size then
size = 3
end
print("------")
print(#global.regionMap.processQueue)
print(playerChunkX .. ", " .. playerChunkY)
print("--")
for x=playerChunkX-9, playerChunkX+9 do
for y=playerChunkY-9, playerChunkY+9 do
for y=playerChunkY-size, playerChunkY+size do
for x=playerChunkX-size, playerChunkX+size do
if (global.regionMap[x] ~= nil) then
local chunk = global.regionMap[x][y]
if (chunk ~= nil) then
@@ -25,15 +30,18 @@ function tests.pheromoneLevels()
end
str = str .. " " .. "p/" .. game.surfaces[1].get_pollution(chunk)
if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then
print("*", chunk.cX, chunk.cY, str)
print("=============")
print(chunk.cX, chunk.cY, str)
print("=============")
else
print(chunk.cX, chunk.cY, str)
end
-- print(str)
print("-")
print("----")
end
end
end
print("------------------")
end
end
@@ -113,9 +121,9 @@ end
function tests.registeredNest(x)
local entity = tests.createEnemy(x)
baseUtils.registerEnemyBaseStructure(global.regionMap,
entity,
nil)
baseRegisterUtils.registerEnemyBaseStructure(global.regionMap,
entity,
nil)
end
function tests.attackOrigin()
@@ -140,7 +148,7 @@ function tests.gaussianRandomTest()
result[x] = 0
end
for _=1,10000 do
local s = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(10, 17, 0, 100), 1)
local s = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(50, 25, 0, 100), 1)
result[s] = result[s] + 1
end
for x=0,100,1 do
@@ -161,6 +169,7 @@ function tests.baseStats()
local nestCount = 0
local wormCount = 0
local eggCount = 0
local hiveCount = 0
for _,_ in pairs(base.nests) do
nestCount = nestCount + 1
end
@@ -170,7 +179,12 @@ function tests.baseStats()
for _,_ in pairs(base.eggs) do
eggCount = eggCount + 1
end
print(base.x, base.y, base.x * 32, base.y * 32, base.created, base.alignment, base.strength, base.upgradePoints, nestCount, wormCount, eggCount, base.hive)
for _,_ in pairs(base.hives) do
hiveCount = hiveCount + 1
end
print(base.x, base.y, base.created, base.alignment, base.strength, base.upgradePoints, nestCount, wormCount, eggCount, hiveCount)
print(serpent.dump(base.tendrils))
print("---")
end
end
@@ -232,9 +246,9 @@ function tests.colorResourcePoints()
local chunks = global.regionMap.processQueue
for i=1,#chunks do
local chunk = chunks[i]
local color = "deepwater-green"
local color = "concrete"
if (chunk[constants.RESOURCE_GENERATOR] ~= 0) and (chunk[constants.NEST_COUNT] ~= 0) then
color = "water"
color = "hazard-concrete-left"
elseif (chunk[constants.RESOURCE_GENERATOR] ~= 0) then
color = "deepwater"
elseif (chunk[constants.NEST_COUNT] ~= 0) then
@@ -253,15 +267,21 @@ function tests.showMovementGrid()
local chunks = global.regionMap.processQueue
for i=1,#chunks do
local chunk = chunks[i]
local color = "deepwater-green"
local color = "concrete"
if (chunk[constants.NORTH_SOUTH_PASSABLE] and chunk[constants.EAST_WEST_PASSABLE]) then
color = "water"
color = "hazard-concrete-left"
elseif chunk[constants.NORTH_SOUTH_PASSABLE] then
color = "deepwater"
elseif chunk[constants.EAST_WEST_PASSABLE] then
color = "water-green"
end
chunkUtils.colorChunk(chunk.pX, chunk.pY, color, game.surfaces[1])
chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[1])
end
end
function tests.stepAdvanceTendrils()
for _, base in pairs(global.natives.bases) do
tendrilUtils.advanceTendrils(global.regionMap, base, game.surfaces[1], {nil,nil,nil,nil,nil,nil,nil,nil})
end
end