Skip to content

Commit

Permalink
Scav Defensive Units Rework - Init. (beyond-all-reason#3671)
Browse files Browse the repository at this point in the history
- Mists no longer spawn
- Backup squads are now spawned by spawn beacons
- Backup squad spawn can be triggered by standing in the cloud, or by damaging unit close enough to a beacon
- Beacons no longer spawn freely at the start of the game. Instead they have big spawn box that is extension of the startbox, and it grows to be the whole map later in the game.
  • Loading branch information
Damgam authored Sep 2, 2024
1 parent 2246096 commit 49b13c6
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 73 deletions.
74 changes: 37 additions & 37 deletions luarules/gadgets/scav_cloud_spawner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,43 +52,43 @@ function gadget:GameFrame(frame)
if GG.IsPosInRaptorScum(randomx, randomy, randomz) then
Spring.SpawnCEG("scavradiation-lightning",randomx,randomy+100,randomz,0,0,0)

if math.random(0, 10) == 0 then
if Spring.GetGameRulesParam("scavTechAnger") > 10 and Spring.GetGameRulesParam("scavTechAnger") < 50 and Spring.GetTeamUnitDefCount(scavTeamID, UnitDefNames["scavmist_scav"].id) < maxMists then
local mist = Spring.CreateUnit("scavmist_scav", randomx, randomy, randomz, math.random(0,3), scavTeamID)
if mist then
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
end
end
elseif math.random(0, 10) == 0 then
if Spring.GetGameRulesParam("scavTechAnger") > 40 and Spring.GetGameRulesParam("scavTechAnger") < 90 and Spring.GetTeamUnitDefCount(scavTeamID, UnitDefNames["scavmistxl_scav"].id) < maxMists then
local mist = Spring.CreateUnit("scavmistxl_scav", randomx, randomy, randomz, math.random(0,3), scavTeamID)
if mist then
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
end
end
elseif math.random(0, 10) == 0 then
if Spring.GetGameRulesParam("scavTechAnger") > 80 and Spring.GetTeamUnitDefCount(scavTeamID, UnitDefNames["scavmistxxl_scav"].id) < maxMists then
local mist = Spring.CreateUnit("scavmistxxl_scav", randomx, randomy, randomz, math.random(0,3), scavTeamID)
if mist then
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
end
end
end
--if math.random(0, 10) == 0 then
-- if Spring.GetGameRulesParam("scavTechAnger") > 10 and Spring.GetGameRulesParam("scavTechAnger") < 50 and Spring.GetTeamUnitDefCount(scavTeamID, UnitDefNames["scavmist_scav"].id) < maxMists then
-- local mist = Spring.CreateUnit("scavmist_scav", randomx, randomy, randomz, math.random(0,3), scavTeamID)
-- if mist then
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- end
-- end
--elseif math.random(0, 10) == 0 then
-- if Spring.GetGameRulesParam("scavTechAnger") > 40 and Spring.GetGameRulesParam("scavTechAnger") < 90 and Spring.GetTeamUnitDefCount(scavTeamID, UnitDefNames["scavmistxl_scav"].id) < maxMists then
-- local mist = Spring.CreateUnit("scavmistxl_scav", randomx, randomy, randomz, math.random(0,3), scavTeamID)
-- if mist then
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- end
-- end
--elseif math.random(0, 10) == 0 then
-- if Spring.GetGameRulesParam("scavTechAnger") > 80 and Spring.GetTeamUnitDefCount(scavTeamID, UnitDefNames["scavmistxxl_scav"].id) < maxMists then
-- local mist = Spring.CreateUnit("scavmistxxl_scav", randomx, randomy, randomz, math.random(0,3), scavTeamID)
-- if mist then
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- Spring.GiveOrderToUnit(mist, CMD.PATROL, {randomx+math.random(-256,256), randomy, randomz+math.random(-256,256)}, {"shift"})
-- end
-- end
--end
end

for i = 1,5 do
Expand Down
116 changes: 86 additions & 30 deletions luarules/gadgets/scav_spawner_defense.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ if gadgetHandler:IsSyncedCode() then
waveCommanderCount = 0,
waveDecoyCommanders = {},
waveDecoyCommanderCount = 0,
}
},
lastBackupSquadSpawnFrame = 0,
}
local squadSpawnOptions = config.squadSpawnOptionsTable
--local miniBossCooldown = 0
Expand Down Expand Up @@ -678,7 +679,23 @@ if gadgetHandler:IsSyncedCode() then

end

