if baseUtilsG then return baseUtilsG end local baseUtils = {} -- imports local mathUtils = require("MathUtils") local constants = require("Constants") local chunkPropertyUtils = require("ChunkPropertyUtils") local neUnits = require("NEBaseUtils") local bobsUnits = require("BobsBaseUtils") -- constants local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER local BASE_AI_STATE_DORMANT = constants.BASE_AI_STATE_DORMANT local BASE_AI_STATE_ACTIVE = constants.BASE_AI_STATE_ACTIVE local BASE_AI_STATE_WORMS = constants.BASE_AI_STATE_WORMS local BASE_AI_STATE_NESTS = constants.BASE_AI_STATE_NESTS local BASE_AI_STATE_OVERDRIVE = constants.BASE_AI_STATE_OVERDRIVE local BASE_AI_STATE_MUTATE = constants.BASE_AI_STATE_MUTATE local BASE_DEADZONE_TTL = constants.BASE_DEADZONE_TTL local TIER_NAMING_SET_10 = constants.TIER_NAMING_SET_10 local TIER_NAMING_SET_5 = constants.TIER_NAMING_SET_5 local ENABLED_BOBS_UNITS = constants.ENABLED_BOBS_UNITS local ENABLED_NE_UNITS = constants.ENABLED_NE_UNITS local NEUTRAL_WORM_TIERS = constants.NEUTRAL_WORM_TIERS local NEUTRAL_WORM_VARIATIONS = constants.NEUTRAL_WORM_VARIATIONS local NEUTRAL_NEST_TIERS = constants.NEUTRAL_NEST_TIERS local NEUTRAL_NEST_VARIATIONS = constants.NEUTRAL_NEST_VARIATIONS local PHYSICAL_WORM_TIERS = constants.PHYSICAL_WORM_TIERS local PHYSICAL_WORM_VARIATIONS = constants.PHYSICAL_WORM_VARIATIONS local PHYSICAL_NEST_TIERS = constants.PHYSICAL_NEST_TIERS local PHYSICAL_NEST_VARIATIONS = constants.PHYSICAL_NEST_VARIATIONS local ELECTRIC_WORM_TIERS = constants.ELECTRIC_WORM_TIERS local ELECTRIC_WORM_VARIATIONS = constants.ELECTRIC_WORM_VARIATIONS local ELECTRIC_NEST_TIERS = constants.ELECTRIC_NEST_TIERS local ELECTRIC_NEST_VARIATIONS = constants.ELECTRIC_NEST_VARIATIONS local ACID_WORM_TIERS = constants.ACID_WORM_TIERS local ACID_WORM_VARIATIONS = constants.ACID_WORM_VARIATIONS local ACID_NEST_TIERS = constants.ACID_NEST_TIERS local ACID_NEST_VARIATIONS = constants.ACID_NEST_VARIATIONS local SUICIDE_WORM_TIERS = constants.SUICIDE_WORM_TIERS local SUICIDE_WORM_VARIATIONS = constants.SUICIDE_WORM_VARIATIONS local SUICIDE_NEST_TIERS = constants.SUICIDE_NEST_TIERS local SUICIDE_NEST_VARIATIONS = constants.SUICIDE_NEST_VARIATIONS local NUCLEAR_WORM_TIERS = constants.NUCLEAR_WORM_TIERS local NUCLEAR_WORM_VARIATIONS = constants.NUCLEAR_WORM_VARIATIONS local NUCLEAR_NEST_TIERS = constants.NUCLEAR_NEST_TIERS local NUCLEAR_NEST_VARIATIONS = constants.NUCLEAR_NEST_VARIATIONS local FIRE_WORM_TIERS = constants.FIRE_WORM_TIERS local FIRE_WORM_VARIATIONS = constants.FIRE_WORM_VARIATIONS local FIRE_NEST_TIERS = constants.FIRE_NEST_TIERS local FIRE_NEST_VARIATIONS = constants.FIRE_NEST_VARIATIONS local INFERNO_WORM_TIERS = constants.INFERNO_WORM_TIERS local INFERNO_WORM_VARIATIONS = constants.INFERNO_WORM_VARIATIONS local INFERNO_NEST_TIERS = constants.INFERNO_NEST_TIERS local INFERNO_NEST_VARIATIONS = constants.INFERNO_NEST_VARIATIONS local TROLL_WORM_TIERS = constants.TROLL_WORM_TIERS local TROLL_WORM_VARIATIONS = constants.TROLL_WORM_VARIATIONS local TROLL_NEST_TIERS = constants.TROLL_NEST_TIERS local TROLL_NEST_VARIATIONS = constants.TROLL_NEST_VARIATIONS local FAST_WORM_TIERS = constants.FAST_WORM_TIERS local FAST_WORM_VARIATIONS = constants.FAST_WORM_VARIATIONS local FAST_NEST_TIERS = constants.FAST_NEST_TIERS local FAST_NEST_VARIATIONS = constants.FAST_NEST_VARIATIONS local LASER_WORM_TIERS = constants.LASER_WORM_TIERS local LASER_WORM_VARIATIONS = constants.LASER_WORM_VARIATIONS local LASER_NEST_TIERS = constants.LASER_NEST_TIERS local LASER_NEST_VARIATIONS = constants.LASER_NEST_VARIATIONS local WASP_WORM_TIERS = constants.WASP_WORM_TIERS local WASP_WORM_VARIATIONS = constants.WASP_WORM_VARIATIONS local WASP_NEST_TIERS = constants.WASP_NEST_TIERS local WASP_NEST_VARIATIONS = constants.WASP_NEST_VARIATIONS local SPAWNER_WORM_TIERS = constants.SPAWNER_WORM_TIERS local SPAWNER_WORM_VARIATIONS = constants.SPAWNER_WORM_VARIATIONS local SPAWNER_NEST_TIERS = constants.SPAWNER_NEST_TIERS local SPAWNER_NEST_VARIATIONS = constants.SPAWNER_NEST_VARIATIONS local POISON_WORM_TIERS = constants.POISON_WORM_TIERS local POISON_WORM_VARIATIONS = constants.POISON_WORM_VARIATIONS local POISON_NEST_TIERS = constants.POISON_NEST_TIERS local POISON_NEST_VARIATIONS = constants.POISON_NEST_VARIATIONS local ENERGY_THIEF_WORM_TIERS = constants.ENERGY_THIEF_WORM_TIERS local ENERGY_THIEF_WORM_VARIATIONS = constants.ENERGY_THIEF_WORM_VARIATIONS local ENERGY_THIEF_NEST_TIERS = constants.ENERGY_THIEF_NEST_TIERS local ENERGY_THIEF_NEST_VARIATIONS = constants.ENERGY_THIEF_NEST_VARIATIONS local BASE_ALIGNMENT_SPAWNER = constants.BASE_ALIGNMENT_SPAWNER local BASE_ALIGNMENT_WASP = constants.BASE_ALIGNMENT_WASP local BASE_ALIGNMENT_NEUTRAL = constants.BASE_ALIGNMENT_NEUTRAL local BASE_ALIGNMENT_ACID = constants.BASE_ALIGNMENT_ACID local BASE_ALIGNMENT_ELECTRIC = constants.BASE_ALIGNMENT_ELECTRIC local BASE_ALIGNMENT_PHYSICAL = constants.BASE_ALIGNMENT_PHYSICAL local BASE_ALIGNMENT_SUICIDE = constants.BASE_ALIGNMENT_SUICIDE local BASE_ALIGNMENT_NUCLEAR = constants.BASE_ALIGNMENT_NUCLEAR local BASE_ALIGNMENT_INFERNO = constants.BASE_ALIGNMENT_INFERNO local BASE_ALIGNMENT_FIRE = constants.BASE_ALIGNMENT_FIRE local BASE_ALIGNMENT_FAST = constants.BASE_ALIGNMENT_FAST local BASE_ALIGNMENT_LASER = constants.BASE_ALIGNMENT_LASER local BASE_ALIGNMENT_TROLL = constants.BASE_ALIGNMENT_TROLL local BASE_ALIGNMENT_ENERGY_THIEF = constants.BASE_ALIGNMENT_ENERGY_THIEF local BASE_ALIGNMENT_DEADZONE = constants.BASE_ALIGNMENT_DEADZONE local BASE_ALIGNMENT_POISON = constants.BASE_ALIGNMENT_POISON local BASE_AI_MIN_STATE_DURATION = constants.BASE_AI_MIN_STATE_DURATION local BASE_AI_MIN_TEMPERAMENT_DURATION = constants.BASE_AI_MIN_TEMPERAMENT_DURATION local BASE_AI_MAX_STATE_DURATION = constants.BASE_AI_MAX_STATE_DURATION local BASE_AI_MAX_TEMPERAMENT_DURATION = constants.BASE_AI_MAX_TEMPERAMENT_DURATION local BASE_WORM_UPGRADE = constants.BASE_WORM_UPGRADE local BASE_SPAWNER_UPGRADE = constants.BASE_SPAWNER_UPGRADE local BASE_UPGRADE = constants.BASE_UPGRADE local BASE_DISTANCE_THRESHOLD = constants.BASE_DISTANCE_THRESHOLD local BASE_DISTANCE_LEVEL_BONUS = constants.BASE_DISTANCE_LEVEL_BONUS local BASE_DISTANCE_TO_EVO_INDEX = constants.BASE_DISTANCE_TO_EVO_INDEX local BASE_ALIGNMENT_EVOLUTION_BASELINE = constants.BASE_ALIGNMENT_EVOLUTION_BASELINE local BASE_QUEUE_SIZE = constants.BASE_QUEUE_SIZE local BASE_COLLECTION_THRESHOLD = constants.BASE_COLLECTION_THRESHOLD local CHUNK_SIZE = constants.CHUNK_SIZE local EVOLUTION_INCREMENTS = constants.EVOLUTION_INCREMENTS -- local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK -- imported functions local randomTickEvent = mathUtils.randomTickEvent local euclideanDistancePoints = mathUtils.euclideanDistancePoints local roundToFloor = mathUtils.roundToFloor local processNEUnitClass = neUnits.processNEUnitClass local processBobsUnitClass = bobsUnits.processBobsUnitClass local gaussianRandomRange = mathUtils.gaussianRandomRange local gaussianRandomRangeRG = mathUtils.gaussianRandomRangeRG local mFloor = math.floor local mMin = math.min local mMax = math.max local getChunkBase = chunkPropertyUtils.getChunkBase local setChunkBase = chunkPropertyUtils.setChunkBase local tRemove = table.remove local mRandom = math.random -- module code local function nonRepeatingRandom(evoTable, rg) local ordering = {} for evo in pairs(evoTable) do ordering[#ordering+1] = evo end for i=#ordering,1,-1 do local s = rg(i) local t = ordering[i] ordering[i] = ordering[s] ordering[s] = t end return ordering end local function sortNormals(a, b) return a[1] < b[1] end local function normalizeProbabilities(probabilityTable) local result = {} for alignment,probabilitySet in pairs(probabilityTable) do local max = 0 local min = MAGIC_MAXIMUM_NUMBER for probability, _ in pairs(probabilitySet) do if (probability > max) then max = probability end if (probability < min) then min = probability end end local alignmentResult = {} for probability, entities in pairs(probabilitySet) do local normalizeProbability = 0 if (probability ~= 0) then normalizeProbability = mMin(mFloor(((probability - min) / (max - min)) * 100), 97) end local set = alignmentResult[normalizeProbability] if (not set) then set = {} alignmentResult[normalizeProbability] = set end for i=1,#entities do set[#set+1] = entities[i] end end local paired = {} for probability, entities in pairs(alignmentResult) do paired[#paired+1] = {probability, entities} end result[alignment] = paired table.sort(paired, sortNormals) end return result end function baseUtils.findNearbyBase(map, chunk, natives) local x = chunk.x local y = chunk.y local foundBase = getChunkBase(map, chunk) if foundBase then return foundBase end local bases = natives.bases local closet = MAGIC_MAXIMUM_NUMBER for i=1, #bases do local base = bases[i] local distance = euclideanDistancePoints(base.x, base.y, x, y) if (distance <= base.distanceThreshold) and (distance < closet) then closet = distance foundBase = base end end return foundBase end local function findEntityUpgrade(baseAlignment, currentEvo, evoIndex, entityAlignment, evolutionTable) local alignments = evolutionTable[baseAlignment] local adjCurrentEvo = mMax( ((baseAlignment ~= entityAlignment) and 0) or currentEvo, 0 ) if not alignments or (adjCurrentEvo > evoIndex) then return nil end local entity = nil if (evoIndex >= 0.5) then for i=#alignments,1,-1 do local pair = alignments[i] local evo = pair[1] local entitySet = pair[2] if (evo <= evoIndex) then if (evo < adjCurrentEvo) then break end entity = entitySet[mRandom(#entitySet)] if (mRandom() < 0.25) then break end end end else for i=1,#alignments do local pair = alignments[i] local evo = pair[1] local entitySet = pair[2] if (adjCurrentEvo <= evo) then if (evo > evoIndex) then break end entity = entitySet[mRandom(#entitySet)] if (mRandom() < 0.25) then break end end end end return entity end local function findBaseInitialAlignment(evoIndex, natives, evolutionTable) local evoTop = gaussianRandomRange(evoIndex, evoIndex * 0.3, 0, evoIndex) local pickedEvo local alignment for i=1,#natives.evolutionTableAlignmentOrder do local evo = natives.evolutionTableAlignmentOrder[i] local entitySet = evolutionTable[evo] if (evo <= evoTop) and entitySet and (#entitySet > 0) then if not pickedEvo then alignment = entitySet[mRandom(#entitySet)] pickedEvo = evo else local diff = pickedEvo - evo if (diff > 0.2) then if (mRandom() < 0.10) then alignment = entitySet[mRandom(#entitySet)] break end elseif (diff >= 0) then if (mRandom() < 0.15)then alignment = entitySet[mRandom(#entitySet)] break end elseif (diff <= -0.2) then if (mRandom() < 0.35)then alignment = entitySet[mRandom(#entitySet)] break end elseif (diff < 0) then if (mRandom() < 0.25)then alignment = entitySet[mRandom(#entitySet)] break end end end end end return alignment end function baseUtils.recycleBases(natives, tick) local baseIndex = natives.baseIndex local bases = natives.bases local endIndex = mMin(baseIndex+BASE_QUEUE_SIZE, #bases) for index = endIndex, baseIndex, -1 do local base = bases[index] if ((tick - base.tick) > BASE_COLLECTION_THRESHOLD) then tRemove(bases, index) end end if (endIndex == #bases) then natives.baseIndex = 1 else natives.baseIndex = endIndex + 1 end end function baseUtils.upgradeEntity(entity, surface, baseAlignment, natives, evolutionFactor) local position = entity.position local entityType = entity.type -- local entityName = entity.name local currentEvo = entity.prototype.build_base_evolution_requirement or 0 if not baseAlignment or (baseAlignment == BASE_ALIGNMENT_DEADZONE) then entity.destroy() return nil end local distance = mMin(1, euclideanDistancePoints(position.x, position.y, 0, 0) * BASE_DISTANCE_TO_EVO_INDEX) local evoIndex = mMax(distance, evolutionFactor) local spawnerName = findEntityUpgrade(baseAlignment, mFloor(currentEvo * 100), mFloor(evoIndex * 100), natives.enemyAlignmentLookup[entity.name], ((entityType == "unit-spawner") and natives.evolutionTableUnitSpawner) or natives.evolutionTableWorm) if spawnerName then entity.destroy() local newPosition = surface.find_non_colliding_position( spawnerName, -- ((entityType == "unit-spawner") and "chunk-scanner-nest-rampant") or -- "chunk-scanner-worm-rampant", position, CHUNK_SIZE, 2, true ) if newPosition then return surface.create_entity({name = spawnerName, position = newPosition}) end end return nil end local function findMutation(natives, evolutionFactor) local shuffled = nonRepeatingRandom(natives.evolutionTableAlignment, natives.randomGenerator) local evoTable = natives.evolutionTableAlignment local alignment for i=1,#shuffled do local evo = shuffled[i] if (evo <= evolutionFactor) then local alignmentSet = evoTable[evo] alignment = alignmentSet[mRandom(#alignmentSet)] break end end return alignment end local function upgradeBase(natives, evolutionFactor, base) local alignmentCount = #base.alignment local roll = mRandom() if alignmentCount == 2 then if (roll < 0.05) then base.alignment = {findMutation(natives, evolutionFactor)} elseif (roll < 0.4) then base.alignment = {findMutation(natives, evolutionFactor), base.alignment[2]} else base.alignment = {base.alignment[1], findMutation(natives, evolutionFactor)} end return true elseif alignmentCount == 1 then if (roll < 0.85) then base.alignment = {findMutation(natives, evolutionFactor)} else base.alignment = {base.alignment[1], findMutation(natives, evolutionFactor)} end return true end return false end function baseUtils.processBase(map, chunk, surface, natives, tick, base, evolutionFactor) if (base.alignment[1] == BASE_ALIGNMENT_DEADZONE) then base.state = BASE_AI_STATE_DORMANT return end local areaTop = map.position2Top local areaBottom = map.position2Bottom areaTop[1] = chunk.x areaTop[2] = chunk.y areaBottom[1] = chunk.x + CHUNK_SIZE areaBottom[2] = chunk.y + CHUNK_SIZE local entity local cost local choice = mRandom() if (base.state == BASE_AI_STATE_NESTS) or ((base.state == BASE_AI_STATE_ACTIVE) and (choice < 0.5)) then if (base.points >= BASE_SPAWNER_UPGRADE) then entity = surface.find_entities_filtered(map.filteredEntitiesSpawnerQueryLimited) cost = BASE_SPAWNER_UPGRADE end elseif (base.state == BASE_AI_STATE_WORMS) or (base.state == BASE_AI_STATE_ACTIVE) then if (base.points >= BASE_WORM_UPGRADE) then entity = surface.find_entities_filtered(map.filteredEntitiesWormQueryLimited) cost = BASE_WORM_UPGRADE end elseif (base.state == BASE_AI_STATE_MUTATE) then if (base.points >= BASE_UPGRADE) then if upgradeBase(natives, evolutionFactor, base) then base.points = base.points - BASE_UPGRADE end end end if entity and (#entity > 0) then baseUtils.upgradeEntity(entity[mRandom(#entity)], surface, base.alignment[mRandom(#base.alignment)], natives, evolutionFactor) base.points = base.points - cost end if (base.state == BASE_AI_STATE_OVERDRIVE) then base.points = base.points + (natives.baseIncrement * 5) elseif (base.state ~= BASE_AI_STATE_DORMANT) then base.points = base.points + natives.baseIncrement end if (base.temperamentTick <= tick) then base.temperament = mRandom() base.temperamentTick = randomTickEvent(tick, BASE_AI_MIN_TEMPERAMENT_DURATION, BASE_AI_MAX_TEMPERAMENT_DURATION) end if (base.stateTick <= tick) then local roll = mRandom() * mMax(1 - evolutionFactor, 0.15) if (roll > natives.temperament) then base.state = BASE_AI_STATE_DORMANT else roll = mRandom() if (roll < 0.70) then base.state = BASE_AI_STATE_ACTIVE elseif (roll < 0.80) then base.state = BASE_AI_STATE_NESTS elseif (roll < 0.90) then base.state = BASE_AI_STATE_WORMS elseif (roll < 0.975) then base.state = BASE_AI_STATE_OVERDRIVE else base.state = BASE_AI_STATE_MUTATE end end base.stateTick = randomTickEvent(tick, BASE_AI_MIN_STATE_DURATION, BASE_AI_MAX_STATE_DURATION) end base.tick = tick end function baseUtils.createBase(map, natives, evolutionFactor, chunk, tick, rebuilding) local x = chunk.x local y = chunk.y local distance = euclideanDistancePoints(x, y, 0, 0) local meanLevel = mFloor(distance * 0.005) -- / 200 local distanceIndex = mMin(1, distance * BASE_DISTANCE_TO_EVO_INDEX) local evoIndex = mMax(distanceIndex, evolutionFactor) local alignment if (not rebuilding) and (mRandom() < natives.deadZoneFrequency) then alignment = BASE_ALIGNMENT_DEADZONE else alignment = findBaseInitialAlignment(evoIndex, natives, natives.evolutionTableAlignment) or BASE_ALIGNMENT_NEUTRAL end local baseLevel = gaussianRandomRange(meanLevel, meanLevel * 0.3, meanLevel * 0.50, meanLevel * 1.50) local baseDistanceThreshold = gaussianRandomRange(BASE_DISTANCE_THRESHOLD, BASE_DISTANCE_THRESHOLD * 0.2, BASE_DISTANCE_THRESHOLD * 0.75, BASE_DISTANCE_THRESHOLD * 1.50) local distanceThreshold = (baseLevel * BASE_DISTANCE_LEVEL_BONUS) + baseDistanceThreshold local base = { x = x, y = y, distanceThreshold = distanceThreshold, tick = ((alignment == BASE_ALIGNMENT_DEADZONE) and BASE_DEADZONE_TTL) or tick, alignment = {alignment}, state = BASE_AI_STATE_DORMANT, stateTick = 0, temperamentTick = 0, createdTick = tick, temperament = 0, points = 0 } setChunkBase(map, chunk, base) natives.bases[#natives.bases+1] = base return base end local function fileEntity(baseAlignment, entity, evolutionTable) local evoRequirement = mMin(entity.prototype.build_base_evolution_requirement, 1) local eTable = evolutionTable[baseAlignment] if not eTable then eTable = {} evolutionTable[baseAlignment] = eTable end local aTable = eTable[evoRequirement] if not aTable then aTable = {} eTable[evoRequirement] = aTable end aTable[#aTable+1] = entity.name end local function fileAlignment(baseAlignment, evolution, evolutionTable) local evoRequirement = mMin(evolution, 1) local eTable = evolutionTable[evolution] if not eTable then eTable = {} evolutionTable[evoRequirement] = eTable end eTable[#eTable+1] = baseAlignment end local function processUnitClass(biterVariation, biterTier, spitterVariation, spitterTier, wormVariation, wormTier, surface, natives, baseAlignment, baseAlignmentString) local position = { x = 0, y = 0 } for tier=1,biterTier do local t = ((biterTier == 5) and TIER_NAMING_SET_5[tier]) or TIER_NAMING_SET_10[tier] for v=1,biterVariation do local entityName = baseAlignmentString .. "-biter-nest-v" .. v .. "-t" .. t .. "-rampant" local entity = surface.create_entity({ name= entityName, position = position }) natives.enemyAlignmentLookup[entityName] = baseAlignment fileEntity(baseAlignment, entity, natives.evolutionTableUnitSpawner) entity.destroy() end end for tier=1,spitterTier do local t = ((spitterTier == 5) and TIER_NAMING_SET_5[tier]) or TIER_NAMING_SET_10[tier] for v=1,spitterVariation do local entityName = baseAlignmentString .. "-spitter-nest-v" .. v .. "-t" .. t .. "-rampant" local entity = surface.create_entity({ name = entityName, position = position }) natives.enemyAlignmentLookup[entityName] = baseAlignment fileEntity(baseAlignment, entity, natives.evolutionTableUnitSpawner) entity.destroy() end end for tier=1,wormTier do local t = ((wormTier == 5) and TIER_NAMING_SET_5[tier]) or TIER_NAMING_SET_10[tier] for v=1,wormVariation do local entityName = baseAlignmentString .. "-worm-v" .. v .. "-t" .. t .. "-rampant" local entity = surface.create_entity({ name=entityName, position = position }) natives.enemyAlignmentLookup[entityName] = baseAlignment fileEntity(baseAlignment, entity, natives.evolutionTableWorm) entity.destroy() end end end function baseUtils.rebuildNativeTables(natives, surface, rg) natives.evolutionTableUnitSpawner = {} natives.evolutionTableWorm = {} natives.evolutionTableAlignment = {} -- todo fill out alignment evolution levels for alignment,evo in pairs(BASE_ALIGNMENT_EVOLUTION_BASELINE) do fileAlignment(alignment, gaussianRandomRangeRG(evo, evo * 0.2, evo * 0.5, evo * 1.5, rg), natives.evolutionTableAlignment) end natives.evolutionTableAlignmentOrder = nonRepeatingRandom(natives.evolutionTableAlignment, natives.randomGenerator) if ENABLED_NE_UNITS then processNEUnitClass(natives, surface) end if ENABLED_BOBS_UNITS then processBobsUnitClass(natives, surface) end processUnitClass(NEUTRAL_NEST_VARIATIONS, NEUTRAL_NEST_TIERS, NEUTRAL_NEST_VARIATIONS, NEUTRAL_NEST_TIERS, NEUTRAL_WORM_VARIATIONS, NEUTRAL_WORM_TIERS, surface, natives, BASE_ALIGNMENT_NEUTRAL, "neutral") if settings.startup["rampant-acidEnemy"].value then processUnitClass(ACID_NEST_VARIATIONS, ACID_NEST_TIERS, ACID_NEST_VARIATIONS, ACID_NEST_TIERS, ACID_WORM_VARIATIONS, ACID_WORM_TIERS, surface, natives, BASE_ALIGNMENT_ACID, "acid") end if settings.startup["rampant-physicalEnemy"].value then processUnitClass(PHYSICAL_NEST_VARIATIONS, PHYSICAL_NEST_TIERS, 0, 0, PHYSICAL_WORM_VARIATIONS, PHYSICAL_WORM_TIERS, surface, natives, BASE_ALIGNMENT_PHYSICAL, "physical") end if settings.startup["rampant-fireEnemy"].value then processUnitClass(FIRE_NEST_VARIATIONS, FIRE_NEST_TIERS, FIRE_NEST_VARIATIONS, FIRE_NEST_TIERS, FIRE_WORM_VARIATIONS, FIRE_WORM_TIERS, surface, natives, BASE_ALIGNMENT_FIRE, "fire") end if settings.startup["rampant-electricEnemy"].value then processUnitClass(ELECTRIC_NEST_VARIATIONS, ELECTRIC_NEST_TIERS, 0, 0, ELECTRIC_WORM_VARIATIONS, ELECTRIC_WORM_TIERS, surface, natives, BASE_ALIGNMENT_ELECTRIC, "electric") end if settings.startup["rampant-suicideEnemy"].value then processUnitClass(SUICIDE_NEST_VARIATIONS, SUICIDE_NEST_TIERS, 0, 0, SUICIDE_WORM_VARIATIONS, SUICIDE_WORM_TIERS, surface, natives, BASE_ALIGNMENT_SUICIDE, "suicide") end if settings.startup["rampant-nuclearEnemy"].value then processUnitClass(NUCLEAR_NEST_VARIATIONS, NUCLEAR_NEST_TIERS, 0, 0, NUCLEAR_WORM_VARIATIONS, NUCLEAR_WORM_TIERS, surface, natives, BASE_ALIGNMENT_NUCLEAR, "nuclear") end if settings.startup["rampant-trollEnemy"].value then processUnitClass(TROLL_NEST_VARIATIONS, TROLL_NEST_TIERS, TROLL_NEST_VARIATIONS, TROLL_NEST_TIERS, TROLL_WORM_VARIATIONS, TROLL_WORM_TIERS, surface, natives, BASE_ALIGNMENT_TROLL, "troll") end if settings.startup["rampant-infernoEnemy"].value then processUnitClass(0, 0, INFERNO_NEST_VARIATIONS, INFERNO_NEST_TIERS, INFERNO_WORM_VARIATIONS, INFERNO_WORM_TIERS, surface, natives, BASE_ALIGNMENT_INFERNO, "inferno") end if settings.startup["rampant-fastEnemy"].value then processUnitClass(FAST_NEST_VARIATIONS, FAST_NEST_TIERS, FAST_NEST_VARIATIONS, FAST_NEST_TIERS, FAST_WORM_VARIATIONS, FAST_WORM_TIERS, surface, natives, BASE_ALIGNMENT_FAST, "fast") end if settings.startup["rampant-laserEnemy"].value then processUnitClass(LASER_NEST_VARIATIONS, LASER_NEST_TIERS, LASER_NEST_VARIATIONS, LASER_NEST_TIERS, LASER_WORM_VARIATIONS, LASER_WORM_TIERS, surface, natives, BASE_ALIGNMENT_LASER, "laser") end if settings.startup["rampant-waspEnemy"].value then processUnitClass(0, 0, WASP_NEST_VARIATIONS, WASP_NEST_TIERS, WASP_WORM_VARIATIONS, WASP_WORM_TIERS, surface, natives, BASE_ALIGNMENT_WASP, "wasp") end if settings.startup["rampant-spawnerEnemy"].value then processUnitClass(0, 0, SPAWNER_NEST_VARIATIONS, SPAWNER_NEST_TIERS, SPAWNER_WORM_VARIATIONS, SPAWNER_WORM_TIERS, surface, natives, BASE_ALIGNMENT_SPAWNER, "spawner") end if settings.startup["rampant-energyThiefEnemy"].value then processUnitClass(ENERGY_THIEF_NEST_VARIATIONS, ENERGY_THIEF_NEST_TIERS, 0, 0, ENERGY_THIEF_WORM_VARIATIONS, ENERGY_THIEF_WORM_TIERS, surface, natives, BASE_ALIGNMENT_ENERGY_THIEF, "energy-thief") end if settings.startup["rampant-poisonEnemy"].value then processUnitClass(POISON_NEST_VARIATIONS, POISON_NEST_TIERS, 0, 0, POISON_WORM_VARIATIONS, POISON_WORM_TIERS, surface, natives, BASE_ALIGNMENT_POISON, "poison") end -- processUnitClass(DECAYING_NEST_VARIATIONS, -- DECAYING_NEST_TIERS, -- DECAYING_NEST_VARIATIONS, -- DECAYING_NEST_TIERS, -- DECAYING_WORM_VARIATIONS, -- DECAYING_WORM_TIERS, -- surface, -- natives, -- BASE_ALIGNMENT_DECAYING, -- "decaying") -- processUnitClass(UNDYING_NEST_VARIATIONS, -- UNDYING_NEST_TIERS, -- UNDYING_NEST_VARIATIONS, -- UNDYING_NEST_TIERS, -- UNDYING_WORM_VARIATIONS, -- UNDYING_WORM_TIERS, -- surface, -- natives, -- BASE_ALIGNMENT_UNDYING, -- "undying") natives.evolutionTableUnitSpawner = normalizeProbabilities(natives.evolutionTableUnitSpawner) natives.evolutionTableWorm = normalizeProbabilities(natives.evolutionTableWorm) end baseUtilsG = baseUtils return baseUtils