1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-12 10:13:58 +02:00

Merge pull request #268 from Oarcinae/220-sa-need-to-setup-spawn-areas-for-each-planet-gleba

220 sa need to setup spawn areas for each planet gleba
This commit is contained in:
Oarcinae 2024-11-20 11:51:09 -05:00 committed by GitHub
commit 04bd237cf5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 239 additions and 31 deletions

View File

@ -18,6 +18,7 @@
require("lib/planet_configs/nauvis")
require("lib/planet_configs/fulgora")
require("lib/planet_configs/vulcanus")
require("lib/planet_configs/gleba")
---@alias SpawnShapeChoice "circle" | "octagon" | "square"
SPAWN_SHAPE_CHOICE_CIRCLE = "circle"
@ -372,13 +373,13 @@ OCFG = {
starting_items = FULGORA_STARTER_ITEMS,
spawn_config = FULGORA_SPAWN_CONFIG
},
-- ["gleba"] = {
-- starting_items = NAUVIS_STARTER_ITEMS,
-- spawn_config = NAUVIS_SPAWN_CONFIG
-- },
["gleba"] = {
starting_items = GLEBA_STARTER_ITEMS,
spawn_config = GLEBA_SPAWN_CONFIG
},
-- ["aquilo"] = {
-- starting_items = NAUVIS_STARTER_ITEMS,
-- spawn_config = NAUVIS_SPAWN_CONFIG
-- starting_items = AQUILO_STARTER_ITEMS,
-- spawn_config = AQUILO_SPAWN_CONFIG
-- }
},
@ -512,6 +513,7 @@ OCFG = {
---@field shared_chest_position OarcOffsetPosition Location of shared chest relative to spawn center (if enabled)
---@field solid_resources table<string, OarcConfigSolidResource> Spawn area config for solid resource tiles
---@field fluid_resources table<string, OarcConfigFluidResource> Spawn area config for fluid resource patches (like oil)
---@field gleba_resources table<string, OarcConfigGlebaResource> Spawn area config for gleba-style resources (like plants and stromatolites)
---@class OarcConfigSpawnGeneral
---@field spawn_radius_tiles number THIS IS WHAT SETS THE SPAWN CIRCLE SIZE! Create a circle of land area for the spawn If you make this much bigger than a few chunks, good luck.
@ -561,6 +563,12 @@ OCFG = {
---@field x_offset_next integer
---@field y_offset_next integer
---@class OarcConfigGlebaResource
---@field tile string The tile to place
---@field entities string[] The entities that can be placed on the tile
---@field size integer The size of the resource patch
---@field density number How often we attempt to place an entity per tile (so if the entity is bigger, then even a density < 1 might still completely fill the area)
---@class OarcStoreItem
---@field cost integer
---@field count integer

View File

@ -0,0 +1,60 @@
-- This config is used as the default config for the planet gleba.
---@type OarcConfigStartingItems
GLEBA_STARTER_ITEMS = table.deepcopy(NO_STARTER_ITEMS)
---@type OarcConfigSpawn
GLEBA_SPAWN_CONFIG = table.deepcopy(NAUVIS_SPAWN_CONFIG)
GLEBA_SPAWN_CONFIG.fill_tile = "lowland-olive-blubber"
GLEBA_SPAWN_CONFIG.liquid_tile = "gleba-deep-lake"
GLEBA_SPAWN_CONFIG.tree_entity = "funneltrunk"
GLEBA_SPAWN_CONFIG.random_entities = {
{name = "boompuff", count = 10},
{name = "sunnycomb", count = 10},
{name = "stingfrond", count = 10},
{name = "funneltrunk", count = 10},
{name = "teflilly", count = 10},
{name = "slipstack", count = 10},
{name = "cuttlepop", count = 10},
{name = "water-cane", count = 10},
}
-- Make the warning and danger areas a bit bigger for this planet.
GLEBA_SPAWN_CONFIG.safe_area.warn_radius = 16
GLEBA_SPAWN_CONFIG.safe_area.danger_radius = 32
GLEBA_SPAWN_CONFIG.solid_resources =
{
["stone"] = {
amount = 1000,
size = 20,
-- These are only used if not using automatic placing.
x_offset = -29,
y_offset = 16
}
}
GLEBA_SPAWN_CONFIG.fluid_resources = { }
GLEBA_SPAWN_CONFIG.gleba_resources =
{
["yumako"] = {
tile = "natural-yumako-soil",
entities = {"yumako-tree"},
size = 25,
density = 0.05
},
["jellystem"] = {
tile = "natural-jellynut-soil",
entities = {"jellystem"},
size = 25,
density = 0.05
},
["iron"] = {
tile = "wetland-green-slime",
entities = {"iron-stromatolite", "copper-stromatolite"},
size = 25,
density = 0.10
},
}

View File

@ -170,6 +170,8 @@ NAUVIS_SPAWN_CONFIG =
y_offset_next = 0
}
},
gleba_resources = {}
}
---@type OarcConfigSurface