function SpawnRandomOffWaveSquad(burrowID, scavType, count)
function getNearestScavBeacon(tx, ty, tz)
local nearestBurrow = nil
local nearestDistance = 999999
for burrowID, _ in pairs(burrows) do
local bx, by, bz = GetUnitPosition(burrowID)
if bx and by and bz then
local distance = math.ceil((math.abs(tx-bx) + math.abs(ty-by) + math.abs(tz-bz))*0.5)
if distance < nearestDistance then
nearestDistance = distance
nearestBurrow = burrowID
end
end
end
return nearestBurrow, nearestDistance
end

function SpawnRandomOffWaveSquad(burrowID, attackNearestEnemy, scavType, count)
if gameOver then
return
end
Expand All @@ -693,7 +710,7 @@ if gadgetHandler:IsSyncedCode() then
for j = 1, unitNumber, 1 do
if mRandom() <= config.spawnChance or j == 1 then
squadCounter = squadCounter + 1
table.insert(spawnQueue, { burrow = burrowID, unitName = scavName, team = scavTeamID, squadID = squadCounter })
table.insert(spawnQueue, { burrow = burrowID, unitName = scavName, team = scavTeamID, squadID = squadCounter, attackNearestEnemy = attackNearestEnemy })
end
end
end
Expand Down Expand Up @@ -741,7 +758,7 @@ if gadgetHandler:IsSyncedCode() then
for j = 1, unitNumber, 1 do
if mRandom() <= config.spawnChance or j == 1 then
squadCounter = squadCounter + 1
table.insert(spawnQueue, { burrow = burrowID, unitName = scavName, team = scavTeamID, squadID = squadCounter })
table.insert(spawnQueue, { burrow = burrowID, unitName = scavName, team = scavTeamID, squadID = squadCounter, attackNearestEnemy = attackNearestEnemy })
end
end
end
Expand All @@ -763,7 +780,7 @@ if gadgetHandler:IsSyncedCode() then
local spawnPosX, spawnPosY, spawnPosZ

if config.burrowSpawnType ~= "avoid" then
if config.useScum then -- Attempt #1, find position in creep/scum (skipped if creep is disabled or alwaysbox is enabled)
if config.useScum and (canSpawnBurrow and GetGameSeconds() >= config.gracePeriod) then -- Attempt #1, find position in creep/scum (skipped if creep is disabled)
for _ = 1,1000 do
spawnPosX = mRandom(spread, MAPSIZEX - spread)
spawnPosZ = mRandom(spread, MAPSIZEZ - spread)
Expand All @@ -784,39 +801,39 @@ if gadgetHandler:IsSyncedCode() then
end
end

if (not canSpawnBurrow) then -- Attempt #2 Force spawn in Startbox, ignore any kind of player vision
for _ = 1,100 do
spawnPosX = mRandom(ScavStartboxXMin + spread, ScavStartboxXMax - spread)
spawnPosZ = mRandom(ScavStartboxZMin + spread, ScavStartboxZMax - spread)
if (not canSpawnBurrow) then -- Attempt #3 Find some good position in Spawnbox (not Startbox)
for _ = 1,1000 do
spawnPosX = mRandom(lsx1 + spread, lsx2 - spread)
spawnPosZ = mRandom(lsz1 + spread, lsz2 - spread)
spawnPosY = Spring.GetGroundHeight(spawnPosX, spawnPosZ)
canSpawnBurrow = positionCheckLibrary.FlatAreaCheck(spawnPosX, spawnPosY, spawnPosZ, spread, 30, true)
if canSpawnBurrow then
canSpawnBurrow = positionCheckLibrary.OccupancyCheck(spawnPosX, spawnPosY, spawnPosZ, spread)
end
if canSpawnBurrow and noScavStartbox then -- this is for case where they have no startbox. We don't want them spawning on top of your stuff.
if canSpawnBurrow then
canSpawnBurrow = positionCheckLibrary.VisibilityCheckEnemy(spawnPosX, spawnPosY, spawnPosZ, spread, scavAllyTeamID, true, true, true)
end
if canSpawnBurrow then
canSpawnBurrow = positionCheckLibrary.VisibilityCheck(spawnPosX, spawnPosY, spawnPosZ, spread, scavAllyTeamID, true, false, false)
end
if canSpawnBurrow then
break
end
end
end

