1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-04 09:43:00 +02:00

Saving initial Gleba work. Have a dumb but simple method for placing plants and iron-copper things. Needs refining and testing.

This commit is contained in:
Oarcinae 2024-11-19 23:16:52 -05:00
parent d06d6eadf3
commit 553389ce6e
6 changed files with 196 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 growth_resources table<string, OarcConfigGrowthResource> Spawn area config for growth resources (like gleba trees)
---@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,11 @@ OCFG = {
---@field x_offset_next integer
---@field y_offset_next integer
---@class OarcConfigGrowthResource
---@field tile string The tile to place
---@field entity string The entity (tree that grows on this specific tile)
---@field size integer
---@class OarcStoreItem
---@field cost integer
---@field count integer

View File

@ -0,0 +1,58 @@
-- 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 = "highland-dark-rock-2"
GLEBA_SPAWN_CONFIG.liquid_tile = "gleba-deep-lake"
GLEBA_SPAWN_CONFIG.tree_entity = nil
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},
}
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.growth_resources =
{
["yumako"] = {
tile = "natural-yumako-soil",
entity = "yumako-tree",
size = 20
},
["jellystem"] = {
tile = "natural-jellynut-soil",
entity = "jellystem",
size = 20
},
["iron"] = {
tile = "wetland-dead-skin",
entity = "iron-stromatolite",
size = 20
},
["copper"] = {
tile = "wetland-dead-skin",
entity = "copper-stromatolite",
size = 20
},
}
GLEBA_SPAWN_CONFIG.fluid_resources = { }

View File

@ -170,6 +170,8 @@ NAUVIS_SPAWN_CONFIG =
y_offset_next = 0
}
},
growth_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,17 +68,21 @@ 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
-- 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
@ -203,36 +215,54 @@ 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 }
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.growth_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.growth_resources[r_name]
GenerateGrowthResourcePatch(surface, gResourceConfig.tile, gResourceConfig.entity, 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.growth_resources[r_name]
GenerateGrowthResourcePatch(surface, gResourceConfig.tile, gResourceConfig.entity, 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,55 @@ 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 growth resource patch, of a certain size at a pos.
---@param surface LuaSurface
---@param tile_name string
---@param entity_name string
---@param diameter integer
---@param position TilePosition
---@return nil
function GenerateGrowthResourcePatch(surface, tile_name, entity_name, diameter, position)
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
-- Reduce chances to spawn to make it more sparse.
if (math.random(1, 20) == 1) then
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