View File

@ -8,9 +8,14 @@
ENEMY_FORCES_NAMES = { "enemy" }
ENEMY_FORCES_NAMES_INCL_NEUTRAL = { "enemy", "neutral" }
ENEMY_BUILT_TYPES = { "biter-spawner", "spitter-spawner", "small-worm-turret", "medium-worm-turret", "big-worm-turret",
"behemoth-worm-turret" }
-- gleba-spawner-small
-- gleba-spawner
-- yumako-tree
-- copper-stromatolite
-- jellystem
-- yumako-tree
---Downgrades worms based on distance from origin and near/far spawn distances.
---This helps make sure worms aren't too overwhelming even at these further spawn distances.
@ -47,12 +52,15 @@ function DowngradeAndReduceEnemiesOnChunkGenerate(event)
y = chunk_area.left_top.y + (CHUNK_SIZE / 2)
}
-- TODO: Change this lookup to be done once during surface init.
local nauvis_enemies = surface.map_gen_settings.autoplace_controls["enemy-base"] ~= nil
local gleba_enemies = surface.map_gen_settings.autoplace_controls["gleba_enemy_base"] ~= nil
-- local vulcanus_enemies = surface.map_gen_settings.territory_settings ~= nil
-- Make chunks near a spawn safe by removing enemies
-- TODO: Refactor this to reduce calls to find_entities_filtered maybe?
if (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.safe_radius * CHUNK_SIZE) then
if nauvis_enemies or gleba_enemies then
RemoveEnemiesInArea(surface, chunk_area)
@ -60,22 +68,42 @@ function DowngradeAndReduceEnemiesOnChunkGenerate(event)
-- Create a warning area with heavily reduced enemies
elseif (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.warn_radius * CHUNK_SIZE) then
if nauvis_enemies then
-- TODO: Refactor this to reduce calls to find_entities_filtered!
if nauvis_enemies or gleba_enemies then
ReduceEnemiesInArea(surface, chunk_area, spawn_config.safe_area.warn_reduction)
end
if nauvis_enemies then
RemoveWormsInArea(surface, chunk_area, false, true, true, true) -- remove all non-small worms.
end
if gleba_enemies then
DowngradeGlebaSpawnersInArea(surface, chunk_area)
end
-- Create a third area with moderately reduced enemies
elseif (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.danger_radius * CHUNK_SIZE) then
if nauvis_enemies then
-- TODO: Refactor this to reduce calls to find_entities_filtered!
if nauvis_enemies or gleba_enemies then
ReduceEnemiesInArea(surface, chunk_area, spawn_config.safe_area.danger_reduction)
end
if nauvis_enemies then
RemoveWormsInArea(surface, chunk_area, false, false, true, true) -- remove all huge/behemoth worms.
end
end
end
---Downgrades gleba spawners in the area
---@param surface LuaSurface
---@param area BoundingBox
---@return nil
function DowngradeGlebaSpawnersInArea(surface, area)
for _, entity in pairs(surface.find_entities_filtered { area = area, name = "gleba-spawner", force = "enemy" }) do
local position = entity.position
entity.destroy()
local spawner = surface.create_entity { name = "gleba-spawner-small", position = position, force = game.forces.enemy }
end
end
---Convenient way to remove aliens, just provide an area
---@param surface LuaSurface
---@param area BoundingBox
@ -203,36 +231,60 @@ function ModifyEnemySpawnsNearPlayerStartingAreas(event)
-- Warn distance is all SMALL only.
elseif (util.distance(enemy_pos, closest_spawn.position) < storage.ocfg.surfaces_config[surface.name].spawn_config.safe_area.warn_radius * CHUNK_SIZE) then
if ((enemy_name == "biter-spawner") or (enemy_name == "spitter-spawner")) then
-- Do nothing.
elseif ((enemy_name == "big-biter") or (enemy_name == "behemoth-biter") or (enemy_name == "medium-biter")) then
-- Nauvis enemies
if ((enemy_name == "big-biter") or (enemy_name == "behemoth-biter") or (enemy_name == "medium-biter")) then
event.entity.destroy()
surface.create_entity { name = "small-biter", position = enemy_pos, force = game.forces.enemy }
-- log("Downgraded biter close to spawn.")
elseif ((enemy_name == "big-spitter") or (enemy_name == "behemoth-spitter") or (enemy_name == "medium-spitter")) then
event.entity.destroy()
surface.create_entity { name = "small-spitter", position = enemy_pos, force = game.forces.enemy }
-- log("Downgraded spitter close to spawn.")
elseif ((enemy_name == "big-worm-turret") or (enemy_name == "behemoth-worm-turret") or (enemy_name == "medium-worm-turret")) then
event.entity.destroy()
surface.create_entity { name = "small-worm-turret", position = enemy_pos, force = game.forces.enemy }
-- log("Downgraded worm close to spawn.")
-- Gleba enemies
elseif ((enemy_name == "big-wriggler-pentapod") or (enemy_name == "medium-wriggler-pentapod")) then
event.entity.destroy()
surface.create_entity { name = "small-wriggler-pentapod", position = enemy_pos, force = game.forces.enemy }
elseif ((enemy_name == "big-stomper-pentapod") or (enemy_name == "medium-stomper-pentapod")) then
event.entity.destroy()
surface.create_entity { name = "small-stomper-pentapod", position = enemy_pos, force = game.forces.enemy }
elseif ((enemy_name == "big-strafer-pentapod") or (enemy_name == "medium-strafer-pentapod")) then
event.entity.destroy()
surface.create_entity { name = "small-strafer-pentapod", position = enemy_pos, force = game.forces.enemy }
-- Gleba spawners downgrade
elseif (enemy_name == "gleba-spawner") then
event.entity.destroy()
surface.create_entity { name = "gleba-spawner-small", position = enemy_pos, force = game.forces.enemy }
end
-- Danger distance is MEDIUM max.
elseif (util.distance(enemy_pos, closest_spawn.position) < storage.ocfg.surfaces_config[surface.name].spawn_config.safe_area.danger_radius * CHUNK_SIZE) then
-- Nauvis enemies
if ((enemy_name == "big-biter") or (enemy_name == "behemoth-biter")) then
event.entity.destroy()
surface.create_entity { name = "medium-biter", position = enemy_pos, force = game.forces.enemy }
-- log("Downgraded biter further from spawn.")
elseif ((enemy_name == "big-spitter") or (enemy_name == "behemoth-spitter")) then
event.entity.destroy()
surface.create_entity { name = "medium-spitter", position = enemy_pos, force = game.forces.enemy }
-- log("Downgraded spitter further from spawn
elseif ((enemy_name == "big-worm-turret") or (enemy_name == "behemoth-worm-turret")) then
event.entity.destroy()
surface.create_entity { name = "medium-worm-turret", position = enemy_pos, force = game.forces.enemy }
-- log("Downgraded worm further from spawn.")
-- Gleba enemies
elseif (enemy_name == "big-wriggler-pentapod") then
event.entity.destroy()
surface.create_entity { name = "medium-wriggler-pentapod", position = enemy_pos, force = game.forces.enemy }
elseif (enemy_name == "big-stomper-pentapod") then
event.entity.destroy()
surface.create_entity { name = "medium-stomper-pentapod", position = enemy_pos, force = game.forces.enemy }
elseif (enemy_name == "big-strafer-pentapod") then
event.entity.destroy()
surface.create_entity { name = "medium-strafer-pentapod", position = enemy_pos, force = game.forces.enemy }
end
end
end

View File

@ -372,7 +372,7 @@ end
---@param spawn_config OarcConfigSpawn
---@param surface LuaSurface
---@return nil
function GenerateStartingLiquedStrip(delayed_spawn, spawn_config, surface)
function GenerateStartingLiquidStrip(delayed_spawn, spawn_config, surface)
local water_data = spawn_config.water
-- Reference position is the top of the spawn area.
@ -398,6 +398,7 @@ end
---@return nil
function GenerateStartingResources(surface, position)
--TODO: This should come from map gen settings instead:
local size_mod = storage.ocfg.resource_placement.size_multiplier
local amount_mod = storage.ocfg.resource_placement.amount_multiplier
@ -478,19 +479,26 @@ function PlaceResourcesInSemiCircle(surface, position, size_mod, amount_mod)
-- Create list of resource tiles
---@type table<string>
local r_list = {}
for r_name, _ in pairs(storage.ocfg.surfaces_config[surface.name].spawn_config.solid_resources --[[@as table<string, OarcConfigSolidResource>]]) do
for r_name, _ in pairs(storage.ocfg.surfaces_config[surface.name].spawn_config.solid_resources) do
if (r_name ~= "") then
table.insert(r_list, r_name)
end
end
for g_name,_ in pairs(storage.ocfg.surfaces_config[surface.name].spawn_config.gleba_resources) do
if (g_name ~= "") then
table.insert(r_list, g_name)
end
end
---@type table<string>
local shuffled_list = FYShuffle(r_list)
local num_resources = table_size(shuffled_list)
-- This places resources in a semi-circle
local surface_config = storage.ocfg.surfaces_config[surface.name]
local angle_offset_radians = math.rad(storage.ocfg.resource_placement.angle_offset)
local angle_final_radians = math.rad(storage.ocfg.resource_placement.angle_final)
local num_resources = table_size(storage.ocfg.surfaces_config[surface.name].spawn_config.solid_resources)
local radius = storage.ocfg.spawn_general.spawn_radius_tiles * surface_config.spawn_config.radius_modifier - storage.ocfg.resource_placement.distance_to_edge
-- Special case for only one resource, place it in the middle of the semi-circle.
@ -504,7 +512,13 @@ function PlaceResourcesInSemiCircle(surface, position, size_mod, amount_mod)
local pos = { x = math.floor(tx), y = math.floor(ty) }
local resourceConfig = surface_config.spawn_config.solid_resources[r_name]
GenerateResourcePatch(surface, r_name, resourceConfig.size * size_mod, pos, resourceConfig.amount * amount_mod)
if (resourceConfig ~= nil) then
GenerateResourcePatch(surface, r_name, resourceConfig.size * size_mod, pos, resourceConfig.amount * amount_mod)
else
local gResourceConfig = surface_config.spawn_config.gleba_resources[r_name]
GenerateGlebaStyleResourcePatch(surface, gResourceConfig, gResourceConfig.size * size_mod, pos)
end
else
local theta = ((angle_final_radians - angle_offset_radians) / (num_resources-1));
local count = 0
@ -518,8 +532,13 @@ function PlaceResourcesInSemiCircle(surface, position, size_mod, amount_mod)
local pos = { x = math.floor(tx), y = math.floor(ty) }
local resourceConfig = storage.ocfg.surfaces_config[surface.name].spawn_config.solid_resources[r_name]
GenerateResourcePatch(surface, r_name, resourceConfig.size * size_mod, pos, resourceConfig.amount * amount_mod)
local resourceConfig = surface_config.spawn_config.solid_resources[r_name]
if (resourceConfig ~= nil) then
GenerateResourcePatch(surface, r_name, resourceConfig.size * size_mod, pos, resourceConfig.amount * amount_mod)
else
local gResourceConfig = surface_config.spawn_config.gleba_resources[r_name]
GenerateGlebaStyleResourcePatch(surface, gResourceConfig, gResourceConfig.size * size_mod, pos)
end
count = count + 1
end
end
@ -580,7 +599,7 @@ function GenerateFinalSpawnPieces(delayed_spawn)
-- Generate water strip only if we don't have a moat.
if (not delayed_spawn.moat or spawn_config.liquid_tile == "lava") then
GenerateStartingLiquedStrip(delayed_spawn, spawn_config, surface)
GenerateStartingLiquidStrip(delayed_spawn, spawn_config, surface)
end
-- Create the spawn resources here
@ -754,9 +773,9 @@ function SetupAndClearSpawnAreas(surface, chunkArea)
-- Remove trees/resources inside the spawn area
if (general_spawn_config.shape == SPAWN_SHAPE_CHOICE_CIRCLE) or (general_spawn_config.shape == SPAWN_SHAPE_CHOICE_OCTAGON) then
RemoveInCircle(surface, chunkArea, {"resource", "cliff", "tree", "lightning-attractor", "simple-entity"}, spawn.position, radius + 5)
RemoveInCircle(surface, chunkArea, {"resource", "cliff", "tree", "plant", "lightning-attractor", "simple-entity"}, spawn.position, radius + 5)
elseif (general_spawn_config.shape == SPAWN_SHAPE_CHOICE_SQUARE) then
RemoveInSquare(surface, chunkArea, {"resource", "cliff", "tree", "lightning-attractor", "simple-entity"}, spawn.position, radius + 5)
RemoveInSquare(surface, chunkArea, {"resource", "cliff", "tree", "plant", "lightning-attractor", "simple-entity"}, spawn.position, radius + 5)
end
if (general_spawn_config.shape == SPAWN_SHAPE_CHOICE_CIRCLE) then

View File

@ -277,6 +277,7 @@ end
---@param diameter integer
---@param position TilePosition
---@param amount integer
---@return nil
function GenerateResourcePatch(surface, resourceName, diameter, position, amount)
local midPoint = math.floor(diameter / 2)
if (diameter == 0) then
@ -300,7 +301,59 @@ function GenerateResourcePatch(surface, resourceName, diameter, position, amount
end
end
--- Function to generate a resource patch, of a certain size/amount at a pos.
--- Function to generate a gleba style resource patch (plants or stromatolites), of a certain size at a pos.
---@param surface LuaSurface
---@param gleba_resource OarcConfigGlebaResource
---@param diameter integer
---@param position TilePosition
---@return nil
function GenerateGlebaStyleResourcePatch(surface, gleba_resource, diameter, position)
local tile_name = gleba_resource.tile
local entity_names = gleba_resource.entities
local midPoint = math.floor(diameter / 2)
if (diameter == 0) then
return
end
-- Right now only 2 shapes are supported. Circle and Square.
local square_shape = (storage.ocfg.spawn_general.resources_shape == RESOURCES_SHAPE_CHOICE_SQUARE)
local tiles = {}
for y = -midPoint, midPoint do
for x = -midPoint, midPoint do
-- Either it's a square, or it's a circle so we check if it's inside the circle.
if (square_shape or ((x) ^ 2 + (y) ^ 2 < midPoint ^ 2)) then
table.insert(tiles, { name = tile_name, position = { position.x + x, position.y + y } })
end
end
end
surface.set_tiles(tiles)
for y = -midPoint, midPoint do
for x = -midPoint, midPoint do
-- Either it's a square, or it's a circle so we check if it's inside the circle.
if (square_shape or ((x) ^ 2 + (y) ^ 2 < midPoint ^ 2)) then
-- Density controls how often we try to place an entity per tile.
if (math.random() <= gleba_resource.density) then
local entity_name = entity_names[math.random(1, #entity_names)]
local pos = surface.find_non_colliding_position(entity_name, { position.x + x, position.y + y }, 2, 0.5)
if (pos ~= nil) then
local entity = surface.create_entity({ name = entity_name, position = pos })
if (entity.type == "plant") then
entity.tick_grown = game.tick
end
end
end
end
end
end
end
---Places random entities around the spawn area.
---@param surface LuaSurface
---@param position MapPosition
---@return nil

View File

@ -27,4 +27,18 @@ if script.active_mods["space-age"] ~= nil then
}
log("Updating vulcanus config with new spawn_config and starting_items.")
end
end
-- Make sure gleba config is set up if it is missing.
if script.active_mods["space-age"] ~= nil then
if (storage.ocfg.surfaces_config["gleba"] == nil) or
(storage.ocfg.surfaces_config["gleba"].spawn_config.gleba_resources == nil) or
(#storage.ocfg.surfaces_config["gleba"].spawn_config.gleba_resources == 0) then
storage.ocfg.surfaces_config["gleba"] =
{
spawn_config = GLEBA_SPAWN_CONFIG,
starting_items = GLEBA_STARTER_ITEMS
}
log("Updating gleba config with new spawn_config and starting_items.")
end
end