if (not canSpawnBurrow) then -- Attempt #3 Find some good position in Spawnbox (not Startbox)
if (not canSpawnBurrow) then -- Attempt #2 Force spawn in Startbox, ignore any kind of player vision
for _ = 1,100 do
spawnPosX = mRandom(lsx1 + spread, lsx2 - spread)
spawnPosZ = mRandom(lsz1 + spread, lsz2 - spread)
spawnPosX = mRandom(ScavStartboxXMin + spread, ScavStartboxXMax - spread)
spawnPosZ = mRandom(ScavStartboxZMin + spread, ScavStartboxZMax - spread)
spawnPosY = Spring.GetGroundHeight(spawnPosX, spawnPosZ)
canSpawnBurrow = positionCheckLibrary.FlatAreaCheck(spawnPosX, spawnPosY, spawnPosZ, spread, 30, true)
if canSpawnBurrow then
canSpawnBurrow = positionCheckLibrary.OccupancyCheck(spawnPosX, spawnPosY, spawnPosZ, spread)
end
if canSpawnBurrow then
if canSpawnBurrow and noScavStartbox then -- this is for case where they have no startbox. We don't want them spawning on top of your stuff.
canSpawnBurrow = positionCheckLibrary.VisibilityCheckEnemy(spawnPosX, spawnPosY, spawnPosZ, spread, scavAllyTeamID, true, true, true)
end
if canSpawnBurrow then
canSpawnBurrow = not (positionCheckLibrary.VisibilityCheck(spawnPosX, spawnPosY, spawnPosZ, spread, scavAllyTeamID, true, false, false)) -- we need to reverse result of this, because we want this to be true when pos is in LoS of Scav team, and the visibility check does the opposite.
end
if canSpawnBurrow then
break
end
Expand Down Expand Up @@ -878,14 +895,14 @@ if gadgetHandler:IsSyncedCode() then
end
end

if (canSpawnBurrow and GetGameSeconds() < config.gracePeriod) or (canSpawnBurrow and config.burrowSpawnType == "avoid") then -- Don't spawn new burrows in existing creep during grace period - Force them to spread as much as they can..... AT LEAST THAT'S HOW IT'S SUPPOSED TO WORK, lol.
canSpawnBurrow = not GG.IsPosInRaptorScum(spawnPosX, spawnPosY, spawnPosZ)
end

if canSpawnBurrow and (positionCheckLibrary.LandOrSeaCheck(spawnPosX, spawnPosY, spawnPosZ, config.burrowSize) == "mixed" or positionCheckLibrary.LandOrSeaCheck(spawnPosX, spawnPosY, spawnPosZ, config.burrowSize) == "death") then
canSpawnBurrow = false
end

if (canSpawnBurrow and GetGameSeconds() < config.gracePeriod) then -- Don't spawn new burrows in existing creep during grace period - Force them to spread as much as they can..... AT LEAST THAT'S HOW IT'S SUPPOSED TO WORK, lol.
canSpawnBurrow = not GG.IsPosInRaptorScum(spawnPosX, spawnPosY, spawnPosZ)
end

