1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-14 02:23:01 +02:00

almost finished unit generation

This commit is contained in:
Aaron Veden 2018-01-12 18:55:20 -08:00
parent f69075850d
commit 347c057dc2
6 changed files with 518 additions and 29 deletions

429
BuildSwarm.lua Executable file
View File

@ -0,0 +1,429 @@
-- imports
local biterUtils = require("prototypes/enemies/BiterUtils")
local mathUtils = require("libs/MathUtils")
-- imported functions
local gaussianRandomRange = mathUtils.gaussianRandomRange
local mRandom = math.random
local mMin = math.min
local mMax = math.max
local deepcopy = util.table.deepcopy
local makeBiter = biterUtils.makeBiter
local makeSpitter = biterUtils.makeSpitter
local makeWorm = biterUtils.makeWorm
local makeUnitSpawner = biterUtils.makeUnitSpawner
local createSuicideAttack = biterUtils.createSuicideAttack
-- module code
local function unitSetToProbabilityTable(points, upgradeTable, unitSet)
local dividers = {}
for i=1,#unitSet do
dividers[i] = 1
end
while (points > 0) do
local upgrade = upgradeTable[mRandom(#upgradeTable)]
local cost = upgrade.cost
local index = upgrade.index
dividers[index] = dividers[index] + upgrade.adjustment
points = points - cost
end
local total = 0
for i=1,#dividers do
total = total + dividers[i]
end
local runningTotal = 0
for i=1,#dividers do
runningTotal = runningTotal + (dividers[i] / total)
dividers[i] = runningTotal
end
local stepUnit = 1 / #unitSet[1]
local probabilityTable = {}
for i=1,#unitSet do
local result
if (i == 1) then
result = {
{
0,
stepUnit
},
{
dividers[i],
0
}
}
elseif (i == #unitSet) then
result = {
{
dividers[i-2],
0
},
{
1,
stepUnit
}
}
else
result = {
{
((i - 2) > 0 and dividers[i-2]) or 0,
0
},
{
dividers[i-1],
stepUnit
},
{
dividers[i],
0
}
}
end
probabilityTable[i] = result
end
local result = {}
for i=1, #probabilityTable do
local probability = probabilityTable[i]
for x=1, #unitSet[i] do
result[#result+1] = {unitSet[i][x], probability}
end
end
return result
end
local function buildUnits(startingPoints, template, attackGenerator, upgradeTable, variations, tiers)
local unitSet = {}
for t=1, tiers do
local result = {}
local allottedPoints = startingPoints * t
for i=1,variations do
local unit = deepcopy(template)
unit.name = unit.name .. "-v" .. i .. "-t" .. t
local remainingPoints = allottedPoints
while (remainingPoints > 0) do
local upgrade = upgradeTable[mRandom(#upgradeTable)]
local cost = upgrade.cost
if upgrade.attribute then
local attribute = upgrade.attribute
unit.attributes[attribute.name] = unit.attributes[attribute.name] + attribute.adjustment
end
if upgrade.resistance then
local field = upgrade.resistance.name
if not unit.resistances[field] then
unit.resistances[field] = {}
end
if upgrade.resistance.decrease then
unit.resistances[field].decrease = (unit.resistances[field].decrease or 0) + upgrade.resistance.decrease
end
if upgrade.resistance.percentage then
unit.resistances[field].percentage = (unit.resistances[field].percentage or 0) + upgrade.resistance.percentage
end
end
if upgrade.attack then
local attack = upgrade.attack
unit.attack[attack.name] = (unit.attack[attack.name] or 0) + attack.adjustment
end
remainingPoints = remainingPoints - cost
end
local scale = gaussianRandomRange(unit.scale, unit.scale * 0.12, unit.scale * 0.60, unit.scale * 1.40) + (0.05 * t)
local tint1 = {
gaussianRandomRange(unit.tint1.r, unit.tint1.r * 0.06 + (0.005 * t), unit.tint1.r * 0.85 - (0.005 * t), unit.tint1.r * 1.15),
gaussianRandomRange(unit.tint1.g, unit.tint1.g * 0.06 + (0.005 * t), unit.tint1.g * 0.85 - (0.005 * t), unit.tint1.g * 1.15),
gaussianRandomRange(unit.tint1.b, unit.tint1.b * 0.06 + (0.005 * t), unit.tint1.b * 0.85 - (0.005 * t), unit.tint1.b * 1.15),
gaussianRandomRange(unit.tint1.a, unit.tint1.a * 0.06 + (0.005 * t), unit.tint1.a * 0.85 - (0.005 * t), unit.tint1.a * 1.15)
}
local tint2 = {
gaussianRandomRange(unit.tint2.r, unit.tint2.r * 0.06 + (0.005 * t), unit.tint2.r * 0.85 - (0.005 * t), unit.tint2.r * 1.15),
gaussianRandomRange(unit.tint2.g, unit.tint2.g * 0.06 + (0.005 * t), unit.tint2.g * 0.85 - (0.005 * t), unit.tint2.g * 1.15),
gaussianRandomRange(unit.tint2.b, unit.tint2.b * 0.06 + (0.005 * t), unit.tint2.b * 0.85 - (0.005 * t), unit.tint2.b * 1.15),
gaussianRandomRange(unit.tint2.a, unit.tint2.a * 0.06 + (0.005 * t), unit.tint2.a * 0.85 - (0.005 * t), unit.tint2.a * 1.15)
}
unit.attributes.scale = scale
unit.attributes.tint1 = tint1
unit.attributes.tint2 = tint2
unit.attack.scale = scale
unit.attack.tint1 = tint1
unit.attack.tint2 = tint2
local entity
if (unit.type == "spitter") then
entity = makeSpitter(unit.name,
unit.attributes,
attackGenerator(unit.attack),
unit.resistances)
elseif (unit.type == "biter") then
entity = makeBiter(unit.name,
unit.attributes,
attackGenerator(unit.attack),
unit.resistances)
end
result[i] = entity.name
data:extend({entity})
end
unitSet[t] = result
end
return unitSet
end
local function buildUnitSpawner(startingPoints, template, upgradeTable, unitTable, variations, tiers)
for t=1, tiers do
local allottedPoints = startingPoints * t
for i=1,variations do
local unitSpawner = deepcopy(template)
unitSpawner.name = unitSpawner.name .. "-v" .. i .. "-t" .. t
local remainingPoints = allottedPoints
while (remainingPoints > 0) do
local upgrade = upgradeTable[mRandom(#upgradeTable)]
local cost = upgrade.cost
if upgrade.attribute then
local attribute = upgrade.attribute
unitSpawner.attributes[attribute.name] = unitSpawner.attributes[attribute.name] + attribute.adjustment
end
if upgrade.resistance then
local field = upgrade.resistance.name
if not unitSpawner.resistances[field] then
unitSpawner.resistances[field] = {}
unitSpawner.resistances[field].type = field
end
if upgrade.resistance.decrease then
unitSpawner.resistances[field].decrease = (unitSpawner.resistances[field].decrease or 0) + upgrade.resistance.decrease
end
if upgrade.resistance.percentage then
unitSpawner.resistances[field].percentage = (unitSpawner.resistances[field].percentage or 0) + upgrade.resistance.percentage
end
end
remainingPoints = remainingPoints - cost
end
local scale = gaussianRandomRange(unitSpawner.scale, unitSpawner.scale * 0.12, unitSpawner.scale * 0.60, unitSpawner.scale * 1.40) + (0.05 * t)
local tint = {
gaussianRandomRange(unitSpawner.tint1.r, unitSpawner.tint1.r * 0.06 + (0.005 * t), unitSpawner.tint1.r * 0.85 - (0.005 * t), unitSpawner.tint1.r * 1.15),
gaussianRandomRange(unitSpawner.tint1.g, unitSpawner.tint1.g * 0.06 + (0.005 * t), unitSpawner.tint1.g * 0.85 - (0.005 * t), unitSpawner.tint1.g * 1.15),
gaussianRandomRange(unitSpawner.tint1.b, unitSpawner.tint1.b * 0.06 + (0.005 * t), unitSpawner.tint1.b * 0.85 - (0.005 * t), unitSpawner.tint1.b * 1.15),
gaussianRandomRange(unitSpawner.tint1.a, unitSpawner.tint1.a * 0.06 + (0.005 * t), unitSpawner.tint1.a * 0.85 - (0.005 * t), unitSpawner.tint1.a * 1.15)
}
unitSpawner.attributes.scale = scale
unitSpawner.attributes.tint = tint
data:extend({
makeUnitSpawner(unitSpawner.name,
unitSpawner.attributes,
unitSpawner.resistances,
unitTable)
})
end
end
end
local function buildWorm(startingPoints, template, attackGenerator, upgradeTable, variations, tiers)
for t=1, tiers do
local allottedPoints = startingPoints * t
for i=1,variations do
local worm = deepcopy(template)
worm.name = worm.name .. "-v" .. i .. "-t" .. t
local remainingPoints = allottedPoints
while (remainingPoints > 0) do
local upgrade = upgradeTable[mRandom(#upgradeTable)]
local cost = upgrade.cost
if upgrade.attribute then
local attribute = upgrade.attribute
worm.attributes[attribute.name] = worm.attributes[attribute.name] + attribute.adjustment
end
if upgrade.resistance then
local field = upgrade.resistance.name
if not worm.resistances[field] then
worm.resistances[field] = {}
worm.resistances[field].type = field
end
if upgrade.resistance.decrease then
worm.resistances[field].decrease = (worm.resistances[field].decrease or 0) + upgrade.resistance.decrease
end
if upgrade.resistance.percentage then
worm.resistances[field].percentage = (worm.resistances[field].percentage or 0) + upgrade.resistance.percentage
end
end
remainingPoints = remainingPoints - cost
end
local scale = gaussianRandomRange(worm.scale, worm.scale * 0.12, worm.scale * 0.60, worm.scale * 1.40) + (0.05 * t)
local tint1 = {
gaussianRandomRange(worm.tint1.r, worm.tint1.r * 0.06 + (0.005 * t), worm.tint1.r * 0.85 - (0.005 * t), worm.tint1.r * 1.15),
gaussianRandomRange(worm.tint1.g, worm.tint1.g * 0.06 + (0.005 * t), worm.tint1.g * 0.85 - (0.005 * t), worm.tint1.g * 1.15),
gaussianRandomRange(worm.tint1.b, worm.tint1.b * 0.06 + (0.005 * t), worm.tint1.b * 0.85 - (0.005 * t), worm.tint1.b * 1.15),
gaussianRandomRange(worm.tint1.a, worm.tint1.a * 0.06 + (0.005 * t), worm.tint1.a * 0.85 - (0.005 * t), worm.tint1.a * 1.15)
}
local tint2 = {
gaussianRandomRange(worm.tint2.r, worm.tint2.r * 0.06 + (0.005 * t), worm.tint2.r * 0.85 - (0.005 * t), worm.tint2.r * 1.15),
gaussianRandomRange(worm.tint2.g, worm.tint2.g * 0.06 + (0.005 * t), worm.tint2.g * 0.85 - (0.005 * t), worm.tint2.g * 1.15),
gaussianRandomRange(worm.tint2.b, worm.tint2.b * 0.06 + (0.005 * t), worm.tint2.b * 0.85 - (0.005 * t), worm.tint2.b * 1.15),
gaussianRandomRange(worm.tint2.a, worm.tint2.a * 0.06 + (0.005 * t), worm.tint2.a * 0.85 - (0.005 * t), worm.tint2.a * 1.15)
}
worm.attributes.scale = scale
worm.attributes.tint1 = tint1
worm.attributes.tint2 = tint2
worm.attack.scale = scale
worm.attack.tint1 = tint1
worm.attack.tint2 = tint2
data:extend({
makeWorm(worm.name,
worm.attributes,
attackGenerator(worm.attack),
worm.resistances)
})
end
end
end
local function createUnitClass(points, templates, upgradeTable, attackGenerator, variations, tiers)
buildUnitSpawner(points.unitSpawner,
templates.unitSpawner,
upgradeTable.unitSpawner,
variations.unitSpawner,
tiers.unitSpawner,
unitSetToProbabilityTable(points.probabilityTable,
upgradeTable.probabilityTable,
buildUnits(points.unit,
templates.unit,
attackGenerator,
upgradeTable.unit,
variations.unit,
tiers.unit)),
tiers.unitSpawner)
end
createUnitClass({
unit = 10,
unitSpawner = 5,
probabilityTable = 5
},
{
unit = {
name = "rampant-suicide-biter",
attributes = {
health = 30,
movement = 0.21,
distancePerFrame = 0.1,
healing = 0.01,
explosion = "blood-explosion-small",
},
attack = {
area = 3.5,
damage = 20,
explosion = "explosion",
scorchmark = "small-scorchmark",
explosionCount = 2,
explosionDistance = 2,
},
resistances = {
explosion = {
decrease = 0,
percentage = -50
},
laser = {
decrease = 1,
percentage = 0
},
fire = {
decrease = 0,
percentage = -60
}
},
type = "biter",
scale = 0.55,
tint1 = {r=0.6, g=0.0, b=0.70, a=0.8},
tint2 = {r=0.7, g=0.0, b=0.72, a=0.4}
},
unitSpawner = {
scale = 0.55,
tint1 = {},
tint2 = {}
}
},
{
unit = {
{
cost = 1,
attribute = {
name = "health",
adjustment = 50
}
}
},
unitSpawner = {
{
cost = 1,
attribute = {
name = "health",
adjustment = 50
}
}
},
probabilityTable = {
{
cost = 1,
index = 1,
adjustment = 1
}
}
},
createSuicideAttack,
{
unit = 5,
unitSpawner = 5
},
{
unit = 7,
unitSpawner = 7
}
)
local function dog(a)
a[1] = 2
end
dog()

View File

@ -6,8 +6,12 @@ require("prototypes/buildings/UnitSpawners")
require("prototypes/tile/fillableDirt") require("prototypes/tile/fillableDirt")
-- if settings.startup["rampant-newEnemies"].value then
require("BuildSwarm")
-- end
require("prototypes/enemies/UnitSuicideBiters") require("prototypes/enemies/UnitSuicideBiters")
require("prototypes/enemies/UnitFireSpitters") require("prototypes/enemies/UnitFireSpitters")
require("prototypes/enemies/UnitTendril") require("prototypes/enemies/UnitTendril")

View File

@ -1,7 +1,7 @@
{ {
"name" : "Rampant", "name" : "Rampant",
"factorio_version" : "0.16", "factorio_version" : "0.16",
"version" : "0.16.2", "version" : "0.16.3",
"title" : "Rampant", "title" : "Rampant",
"author" : "Veden", "author" : "Veden",
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445", "homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",

View File

@ -66,10 +66,6 @@ function mathUtils.gaussianRandomRange(mean, std_dev, min, max, rg)
return q return q
end end
function mathUtils.positionToChunkOffset(position)
return mFloor(position.x * 0.03125), mFloor(position.y * 0.03125)
end
function mathUtils.euclideanDistanceNamed(p1, p2) function mathUtils.euclideanDistanceNamed(p1, p2)
local xs = p1.x - p2.x local xs = p1.x - p2.x
local ys = p1.y - p2.y local ys = p1.y - p2.y

View File

@ -34,6 +34,7 @@
(string->path "changelog.txt") (string->path "changelog.txt")
(string->path "Upgrade.lua") (string->path "Upgrade.lua")
(string->path "settings.lua") (string->path "settings.lua")
(string->path "BuildSwarm.lua")
(string->path "README.md") (string->path "README.md")
(string->path "NOTICE") (string->path "NOTICE")
(string->path "libs") (string->path "libs")
@ -73,6 +74,7 @@
(copyFile "changelog.txt" modFolder) (copyFile "changelog.txt" modFolder)
(copyFile "Upgrade.lua" modFolder) (copyFile "Upgrade.lua" modFolder)
(copyFile "tests.lua" modFolder) (copyFile "tests.lua" modFolder)
(copyFile "BuildSwarm.lua" modFolder)
(copyDirectory "libs" modFolder) (copyDirectory "libs" modFolder)
(copyDirectory "locale" modFolder) (copyDirectory "locale" modFolder)
(copyDirectory "sounds" modFolder) (copyDirectory "sounds" modFolder)
@ -80,6 +82,6 @@
(copyDirectory "prototypes" modFolder))) (copyDirectory "prototypes" modFolder)))
(define (run) (define (run)
;;(copyFiles modFolder) (copyFiles modFolder)
(makeZip modFolder) ;;(makeZip modFolder)
(system*/exit-code "/data/games/factorio/bin/x64/factorio"))) (system*/exit-code "/data/games/factorio/bin/x64/factorio")))

View File

@ -1,15 +1,12 @@
local biterFunctions = {} local biterFunctions = {}
function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances) function biterFunctions.makeBiter(name, biterAttributes, biterAttack, biterResistances)
biterAttack.scale = biterAttributes.scale;
biterAttack.tint1 = biterAttributes.tint1;
biterAttack.tint2 = biterAttributes.tint2;
return { return {
type = "unit", type = "unit",
name = biterAttributes.name, name = name,
icon = "__base__/graphics/icons/small-biter.png", icon = "__base__/graphics/icons/small-biter.png",
icon_size = 32, icon_size = 32,
flags = {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"}, flags = biterAttributes.flags or {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"},
max_health = biterAttributes.health, max_health = biterAttributes.health,
order = "b-b-a", order = "b-b-a",
subgroup="enemies", subgroup="enemies",
@ -22,11 +19,11 @@ function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances
sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale}, sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale},
{0.6 * biterAttributes.scale, 0}}, {0.6 * biterAttributes.scale, 0}},
attack_parameters = biterAttack, attack_parameters = biterAttack,
vision_distance = 30, vision_distance = biterAttributes.vision or 30,
movement_speed = biterAttributes.movement, movement_speed = biterAttributes.movement,
distance_per_frame = 0.1, distance_per_frame = biterAttributes.distancePerFrame or 0.1,
pollution_to_join_attack = 200, pollution_to_join_attack = biterAttributes.pollutionToAttack or 200,
distraction_cooldown = 300, distraction_cooldown = biterAttributes.distractionCooldown or 300,
corpse = biterAttributes.corpse, corpse = biterAttributes.corpse,
dying_explosion = biterAttributes.explosion, dying_explosion = biterAttributes.explosion,
dying_sound = make_biter_dying_sounds(1.0), dying_sound = make_biter_dying_sounds(1.0),
@ -35,16 +32,13 @@ function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances
} }
end end
function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistances) function biterFunctions.makeSpitter(name, biterAttributes, biterAttack, biterResistances)
-- biterAttack.scale = biterAttributes.scale;
-- biterAttack.tint1 = biterAttributes.tint1;
-- biterAttack.tint2 = biterAttributes.tint2;
return { return {
type = "unit", type = "unit",
name = biterAttributes.name, name = name,
icon = "__base__/graphics/icons/small-spitter.png", icon = "__base__/graphics/icons/small-spitter.png",
icon_size = 32, icon_size = 32,
flags = {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"}, flags = biterAttributes.flags or {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"},
max_health = biterAttributes.health, max_health = biterAttributes.health,
order = "b-b-a", order = "b-b-a",
subgroup="enemies", subgroup="enemies",
@ -57,11 +51,11 @@ function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistanc
sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale}, sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale},
{0.6 * biterAttributes.scale, 0}}, {0.6 * biterAttributes.scale, 0}},
attack_parameters = biterAttack, attack_parameters = biterAttack,
vision_distance = 30, vision_distance = biterAttributes.vision or 30,
movement_speed = biterAttributes.movement, movement_speed = biterAttributes.movement,
distance_per_frame = biterAttributes.distancePerFrame, distance_per_frame = biterAttributes.distancePerFrame or 0.1,
pollution_to_join_attack = 200, pollution_to_join_attack = biterAttributes.pollutionToAttack or 200,
distraction_cooldown = 300, distraction_cooldown = biterAttributes.distractionCooldown or 300,
corpse = biterAttributes.corpse, corpse = biterAttributes.corpse,
dying_explosion = biterAttributes.explosion, dying_explosion = biterAttributes.explosion,
dying_sound = make_biter_dying_sounds(1.0), dying_sound = make_biter_dying_sounds(1.0),
@ -70,6 +64,70 @@ function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistanc
} }
end end
function biterFunctions.makeUnitSpawner(name, biterAttributes, biterResistances, unitSet)
local o = {
type = "unit-spawner",
name = name,
icon = "__base__/graphics/icons/biter-spawner.png",
icon_size = 32,
flags = {"placeable-player", "placeable-enemy", "not-repairable"},
max_health = biterAttributes.health,
order="b-b-g",
subgroup="enemies",
resistances = biterResistances,
working_sound = {
sound =
{
{
filename = "__base__/sound/creatures/spawner.ogg",
volume = 1.0
}
},
apparent_volume = 2
},
dying_sound =
{
{
filename = "__base__/sound/creatures/spawner-death-1.ogg",
volume = 1.0
},
{
filename = "__base__/sound/creatures/spawner-death-2.ogg",
volume = 1.0
}
},
healing_per_tick = biterAttributes.healing or 0.02,
collision_box = {{-3.2 * biterAttributes.scale, -2.2 * biterAttributes.scale}, {2.2 * biterAttributes.scale, 2.2 * biterAttributes.scale}},
selection_box = {{-3.5 * biterAttributes.scale, -2.5 * biterAttributes.scale}, {2.5 * biterAttributes.scale, 2.5 * biterAttributes.scale}},
-- in ticks per 1 pu
pollution_absorbtion_absolute = biterAttributes.pollutionAbsorbtionAbs or 20,
pollution_absorbtion_proportional = biterAttributes.pollutionAbsorbtionPro or 0.01,
corpse = "biter-spawner-corpse",
dying_explosion = "blood-explosion-huge",
max_count_of_owned_units = biterAttributes.unitsOwned or 7,
max_friends_around_to_spawn = biterAttributes.unitsToSpawn or 5,
animations =
{
spawner_idle_animation(0, biterAttributes.tint),
spawner_idle_animation(1, biterAttributes.tint),
spawner_idle_animation(2, biterAttributes.tint),
spawner_idle_animation(3, biterAttributes.tint)
},
result_units = unitSet,
-- With zero evolution the spawn rate is 6 seconds, with max evolution it is 2.5 seconds
spawning_cooldown = biterAttributes.spawningCooldown or {360, 150},
spawning_radius = biterAttributes.spawningRadius or 10,
spawning_spacing = biterAttributes.spawningSpacing or 3,
max_spawn_shift = 0,
max_richness_for_spawn_shift = 100,
call_for_help_radius = 50
}
if biterAttributes.autoplace then
o["autoplace"] = enemy_spawner_autoplace(biterAttributes.autoplace)
end
return o
end
function biterFunctions.createSuicideAttack(attributes) function biterFunctions.createSuicideAttack(attributes)
return { type = "projectile", return { type = "projectile",
range = 0.5, range = 0.5,