1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-03 22:52:20 +02:00
Rampant/prototypes/SwarmUtils.lua
2021-12-28 09:17:56 -08:00

1475 lines
63 KiB
Lua

local swarmUtils = {}
-- imports
local bombUtils = require("utils/BombUtils")
local attackFlame = require("utils/AttackFlame")
local energyThiefFaction = require("EnergyThief")
local poisonFaction = require("Poison")
local beamUtils = require("utils/BeamUtils")
local acidBall = require("utils/AttackBall")
local droneUtils = require("utils/DroneUtils")
local biterUtils = require("utils/BiterUtils")
local particleUtils = require("utils/ParticleUtils")
local stickerUtils = require("utils/StickerUtils")
local unitUtils = require("utils/UnitUtils")
local fireUtils = require("utils/FireUtils")
local constants = require("__Rampant__/libs/Constants")
local mathUtils = require("__Rampant__/libs/MathUtils")
-- imported functions
local roundToNearest = mathUtils.roundToNearest
local mMax = math.max
local mMin = math.min
local distort = mathUtils.distort
local deepcopy = util.table.deepcopy
local TIER_UPGRADE_SET_10 = constants.TIER_UPGRADE_SET_10
local xorRandom = mathUtils.xorRandom(settings.startup["rampant--enemySeed"].value)
local biterattackanimation = unitUtils.biterattackanimation
local createProjectileAttack = biterUtils.createProjectileAttack
local createCapsuleProjectile = droneUtils.createCapsuleProjectile
local makeSticker = stickerUtils.makeSticker
local makeAtomicBlast = bombUtils.makeAtomicBlast
local makeLaser = beamUtils.makeLaser
local createAttackBall = acidBall.createAttackBall
local createRangedAttack = biterUtils.createRangedAttack
local createMeleeAttack = biterUtils.createMeleeAttack
local makeAcidSplashFire = fireUtils.makeAcidSplashFire
local makeWormAlienLootTable = biterUtils.makeWormAlienLootTable
local makeUnitAlienLootTable = biterUtils.makeUnitAlienLootTable
local makeSpawnerAlienLootTable = biterUtils.makeSpawnerAlienLootTable
local createSuicideAttack = biterUtils.createSuicideAttack
local createAttackFlame = attackFlame.createAttackFlame
local createStreamAttack = biterUtils.createStreamAttack
local gaussianRandomRangeRG = mathUtils.gaussianRandomRangeRG
local makeBloodFountains = particleUtils.makeBloodFountains
local makeBubble = beamUtils.makeBubble
local makeBeam = beamUtils.makeBeam
local createElectricAttack = biterUtils.createElectricAttack
local createBeamAttack = biterUtils.createBeamAttack
local makeBiter = biterUtils.makeBiter
local makeDrone = droneUtils.makeDrone
local makeSpitter = biterUtils.makeSpitter
local makeWorm = biterUtils.makeWorm
local makeUnitSpawner = biterUtils.makeUnitSpawner
-- module code
local scorchmarkTiers = {
"small-scorchmark",
"small-scorchmark",
"medium-scorchmark",
"medium-scorchmark",
"medium-scorchmark",
"big-scorchmark",
"big-scorchmark",
"big-scorchmark",
"huge-scorchmark",
"huge-scorchmark"
}
local explosionTiers = {
"explosion",
"explosion",
"big-explosion",
"big-explosion",
"big-explosion",
"big-explosion",
"massive-explosion",
"massive-explosion",
"massive-explosion",
"massive-explosion"
}
local bloodFountains = {
"blood-explosion-small-rampant",
"blood-explosion-small-rampant",
"blood-explosion-small-rampant",
"blood-explosion-small-rampant",
"blood-explosion-big-rampant",
"blood-explosion-big-rampant",
"blood-explosion-big-rampant",
"blood-explosion-huge-rampant",
"blood-explosion-huge-rampant",
"blood-explosion-huge-rampant",
}
local nuclearAttackNumeric = {
["damage"] = { 15, 15, 25, 25, 35, 35, 45, 45, 55, 55 },
["repeatCount"] = { 150, 175, 250, 300, 350, 400, 450, 500, 550, 600 },
["radius"] = { 5, 10, 10, 12, 14, 16, 16, 18, 18, 20 },
["explosionDistance"] = { 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 },
["explosionCount"] = { 3, 3, 3, 4, 4, 4, 5, 5, 6, 6 }
}
local bombAttackNumeric = {
["damage"] = { 75, 112, 150, 187, 270, 360, 600, 720, 975, 1050 },
["radius"] = { 1.75, 1.75, 2, 2.5, 3, 3, 3.5, 3.5, 3.75, 4 },
["explosionDistance"] = { 2, 2, 2, 2, 2, 2.5, 2.5, 2.5, 3, 3 },
["explosionCount"] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
}
local streamAttackNumeric = {
["stickerDamagePerTick"] = { 0.6, 0.6, 0.8, 0.8, 0.8, 0.9, 1, 1, 1.3, 1.5 },
["particleTimeout"] = { 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 },
["fireSpreadRadius"] = { 0.75, 0.75, 0.77, 0.77, 0.79, 0.79, 0.83, 0.83, 0.85, 0.85 },
["damageMaxMultipler"] = { 6, 6, 7, 7, 7, 7, 8, 8, 8, 9 },
["stickerMovementModifier"] = { 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1 },
["fireSpreadCooldown"] = { 30, 30, 29, 29, 28, 28, 27, 27, 25, 25 },
["stickerDuration"] = { 800, 800, 900, 900, 1000, 1000, 1100, 1100, 1200, 1200 },
["damage"] = { 3, 3, 4, 4, 5, 5, 5, 5, 5, 6 }
}
local beamAttackNumeric = {
["range"] = { 11, 11, 12, 12, 13, 13, 14, 14, 15, 15 },
["damage"] = { 3.6, 6, 9, 12, 18, 27, 36, 45, 54, 90 },
["duration"] = { 20, 20, 21, 21, 22, 22, 23, 23, 24, 24 },
["damageInterval"] = { 20, 20, 21, 21, 22, 22, 23, 23, 24, 24 },
["width"] = { 1.5, 1.5, 1.6, 1.6, 1.7, 1.7, 1.8, 1.8, 1.9, 1.9 }
}
local clusterAttackNumeric = {
["clusterDistance"] = { 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 },
["clusters"] = { 5, 5, 6, 6, 7, 7, 8, 8, 9, 9 },
["startingSpeed"] = { 0.25, 0.25, 0.27, 0.27, 0.29, 0.29, 0.31, 0.31, 0.33, 0.33 }
}
local liteClusterAttackNumeric = {
["clusterDistance"] = { 2, 2, 3, 3, 3, 4, 4, 4, 5, 5 },
["clusters"] = { 2, 2, 3, 3, 4, 4, 5, 5, 6, 6 },
["startingSpeed"] = { 0.25, 0.25, 0.27, 0.27, 0.29, 0.29, 0.31, 0.31, 0.33, 0.33 },
["damage"] = { 4, 7.5, 11.25, 15, 22.5, 27.5, 32.5, 37.5, 42.5, 47.5 }
}
local biterAttributeNumeric = {
["range"] = { 0.5, 0.5, 0.75, 0.75, 1.0, 1.0, 1.25, 1.50, 1.75, 2.0 },
["radius"] = { 0.5, 0.65, 0.75, 0.85, 0.95, 1.1, 1.2, 1.3, 1.4, 1.5 },
["cooldown"] = { 40, 41, 42, 44, 46, 48, 50, 52, 55, 57 },
["damage"] = { 16, 35, 65, 85, 115, 145, 175, 205.0, 235.0, 265.0 },
["scale"] = { 0.25, 0.40, 0.60, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8 },
["healing"] = { 0.01, 0.01, 0.015, 0.02, 0.05, 0.075, 0.1, 0.12, 0.14, 0.16 },
["physicalDecrease"] = { 0, 0, 4, 5, 6, 8, 11, 13, 16, 17 },
["physicalPercent"] = { 0, 0, 0, 10, 12, 12, 14, 16, 18, 20 },
["explosionDecrease"] = { 0, 0, 0, 0, 0, 10, 12, 14, 16, 20 },
["explosionPercent"] = { 0, 0, 0, 10, 12, 13, 15, 16, 17, 20 },
-- ["distancePerFrame"] = { 0.1, 0.125, 0.15, 0.19, 0.195, 0.2, 0.2, 0.2, 0.2, 0.2 },
["distancePerFrame"] = { 0.08, 0.10, 0.125, 0.15, 0.18, 0.195, 0.2, 0.2, 0.2, 0.2 },
["movement"] = { 0.2, 0.19, 0.185, 0.18, 0.175, 0.17, 0.17, 0.17, 0.17, 0.17 },
["health"] = { 15, 75, 150, 250, 1000, 2000, 3500, 7500, 15000, 30000 },
["pollutionToAttack"] = { 10, 40, 80, 120, 200, 300, 450, 550, 650, 750 },
["spawningTimeModifer"] = { 1, 1, 2, 2, 4, 4, 6, 6, 8, 8 }
}
local acidPuddleAttributeNumeric = {
["damagePerTick"] = { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5 },
["stickerDamagePerTick"] = { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5 },
["stickerDuration"] = { 600, 610, 620, 630, 640, 650, 660, 670, 680, 690 }
}
local spitterAttributeNumeric = {
["range"] = { 11, 11, 11, 12, 12, 12, 13, 13, 14, 14 },
["radius"] = { 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.5 },
["cooldown"] = { 100, 100, 97, 97, 95, 95, 93, 93, 90, 90 },
["warmup"] = { 30, 29, 28, 27, 26, 25, 24, 23, 22, 21 },
["stickerDuration"] = { 600, 610, 620, 630, 640, 650, 660, 670, 680, 690 },
["damagePerTick"] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1 },
["stickerDamagePerTick"] = { 0.025, 0.05, 0.075, 0.1, 0.125, 0.15, 0.175, 0.2, 0.225, 0.25 },
["stickerMovementModifier"] = { 0.97, 0.96, 0.95, 0.94, 0.93, 0.92, 0.91, 0.90, 0.89, 0.88 },
["damage"] = { 4, 7.5, 11.25, 15, 22.5, 27.5, 32.5, 37.5, 42.5, 47.5 },
["particleVerticalAcceleration"] = { 0.01, 0.01, 0.02, 0.02, 0.03, 0.03, 0.04, 0.04, 0.05, 0.05 },
["particleHoizontalSpeed"] = { 0.6, 0.6, 0.7, 0.7, 0.8, 0.8, 0.9, 0.9, 1, 1 },
["particleHoizontalSpeedDeviation"] = { 0.0025, 0.0025, 0.0024, 0.0024, 0.0023, 0.0023, 0.0022, 0.0022, 0.0021, 0.0021 },
["scale"] = { 0.25, 0.40, 0.60, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8 },
["healing"] = { 0.01, 0.01, 0.015, 0.02, 0.05, 0.075, 0.1, 0.12, 0.14, 0.16 },
["physicalDecrease"] = { 0, 0, 0, 0, 2, 4, 6, 8, 10, 12 },
["physicalPercent"] = { 0, 0, 0, 10, 12, 12, 14, 14, 15, 15 },
["explosionPercent"] = { 0, 0, 10, 10, 20, 20, 30, 30, 40, 40 },
["distancePerFrame"] = { 0.04, 0.045, 0.050, 0.055, 0.060, 0.065, 0.067, 0.069, 0.071, 0.073 },
["movement"] = { 0.185, 0.18, 0.18, 0.17, 0.17, 0.16, 0.16, 0.15, 0.15, 0.14 },
["health"] = { 10, 50, 200, 350, 1250, 2250, 3250, 6500, 12500, 25000 },
["pollutionToAttack"] = { 10, 40, 80, 120, 200, 300, 450, 550, 650, 750 },
["spawningTimeModifer"] = { 1, 1, 2, 2, 4, 4, 6, 6, 8, 8 }
}
local droneAttributeNumeric = {
["scale"] = { 0.3, 0.32, 0.34, 0.36, 0.4, 0.42, 0.44, 0.5, 0.52, 0.54 },
["particleVerticalAcceleration"] = { 0.01, 0.01, 0.02, 0.02, 0.03, 0.03, 0.04, 0.04, 0.05, 0.05 },
["particleHoizontalSpeed"] = { 0.6, 0.6, 0.7, 0.7, 0.8, 0.8, 0.9, 0.9, 1, 1 },
["particleHoizontalSpeedDeviation"] = { 0.0025, 0.0025, 0.0024, 0.0024, 0.0023, 0.0023, 0.0022, 0.0022, 0.0021, 0.0021 },
["stickerDuration"] = { 600, 610, 620, 630, 640, 650, 660, 670, 680, 690 },
["stickerMovementModifier"] = { 0.8, 0.8, 0.75, 0.75, 0.7, 0.7, 0.65, 0.65, 0.5, 0.5 },
["damagePerTick"] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1 },
["cooldown"] = { 60, 60, 55, 55, 50, 50, 45, 45, 40, 40 },
["warmup"] = { 20, 19, 18, 17, 16, 15, 14, 13, 12, 11 },
["ttl"] = { 300, 300, 350, 350, 400, 400, 450, 450, 500, 500 },
["damage"] = { 2, 4, 7, 13, 15, 18, 22, 28, 35, 40 },
["movement"] = { 0.06, 0.06, 0.07, 0.07, 0.08, 0.08, 0.09, 0.09, 0.1, 0.1 },
["distancePerFrame"] = { 0.1, 0.1, 0.105, 0.105, 0.110, 0.110, 0.112, 0.112, 0.114, 0.114 },
["rangeFromPlayer"] = { 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 },
["range"] = { 10, 10, 11, 11, 12, 12, 13, 13, 14, 14 },
["radius"] = { 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.5 },
["health"] = { 15, 75, 100, 150, 200, 250, 275, 300, 325, 350 },
["healing"] = { 0.01, 0.01, 0.015, 0.02, 0.05, 0.075, 0.1, 0.12, 0.14, 0.16 },
}
local unitSpawnerAttributeNumeric = {
["health"] = { 350, 500, 750, 1500, 3500, 7500, 11000, 20000, 30000, 45000 },
["healing"] = { 0.02, 0.02, 0.022, 0.024, 0.026, 0.028, 0.03, 0.032, 0.034, 0.036 },
["spawningCooldownStart"] = { 1080, 1075, 1070, 1065, 1060, 1055, 1050, 1045, 1040, 1035 },
["spawningCooldownEnd"] = { 350, 345, 340, 335, 330, 325, 320, 315, 310, 305 },
["unitsToSpawn"] = { 11, 11, 12, 12, 13, 13, 14, 14, 15, 15 },
["scale"] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8 },
["unitsOwned"] = { 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 },
["physicalDecrease"] = { 1, 2, 3, 4, 6, 6, 8, 10, 12, 14 },
["physicalPercent"] = { 15, 15, 17, 17, 18, 18, 19, 19, 20, 20 },
["explosionDecrease"] = { 5, 5, 6, 6, 7, 7, 8, 8, 9, 9 },
["explosionPercent"] = { 15, 15, 17, 17, 18, 18, 19, 19, 20, 20 },
["fireDecrease"] = { 3, 3, 4, 4, 4, 4, 4, 4, 5, 5 },
["firePercent"] = { 40, 40, 42, 42, 43, 43, 44, 44, 45, 45 },
["evolutionRequirement"] = { 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 },
["cooldown"] = { 50, 50, 45, 45, 40, 40, 35, 35, 30, 30 }
}
local hiveAttributeNumeric = {
["health"] = { 700, 1000, 1500, 3000, 7000, 15000, 22000, 40000, 60000, 90000 },
["healing"] = { 0.02, 0.02, 0.022, 0.024, 0.026, 0.028, 0.03, 0.032, 0.034, 0.036 },
["spawningCooldownStart"] = { 4970, 4930, 4890, 4850, 4810, 4780, 4740, 4700, 4660, 4620 },
-- ["spawningCooldownStart"] = { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 },
["spawningRadius"] = { 10, 13, 15, 17, 20, 23, 26, 29, 32, 35 },
["spawningSpacing"] = { 5, 5, 5, 6, 6, 6, 7, 7, 7, 8 },
["spawningCooldownEnd"] = { 1785, 1780, 1775, 1770, 1765, 1760, 1755, 1750, 1745, 1740 },
-- ["spawningCooldownEnd"] = { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 },
["unitsToSpawn"] = { 3000, 3000, 300, 3000, 3000, 3000, 3000, 3000, 3000, 3000 },
["scale"] = { 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1 },
["unitsOwned"] = { 7, 7, 8, 8, 9, 9, 10, 10, 11, 11 },
["physicalDecrease"] = { 1, 2, 3, 4, 6, 6, 8, 10, 12, 14 },
["physicalPercent"] = { 15, 15, 17, 17, 18, 18, 19, 19, 20, 20 },
["explosionDecrease"] = { 5, 5, 6, 6, 7, 7, 8, 8, 9, 9 },
["explosionPercent"] = { 15, 15, 17, 17, 18, 18, 19, 19, 20, 20 },
["fireDecrease"] = { 3, 3, 4, 4, 4, 4, 4, 4, 5, 5 },
["firePercent"] = { 40, 40, 42, 42, 43, 43, 44, 44, 45, 45 },
["evolutionRequirement"] = { 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 },
["cooldown"] = { 50, 50, 45, 45, 40, 40, 35, 35, 30, 30 }
}
local wormAttributeNumeric = {
["stickerDuration"] = { 800, 810, 820, 830, 840, 850, 860, 870, 880, 890 },
["stickerMovementModifier"] = { 0.8, 0.8, 0.75, 0.75, 0.7, 0.7, 0.65, 0.65, 0.5, 0.5 },
["damagePerTick"] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1 },
["range"] = { 25, 27, 31, 33, 35, 36, 37, 38, 39, 40 },
["cooldown"] = { 70, 70, 68, 66, 64, 62, 60, 58, 56, 54 },
["damage"] = { 12, 22.5, 33.75, 45, 67.5, 82.5, 97.5, 112.5, 127.5, 142.5 },
["scale"] = { 0.25, 0.40, 0.60, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8 },
["radius"] = { 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.3, 2.5, 3.0 },
["stickerDamagePerTick"] = { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5 },
["particleVerticalAcceleration"] = { 0.01, 0.01, 0.02, 0.02, 0.03, 0.03, 0.04, 0.04, 0.05, 0.05 },
["particleHoizontalSpeed"] = { 0.6, 0.6, 0.7, 0.7, 0.8, 0.8, 0.9, 0.9, 1, 1 },
["particleHoizontalSpeedDeviation"] = { 0.0025, 0.0025, 0.0024, 0.0024, 0.0023, 0.0023, 0.0022, 0.0022, 0.0021, 0.0021 },
["foldingSpeed"] = { 0.15, 0.15, 0.16, 0.16, 0.16, 0.17, 0.17, 0.18, 0.18, 0.19 },
["preparingSpeed"] = { 0.025, 0.025, 0.026, 0.026, 0.027, 0.027, 0.028, 0.028, 0.029, 0.029 },
["prepareRange"] = { 30, 30, 35, 35, 40, 40, 40, 40, 45, 45 },
["physicalDecrease"] = { 0, 0, 5, 5, 8, 8, 10, 10, 12, 12 },
["explosionDecrease"] = { 0, 0, 5, 5, 8, 8, 10, 10, 12, 12 },
["explosionPercent"] = { 0, 0, 10, 10, 20, 20, 30, 30, 40, 40 },
["fireDecrease"] = { 3, 3, 4, 4, 5, 5, 5, 5, 5, 6 },
["health"] = { 200, 350, 500, 750, 2000, 3500, 7500, 12000, 20000, 25000 },
["firePercent"] = { 40, 40, 42, 42, 43, 43, 44, 44, 45, 45 },
["healing"] = { 0.01, 0.01, 0.015, 0.02, 0.05, 0.075, 0.1, 0.12, 0.14, 0.16 },
["evolutionRequirement"] = { 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 }
}
local propTables10 = {
{{0, 1}, {0.65, 0.0}},
{{0.3, 0}, {0.35, 0.5}, {0.80, 0.0}},
{{0.4, 0}, {0.45, 0.5}, {0.90, 0.0}},
{{0.5, 0}, {0.55, 0.5}, {0.90, 0.0}},
{{0.6, 0}, {0.65, 0.5}, {0.95, 0.0}},
{{0.7, 0}, {0.75, 0.5}, {0.975, 0.0}},
{{0.8, 0}, {0.825, 0.5}, {0.975, 0.0}},
{{0.85, 0}, {0.875, 0.5}, {0.975, 0.0}},
{{0.90, 0}, {0.925, 0.5}, {0.975, 0.0}},
{{0.93, 0}, {1, 1.0}}
}
local function fillUnitTable(result, unitSet, tier, probability)
for x=1,#unitSet[tier] do
result[#result+1] = {unitSet[tier][x], probability}
end
end
local function unitSetToProbabilityTable(unitSet)
local result = {}
fillUnitTable(result, unitSet, 1, {{0, 1}, {0.65, 0.0}})
fillUnitTable(result, unitSet, 2, {{0.3, 0}, {0.35, 0.5}, {0.80, 0.0}})
fillUnitTable(result, unitSet, 3, {{0.4, 0}, {0.45, 0.5}, {0.90, 0.0}})
fillUnitTable(result, unitSet, 4, {{0.5, 0}, {0.55, 0.5}, {0.90, 0.0}})
fillUnitTable(result, unitSet, 5, {{0.6, 0}, {0.65, 0.5}, {0.95, 0.0}})
fillUnitTable(result, unitSet, 6, {{0.7, 0}, {0.75, 0.5}, {0.975, 0.0}})
fillUnitTable(result, unitSet, 7, {{0.8, 0}, {0.825, 0.5}, {0.975, 0.0}})
fillUnitTable(result, unitSet, 8, {{0.85, 0}, {0.875, 0.5}, {0.975, 0.0}})
fillUnitTable(result, unitSet, 9, {{0.90, 0}, {0.925, 0.5}, {0.975, 0.0}})
fillUnitTable(result, unitSet, 10, {{0.93, 0}, {1, 1.0}})
return result
end
local function addMajorResistance(entity, name, tier)
local decreases = { 7, 7, 10, 10, 13, 13, 16, 16, 19, 23 }
local percents = { 65, 65, 70, 75, 75, 80, 85, 85, 90, 90 }
entity.resistances[name] = {
decrease = roundToNearest(gaussianRandomRangeRG(decreases[tier], decreases[tier] * 0.1, decreases[tier] * 0.85, decreases[tier] * 1.30, xorRandom), 0.1),
percent = roundToNearest(gaussianRandomRangeRG(percents[tier], percents[tier] * 0.1, percents[tier] * 0.85, percents[tier] * 1.30, xorRandom), 0.1)
}
end
local function addMinorResistance(entity, name, tier)
-- {
-- type = "resistance",
-- name = "fire",
-- decrease = { 1, 1, 1, 1, 2, 2, 3, 3, 3, 4 },
-- percent = { 30, 30, 30, 40, 40, 40, 45, 45, 45, 50 }
-- }
local decreases = { 3, 3, 7, 7, 10, 10, 13, 13, 16, 18 }
local percents = { 35, 35, 40, 40, 45, 45, 50, 55, 55, 60 }
entity.resistances[name] = {
decrease = roundToNearest(gaussianRandomRangeRG(decreases[tier], decreases[tier] * 0.1, decreases[tier] * 0.85, decreases[tier] * 1.30, xorRandom), 0.1),
percent = roundToNearest(gaussianRandomRangeRG(percents[tier], percents[tier] * 0.1, percents[tier] * 0.85, percents[tier] * 1.30, xorRandom), 0.1)
}
end
local function addMajorWeakness(entity, name, tier)
local decreases = { -7, -7, -10, -10, -13, -13, -16, -16, -19, -23 }
local percents = { -65, -65, -70, -75, -75, -80, -85, -85, -90, -90 }
entity.resistances[name] = {
decrease = roundToNearest(gaussianRandomRangeRG(decreases[tier], decreases[tier] * 0.1, decreases[tier] * 0.85, decreases[tier] * 1.30, xorRandom), 0.1),
percent = roundToNearest(gaussianRandomRangeRG(percents[tier], percents[tier] * 0.1, percents[tier] * 0.85, percents[tier] * 1.30, xorRandom), 0.1)
}
end
local function addMinorWeakness(entity, name, tier)
local decreases = { -3, -3, -7, -7, -10, -10, -13, -13, -16, -18 }
local percents = { -35, -35, -40, -40, -45, -45, -50, -55, -55, -60 }
entity.resistances[name] = {
decrease = roundToNearest(gaussianRandomRangeRG(decreases[tier], decreases[tier] * 0.1, decreases[tier] * 0.85, decreases[tier] * 1.30, xorRandom), 0.1),
percent = roundToNearest(gaussianRandomRangeRG(percents[tier], percents[tier] * 0.1, percents[tier] * 0.85, percents[tier] * 1.30, xorRandom), 0.1)
}
end
local function scaleAttributes (entity)
if (entity.type == "biter") then
entity["health"] = entity["health"] * settings.startup["rampant--unitBiterHealthScaler"].value
entity["movement"] = entity["movement"] * settings.startup["rampant--unitBiterSpeedScaler"].value
entity["distancePerFrame"] = entity["distancePerFrame"] * settings.startup["rampant--unitBiterSpeedScaler"].value
entity["damage"] = entity["damage"] * settings.startup["rampant--unitBiterDamageScaler"].value
entity["range"] = entity["range"] * settings.startup["rampant--unitBiterRangeScaler"].value
entity["healing"] = entity["healing"] * settings.startup["rampant--unitBiterHealingScaler"].value
elseif (entity.type == "spitter") then
entity["health"] = entity["health"] * settings.startup["rampant--unitSpitterHealthScaler"].value
entity["movement"] = entity["movement"] * settings.startup["rampant--unitSpitterSpeedScaler"].value
entity["distancePerFrame"] = entity["distancePerFrame"] * settings.startup["rampant--unitSpitterSpeedScaler"].value
entity["damage"] = entity["damage"] * settings.startup["rampant--unitSpitterDamageScaler"].value
if entity["stickerDamagePerTick"] then
entity["stickerDamagePerTick"] = entity["stickerDamagePerTick"] * settings.startup["rampant--unitSpitterDamageScaler"].value
end
entity["damagePerTick"] = entity["damagePerTick"] * settings.startup["rampant--unitSpitterDamageScaler"].value
entity["range"] = entity["range"] * settings.startup["rampant--unitSpitterRangeScaler"].value
entity["healing"] = entity["healing"] * settings.startup["rampant--unitSpitterHealingScaler"].value
elseif (entity.type == "drone") then
entity["health"] = entity["health"] * settings.startup["rampant--unitDroneHealthScaler"].value
entity["movement"] = entity["movement"] * settings.startup["rampant--unitDroneSpeedScaler"].value
entity["distancePerFrame"] = entity["distancePerFrame"] * settings.startup["rampant--unitDroneSpeedScaler"].value
entity["damage"] = entity["damage"] * settings.startup["rampant--unitDroneDamageScaler"].value
entity["damagePerTick"] = entity["damagePerTick"] * settings.startup["rampant--unitDroneDamageScaler"].value
entity["range"] = entity["range"] * settings.startup["rampant--unitDroneRangeScaler"].value
entity["healing"] = entity["healing"] * settings.startup["rampant--unitDroneHealingScaler"].value
elseif (entity.type == "biter-spawner") or (entity.type == "spitter-spawner") then
entity["health"] = entity["health"] * settings.startup["rampant--unitSpawnerHealthScaler"].value
entity["unitsOwned"] = entity["unitsOwned"] * settings.startup["rampant--unitSpawnerOwnedScaler"].value
entity["unitsToSpawn"] = entity["unitsToSpawn"] * settings.startup["rampant--unitSpawnerSpawnScaler"].value
entity["spawningCooldownStart"] = entity["spawningCooldownStart"] * settings.startup["rampant--unitSpawnerRespawnScaler"].value
entity["spawningCooldownEnd"] = entity["spawningCooldownEnd"] * settings.startup["rampant--unitSpawnerRespawnScaler"].value
entity["healing"] = entity["healing"] * settings.startup["rampant--unitSpawnerHealingScaler"].value
elseif (entity.type == "turret") then
entity["health"] = entity["health"] * settings.startup["rampant--unitWormHealthScaler"].value
entity["damage"] = entity["damage"] * settings.startup["rampant--unitWormDamageScaler"].value
entity["damagePerTick"] = entity["damagePerTick"] * settings.startup["rampant--unitWormDamageScaler"].value
entity["range"] = entity["range"] * settings.startup["rampant--unitWormRangeScaler"].value
entity["healing"] = entity["healing"] * settings.startup["rampant--unitWormHealingScaler"].value
elseif (entity.type == "hive") then
entity["health"] = entity["health"] * settings.startup["rampant--unitHiveHealthScaler"].value
entity["healing"] = entity["healing"] * settings.startup["rampant--unitHiveHealingScaler"].value
entity["spawningCooldownStart"] = entity["spawningCooldownStart"] * settings.startup["rampant--unitHiveRespawnScaler"].value
entity["spawningCooldownEnd"] = entity["spawningCooldownEnd"] * settings.startup["rampant--unitHiveRespawnScaler"].value
end
end
-- local function distort(xorRandom, num, min, max)
-- local min = min or num * 0.85
-- local max = max or num * 1.30
-- if (num < 0) then
-- local t = min
-- min = max
-- max = t
-- end
-- return roundToNearest(gaussianRandomRangeRG(num, num * 0.15, min, max, xorRandom), 0.01)
-- end
local function fillEntityTemplate(entity)
local tier = entity.effectiveLevel
if (entity.type == "biter") then
for key,value in pairs(biterAttributeNumeric) do
if not entity[key] then
entity[key] = distort(xorRandom, value[tier])
else
entity[key] = distort(xorRandom, entity[key][tier])
end
end
elseif (entity.type == "spitter") then
for key,value in pairs(spitterAttributeNumeric) do
if not entity[key] then
entity[key] = distort(xorRandom, value[tier])
else
entity[key] = distort(xorRandom, entity[key][tier])
end
end
elseif (entity.type == "biter-spawner") or (entity.type == "spitter-spawner") then
for key,value in pairs(unitSpawnerAttributeNumeric) do
if not entity[key] then
entity[key] = distort(xorRandom, value[tier])
else
entity[key] = distort(xorRandom, entity[key][tier])
end
end
elseif (entity.type == "hive") then
for key,value in pairs(hiveAttributeNumeric) do
if not entity[key] then
entity[key] = distort(xorRandom, value[tier])
else
entity[key] = distort(xorRandom, entity[key][tier])
end
end
elseif (entity.type == "turret") then
for key,value in pairs(wormAttributeNumeric) do
if not entity[key] then
entity[key] = distort(xorRandom, value[tier])
else
entity[key] = distort(xorRandom, entity[key][tier])
end
end
elseif (entity.type == "drone") then
for key,value in pairs(droneAttributeNumeric) do
if not entity[key] then
entity[key] = distort(xorRandom, value[tier])
else
entity[key] = distort(xorRandom, entity[key][tier])
end
end
end
for k,v in pairs(entity) do
local startDecrease = string.find(k, "Decrease")
local startPercent = string.find(k, "Percent")
if startDecrease or startPercent then
local damageType = string.sub(k, 1, (startDecrease or startPercent)-1)
if not entity.resistances[damageType] then
entity.resistances[damageType] = {}
end
if startDecrease then
entity.resistances[damageType].decrease = v
elseif startPercent then
entity.resistances[damageType].percent = v
end
end
end
for i=1,#entity.addon do
for k,v in pairs(entity.addon[i]) do
entity[k] = v[tier]
end
end
for key, value in pairs(entity) do
if (key == "drops") then
if not entity.loot then
entity.loot = {}
end
for _,lootTable in pairs(entity.drops) do
entity.loot[#entity.loot+1] = lootTable[tier]
end
elseif (key == "explosion") then
local ti = tier
if (entity.type == "drone") then
ti = 1
end
entity["hitSprayName"] = entity[key] .. "-" .. "damaged-fountain-rampant"
entity[key] = entity[key] .. "-" .. bloodFountains[ti]
elseif (key == "evolutionFunction") then
entity["evolutionRequirement"] = distort(xorRandom, value(tier))
elseif (key == "majorResistances") then
for i=1,#value do
addMajorResistance(entity, value[i], tier)
end
elseif (key == "minorResistances") then
for i=1,#value do
addMinorResistance(entity, value[i], tier)
end
elseif (key == "majorWeaknesses") then
for i=1,#value do
addMajorWeakness(entity, value[i], tier)
end
elseif (key == "minorWeaknesses") then
for i=1,#value do
addMinorWeakness(entity, value[i], tier)
end
elseif (key == "explosionTiers") then
entity.attackExplosion = entity.explosionTiers[tier]
entity.attackScorchmark = entity.scorchmarkTiers[tier]
elseif (key == "attributes") then
for i=1,#entity[key] do
local attribute = entity[key][i]
if (attribute == "lowHealth") then
entity["health"] = entity["health"] * 0.75
elseif (attribute == "lowestHealth") then
entity["health"] = entity["health"] * 0.50
elseif (attribute == "quickCooldown") then
entity["cooldown"] = entity["cooldown"] * 0.50
entity["damage"] = entity["damage"] * 0.65
if entity["damagePerTick"] then
entity["damagePerTick"] = entity["damagePerTick"] * 0.65
end
elseif (attribute == "slowMovement") then
entity["movement"] = entity["movement"] * 0.35
entity["distancePerFrame"] = entity["distancePerFrame"] * 0.65
elseif (attribute == "quickMovement") then
entity["movement"] = entity["movement"] * 1.25
entity["distancePerFrame"] = entity["distancePerFrame"] * 1.35
elseif (attribute == "quickSpawning") then
if entity["spawningCooldownStart"] then
entity["spawningCooldownStart"] = entity["spawningCooldownStart"] * 0.85
entity["spawningCooldownEnd"] = entity["spawningCooldownEnd"] * 0.85
end
if entity["spawningTimeModifer"] then
entity["spawningTimeModifer"] = entity["spawningTimeModifer"] * 0.85
end
elseif (attribute == "altBiterArmored") then
entity["altBiter"] = "armored"
elseif (attribute == "highRegen") then
entity["healing"] = entity["healing"] * 1.5
elseif (attribute == "highestRegen") then
entity["healing"] = entity["healing"] * 3.5
elseif (attribute == "big") then
entity["scale"] = entity["scale"] * 1.2
elseif (attribute == "bigger") then
entity["scale"] = entity["scale"] * 1.35
elseif (attribute == "longReach") then
entity["range"] = entity["range"] * 3
elseif (attribute == "smallest") then
entity["scale"] = entity["scale"] * 0.5
elseif (attribute == "fragile") then
entity["health"] = entity["health"] * 0.1
elseif (attribute == "selfDamaging") then
local divider
if entity.health < 100 then
divider = 2
else
divider = 2.5
end
entity.healthDamage = entity.health / divider
entity.sourceEffect = function (attributes)
return
{
{
type = "damage",
affects_target = true,
damage = {amount = attributes.healthDamage or 5, type = attributes.damageType or "physical"}
}
}
end
elseif (attribute == "killsSelf") then
entity.healthDamage = entity.health * 3
elseif (attribute == "unstable") then
entity["healing"] = entity["healing"] * -1
elseif (attribute == "checkBuildability") then
entity.checkBuildability = true
elseif (attribute == "followsPlayer") then
entity.followsPlayer = true
elseif (attribute == "stationary") then
entity.movement = 0
entity.distancePerFrame = 0
elseif (attribute == "highHealth") then
entity["health"] = entity["health"] * 1.50
elseif (attribute == "poisonDeathCloud") then
entity.dyingEffect = {
type = "create-entity",
entity_name = "poison-cloud-v" .. tier .. "-cloud-rampant"
}
elseif (attribute == "highestHealth") then
entity["health"] = entity["health"] * 2
elseif type(attribute) == "table" then
if (attribute[1] == "clusterDeath") then
entity.deathGenerator = function (attack)
return {
{
type = "cluster",
cluster_count = attack.clusters,
distance = attack.clusterDistance,
distance_deviation = 3,
action_delivery =
{
type = "projectile",
projectile = createCapsuleProjectile(attack,
attack.faction .. "-" .. attribute[2]
.. "-v" .. attack.variation .. "-t"
.. attack.effectiveLevel .. "-rampant"),
direction_deviation = 0.6,
starting_speed = 0.25,
max_range = attack.range,
starting_speed_deviation = 0.3
}
}
}
end
else
error("Unknown table attribute " .. attribute[1])
end
else
error("Unknown attribute " .. attribute)
end
end
end
end
-- print(serpent.dump(entity))
scaleAttributes(entity)
end
local function calculateRGBa(tint, tier, staticAlpha)
local r = gaussianRandomRangeRG(tint.r, tint.r * 0.10 + (0.005 * tier), mMax(tint.r * 0.85 - (0.005 * tier), 0), mMin(tint.r * 1.15, 1), xorRandom)
local g = gaussianRandomRangeRG(tint.g, tint.g * 0.10 + (0.005 * tier), mMax(tint.g * 0.85 - (0.005 * tier), 0), mMin(tint.g * 1.15, 1), xorRandom)
local b = gaussianRandomRangeRG(tint.b, tint.b * 0.10 + (0.005 * tier), mMax(tint.b * 0.85 - (0.005 * tier), 0), mMin(tint.b * 1.15, 1), xorRandom)
local a = tint.a
if not staticAlpha then
a = gaussianRandomRangeRG(tint.a, tint.a * 0.10 + (0.005 * tier), mMax(tint.a * 0.85 - (0.005 * tier), 0), mMin(tint.a * 1.15, 1), xorRandom)
end
return { r=r, g=g, b=b, a=a }
end
local function generateApperance(unit)
local tier = unit.effectiveLevel
if unit.scale then
local scaleValue = unit.scale[tier]
local scale = gaussianRandomRangeRG(scaleValue, scaleValue * 0.24, scaleValue * 0.40, scaleValue * 1.50, xorRandom)
unit.scale = scale
end
if unit.tint then
unit.tint = calculateRGBa(unit.tint, tier, true)
end
if unit.tint2 then
unit.tint2 = calculateRGBa(unit.tint2, tier, true)
end
end
function swarmUtils.buildUnits(template)
local unitSet = {}
local variations = settings.startup["rampant--newEnemyVariations"].value
for tier=1, 10 do
local effectiveLevel = TIER_UPGRADE_SET_10[tier]
local result = {}
for i=1,variations do
local unit = deepcopy(template)
unit.name = unit.name .. "-v" .. i .. "-t" .. tier
-- unit.nameSuffix = "-v" .. i .. "-t" .. tier
unit.effectiveLevel = effectiveLevel
unit.variation = i
generateApperance(unit)
fillEntityTemplate(unit)
unit.attack = unit.attackGenerator(unit)
unit.death = (unit.deathGenerator and unit.deathGenerator(unit)) or nil
local entity
if (unit.type == "spitter") then
entity = makeSpitter(unit)
elseif (unit.type == "biter") then
entity = makeBiter(unit)
elseif (unit.type == "drone") then
-- if not unit.death then
-- unit.death = {
-- type = "direct",
-- action_delivery =
-- {
-- type = "instant",
-- target_effects =
-- {
-- type = "create-entity",
-- entity_name = "massive-explosion"
-- }
-- }
-- }
-- end
entity = makeDrone(unit)
end
result[#result+1] = entity.name
data:extend({entity})
end
unitSet[#unitSet+1] = result
end
return unitSet
end
local function buildEntities(entityTemplates)
local unitSet = {}
for tier=1, 10 do
local effectiveLevel = TIER_UPGRADE_SET_10[tier]
local entityTemplate = entityTemplates[effectiveLevel]
for ei=1,#entityTemplate do
local template = entityTemplate[ei]
local probability = deepcopy(propTables10[tier])
for z=1,#probability do
probability[z][2] = probability[z][2] * template[2]
end
unitSet[#unitSet+1] = {template[1] .. "-t" .. tier .. "-rampant", probability}
end
end
return unitSet
end
function swarmUtils.buildEntitySpawner(template)
local variations = settings.startup["rampant--newEnemyVariations"].value
for tier=1, 10 do
local effectiveLevel = TIER_UPGRADE_SET_10[tier]
for i=1,variations do
local unitSpawner = deepcopy(template)
unitSpawner.name = unitSpawner.name .. "-v" .. i .. "-t" .. tier
unitSpawner.effectiveLevel = effectiveLevel
unitSpawner.variation = i
generateApperance(unitSpawner)
fillEntityTemplate(unitSpawner)
if unitSpawner.autoplace then
unitSpawner.autoplace = unitSpawner.autoplace[effectiveLevel]
end
data:extend({
makeUnitSpawner(unitSpawner)
})
end
end
end
function swarmUtils.buildUnitSpawner(template)
local variations = settings.startup["rampant--newEnemyVariations"].value
for tier=1, 10 do
local effectiveLevel = TIER_UPGRADE_SET_10[tier]
for i=1,variations do
local unitSpawner = deepcopy(template)
unitSpawner.name = unitSpawner.name .. "-v" .. i .. "-t" .. tier
unitSpawner.effectiveLevel = effectiveLevel
unitSpawner.variation = i
local unitTable = unitSetToProbabilityTable(template.unitSet)
unitSpawner.unitSet = unitTable
generateApperance(unitSpawner)
fillEntityTemplate(unitSpawner)
if unitSpawner.autoplace then
unitSpawner.autoplace = unitSpawner.autoplace[effectiveLevel]
end
data:extend({
makeUnitSpawner(unitSpawner)
})
end
end
end
function swarmUtils.buildWorm(template)
local variations = settings.startup["rampant--newEnemyVariations"].value
for tier=1, 10 do
local effectiveLevel = TIER_UPGRADE_SET_10[tier]
for i=1,variations do
local worm = deepcopy(template)
worm.name = worm.name .. "-v" .. i .. "-t" .. tier
worm.effectiveLevel = effectiveLevel
worm.variation = i
generateApperance(worm)
fillEntityTemplate(worm)
worm.attack = worm.attackGenerator(worm)
if worm.autoplace then
worm.attributes["autoplace"] = worm.autoplace[effectiveLevel]
end
data:extend({
makeWorm(worm)
})
end
end
end
local function makeLootTables(template)
local makeLootTable
if (template.type == "biter") or (template.type == "spitter") then
makeLootTable = makeUnitAlienLootTable
elseif (template.type == "worm") then
makeLootTable = makeWormAlienLootTable
elseif (template.type == "biter-spawner") or (template.type == "spitter-spawner") then
makeLootTable = makeSpawnerAlienLootTable
elseif (template.type == "hive") then
makeLootTable = makeSpawnerAlienLootTable
else
return nil
end
local newDrops = {}
for i=1,#template.drops do
local attribute = template.drops[i]
if (attribute == "greenArtifact") then
newDrops[#newDrops+1] = makeLootTable("green")
elseif (attribute == "yellowArtifact") then
newDrops[#newDrops+1] = makeLootTable("yellow")
elseif (attribute == "blueArtifact") then
newDrops[#newDrops+1] = makeLootTable("blue")
elseif (attribute == "orangeArtifact") then
newDrops[#newDrops+1] = makeLootTable("orange")
elseif (attribute == "redArtifact") then
newDrops[#newDrops+1] = makeLootTable("red")
elseif (attribute == "purpleArtifact") then
newDrops[#newDrops+1] = makeLootTable("purple")
elseif (attribute == "nilArtifact") then
newDrops[#newDrops+1] = makeLootTable(nil)
end
end
return newDrops
end
local function buildAttack(faction, template)
for i=1,#template.attackAttributes do
local attack = template.attackAttributes[i]
if (attack == "melee") then
template.attackGenerator = createMeleeAttack
elseif (attack == "acidPool") then
template.addon[#template.addon+1] = acidPuddleAttributeNumeric
template.meleePuddleGenerator = function (attributes)
attributes.stickerDamagePerTickType = "acid"
return {
type="create-fire",
entity_name = makeAcidSplashFire(attributes, attributes.stickerName or makeSticker(attributes)),
check_buildability = true,
initial_ground_flame_count = 2,
show_in_tooltip = true
}
end
elseif (attack == "spit") then
template.attackType = "projectile"
-- template.attackDirectionOnly = true
template.attackGenerator = function (attack)
return createRangedAttack(attack,
createAttackBall(attack),
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "touch") then
template.attackType = "projectile"
-- template.attackDirectionOnly = true
template.range = { 0.1, 0.1, 0.1, 0.2, 0.2, 0.3, 0.3, 0.3, 0.3, 0.4 }
template.attackGenerator = function (attack)
return createRangedAttack(attack,
createAttackBall(attack),
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "drainCrystal") then
template.range = { 6, 6, 7, 7, 8, 8, 9, 9, 10, 10 }
template.addon[#template.addon+1] = liteClusterAttackNumeric
template.attackPointEffects = function(attributes)
return
{
{
type = "script",
effect_id = "rampant-drain-trigger"
},
{
type = "damage",
damage = { type="laser", amount = attributes.damage }
},
{
type="nested-result",
action = {
{
type = "cluster",
cluster_count = attributes.clusters,
distance = attributes.clusterDistance,
distance_deviation = 1,
action_delivery =
{
type = "projectile",
projectile = makeLaser(attributes),
duration = 20,
direction_deviation = 0.6,
starting_speed = attributes.startingSpeed,
starting_speed_deviation = 0.3
},
repeat_count = 2
}
}
}
}
end
elseif (attack == "physical") then
template.explosionTiers = explosionTiers
template.scorchmarkTiers = scorchmarkTiers
template.damageType = "physical"
template.fireDamagePerTickType = "physical"
template.stickerDamagePerTickType = "physical"
template.attackPointEffects = function (attributes)
return {
{
type= "create-entity",
entity_name = attributes.attackScorchmark
},
{
type= "create-entity",
entity_name = attributes.attackExplosion
}
}
end
elseif (attack == "acid") then
template.damageType = "acid"
template.fireDamagePerTickType = "acid"
template.stickerDamagePerTickType = "acid"
elseif (attack == "laser") then
template.damageType = "laser"
template.fireDamagePerTickType = "laser"
template.stickerDamagePerTickType = "laser"
elseif (attack == "electric") then
template.damageType = "electric"
template.fireDamagePerTickType = "electric"
template.stickerDamagePerTickType = "electric"
elseif (attack == "poison") then
template.damageType = "poison"
template.fireDamagePerTickType = "poison"
template.stickerDamagePerTickType = "poison"
template.attackPointEffects = function(attributes)
return
{
{
type="create-entity",
entity_name = "poison-cloud-v" .. attributes.effectiveLevel .. "-cloud-rampant"
}
}
end
elseif (attack == "stream") then
template.addon[#template.addon+1] = streamAttackNumeric
template.attackGenerator = function (attack)
return createStreamAttack(attack,
createAttackFlame(attack),
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "scatterBeam") then
template.addon[#template.addon+1] = beamAttackNumeric
template.attackGenerator = function (attack)
return createElectricAttack(attack,
makeBeam(attack),
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "beam") then
template.addon[#template.addon+1] = beamAttackNumeric
template.attackGenerator = function (attack)
return createBeamAttack(attack,
makeBeam(attack),
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "cluster") then
template.addon[#template.addon+1] = clusterAttackNumeric
template.attackBubble = makeBubble(template)
template.attackPointEffects = function(attributes)
return
{
{
type="nested-result",
action = {
{
type = "cluster",
cluster_count = attributes.clusters,
distance = attributes.clusterDistance,
distance_deviation = 3,
action_delivery =
{
type = "projectile",
projectile = makeLaser(attributes),
duration = 20,
direction_deviation = 0.6,
starting_speed = attributes.startingSpeed,
starting_speed_deviation = 0.3
},
repeat_count = 2
}
}
}
}
end
elseif (attack == "slow") then
template.force = "not-same"
template.stickerAnimation = {
filename = "__base__/graphics/entity/slowdown-sticker/slowdown-sticker.png",
priority = "extra-high",
line_length = 5,
width = 22,
height = 24,
frame_count = 50,
animation_speed = 0.5,
tint = {r = 0.3500, g = 0.663, b = 0.000, a = 0.694}, -- #4a900b1
shift = util.by_pixel (2,-1),
hr_version =
{
filename = "__base__/graphics/entity/slowdown-sticker/hr-slowdown-sticker.png",
line_length = 5,
width = 42,
height = 48,
frame_count = 50,
animation_speed = 0.5,
tint = {r = 0.3500, g = 0.663, b = 0.000, a = 0.694}, -- #ffa900b1
shift = util.by_pixel(2, -0.5),
scale = 0.5
}
}
template.areaEffects = function (attributes)
return {
{
type = "damage",
damage = { amount = attributes.damage, type = "acid" }
},
{
type = "create-sticker",
sticker = makeSticker(attributes)
}
}
end
elseif (attack == "nuclear") then
template.addon[#template.addon+1] = nuclearAttackNumeric
template.explosionTiers = explosionTiers
template.scorchmarkTiers = scorchmarkTiers
template.nuclear = true
template.attackGenerator = function (attack)
return createSuicideAttack(attack,
makeAtomicBlast(attack),
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "bomb") then
template.addon[#template.addon+1] = bombAttackNumeric
template.explosionTiers = explosionTiers
template.scorchmarkTiers = scorchmarkTiers
template.attackGenerator = function (attack)
return createSuicideAttack(attack,
nil,
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "capsule") then
template.attackType = "projectile"
-- template.attackDirectionOnly = true
template.attackGenerator = function (attack)
return createProjectileAttack(attack,
createCapsuleProjectile(attack,
attack.entityGenerator(attack)),
(template.attackAnimation and template.attackAnimation(attack.scale,
attack.tint,
attack.tint2)) or nil)
end
elseif (attack == "noFriendlyFire") then
template["force"] = "not-same"
elseif (attack == "noAcidPuddle") then
template.noAcidPuddle = true
elseif (type(attack) == "table") then
if (attack[1] == "drone") then
template.entityGenerator = function (attributes)
return template.faction .. "-" .. attack[2] .. "-v" ..
attributes.variation .. "-t" .. attributes.effectiveLevel .. "-drone-rampant"
end
end
else
error ("unknown attack " .. attack)
end
end
end
local function checkForAddons(template)
for i=1,#template.attributes do
local attribute = template.attributes[i]
if (type(attribute) == "table") then
if (attribute[1] == "clusterDeath") then
template.addon[#template.addon+1] = clusterAttackNumeric
end
end
end
end
local function buildUnitTemplate(faction, unit)
local template = deepcopy(unit)
template.name = faction.type .. "-" .. unit.name
template.tint = faction.tint
template.tint2 = faction.tint2
template.faction = faction.type
template.addon = {}
template.explosion = faction.type
template.resistances = {}
if (template.type == "biter") then
template.attackAnimation = biterattackanimation
elseif (template.type == "spitter") then
template.attackAnimation = spitterattackanimation
end
checkForAddons(template)
buildAttack(faction, template)
if template.drops then
template.drops = makeLootTables(template)
end
if not template.attackGenerator then
error("missing attack generator " .. faction.type .. " " .. template.name)
end
return template
end
local function buildTurretTemplate(faction, turret)
local template = deepcopy(turret)
template.name = faction.type .. "-" .. turret.name
template.tint = faction.tint
template.tint2 = faction.tint2
template.faction = faction.type
template.evolutionFunction = function (tier)
if (tier == 0) then
return 0
else
return math.min(faction.evo + ((tier - 2) * 0.10), 0.92)
end
end
template.explosion = faction.type
template.addon = {}
template.resistances = {}
buildAttack(faction, template)
checkForAddons(template)
if template.drops then
template.drops = makeLootTables(template)
end
if not template.attackGenerator then
error("missing attack generator " .. faction.type .. " " .. template.name)
end
return template
end
local function buildUnitSpawnerTemplate(faction, incomingTemplate, unitSets)
local template = deepcopy(incomingTemplate)
template.name = faction.type .. "-" .. template.name
template.tint = faction.tint
template.tint2 = faction.tint2
template.faction = faction.type
template.evolutionFunction = function (tier)
if (tier == 0) then
return 0
else
return math.min(faction.evo + ((tier - 2) * 0.10), 0.92)
end
end
template.explosion = faction.type
template.addon = {}
checkForAddons(template)
template.resistances = {}
local unitSet = {}
-- local unitVariations = settings.startup["rampant--newEnemyVariations"].value
for t=1,10 do
for i=1,#template.buildSets do
local buildSet = template.buildSets[i]
if (buildSet[2] <= t) and (t <= buildSet[3]) then
local activeUnitSet = unitSets[buildSet[1]][t]
local unitSetTier = unitSet[t]
if unitSetTier then
for b=1,#activeUnitSet do
unitSetTier[#unitSetTier+1] = activeUnitSet[b]
end
else
unitSet[t] = deepcopy(activeUnitSet)
end
end
end
-- while (#unitSet[t] > unitVariations) do
-- table.remove(unitSet, math.random(#unitSet[t]))
-- end
end
template.unitSet = unitSet
if template.drops then
template.drops = makeLootTables(template)
end
return template
end
local function buildHiveTemplate(faction, incomingTemplate)
local template = deepcopy(incomingTemplate)
template.name = faction.type .. "-" .. template.name
template.tint = faction.tint
template.tint2 = faction.tint2
template.faction = faction.type
template.evolutionFunction = function (tier)
if (tier == 0) then
return 0
else
return math.min(faction.evo + ((tier - 2) * 0.10), 0.92)
end
end
template.addon = {}
template.explosion = faction.type
checkForAddons(template)
template.resistances = {}
local unitSet = {}
for t=1,10 do
local unitSetTier = unitSet[t]
for i=1,#template.buildSets do
local buildSet = template.buildSets[i]
if (buildSet[2] <= t) and (t <= buildSet[3]) then
if not unitSetTier then
unitSetTier = {}
unitSet[t] = unitSetTier
end
unitSetTier[#unitSetTier+1] = {
"entity-proxy-" .. buildSet[1],
mathUtils.linearInterpolation((t-1)/9,
buildSet[4],
buildSet[5])
}
end
end
local total = 0
for i=1,#unitSetTier do
total = total + unitSetTier[i][2]
end
for i=1,#unitSetTier do
unitSetTier[i][2] = unitSetTier[i][2] / total
end
-- while (#unitSet[t] > unitVariations) do
-- table.remove(unitSet, math.random(#unitSet[t]))
-- end
end
template.unitSet = buildEntities(unitSet)
if template.drops then
template.drops = makeLootTables(template)
end
return template
end
local function generateSpawnerProxyTemplate(name, health, result_units)
return {
type = "unit-spawner",
name = name,
icon = "__base__/graphics/icons/biter-spawner.png",
icon_size = 64,
icon_mipmaps = 4,
flags = {"placeable-player", "placeable-enemy", "not-repairable"},
max_health = health,
order="b-b-g",
subgroup="enemies",
loot = nil,
resistances = nil,
working_sound = nil,
dying_sound = nil,
damaged_trigger_effect = nil,
healing_per_tick = -1,
-- collision_box = {{-3,-3},{3,3}},
-- selection_box = {{-3,-3},{3,3}},
collision_box = nil,
selection_box = nil,
-- in ticks per 1 pu
pollution_absorption_absolute = 10,
pollution_absorption_proportional = 0.005,
map_generator_bounding_box = nil,
corpse = nil,
dying_explosion = nil,
dying_trigger_effect = nil,
max_count_of_owned_units = 0,
max_friends_around_to_spawn = 0,
enemy_map_color = {r=0,g=0,b=0,a=0},
-- enemy_map_color = {r=0,g=1,b=1,a=1},
animations = { filename = "__core__/graphics/empty.png", size = 1 },
-- animations ={
-- spawner_idle_animation(0, {r=1,b=1,g=1,a=1}, 1, {r=1,b=1,g=1,a=1}),
-- spawner_idle_animation(1, {r=1,b=1,g=1,a=1}, 1, {r=1,b=1,g=1,a=1}),
-- spawner_idle_animation(2, {r=1,b=1,g=1,a=1}, 1, {r=1,b=1,g=1,a=1}),
-- spawner_idle_animation(3, {r=1,b=1,g=1,a=1}, 1, {r=1,b=1,g=1,a=1})
-- },
integration = nil,
result_units = result_units,
-- With zero evolution the spawn rate is 6 seconds, with max evolution it is 2.5 seconds
spawning_cooldown = {360, 150},
spawning_radius = 10,
spawning_spacing = 3,
max_spawn_shift = 0,
max_richness_for_spawn_shift = 100,
build_base_evolution_requirement = 0.0,
call_for_help_radius = 50
}
end
function swarmUtils.generateSpawnerProxy(result_units)
data:extend({
generateSpawnerProxyTemplate("spawner-proxy-1-rampant", 1 * 60 * 60, result_units),
generateSpawnerProxyTemplate("spawner-proxy-2-rampant", 2 * 60 * 60, result_units),
generateSpawnerProxyTemplate("spawner-proxy-3-rampant", 3 * 60 * 60, result_units)
})
end
function swarmUtils.processFactions()
for i=1,#constants.FACTION_SET do
local faction = constants.FACTION_SET[i]
if (faction.type == "energy-thief") then
energyThiefFaction.addFactionAddon()
elseif (faction.type == "poison") then
data:extend({
{
type = "damage-type",
name = "healing"
}
})
poisonFaction.addFactionAddon()
end
makeBloodFountains({
name = faction.type,
tint2 = faction.tint2
})
local unitSets = {}
for iu=1,#faction.units do
local unit = faction.units[iu]
local template = buildUnitTemplate(faction, unit)
unitSets[unit.name] = swarmUtils.buildUnits(template)
end
for iu=1,#faction.buildings do
local building = faction.buildings[iu]
if (building.type == "spitter-spawner") then
local template = buildUnitSpawnerTemplate(faction, building, unitSets)
swarmUtils.buildUnitSpawner(template)
elseif (building.type == "biter-spawner") then
local template = buildUnitSpawnerTemplate(faction, building, unitSets)
swarmUtils.buildUnitSpawner(template)
elseif (building.type == "turret") then
local template = buildTurretTemplate(faction, building)
swarmUtils.buildWorm(template)
elseif (building.type == "hive") then
local template = buildHiveTemplate(faction, building)
swarmUtils.buildEntitySpawner(template)
elseif (building.type == "trap") then
elseif (building.type == "utility") then
end
end
end
end
return swarmUtils