if canSpawnBurrow then
for name,data in pairs(config.burrowUnitsList) do
if math.random() <= config.spawnChance and data.minAnger < math.max(1, techAnger) and data.maxAnger > math.max(1, techAnger) then
Expand Down Expand Up @@ -1407,7 +1424,7 @@ if gadgetHandler:IsSyncedCode() then
local unitName = UnitDefs[unitDefID].name
if config.scavMinions[unitName] then
local minion = config.scavMinions[unitName][mRandom(1,#config.scavMinions[unitName])]
SpawnRandomOffWaveSquad(unitID, minion, 4)
SpawnRandomOffWaveSquad(unitID, true, minion, 4)
end
end

Expand Down Expand Up @@ -1462,6 +1479,19 @@ if gadgetHandler:IsSyncedCode() then

if unitTeam == scavTeamID then
damage = damage / config.healthMod

if math.random(0,600) == 0 and attackerTeam ~= gaiaTeamID and waveParameters.lastBackupSquadSpawnFrame+600 < Spring.GetGameFrame() and attackerID then
local ux, uy, uz = Spring.GetUnitPosition(attackerID)
local burrow, distance = getNearestScavBeacon(ux, uy, uz)
--Spring.Echo("Nearest Beacon Distance", distance)
if ux and burrow and distance and distance < 2500 then
waveParameters.lastBackupSquadSpawnFrame = Spring.GetGameFrame()
--Spring.Echo("Spawning Backup Squad - Unit Damaged", Spring.GetGameFrame())
for i = 1, SetCount(humanTeams) do
SpawnRandomOffWaveSquad(getNearestScavBeacon(ux, uy, uz), true)
end
end
end
end

if unitID == bossID then -- Boss Resistance
Expand Down Expand Up @@ -1687,9 +1717,24 @@ if gadgetHandler:IsSyncedCode() then
Spring.SetUnitAlwaysVisible(unitID, true)
end

GiveOrderToUnit(unitID, CMD.IDLEMODE, { 0 }, { "shift" })
GiveOrderToUnit(unitID, CMD.MOVE, { x + mRandom(-128, 128), y, z + mRandom(-128, 128) }, { "shift" })
GiveOrderToUnit(unitID, CMD.MOVE, { x + mRandom(-128, 128), y, z + mRandom(-128, 128) }, { "shift" })
if defs.attackNearestEnemy then
local nearestEnemy = Spring.GetUnitNearestEnemy(unitID, 999999, false)
if nearestEnemy then
local tx,ty,tz = Spring.GetUnitPosition(nearestEnemy)
if tx then
--Spring.Echo("Gave Defensive Order")
GiveOrderToUnit(unitID, CMD.STOP, 0, 0)
GiveOrderToUnit(unitID, CMD.IDLEMODE, { 0 }, 0)
GiveOrderToUnit(unitID, CMD.FIGHT, { tx + mRandom(-128, 128), ty, tz + mRandom(-128, 128) }, { "shift" })
GiveOrderToUnit(unitID, CMD.FIGHT, { tx + mRandom(-128, 128), ty, tz + mRandom(-128, 128) }, { "shift" })
end
end
else
GiveOrderToUnit(unitID, CMD.STOP, 0, 0)
GiveOrderToUnit(unitID, CMD.IDLEMODE, { 0 }, 0)
GiveOrderToUnit(unitID, CMD.MOVE, { x + mRandom(-128, 128), y, z + mRandom(-128, 128) }, { "shift" })
GiveOrderToUnit(unitID, CMD.MOVE, { x + mRandom(-128, 128), y, z + mRandom(-128, 128) }, { "shift" })
end

setScavXP(unitID)
end
Expand Down Expand Up @@ -1728,11 +1773,12 @@ if gadgetHandler:IsSyncedCode() then
end

function updateScavSpawnBox()
if config.burrowSpawnType == "initialbox_post" then
lsx1 = math.max(ScavStartboxXMin - ((MAPSIZEX*0.01) * techAnger), 0)
lsz1 = math.max(ScavStartboxZMin - ((MAPSIZEZ*0.01) * techAnger), 0)
lsx2 = math.min(ScavStartboxXMax + ((MAPSIZEX*0.01) * techAnger), MAPSIZEX)
lsz2 = math.min(ScavStartboxZMax + ((MAPSIZEZ*0.01) * techAnger), MAPSIZEZ)
if config.burrowSpawnType == "initialbox_post" or config.burrowSpawnType == "initialbox" then
lsx1 = math.max(ScavStartboxXMin - ((MAPSIZEX*0.01) * (techAnger+30)), 0)
lsz1 = math.max(ScavStartboxZMin - ((MAPSIZEZ*0.01) * (techAnger+30)), 0)
lsx2 = math.min(ScavStartboxXMax + ((MAPSIZEX*0.01) * (techAnger+30)), MAPSIZEX)
lsz2 = math.min(ScavStartboxZMax + ((MAPSIZEZ*0.01) * (techAnger+30)), MAPSIZEZ)
--Spring.Echo("lsx1", lsx1, "lsx2", lsx2, "lsz1", lsz1, "lsz2", lsz2)
end
end

Expand Down Expand Up @@ -1960,6 +2006,16 @@ if gadgetHandler:IsSyncedCode() then
if math.random() <= 0.1 then
Spring.SpawnCEG("scavmist", ux, uy+100, uz, 0,0,0)
end
if math.random(0,60) == 0 and Spring.GetUnitTeam(unitID) ~= gaiaTeamID and waveParameters.lastBackupSquadSpawnFrame+600 < Spring.GetGameFrame() then
local burrow, distance = getNearestScavBeacon(ux, uy, uz)
--Spring.Echo("Nearest Beacon Distance", distance)
if ux and burrow and distance and distance < 5000 then
--Spring.Echo("Spawning Backup Squad - Unit Cloud Capture", Spring.GetGameFrame())
for i = 1, SetCount(humanTeams) do
SpawnRandomOffWaveSquad(getNearestScavBeacon(ux, uy, uz), true)
end
end
end
GG.addUnitToCaptureDecay(unitID)
end
elseif Spring.GetUnitTeam(unitID) == scavTeamID and captureLevel > 0 then
Expand Down
Loading

0 comments on commit 49b13c6

Please sign in to comment.