refactoring files for movement code and tendril stuff

This commit is contained in:
Aaron Veden
2017-06-12 20:16:43 -07:00
parent f144c80235
commit ab1fe32be5
20 changed files with 424 additions and 254 deletions
+3
View File
@@ -56,6 +56,9 @@ Configure Options not in game menu:
# Version History
0.15.16 -
0.15.15 -
- Fixed: Desync when reindexing chunks (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=180#p287941)
- Fixed: Switched from "and" to "or" for player pheromone and base pheromone to form squads
+10 -10
View File
@@ -8,9 +8,9 @@ local baseProcessor = require("libs/BaseProcessor")
local mapProcessor = require("libs/MapProcessor")
local constants = require("libs/Constants")
local pheromoneUtils = require("libs/PheromoneUtils")
local aiDefense = require("libs/AIDefense")
local aiAttack = require("libs/AIAttack")
local aiBuilding = require("libs/AIBuilding")
local squadDefense = require("libs/SquadDefense")
local squadAttack = require("libs/SquadAttack")
local aiAttackWave = require("libs/AIAttackWave")
local aiPlanning = require("libs/AIPlanning")
local interop = require("libs/Interop")
local tests = require("tests")
@@ -44,7 +44,7 @@ local scanMap = mapProcessor.scanMap
local planning = aiPlanning.planning
local rallyUnits = aiBuilding.rallyUnits
local rallyUnits = aiAttackWave.rallyUnits
local deathScent = pheromoneUtils.deathScent
local victoryScent = pheromoneUtils.victoryScent
@@ -53,10 +53,10 @@ local cleanSquads = unitGroupUtils.cleanSquads
local regroupSquads = unitGroupUtils.regroupSquads
local convertUnitGroupToSquad = unitGroupUtils.convertUnitGroupToSquad
local squadAttack = aiAttack.squadAttack
local squadBeginAttack = aiAttack.squadBeginAttack
local squadsAttack = squadAttack.squadsAttack
local squadsBeginAttack = squadAttack.squadsBeginAttack
local retreatUnits = aiDefense.retreatUnits
local retreatUnits = squadDefense.retreatUnits
local addRemovePlayerEntity = entityUtils.addRemovePlayerEntity
local unregisterEnemyBaseStructure = baseRegisterUtils.unregisterEnemyBaseStructure
@@ -209,8 +209,8 @@ local function onTick(event)
processBases(regionMap, surface, natives, tick)
end
squadBeginAttack(natives, players)
squadAttack(regionMap, surface, natives)
squadsBeginAttack(natives, players)
squadsAttack(regionMap, surface, natives)
end
processMap(regionMap, surface, natives, tick)
@@ -316,7 +316,7 @@ end
local function onSurfaceTileChange(event)
-- local player = game.players[event.player_index]
-- if (player.surface.index == 1) then
-- aiBuilding.fillTunnel(regionMap, player.surface, natives, event.positions)
-- aiAttackWave.fillTunnel(regionMap, player.surface, natives, event.positions)
-- end
end
+1
View File
@@ -8,3 +8,4 @@ require("prototypes/tile/fillableDirt")
require("prototypes/enemies/UnitSuicideBiters")
require("prototypes/enemies/UnitFireSpitters")
require("prototypes/enemies/UnitTendril")
@@ -1,4 +1,4 @@
local aiBuilding = {}
local aiAttackWave = {}
-- imports
@@ -76,7 +76,7 @@ local function validUnitGroupLocation(neighborChunk)
return (neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS) and (neighborChunk[NEST_COUNT] == 0)
end
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, tick)
function aiAttackWave.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
@@ -86,7 +86,7 @@ function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, tick)
if (x ~= cX) and (y ~= cY) then
local rallyChunk = getChunkByIndex(regionMap, x, y)
if rallyChunk and (rallyChunk[NEST_COUNT] ~= 0) then
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST)
aiAttackWave.formSquads(regionMap, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST)
if (natives.points < AI_VENGENCE_SQUAD_COST) then
return
end
@@ -97,7 +97,7 @@ function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, tick)
end
end
function aiBuilding.formSquads(regionMap, surface, natives, chunk, cost)
function aiAttackWave.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
@@ -131,4 +131,4 @@ function aiBuilding.formSquads(regionMap, surface, natives, chunk, cost)
end
end
return aiBuilding
return aiAttackWave
+3 -3
View File
@@ -2,7 +2,7 @@ local baseProcessor = {}
-- imports
local baseUtils = require("BaseUtils")
local buildUtils = require("BuildUtils")
local tendrilUtils = require("TendrilUtils")
local constants = require("Constants")
@@ -14,7 +14,7 @@ local BASE_QUEUE_SIZE = constants.BASE_QUEUE_SIZE
local mMin = math.min
local buildOrder = baseUtils.buildOrder
local buildOrder = buildUtils.buildOrder
local advanceTendrils = tendrilUtils.advanceTendrils
-- module code
@@ -28,7 +28,7 @@ function baseProcessor.processBases(regionMap, surface, natives, tick)
local base = bases[index]
buildOrder(regionMap, natives, base, surface, tick)
advanceTendrils(regionMap, base, surface, tick)
advanceTendrils(regionMap, base, surface, tick, natives)
end
if (endIndex == #bases) then
+4 -81
View File
@@ -4,23 +4,17 @@ local baseUtils = {}
local mapUtils = require("MapUtils")
local constants = require("Constants")
local mathUtils = require("MathUtils")
local baseRegisterUtils = require("BaseRegisterUtils")
local tendrilUtils = require("TendrilUtils")
local buildUtils = require("BuildUtils")
-- constants
local BASE_DISTANCE_THRESHOLD = constants.BASE_DISTANCE_THRESHOLD
local BASE_ALIGNMENT_NEUTRAL = constants.BASE_ALIGNMENT_NEUTRAL
local AI_NEST_COST = constants.AI_NEST_COST
local AI_WORM_COST = constants.AI_WORM_COST
local DOUBLE_CHUNK_SIZE = constants.DOUBLE_CHUNK_SIZE
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
local MAGIC_MAXIMUM_BASE_NUMBER = constants.MAGIC_MAXIMUM_BASE_NUMBER
@@ -28,14 +22,12 @@ local MAGIC_MAXIMUM_BASE_NUMBER = constants.MAGIC_MAXIMUM_BASE_NUMBER
local euclideanDistancePoints = mapUtils.euclideanDistancePoints
local gaussianRandomRange = mathUtils.gaussianRandomRange
local buildHive = buildUtils.buildHive
local mFloor = math.floor
local buildTendril = tendrilUtils.buildTendril
local registerEnemyBaseStructure = baseRegisterUtils.registerEnemyBaseStructure
-- module code
function baseUtils.findNearbyBase(natives, position)
@@ -53,75 +45,6 @@ function baseUtils.findNearbyBase(natives, position)
return foundBase
end
function baseUtils.buildHive(regionMap, base, surface)
local valid = false
local position = surface.find_non_colliding_position("biter-spawner-hive", base, DOUBLE_CHUNK_SIZE, 2)
if position then
local biterSpawner = {name="biter-spawner-hive", position=position}
local hive = surface.create_entity(biterSpawner)
if (#base.hives == 0) then
base.x = hive.position.x
base.y = hive.position.y
end
base.hives[#base.hives+1] = hive
registerEnemyBaseStructure(regionMap, hive, base)
valid = true
end
return valid
end
function baseUtils.buildOutpost(natives, base, surface, tick, position)
end
function baseUtils.buildOrder(regionMap, natives, base, surface, tick)
local foundHive = false
for _,_ in pairs(base.hives) do
foundHive = true
break
end
if not foundHive or (base.upgradePoints < 10) then
return
end
local generator = natives.randomGenerator
generator.re_seed(base.pattern)
for level=0,base.level do
local slices = (level * 3)
slices = gaussianRandomRange(slices, slices * 0.1, slices * 0.6, slices * 1.4, generator)
local slice = (2 * math.pi) / slices
local pos = 0
local thing
local cost
local radiusAdjustment
if (generator() < 0.3) then
thing = "small-worm-turret"
cost = AI_WORM_COST
radiusAdjustment = -4
else
thing = "biter-spawner"
cost = AI_NEST_COST
radiusAdjustment = 0
end
for _ = 1, slices do
if (base.upgradePoints < 10) then
return
end
local radius = 10 * level
local distortion = gaussianRandomRange(radius, 10, radius - 7.5 + radiusAdjustment, radius + 7.5 + radiusAdjustment, generator)
local nestPosition = {x = base.x + (distortion * math.cos(pos)),
y = base.y + (distortion * math.sin(pos))}
local biterSpawner = {name=thing, position=nestPosition}
if surface.can_place_entity(biterSpawner) then
registerEnemyBaseStructure(regionMap, surface.create_entity(biterSpawner), base)
base.upgradePoints = base.upgradePoints - cost
end
pos = pos + slice
end
end
end
function baseUtils.createBase(regionMap, natives, position, surface, tick)
local bases = natives.bases
local distance = euclideanDistancePoints(position.x, position.y, 0, 0)
@@ -140,7 +63,7 @@ function baseUtils.createBase(regionMap, natives, position, surface, tick)
pattern = math.random(MAGIC_MAXIMUM_BASE_NUMBER),
level = mFloor(distance / 200)
}
if not baseUtils.buildHive(regionMap, base, surface) then
if not buildHive(regionMap, base, surface) then
return nil
end
buildTendril(regionMap, natives, base, surface, tick)
+139
View File
@@ -0,0 +1,139 @@
local buildUtils = {}
-- imports
local constants = require("Constants")
local mathUtils = require("MathUtils")
local baseRegisterUtils = require("BaseRegisterUtils")
-- constants
local MAGIC_MAXIMUM_BASE_NUMBER = constants.MAGIC_MAXIMUM_BASE_NUMBER
-- imported functions
local AI_NEST_COST = constants.AI_NEST_COST
local AI_WORM_COST = constants.AI_WORM_COST
local DOUBLE_CHUNK_SIZE = constants.DOUBLE_CHUNK_SIZE
local registerEnemyBaseStructure = baseRegisterUtils.registerEnemyBaseStructure
local gaussianRandomRange = mathUtils.gaussianRandomRange
-- module code
function buildUtils.buildHive(regionMap, base, surface)
local valid = false
local position = surface.find_non_colliding_position("biter-spawner-hive", base, DOUBLE_CHUNK_SIZE, 2)
if position then
local biterSpawner = {name="biter-spawner-hive", position=position}
local hive = surface.create_entity(biterSpawner)
if (#base.hives == 0) then
base.x = hive.position.x
base.y = hive.position.y
end
base.hives[#base.hives+1] = hive
registerEnemyBaseStructure(regionMap, hive, base)
valid = true
end
return valid
end
function buildUtils.buildOutpost(regionMap, natives, base, surface, position)
local foundHive = false
for _,_ in pairs(base.hives) do
foundHive = true
break
end
if not foundHive or (base.upgradePoints < 10) then
return
end
local generator = natives.randomGenerator
generator.re_seed(math.random(MAGIC_MAXIMUM_BASE_NUMBER))
for level=0,(base.level * 0.5) do
local slices = (level * 3)
slices = gaussianRandomRange(slices, slices * 0.1, slices * 0.6, slices * 1.4, generator)
local slice = (2 * math.pi) / slices
local pos = 0
local thing
local cost
local radiusAdjustment
if (generator() < 0.3) then
thing = "small-worm-turret"
cost = AI_WORM_COST
radiusAdjustment = -4
else
thing = "biter-spawner"
cost = AI_NEST_COST
radiusAdjustment = 0
end
for _ = 1, slices do
if (base.upgradePoints < 10) then
return
end
local radius = 10 * level
local distortion = gaussianRandomRange(radius, 10, radius - 7.5 + radiusAdjustment, radius + 7.5 + radiusAdjustment, generator)
local nestPosition = {x = position.x + (distortion * math.cos(pos)),
y = position.y + (distortion * math.sin(pos))}
local biterSpawner = {name=thing, position=nestPosition}
if surface.can_place_entity(biterSpawner) then
registerEnemyBaseStructure(regionMap, surface.create_entity(biterSpawner), base)
base.upgradePoints = base.upgradePoints - cost
end
pos = pos + slice
end
end
end
function buildUtils.buildOrder(regionMap, natives, base, surface)
local foundHive = false
for _,_ in pairs(base.hives) do
foundHive = true
break
end
if not foundHive or (base.upgradePoints < 10) then
return
end
local generator = natives.randomGenerator
generator.re_seed(base.pattern)
for level=0,base.level do
local slices = (level * 3)
slices = gaussianRandomRange(slices, slices * 0.1, slices * 0.6, slices * 1.4, generator)
local slice = (2 * math.pi) / slices
local pos = 0
local thing
local cost
local radiusAdjustment
if (generator() < 0.3) then
thing = "small-worm-turret"
cost = AI_WORM_COST
radiusAdjustment = -4
else
thing = "biter-spawner"
cost = AI_NEST_COST
radiusAdjustment = 0
end
for _ = 1, slices do
if (base.upgradePoints < 10) then
return
end
local radius = 10 * level
local distortion = gaussianRandomRange(radius, 10, radius - 7.5 + radiusAdjustment, radius + 7.5 + radiusAdjustment, generator)
local nestPosition = {x = base.x + (distortion * math.cos(pos)),
y = base.y + (distortion * math.sin(pos))}
local biterSpawner = {name=thing, position=nestPosition}
if surface.can_place_entity(biterSpawner) then
registerEnemyBaseStructure(regionMap, surface.create_entity(biterSpawner), base)
base.upgradePoints = base.upgradePoints - cost
end
pos = pos + slice
end
end
end
return buildUtils
+5 -3
View File
@@ -130,10 +130,12 @@ function chunkUtils.scoreChunk(regionMap, chunk, surface, natives, tick, tempQue
if (nests > 0) or (worms > 0) or (biters > 0) then
for f=1, #enemies do
local enemy = enemies[f]
if (enemy.name ~= "biter-spawner-hive") then
enemy.destroy()
else
if (enemy.name == "small-tendril-biter-rampant") then
biters = biters - 1
elseif (enemy.name == "biter-spawner-hive") then
nests = nests - 1
else
enemy.destroy()
end
end
local foundBase = findNearbyBase(natives, chunk) or createBase(regionMap, natives, chunk, surface, tick)
+2 -1
View File
@@ -12,6 +12,7 @@ constants.VERSION_20 = 20
constants.VERSION_22 = 22
constants.VERSION_23 = 23
constants.VERSION_25 = 25
constants.VERSION_26 = 26
-- misc
@@ -33,7 +34,7 @@ constants.INTERVAL_LOGIC = 38
constants.PLAYER_PHEROMONE_MULTIPLER = 100
constants.DEV_CUSTOM_AI = false
constants.DEV_CUSTOM_AI = true
-- chunk properties
+2 -2
View File
@@ -5,7 +5,7 @@ local mapProcessor = {}
local unitGroupUtils = require("UnitGroupUtils")
local pheromoneUtils = require("PheromoneUtils")
local aiBuilding = require("AIBuilding")
local aiAttackWave = require("AIAttackWave")
local aiPredicates = require("AIPredicates")
local constants = require("Constants")
local mapUtils = require("MapUtils")
@@ -40,7 +40,7 @@ local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
local scents = pheromoneUtils.scents
local processPheromone = pheromoneUtils.processPheromone
local formSquads = aiBuilding.formSquads
local formSquads = aiAttackWave.formSquads
local getChunkByIndex = mapUtils.getChunkByIndex
local getChunkByPosition = mapUtils.getChunkByPosition
-34
View File
@@ -4,8 +4,6 @@ local mapUtils = {}
local constants = require("Constants")
local mathUtils = require("MathUtils")
-- constants
local CHUNK_NORTH_SOUTH = constants.CHUNK_NORTH_SOUTH
@@ -21,8 +19,6 @@ local CHUNK_SIZE = constants.CHUNK_SIZE
-- imported functions
local gaussianRandomRange = mathUtils.gaussianRandomRange
local mFloor = math.floor
-- module code
@@ -43,10 +39,6 @@ function mapUtils.getChunkByIndex(regionMap, x, y)
return nil
end
function mapUtils.positionToChunkOffset(position)
return mFloor(position.x * 0.03125), mFloor(position.y * 0.03125)
end
--[[
1 2 3
\|/
@@ -116,33 +108,7 @@ function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY)
return neighbors
end
function mapUtils.euclideanDistanceNamed(p1, p2)
local xs = p1.x - p2.x
local ys = p1.y - p2.y
return ((xs * xs) + (ys * ys)) ^ 0.5
end
function mapUtils.euclideanDistancePoints(x1, y1, x2, y2)
local xs = x1 - x2
local ys = y1 - y2
return ((xs * xs) + (ys * ys)) ^ 0.5
end
function mapUtils.euclideanDistanceArray(p1, p2)
local xs = p1[1] - p2[1]
local ys = p1[2] - p2[2]
return ((xs * xs) + (ys * ys)) ^ 0.5
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
position.x = startPosition.x - CHUNK_SIZE * scaling
position.y = startPosition.y - CHUNK_SIZE * scaling
+33
View File
@@ -16,6 +16,10 @@ local mMax = math.max
local mSqrt = math.sqrt
local mLog10 = math.log10
local mFloor = math.floor
-- module code
function mathUtils.roundToNearest(number, multiple)
local num = number + (multiple * 0.5)
return num - (num % multiple)
@@ -60,4 +64,33 @@ function mathUtils.gaussianRandomRange(mean, std_dev, min, max, rg)
return q
end
function mathUtils.positionToChunkOffset(position)
return mFloor(position.x * 0.03125), mFloor(position.y * 0.03125)
end
function mathUtils.euclideanDistanceNamed(p1, p2)
local xs = p1.x - p2.x
local ys = p1.y - p2.y
return ((xs * xs) + (ys * ys)) ^ 0.5
end
function mathUtils.euclideanDistancePoints(x1, y1, x2, y2)
local xs = x1 - x2
local ys = y1 - y2
return ((xs * xs) + (ys * ys)) ^ 0.5
end
function mathUtils.euclideanDistanceArray(p1, p2)
local xs = p1[1] - p2[1]
local ys = p1[2] - p2[2]
return ((xs * xs) + (ys * ys)) ^ 0.5
end
function mathUtils.distortPosition(position)
local xDistort = mathUtils.gaussianRandomRange(1, 0.5, 0, 2) - 1
local yDistort = mathUtils.gaussianRandomRange(1, 0.5, 0, 2) - 1
position.x = position.x + (xDistort * 48)
position.y = position.y + (yDistort * 48)
end
return mathUtils
+72
View File
@@ -0,0 +1,72 @@
local movementUtils = {}
-- imports
local constants = require("Constants")
local unitGroupUtils = require("UnitGroupUtils")
local mathUtils = require("MathUtils")
-- constants
local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
local MAX_PENALTY_BEFORE_PURGE = constants.MAX_PENALTY_BEFORE_PURGE
-- imported functions
local recycleBiters = unitGroupUtils.recycleBiters
local tableRemove = table.remove
local tableInsert = table.insert
local distortPosition = mathUtils.distortPosition
-- module code
function movementUtils.findMovementPosition(surface, position, distort)
local pos = position
if not surface.can_place_entity({name="behemoth-biter", position=position}) then
pos = surface.find_non_colliding_position("behemoth-biter", position, 5, 2) or position
end
return (distort and distortPosition(pos)) or pos
end
function movementUtils.addMovementPenalty(natives, units, chunkX, chunkY)
local penalties = units.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 = units.group
if group then
recycleBiters(natives, group.members)
group.destroy()
else
units.unit.destroy()
end
end
return
end
end
if (#penalties == 7) then
tableRemove(penalties, 7)
end
tableInsert(penalties, 1, { v = MOVEMENT_PHEROMONE_GENERATOR_AMOUNT,
x = chunkX,
y = chunkY })
end
function movementUtils.lookupMovementPenalty(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
return penalty.v
end
end
return 0
end
return movementUtils
+19 -23
View File
@@ -1,4 +1,4 @@
local aiAttack = {}
local squadAttack = {}
-- imports
@@ -7,6 +7,7 @@ local mapUtils = require("MapUtils")
local unitGroupUtils = require("UnitGroupUtils")
local playerUtils = require("PlayerUtils")
local neighborUtils = require("NeighborUtils")
local movementUtils = require("MovementUtils")
-- constants
@@ -32,9 +33,11 @@ local DEFINES_DISTRACTION_BY_ANYTHING = defines.distraction.by_anything
-- imported functions
local findMovementPoint = movementUtils.findMovementPoint
local getNeighborChunks = mapUtils.getNeighborChunks
local getChunkByPosition = mapUtils.getChunkByPosition
local addSquadMovementPenalty = unitGroupUtils.addSquadMovementPenalty
local addMovementPenalty = unitGroupUtils.addMovementPenalty
local lookupSquadMovementPenalty = unitGroupUtils.lookupSquadMovementPenalty
local calculateKamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
@@ -52,7 +55,7 @@ local function scoreAttackLocation(squad, neighborChunk)
return damage - lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
end
function aiAttack.squadAttack(regionMap, surface, natives)
function squadAttack.squadsAttack(regionMap, surface, natives)
local squads = natives.squads
local attackPosition
local attackCmd
@@ -80,18 +83,12 @@ function aiAttack.squadAttack(regionMap, surface, natives)
chunk.cY),
scoreAttackLocation,
squad)
addSquadMovementPenalty(natives, squad, chunk.cX, chunk.cY)
addMovementPenalty(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.35)
if (#squad.group.members > 80) then
squad.cycles = 6
else
squad.cycles = 4
end
squad.cycles = ((#squad.group.members > 80) and 6) or 4
local moreFrenzy = not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100)
squad.frenzy = moreFrenzy
@@ -102,19 +99,18 @@ function aiAttack.squadAttack(regionMap, surface, natives)
attackCmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
end
if surface.can_place_entity({name="behemoth-biter", position=attackPosition}) then
local position = findMovementPoint(surface,
positionFromDirectionAndChunk(attackDirection,
groupPosition,
attackPosition,
1.35))
if position then
attackPosition.x = position.x
attackPosition.y = position.y
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
addMovementPenalty(natives, squad, attackChunk.cX, attackChunk.cY)
end
elseif not squad.frenzy and not squad.rabid and
((groupState == DEFINES_GROUP_ATTACKING_DISTRACTION) or (groupState == DEFINES_GROUP_ATTACKING_TARGET) or
@@ -130,7 +126,7 @@ function aiAttack.squadAttack(regionMap, surface, natives)
end
end
function aiAttack.squadBeginAttack(natives, players)
function squadAttack.squadsBeginAttack(natives, players)
local squads = natives.squads
for i=1,#squads do
local squad = squads[i]
@@ -154,4 +150,4 @@ function aiAttack.squadBeginAttack(natives, players)
end
end
return aiAttack
return squadAttack
@@ -67,6 +67,7 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
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
+77 -51
View File
@@ -7,6 +7,8 @@ local mapUtils = require("MapUtils")
local baseRegisterUtils = require("BaseRegisterUtils")
local neighborsUtils = require("NeighborUtils")
local buildUtils = require("BuildUtils")
-- constants
local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
@@ -15,7 +17,7 @@ local NEST_COUNT = constants.NEST_COUNT
-- imported functions
local scoreNeighborsWithDirection = neighborsUtils.scoreNeighborsWithDirection
local scoreNeighborsForAttack = neighborsUtils.scoreNeighborsForAttack
local getNeighborChunks = mapUtils.getNeighborChunks
@@ -25,30 +27,26 @@ local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
local registerEnemyBaseStructure = baseRegisterUtils.registerEnemyBaseStructure
local canMoveChunkDirection = mapUtils.canMoveChunkDirection
local buildOutpost = buildUtils.buildOutpost
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
-- module code
local function scoreTendrilChunk(squad, chunk, surface)
local function scoreTendrilChunk(squad, chunk)
return chunk[RESOURCE_PHEROMONE]
end
local function validTendrilChunk(x, chunk, neighborChunk)
return canMoveChunkDirection(x, chunk, neighborChunk)
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 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
@@ -58,57 +56,84 @@ local function removeTendril(base, tendril)
end
end
local function buildTendrilPath(regionMap, tendril, surface, base, tick)
local chunk = getChunkByPosition(regionMap, tendril.x, tendril.y)
local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives)
local tendrilUnit = tendril.unit
if not tendrilUnit.valid then
return
end
if (tendril.cycles > 0) then
tendril.cycles = tendril.cycles - 1
return
end
local tendrilPosition = tendrilUnit.position
local chunk = getChunkByPosition(regionMap, tendrilPosition.x, tendrilPosition.y)
if chunk then
local tendrilPath,tendrilDirection = scoreNeighborsWithDirection(chunk,
getNeighborChunks(regionMap,
chunk.cX,
chunk.cY),
validTendrilChunk,
scoreTendrilChunk,
nil,
surface,
true)
local tendrilPath,tendrilDirection = scoreNeighborsForAttack(chunk,
getNeighborChunks(regionMap,
chunk.cX,
chunk.cY),
scoreTendrilChunk,
nil)
if (tendrilDirection == -1) then
removeTendril(base, tendril)
tendrilUtils.buildTendril(regionMap, nil, base, surface, tick)
-- colorChunk(chunk.x, chunk.y, "hazard-concrete-left", surface)
-- removeTendril(base, tendril)
-- buildOutpost(regionMap, natives, base, surface, tendril)
-- tendrilUtils.buildTendril(regionMap, natives, base, surface, tick)
colorChunk(chunk.x, chunk.y, "hazard-concrete-left", surface)
return
elseif tendrilPath then
positionFromDirectionAndChunk(tendrilDirection, tendril, tendril, 0.5)
mapUtils.distortPosition(tendril)
tendril.path[#tendril.path] = chunk
positionFromDirectionAndChunk(tendrilDirection, tendrilPosition, tendrilPosition, 0.5)
mapUtils.distortPosition(tendrilPosition)
-- tendril.path[#tendril.path] = chunk
local position = surface.find_non_colliding_position("spitter-spawner",
{x=tendril.x,y=tendril.y},
tendrilPosition,
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)
2)
if position then
tendril.target = position
tendrilUnit.set_command({ type = defines.command.go_to_location,
destination = position,
distraction = defines.distraction.by_damage })
-- needs to check to make sure unit still exists as well.
--tendril.cycles = 2
-- 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)
colorChunk(chunk.x, chunk.y, "concrete", surface)
end
end
function tendrilUtils.advanceTendrils(regionMap, base, surface, tick)
function tendrilUtils.advanceTendrils(regionMap, base, surface, tick, natives)
for i=1, #base.tendrils do
buildTendrilPath(regionMap, base.tendrils[i], surface, base, tick)
buildTendrilPath(regionMap, base.tendrils[i], surface, base, tick, natives)
end
end
function tendrilUtils.createTendril(base)
function tendrilUtils.createTendril(base, surface)
local position = surface.find_non_colliding_position("small-tendril-biter-rampant",
{x=base.x,y=base.y},
32,
4)
if not position then
return nil
end
local entity = surface.create_entity({name="small-tendril-biter-rampant", position=position})
local tendril = {
x = base.x,
y = base.y,
unit = entity,
penalties = {},
target = entity.position,
cycles = 0,
path = {}
}
return tendril
end
@@ -117,10 +142,11 @@ function tendrilUtils.buildTendril(regionMap, natives, base, surface, tick)
-- if chunk then
-- local tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil}
-- buildTendrilPath(regionMap, chunk, surface, base, tempNeighbors)
base.tendrils[#base.tendrils+1] = tendrilUtils.createTendril(base)
local tendril = tendrilUtils.createTendril(base, surface)
if tendril then
base.tendrils[#base.tendrils+1] = tendril
end
-- end
end
return tendrilUtils
-39
View File
@@ -7,8 +7,6 @@ local constants = require("Constants")
-- constants
local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
local SQUAD_QUEUE_SIZE = constants.SQUAD_QUEUE_SIZE
local DEFINES_GROUP_STATE_FINISHED = defines.group_state.finished
@@ -17,8 +15,6 @@ 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
@@ -36,8 +32,6 @@ local mLog = math.log10
local mMin = math.min
local tableRemove = table.remove
local tableInsert = table.insert
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
-- module code
@@ -110,39 +104,6 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup)
return returnSquad
end
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
unitGroupUtils.recycleBiters(natives, group.members)
group.destroy()
end
return
end
end
if (#penalties == 7) then
tableRemove(penalties, 7)
end
tableInsert(penalties, 1, { v = MOVEMENT_PHEROMONE_GENERATOR_AMOUNT,
x = chunkX,
y = chunkY })
end
function unitGroupUtils.lookupSquadMovementPenalty(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
return penalty.v
end
end
return 0
end
function unitGroupUtils.calculateKamikazeThreshold(squad, natives)
local squadSizeBonus = mLog((#squad.group.members / natives.attackWaveMaxSize) + 0.1) + 1
return natives.kamikazeThreshold + (NO_RETREAT_SQUAD_SIZE_BONUS_MAX * squadSizeBonus)
+4
View File
@@ -11,6 +11,8 @@ small-fire-spitter=Small Fire Spitter
biter-spawner-hive=Small Hive
small-tendril-biter-rampant=Small Tendril
[entity-description]
tunnel-entrance=This tunnel is used by the biters to bypass player defenses. Fill the hole using landfill.
@@ -23,6 +25,8 @@ small-fire-spitter=These biters will spit fire
biter-spawner-hive=Small Hive
small-tendril-biter-rampant=Small Tendril
[mod-setting-name]
rampant-useDumbProjectiles=Use Dumb Projectiles
rampant-useNEUnitLaunchers=Use Natural Evolution Unit Launchers (Needs NE)
+2 -2
View File
@@ -77,8 +77,8 @@
(copyDirectory "prototypes" modFolder)))
(define (run)
;; (copyFiles modFolder)
(copyFiles modFolder)
;; (copyFiles zipModFolder)
(makeZip modFolder)
;;(makeZip modFolder)
)
)
+42
View File
@@ -0,0 +1,42 @@
-- imports
local biterUtils = require("BiterUtils")
-- import functions
local makeBiter = biterUtils.makeBiter
local createSuicideAttack = biterUtils.createSuicideAttack
local makeResistance = biterUtils.makeResistance
-- local
local smallSuicideBiterScale = 0.75
local smallSuicideBiterTint1 = {r=0.0, g=0.0, b=0.70, a=0.8}
local smallSuicideBiterTint2 = {r=0.0, g=0.0, b=0.72, a=0.4}
-- module code
data:extend({
makeBiter({name = "small-tendril-biter-rampant",
health = 30,
movement = 0.21,
distancePerFrame = 0.1,
healing = 0.01,
scale = smallSuicideBiterScale,
tint1 = smallSuicideBiterTint1,
tint2 = smallSuicideBiterTint2,
explosion = "blood-explosion-small"},
createSuicideAttack({ area = 3.5,
damage = 20,
explosion = "explosion",
scorchmark = "small-scorchmark",
explosionCount = 2,
explosionDistance = 2,
scale = smallSuicideBiterScale,
tint1 = smallSuicideBiterTint1,
tint2 = smallSuicideBiterTint2}),
{makeResistance("explosion", 0, -50),
makeResistance("laser", 1, 0),
makeResistance("fire", 0, -60)}),
})