mirror of
https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git
synced 2024-12-04 09:43:00 +02:00
Saving major work implementing and testing secondary spawns on other surfaces. Still semi-experimental.
This commit is contained in:
parent
3eb2c385c9
commit
30646f63d7
18
control.lua
18
control.lua
@ -69,6 +69,8 @@ script.on_init(function(event)
|
||||
for _,player in pairs(game.players) do
|
||||
SeparateSpawnsInitPlayer(player.index)
|
||||
end
|
||||
|
||||
game.technology_notifications_enabled = false
|
||||
end)
|
||||
|
||||
|
||||
@ -82,14 +84,9 @@ end)
|
||||
--------------------------------------------------------------------------------
|
||||
-- On Configuration Changed - Only runs when the mod configuration changes
|
||||
--------------------------------------------------------------------------------
|
||||
-- oarc_new_spawn_created = script.generate_event_name()
|
||||
|
||||
script.on_configuration_changed(function(data)
|
||||
-- Regenerate event ID:
|
||||
|
||||
-- Reset the players GUI
|
||||
for _,player in pairs(game.players) do
|
||||
RecreateOarcGui(player)
|
||||
RecreateOarcGui(player) -- Reset the players GUI
|
||||
end
|
||||
end)
|
||||
|
||||
@ -149,6 +146,11 @@ script.on_event(defines.events.on_player_driving_changed_state, function (event)
|
||||
end
|
||||
end)
|
||||
|
||||
script.on_event(defines.events.on_research_finished, function(event)
|
||||
local research = event.research
|
||||
SendBroadcastMsg("Team " .. research.force.name .. " finished research: " .. research.name)
|
||||
end)
|
||||
|
||||
----------------------------------------
|
||||
-- CUSTOM OARC Events (shown here for demo and logging purposes)
|
||||
----------------------------------------
|
||||
@ -227,6 +229,7 @@ end)
|
||||
script.on_event(defines.events.on_tick, function(event)
|
||||
DelayedSpawnOnTick()
|
||||
FadeoutRenderOnTick()
|
||||
OnTickNilCharacterTeleportQueue()
|
||||
|
||||
if storage.ocfg.regrowth.enable_regrowth then
|
||||
RegrowthOnTick()
|
||||
@ -243,12 +246,13 @@ script.on_event(defines.events.on_chunk_generated, function(event)
|
||||
end
|
||||
|
||||
CreateHoldingPenChunks(event)
|
||||
SeparateSpawnsGenerateChunk(event)
|
||||
|
||||
if storage.ocfg.gameplay.modified_enemy_spawning then
|
||||
DowngradeWormsDistanceBasedOnChunkGenerate(event)
|
||||
DowngradeAndReduceEnemiesOnChunkGenerate(event)
|
||||
end
|
||||
|
||||
SeparateSpawnsGenerateChunk(event)
|
||||
end)
|
||||
|
||||
----------------------------------------
|
||||
|
82
devplan.txt
82
devplan.txt
@ -1,66 +1,20 @@
|
||||
ACTIVE ITEMS:
|
||||
|
||||
- Need a way to identify if the spawn a player is assigned to is still in the middle of being generated and to queue them for delayed spawn.
|
||||
- Add a flag to unique spawns to tell if it is generated yet or not? Or a way to search delayed spawns first?
|
||||
ACTIVE NOTES:
|
||||
|
||||
|
||||
- Rework spawning to use the oarc-mod-on-spawn-created event
|
||||
- Queue the spawn for creation using whatever player host and player choice data we want.
|
||||
- Event should then look through the hosts and joiners to see if any are waiting for the spawn. (How do we tell if they are waiting?)
|
||||
- Need to handle players leaving before it is done (same as before)
|
||||
- What happens to multiple unique spawn hosts on "main force" when they go to a new planet?
|
||||
- They get unique spawn areas, but they have to coordinate regarding the landing pad, OR they can install a mod to have multiple but it is still up to them to coordinate.
|
||||
|
||||
- Change permissions to be enabled/disabled when entering/leaving the holding pen (use custom surface changed event?)
|
||||
|
||||
- OarcDelayedSpawn table should point directly to the unique spawn? Or deepcopy all of it. It should have host_name instead of playerName
|
||||
|
||||
Secondary Spawns:
|
||||
- What if a joiner gets to a planet before host?
|
||||
- Create the spawn with the host's name as the owner.
|
||||
- How do buddies spawn together on a planet?
|
||||
- They get given a single spawn. Leave the buddy spawn as a Nauvis only gimmick for now.
|
||||
- What happens to multiple unique spawn hosts on "main force" when they go to a new planet?
|
||||
- They get unique spawn areas, but they have to coordinate regarding the landing pad, OR they can install a mod to have multiple but it is still up to them to coordinate.
|
||||
- What if a host and joiner land at the same time?
|
||||
- What if buddies try to land at the same time?
|
||||
|
||||
- What if someone leaves while they are queued to go to a secondary delayed spawn?
|
||||
|
||||
- Joining a shared spawn should be put the player as a joiner into ALL secondary spawns
|
||||
|
||||
|
||||
|
||||
- Methods a player can use to join a game:
|
||||
- Create their own spawn
|
||||
- Join a spawn
|
||||
|
||||
|
||||
Flow
|
||||
- Player selects spawn choices (new, shared, buddy)
|
||||
-
|
||||
|
||||
Cleanup storage.delayed_spawns when a player leaves.
|
||||
Review UniqueSpawnCleanupRemove now that there are secondary spawns.
|
||||
|
||||
Cleanup CreateCropCircle and CreateCropOctagon and CreateCropSquare
|
||||
|
||||
Change permissions to be enabled/disabled when entering/leaving the holding pen (use custom surface changed event?)
|
||||
|
||||
Player deleting base when delayed spawn is in work is more complicated now because in theory other players could be also be waiting on that spawn?
|
||||
|
||||
Get rid of enable secondary spawns setting (redundant.)
|
||||
|
||||
Get rid of storage.buddy_pairs ?? Is basically duplicate info inside the spawns right?
|
||||
- Get rid of storage.buddy_pairs ?? Is basically duplicate info inside the spawns right?
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
BACKLOG:
|
||||
|
||||
Not specific:
|
||||
- Fix wording for "force grass" setting if I allow any tile to be used there...
|
||||
|
||||
Minor:
|
||||
- If dead when resetting spawn... possibly delay the opening of the welcome GUI or block spawning until character is spawned?
|
||||
- Expose old enemy scaling as an option? And/or remove unnecessary checks/logs
|
||||
- Refresh players in admin controls when dropdown is clicked
|
||||
- Add a setting for forcing primary spawns to only be on default surface maybe?
|
||||
|
||||
Performance:
|
||||
- User on_nth_tick for any tick % (modulo) operations.
|
||||
@ -77,12 +31,7 @@ Major:
|
||||
- Pollution changes (regrowth)?
|
||||
- Enemy changes?
|
||||
- Landing pad locations per FORCE limited to 1?
|
||||
- Surface names for space ships?
|
||||
- Spawner health tied to evolution?
|
||||
- Respawn position is surface specific? Each surface needs a separate respawn point? Default respawn behavior?
|
||||
- Confirm launch into scenario works (V2.0 fix supposedly) -- https://forums.factorio.com/110708
|
||||
- Radar quality affects regrowth safe range?
|
||||
- Update electric pole connections for shared power if things change in V2.0
|
||||
|
||||
- Source: https://forums.factorio.com/115737
|
||||
- Specifics that I might need to investigate:
|
||||
@ -93,9 +42,6 @@ Added space-platform-starter-pack, space-location, planet and space-connection p
|
||||
Added surface-property and surface prototypes.
|
||||
Added new controller type (remote), which is to build space platforms, so it allows ghost building but not any physical manipulation.
|
||||
Added LuaPlayer::physical_surface, physical_surface_index, physical_vehicle and physical_position read.
|
||||
Electric pole created through LuaSurface::create_entity can be requested to not auto connect.
|
||||
Added LuaSurface::global_effect read/write.
|
||||
Added LuaSurface::localised_name read/write.
|
||||
LuaGameScript::print, LuaPlayer::print, LuaSurface::print and LuaForce::print no longer accept Color as a second parameter.
|
||||
Added LuaSurface::set_property() and get_property() methods.
|
||||
Added LuaSurface::execute_lightning() method.
|
||||
@ -104,24 +50,10 @@ Added LuaSurface::has_global_electric_network read.
|
||||
Added LuaSurface::platform read.
|
||||
Added LuaSurface::pollutant_type read.
|
||||
Added airborne-pollutant prototype and changed various pollution related properties to support multiple pollution types.
|
||||
Added LuaSurface::deletable read.
|
||||
Added LuaForce::set_surface_hidden() and get_surface_hidden() methods.
|
||||
Added cause argument to LuaSurface::create_entity.
|
||||
Added LuaSurfacePrototype::surface_properties read.
|
||||
Added on_player_controller_changed event.
|
||||
Removed LuaPlayer::open_map, zoom_to_world, and close_map. LuaPlayer::set_controller with type 'remote' replaces these.
|
||||
oved LuaGameScript::styles to LuaPrototypes::style.
|
||||
Removed LuaGameScript::active_mods. Use LuaBootstrap::active_mods instead.
|
||||
Renamed `global` into `storage`.
|
||||
Added LuaGameScript::technology_notifications_enabled (read/write).
|
||||
Added LuaGameScript::planets read.
|
||||
Added LuaGameScript::get_vehicles.
|
||||
Added LuaForce::platforms read.
|
||||
Added LuaGameScript::set_win_ending_info() and set_lose_ending_info() methods.
|
||||
Added LuaForce::unlock_space_location(), lock_space_location() and is_space_location_unlocked() methods.
|
||||
Added LuaForce::create_space_platform() method.
|
||||
Added LuaForce::unlock_space_platforms(), lock_space_platforms() and is_space_platforms_unlocked() methods.
|
||||
Changed LuaForce::evolution_factor, evolution_factor_by_pollution, evolution_factor_by_time and evolution_factor_by_killing_spawners to get_* and set_* methods.
|
||||
Added LuaForce::copy_from() and copy_chart() methods.
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
@ -137,7 +69,6 @@ Other Ideas, Not Committed:
|
||||
- Change enable_shared_team_vision to allow players to change this per player (like BNO)
|
||||
- Change enable_friendly_fire to be per team?
|
||||
- Allow players to spawn "near" an existing player (by request)
|
||||
- Allow players to restart at anytime via GUI button (configurable setting by admin)
|
||||
- Change regrowth to be list of surfaces indexed by surface name?
|
||||
- Figure out how to reset player inventory on player reset to avoid extra items? (save and load items?)
|
||||
- Work on space ex support?
|
||||
@ -228,4 +159,5 @@ Other Ideas, Not Committed:
|
||||
- Pull out general spawn config from surfaces config
|
||||
- Redo resource placement to be simpler (and make a linear layout for square base)
|
||||
- Default to selecting SELF in admin controls player dropdown?
|
||||
- Add refresh chunks around spidertrons based on their vision
|
||||
- Add refresh chunks around spidertrons based on their vision
|
||||
- Allow players to restart at anytime via GUI button (configurable setting by admin)
|
@ -224,10 +224,6 @@ OCFG = {
|
||||
-- The default starting surface.
|
||||
default_surface = "nauvis",
|
||||
|
||||
-- Enable secondary spawns for players.
|
||||
-- This automatically creates a new spawn point when they first move to a separate spawns enabled surface.
|
||||
enable_secondary_spawns = false,
|
||||
|
||||
-- This scales resources so that even if you spawn "far away" from the center
|
||||
-- of the map, resources near to your spawn point scale so you aren't
|
||||
-- surrounded by 100M patches or something. This is useful depending on what
|
||||
@ -310,9 +306,9 @@ OCFG = {
|
||||
-- Starting resources deposits shape.
|
||||
resources_shape = RESOURCES_SHAPE_CHOICE_CIRCLE,
|
||||
|
||||
-- Force the land area circle at the spawn to be fully grass, otherwise it defaults to the existing terrain
|
||||
-- or uses landfill.
|
||||
force_grass = false,
|
||||
-- Force the land area circle at the spawn to be a single tile (default grass on Nauvis), otherwise it defaults
|
||||
-- to the existing terrain and uses landfill to fill gaps.
|
||||
force_tiles = true,
|
||||
|
||||
-- Spawn a circle/octagon/square of trees around this base outline.
|
||||
shape = SPAWN_SHAPE_CHOICE_CIRCLE,
|
||||
@ -474,7 +470,6 @@ OCFG = {
|
||||
---@field number_of_players_per_shared_spawn number Number of players allowed to join a shared spawn.
|
||||
---@field enable_friendly_fire boolean Set to true if you want to shoot your own chests and stuff.
|
||||
---@field default_surface string The starting surface of the main force.
|
||||
---@field enable_secondary_spawns boolean Enable secondary spawns for players. This automatically creates a new spawn point when they first move to a separate spawns enabled surface.
|
||||
---@field scale_resources_around_spawns boolean Scales resources so that even if you spawn "far away" from the center of the map, resources near to your spawn point scale so you aren't surrounded by 100M patches or something. This is useful depending on what map gen settings you pick.
|
||||
---@field modified_enemy_spawning boolean Adjust enemy spawning based on distance to spawns. All it does it make things more balanced based on your distance and makes the game a little easier. No behemoth worms everywhere just because you spawned far away.
|
||||
---@field scale_spawner_damage boolean Scale damage to spawners based on distance to spawn.
|
||||
@ -522,7 +517,7 @@ OCFG = {
|
||||
---@field moat_width_tiles number Width of the moat around the spawn area. If you change the spawn area size, you might have to adjust this as well.
|
||||
---@field tree_width_tiles number Width of the tree ring around the spawn area. If you change the spawn area size, you might have to adjust this as well.
|
||||
---@field resources_shape SpawnResourcesShapeChoice The starting resources deposits shape.
|
||||
---@field force_grass boolean Force the land area circle at the spawn to be fully grass, otherwise it defaults to the existing terrain.
|
||||
---@field force_tiles boolean Force the land area circle at the spawn to be a single tile (default grass on Nauvis), otherwise it defaults to the existing terrain and uses landfill to fill gaps.
|
||||
---@field shape SpawnShapeChoice Spawn a circle/octagon/square of trees around this base outline.
|
||||
|
||||
---@class OarcConfigSpawnSafeArea
|
||||
|
@ -26,15 +26,12 @@ OCFG_KEYS =
|
||||
["gameplay.enable_shared_spawns"] = {mod_key = "oarc-mod-enable-shared-spawns" , ocfg_keys = {"gameplay", "enable_shared_spawns"}, type = "boolean"},
|
||||
["gameplay.number_of_players_per_shared_spawn"] = {mod_key = "oarc-mod-number-of-players-per-shared-spawn" , ocfg_keys = {"gameplay", "number_of_players_per_shared_spawn"}, type = "integer"},
|
||||
["gameplay.default_surface"] = {mod_key = "oarc-mod-default-surface" , ocfg_keys = {"gameplay", "default_surface"}, type = "string"},
|
||||
["gameplay.enable_secondary_spawns"] = {mod_key = "oarc-mod-enable-secondary-spawns" , ocfg_keys = {"gameplay", "enable_secondary_spawns"}, type = "boolean"},
|
||||
-- STARTUP ["gameplay.main_force_name"] = {mod_key = "oarc-mod-main-force-name" , ocfg_keys = {"gameplay", "main_force_name"}, type = "string"},
|
||||
|
||||
["gameplay_difficulty_scaling_SUBHEADER"] = {mod_key = "" , ocfg_keys = {""}, type = "subheader", text = {"oarc-settings-section-subheader-difficulty-scaling"}},
|
||||
["gameplay.enable_offline_protection"] = {mod_key = "oarc-mod-enable-offline-protection" , ocfg_keys = {"gameplay", "enable_offline_protection"}, type = "boolean"},
|
||||
["gameplay.scale_resources_around_spawns"] = {mod_key = "oarc-mod-scale-resources-around-spawns" , ocfg_keys = {"gameplay", "scale_resources_around_spawns"}, type = "boolean"},
|
||||
["gameplay.modified_enemy_spawning"] = {mod_key = "oarc-mod-modified-enemy-spawning" , ocfg_keys = {"gameplay", "modified_enemy_spawning"}, type = "boolean"},
|
||||
-- ["gameplay.modified_enemy_easy_evo"] = {mod_key = "oarc-mod-modified-enemy-easy-evo" , ocfg_keys = {"gameplay", "modified_enemy_easy_evo"}, type = "double"},
|
||||
-- ["gameplay.modified_enemy_medium_evo"] = {mod_key = "oarc-mod-modified-enemy-medium-evo" , ocfg_keys = {"gameplay", "modified_enemy_medium_evo"}, type = "double"},
|
||||
|
||||
["gameplay_misc_SUBHEADER"] = {mod_key = "" , ocfg_keys = {""}, type = "subheader", text = {"oarc-settings-section-subheader-gameplay-misc"}},
|
||||
["gameplay.enable_friendly_fire"] = {mod_key = "oarc-mod-enable-friendly-fire" , ocfg_keys = {"gameplay", "enable_friendly_fire"}, type = "boolean"},
|
||||
@ -62,7 +59,7 @@ OCFG_KEYS =
|
||||
["spawn_general.moat_width_tiles"] = {mod_key = "oarc-mod-spawn-general-moat-width-tiles" , ocfg_keys = {"spawn_general", "moat_width_tiles"}, type = "integer"},
|
||||
["spawn_general.tree_width_tiles"] = {mod_key = "oarc-mod-spawn-general-tree-width-tiles" , ocfg_keys = {"spawn_general", "tree_width_tiles"}, type = "integer"},
|
||||
["spawn_general.resources_shape"] = {mod_key = "oarc-mod-spawn-general-enable-resources-circle-shape" , ocfg_keys = {"spawn_general", "resources_shape"}, type = "string-list"},
|
||||
["spawn_general.force_grass"] = {mod_key = "oarc-mod-spawn-general-enable-force-grass" , ocfg_keys = {"spawn_general", "force_grass"}, type = "boolean"},
|
||||
["spawn_general.force_tiles"] = {mod_key = "oarc-mod-spawn-general-enable-force-tiles" , ocfg_keys = {"spawn_general", "force_tiles"}, type = "boolean"},
|
||||
["spawn_general.shape"] = {mod_key = "oarc-mod-spawn-general-shape" , ocfg_keys = {"spawn_general", "shape"}, type = "string-list"},
|
||||
|
||||
["resource_placement_HEADER"] = {mod_key = "" , ocfg_keys = {""}, type = "header", text = {"oarc-settings-section-header-resource-placement"}},
|
||||
|
@ -461,10 +461,10 @@ function CreateMiscConfig(container, surface_name)
|
||||
|
||||
AddLabel(misc_flow, nil, { "oarc-misc-config" }, my_label_header2_style)
|
||||
|
||||
AddLabel(misc_flow, nil, { "oarc-water" }, my_player_list_style)
|
||||
CreateSpawnConfigIntegerField(misc_flow, surface_name, { "oarc-water-length" }, "water", "length", { "oarc-water-length-tooltip" })
|
||||
CreateSpawnConfigIntegerField(misc_flow, surface_name, { "oarc-water-x-offset" }, "water", "x_offset", { "oarc-water-x-offset-tooltip" })
|
||||
CreateSpawnConfigIntegerField(misc_flow, surface_name, { "oarc-water-y-offset" }, "water", "y_offset", { "oarc-water-y-offset-tooltip" })
|
||||
AddLabel(misc_flow, nil, { "oarc-liquid" }, my_player_list_style)
|
||||
CreateSpawnConfigIntegerField(misc_flow, surface_name, { "oarc-liquid-length" }, "water", "length", { "oarc-liquid-length-tooltip" })
|
||||
CreateSpawnConfigIntegerField(misc_flow, surface_name, { "oarc-liquid-x-offset" }, "water", "x_offset", { "oarc-liquid-x-offset-tooltip" })
|
||||
CreateSpawnConfigIntegerField(misc_flow, surface_name, { "oarc-liquid-y-offset" }, "water", "y_offset", { "oarc-liquid-y-offset-tooltip" })
|
||||
AddSpacerLine(misc_flow)
|
||||
|
||||
AddLabel(misc_flow, nil, { "oarc-shared-chest" }, my_player_list_style)
|
||||
|
@ -254,18 +254,19 @@ function RerollSpawn(player)
|
||||
end
|
||||
|
||||
local surface = player.character.surface
|
||||
local surface_name = surface.name
|
||||
|
||||
-- Confirm there is AN existing spawn point for this player on this surface
|
||||
if (storage.unique_spawns[surface.name] == nil or storage.unique_spawns[surface.name][player.name] == nil) then
|
||||
if (storage.unique_spawns[surface_name] == nil or storage.unique_spawns[surface_name][player.name] == nil) then
|
||||
log("ERROR - RerollSpawn - Can't reroll? No existing spawn for " .. player.name)
|
||||
return
|
||||
end
|
||||
|
||||
-- Save a copy of the previous spawn point
|
||||
local old_spawn_point = table.deepcopy(storage.unique_spawns[surface.name][player.name])
|
||||
local old_spawn_point = table.deepcopy(storage.unique_spawns[surface_name][player.name])
|
||||
|
||||
-- Find a new spawn point
|
||||
local spawn_position = FindUngeneratedCoordinates(surface, spawn_choices.distance, 3)
|
||||
local spawn_position = FindUngeneratedCoordinates(surface_name, spawn_choices.distance, 3)
|
||||
-- If that fails, just throw a warning and don't spawn them. They can try again.
|
||||
if ((spawn_position.x == 0) and (spawn_position.y == 0)) then
|
||||
player.print({ "oarc-no-ungenerated-land-error" })
|
||||
@ -274,17 +275,17 @@ function RerollSpawn(player)
|
||||
|
||||
-- Remove the old spawn point
|
||||
if (storage.ocfg.regrowth.enable_abandoned_base_cleanup) then
|
||||
log("Removing base: " .. spawn_position.x .. "," .. spawn_position.y .. " on surface: " .. old_spawn_point.surface_name)
|
||||
log("Removing base: " .. spawn_position.x .. "," .. spawn_position.y .. " on surface: " .. surface_name)
|
||||
|
||||
-- Clear an area around the spawn that SHOULD not include any other bases.
|
||||
local clear_radius = storage.ocfg.gameplay.minimum_distance_to_existing_chunks - 2 -- Bring in a bit for safety.
|
||||
RegrowthMarkAreaForRemoval(old_spawn_point.surface_name, old_spawn_point.position, clear_radius)
|
||||
RegrowthMarkAreaForRemoval(surface_name, old_spawn_point.position, clear_radius)
|
||||
TriggerCleanup()
|
||||
script.raise_event("oarc-mod-on-spawn-remove-request", {spawn_data = old_spawn_point})
|
||||
end
|
||||
|
||||
-- Queue spawn generation and the player.
|
||||
local delayed_spawn = GenerateNewSpawn(player.name, spawn_choices.surface_name, spawn_position, spawn_choices, old_spawn_point.primary)
|
||||
local delayed_spawn = GenerateNewSpawn(player.name, surface_name, spawn_position, spawn_choices, old_spawn_point.primary)
|
||||
QueuePlayerForSpawn(player.name, delayed_spawn)
|
||||
|
||||
-- Send them to the holding pen
|
||||
|
@ -794,17 +794,32 @@ end
|
||||
|
||||
---Pick a random direction, go at least the minimum distance, and start looking for ungenerated chunks
|
||||
---We try a few times (hardcoded) and then try a different random direction if we fail (up to max_tries)
|
||||
---@param surface LuaSurface
|
||||
---@param surface_name string Surface name because we might need to force the creation of a new surface
|
||||
---@param minimum_distance_chunks number Distance in chunks to start looking for ungenerated chunks
|
||||
---@param max_tries integer Maximum number of tries to find a spawn point
|
||||
---@return MapPosition
|
||||
function FindUngeneratedCoordinates(surface, minimum_distance_chunks, max_tries)
|
||||
function FindUngeneratedCoordinates(surface_name, minimum_distance_chunks, max_tries)
|
||||
|
||||
local final_position = {x=0,y=0}
|
||||
|
||||
-- If surface is nil, it is probably a planet? Check and create if needed.
|
||||
local surface = game.surfaces[surface_name]
|
||||
if (surface == nil) then
|
||||
if (game.planets[surface_name] == nil) then
|
||||
error("ERROR! No surface or planet found for requested player spawn!")
|
||||
return final_position
|
||||
end
|
||||
surface = game.planets[surface_name].create_surface()
|
||||
if (surface == nil) then
|
||||
error("ERROR! Failed to create planet surface for player spawn!")
|
||||
return final_position
|
||||
end
|
||||
end
|
||||
|
||||
--- Get a random vector, figure out how many times to multiply it to get the minimum distance
|
||||
local direction_vector = GetRandomVector()
|
||||
local start_distance_tiles = minimum_distance_chunks * CHUNK_SIZE
|
||||
|
||||
local final_position = {x=0,y=0}
|
||||
local tries_remaining = max_tries - 1
|
||||
|
||||
-- Starting search position
|
||||
@ -826,7 +841,7 @@ function FindUngeneratedCoordinates(surface, minimum_distance_chunks, max_tries)
|
||||
if (jumps_count <= 0) then
|
||||
|
||||
if (tries_remaining > 0) then
|
||||
return FindUngeneratedCoordinates(surface, minimum_distance_chunks, tries_remaining)
|
||||
return FindUngeneratedCoordinates(surface_name, minimum_distance_chunks, tries_remaining)
|
||||
else
|
||||
log("WARNING - FindUngeneratedCoordinates - Hit max distance!")
|
||||
break
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
local util = require("util")
|
||||
local crash_site = require("crash-site")
|
||||
require("lib/spawn_area_generation")
|
||||
|
||||
--[[
|
||||
___ _ _ ___ _____
|
||||
@ -25,6 +26,7 @@ function InitSpawnGlobalsAndForces()
|
||||
for _, surface in pairs(game.surfaces) do
|
||||
SeparateSpawnsInitSurface(surface.name)
|
||||
end
|
||||
SeparateSpawnsInitPlanets()
|
||||
|
||||
-- This contains each player's respawn point. Literally where they will respawn on death
|
||||
-- There is a way in game to change this under one of the little menu features I added. This allows players to
|
||||
@ -65,6 +67,10 @@ function InitSpawnGlobalsAndForces()
|
||||
--[[@type table<integer>]]
|
||||
storage.oarc_renders_fadeout = {}
|
||||
|
||||
-- This is a queue of players that need to be teleported to their spawn point.
|
||||
--[[@type table<string, OarcNilCharacterTeleportQueueEntry>]]
|
||||
storage.nil_character_teleport_queue = {}
|
||||
|
||||
-- Special forces for when players with their own force want a reset.
|
||||
game.create_force(ABANDONED_FORCE_NAME)
|
||||
-- game.create_force(DESTROYED_FORCE_NAME)
|
||||
@ -129,16 +135,20 @@ function SeparateSpawnsInitSurface(surface_name)
|
||||
|
||||
if IsSurfaceBlacklisted(surface_name) then return end
|
||||
|
||||
-- Add the surface to the list of surfaces that allow spawns with value from config.
|
||||
if storage.ocfg.gameplay.default_allow_spawning_on_other_surfaces then
|
||||
storage.oarc_surfaces[surface_name] = { primary = true, secondary = true }
|
||||
|
||||
-- Otherwise only allow the default surface (by default)
|
||||
else
|
||||
storage.oarc_surfaces[surface_name] = {
|
||||
primary = (surface_name == storage.ocfg.gameplay.default_surface),
|
||||
secondary = false
|
||||
}
|
||||
if storage.oarc_surfaces[surface_name] == nil then
|
||||
-- Default surface is set to primary only, all others are secondary only if
|
||||
-- default_allow_spawning_on_other_surfaces is set to true.
|
||||
if (surface_name == storage.ocfg.gameplay.default_surface) then
|
||||
storage.oarc_surfaces[surface_name] = {
|
||||
primary = true,
|
||||
secondary = false
|
||||
}
|
||||
else
|
||||
storage.oarc_surfaces[surface_name] = {
|
||||
primary = false,
|
||||
secondary = storage.ocfg.gameplay.default_allow_spawning_on_other_surfaces
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- Make sure it has a surface configuration entry!
|
||||
@ -148,6 +158,14 @@ function SeparateSpawnsInitSurface(surface_name)
|
||||
end
|
||||
end
|
||||
|
||||
---Init surface globals using game.planets
|
||||
---@return nil
|
||||
function SeparateSpawnsInitPlanets()
|
||||
for _, planet in pairs(game.planets) do
|
||||
SeparateSpawnsInitSurface(planet.name)
|
||||
end
|
||||
end
|
||||
|
||||
---Detects when surfaces are deleted and removes them from the list of surfaces that allow spawns.
|
||||
---@param event EventData.on_pre_surface_deleted
|
||||
---@return nil
|
||||
@ -265,9 +283,8 @@ function SeparateSpawnsPlayerChangedSurface(player, previous_surface_name, new_s
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if secondary spawns are disabled (both globally and on this surface)
|
||||
if (not storage.ocfg.gameplay.enable_secondary_spawns) or
|
||||
(not storage.oarc_surfaces[new_surface_name].secondary) then
|
||||
-- Check if secondary spawns are disabled
|
||||
if (not storage.oarc_surfaces[new_surface_name].secondary) then
|
||||
return
|
||||
end
|
||||
|
||||
@ -314,7 +331,7 @@ function SeparateSpawnsPlayerChangedSurface(player, previous_surface_name, new_s
|
||||
|
||||
-- If there is no spawn for them on their new surface, generate one based on previous choices.
|
||||
log("WARNING - THIS IS NOT FULLY IMPLEMENTED YET!!")
|
||||
SecondarySpawn(player, game.surfaces[new_surface_name])
|
||||
SecondarySpawn(player, new_surface_name)
|
||||
end
|
||||
|
||||
---Updates the player's surface and raises an event if it changes.
|
||||
@ -522,9 +539,13 @@ function PlaceResourcesInSquare(surface, position, size_mod, amount_mod)
|
||||
---@type table<string>
|
||||
local shuffled_list = FYShuffle(r_list)
|
||||
|
||||
local spawn_general = storage.ocfg.spawn_general
|
||||
local spawn_config = storage.ocfg.surfaces_config[surface.name].spawn_config
|
||||
local radius = spawn_general.spawn_radius_tiles * spawn_config.radius_modifier
|
||||
|
||||
-- Get the top left position of the spawn area
|
||||
local resource_position = { x = position.x - storage.ocfg.spawn_general.spawn_radius_tiles,
|
||||
y = position.y - storage.ocfg.spawn_general.spawn_radius_tiles }
|
||||
local resource_position = { x = position.x - radius,
|
||||
y = position.y - radius }
|
||||
|
||||
-- Offset the starting position
|
||||
resource_position.x = resource_position.x + storage.ocfg.resource_placement.horizontal_offset
|
||||
@ -603,10 +624,10 @@ function GenerateFinalSpawnPieces(delayed_spawn)
|
||||
-- Render some welcoming text...
|
||||
DisplayWelcomeGroundTextAtSpawn(delayed_spawn.surface_name, delayed_spawn.position)
|
||||
|
||||
-- Chart the area.
|
||||
local player = game.players[delayed_spawn.host_name]
|
||||
ChartArea(player.force, delayed_spawn.position, math.ceil(storage.ocfg.spawn_general.spawn_radius_tiles / CHUNK_SIZE),
|
||||
surface)
|
||||
-- -- Chart the area.
|
||||
-- local player = game.players[delayed_spawn.host_name]
|
||||
-- ChartArea(player.force, delayed_spawn.position, math.ceil(storage.ocfg.spawn_general.spawn_radius_tiles / CHUNK_SIZE),
|
||||
-- surface)
|
||||
|
||||
-- Trigger the event that the spawn was created.
|
||||
script.raise_event("oarc-mod-on-spawn-created", {spawn_data = storage.unique_spawns[delayed_spawn.surface_name][delayed_spawn.host_name]})
|
||||
@ -619,8 +640,16 @@ end
|
||||
---@return nil
|
||||
function SendPlayerToNewSpawn(player_name, surface_name, first_spawn)
|
||||
|
||||
-- Send the player to that position
|
||||
local player = game.players[player_name]
|
||||
|
||||
-- Check if player character is nil
|
||||
if (player.character == nil) then
|
||||
log("Player character is nil, can't send to spawn point just yet: " .. player_name)
|
||||
QueueNilCharacterForNewSpawnTeleport(player_name, surface_name, first_spawn)
|
||||
return
|
||||
end
|
||||
|
||||
-- Send the player to that position
|
||||
TeleportPlayerToRespawnPoint(surface_name, player, first_spawn)
|
||||
|
||||
-- Remove waiting dialog
|
||||
@ -631,7 +660,7 @@ function SendPlayerToNewSpawn(player_name, surface_name, first_spawn)
|
||||
-- Only first time spawns get starter items.
|
||||
if first_spawn then
|
||||
GivePlayerStarterItems(player)
|
||||
|
||||
|
||||
-- Trigger the event that player was spawned too.
|
||||
script.raise_event("oarc-mod-on-player-spawned", {player_index = player.index})
|
||||
end
|
||||
@ -698,8 +727,8 @@ function SetupAndClearSpawnAreas(surface, chunkArea)
|
||||
|
||||
--[[@type OarcConfigSpawnGeneral]]
|
||||
local general_spawn_config = storage.ocfg.spawn_general
|
||||
|
||||
local surface_config = storage.ocfg.surfaces_config[surface.name]
|
||||
local surface_spawn_config = storage.ocfg.surfaces_config[surface.name].spawn_config
|
||||
local radius = general_spawn_config.spawn_radius_tiles * surface_spawn_config.radius_modifier
|
||||
|
||||
local chunkAreaCenter = {
|
||||
x = chunkArea.left_top.x + (CHUNK_SIZE / 2),
|
||||
@ -716,54 +745,24 @@ function SetupAndClearSpawnAreas(surface, chunkArea)
|
||||
for _, spawn in pairs(spawns) do
|
||||
-- If the chunk is within the main land area, then clear trees/resources and create the land spawn areas
|
||||
-- (guaranteed land with a circle of trees)
|
||||
local landArea = GetAreaAroundPos(spawn.position, general_spawn_config.spawn_radius_tiles + CHUNK_SIZE)
|
||||
local landArea = GetAreaAroundPos(spawn.position, radius + CHUNK_SIZE)
|
||||
if not CheckIfInArea(chunkAreaCenter, landArea) then
|
||||
goto CONTINUE
|
||||
end
|
||||
|
||||
-- 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, general_spawn_config.spawn_radius_tiles + 5)
|
||||
RemoveInCircle(surface, chunkArea, {"resource", "cliff", "tree", "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, general_spawn_config.spawn_radius_tiles + 5)
|
||||
end
|
||||
|
||||
-- Fill in the spawn area with landfill and create a circle of trees around it.
|
||||
local fill_tile = "landfill"
|
||||
if general_spawn_config.force_grass then
|
||||
fill_tile = surface_config.spawn_config.fill_tile
|
||||
RemoveInSquare(surface, chunkArea, {"resource", "cliff", "tree", "lightning-attractor", "simple-entity"}, spawn.position, radius + 5)
|
||||
end
|
||||
|
||||
if (general_spawn_config.shape == SPAWN_SHAPE_CHOICE_CIRCLE) then
|
||||
CreateCropCircle(
|
||||
surface,
|
||||
spawn.position,
|
||||
chunkArea,
|
||||
general_spawn_config.spawn_radius_tiles * surface_config.spawn_config.radius_modifier,
|
||||
fill_tile,
|
||||
spawn.moat,
|
||||
storage.ocfg.gameplay.enable_moat_bridging
|
||||
)
|
||||
CreateCropCircle(surface, spawn, chunkArea)
|
||||
elseif (general_spawn_config.shape == SPAWN_SHAPE_CHOICE_OCTAGON) then
|
||||
CreateCropOctagon(
|
||||
surface,
|
||||
spawn.position,
|
||||
chunkArea,
|
||||
general_spawn_config.spawn_radius_tiles,
|
||||
fill_tile,
|
||||
spawn.moat,
|
||||
storage.ocfg.gameplay.enable_moat_bridging
|
||||
)
|
||||
CreateCropOctagon(surface, spawn, chunkArea)
|
||||
elseif (general_spawn_config.shape == SPAWN_SHAPE_CHOICE_SQUARE) then
|
||||
CreateCropSquare(
|
||||
surface,
|
||||
spawn.position,
|
||||
chunkArea,
|
||||
general_spawn_config.spawn_radius_tiles,
|
||||
fill_tile,
|
||||
spawn.moat,
|
||||
storage.ocfg.gameplay.enable_moat_bridging
|
||||
)
|
||||
CreateCropSquare(surface, spawn, chunkArea)
|
||||
end
|
||||
|
||||
:: CONTINUE ::
|
||||
@ -896,12 +895,16 @@ function RemoveOrResetPlayer(player, remove_player)
|
||||
SafeTeleport(player, game.surfaces[HOLDING_PEN_SURFACE_NAME], {x=0,y=0})
|
||||
local player_old_force = player.force
|
||||
player.force = storage.ocfg.gameplay.main_force_name
|
||||
local player_name = player.name
|
||||
|
||||
-- Clear globals
|
||||
CleanupPlayerGlobals(player.name) -- This cleans storage.unique_spawns IF we are transferring ownership.
|
||||
-- Clear globals and transfers spawn ownership if needed.
|
||||
CleanupPlayerGlobals(player_name) -- This cleans storage.unique_spawns IF we are transferring ownership.
|
||||
|
||||
-- Safely clear the unique spawn IF it is still valid.
|
||||
UniqueSpawnCleanupRemove(player.name) -- Specifically storage.unique_spawns
|
||||
-- Safely clear all spawns if they are the host.
|
||||
local spawns = FindAllUniqueSpawnsWherePlayerIsTheHost(player_name)
|
||||
for _,spawn in pairs(spawns) do
|
||||
UniqueSpawnCleanupRemove(player_name, spawn)
|
||||
end
|
||||
|
||||
-- Remove a force if this player created it and they are the only one on it
|
||||
if ((#player_old_force.players == 0) and (player_old_force.name ~= storage.ocfg.gameplay.main_force_name)) then
|
||||
@ -919,10 +922,10 @@ function RemoveOrResetPlayer(player, remove_player)
|
||||
-- Otherwise, make sure to re-init them!
|
||||
else
|
||||
if (remove_player) then
|
||||
log("ERROR! RemoveOrResetPlayer - Player not removed as they are still connected: " .. player.name)
|
||||
log("ERROR! RemoveOrResetPlayer - Player not removed as they are still connected: " .. player_name)
|
||||
end
|
||||
SeparateSpawnsInitPlayer(player.index --[[@as string]])
|
||||
SendBroadcastMsg({"oarc-player-was-reset-notify", player.name})
|
||||
SendBroadcastMsg({"oarc-player-was-reset-notify", player_name})
|
||||
end
|
||||
|
||||
-- Refresh the shared spawn spawn gui for all players
|
||||
@ -943,6 +946,21 @@ function FindPrimaryUniqueSpawn(player_name)
|
||||
return nil
|
||||
end
|
||||
|
||||
---Returns all spawns (primary and secondary) where this player is the host
|
||||
---@param player_name string
|
||||
---@return OarcUniqueSpawn[]
|
||||
function FindAllUniqueSpawnsWherePlayerIsTheHost(player_name)
|
||||
local found_spawns = {}
|
||||
for _,spawns in pairs(storage.unique_spawns) do
|
||||
for _, spawn in pairs(spawns) do
|
||||
if (spawn.host_name == player_name) then
|
||||
table.insert(found_spawns, spawn)
|
||||
end
|
||||
end
|
||||
end
|
||||
return found_spawns
|
||||
end
|
||||
|
||||
---Find the primary home spawn of a player, if one exists. This will return a shared spawn if they joined one.
|
||||
---@param player_name string
|
||||
---@return OarcUniqueSpawn?
|
||||
@ -1007,22 +1025,23 @@ end
|
||||
|
||||
---Cleans up a player's unique spawn point, if safe to do so.
|
||||
---@param player_name string
|
||||
---@param unique_spawn OarcUniqueSpawn?
|
||||
---@return nil
|
||||
function UniqueSpawnCleanupRemove(player_name)
|
||||
function UniqueSpawnCleanupRemove(player_name, unique_spawn)
|
||||
|
||||
-- Assumes we only remove the one primary unique spawn per player.
|
||||
local primary_spawn = FindPrimaryUniqueSpawn(player_name)
|
||||
if (primary_spawn == nil) then return end -- Safety
|
||||
log("UniqueSpawnCleanupRemove - " .. player_name)
|
||||
if (unique_spawn == nil) then return end -- Safety
|
||||
log("UniqueSpawnCleanupRemove - " .. player_name .. " on surface: " .. unique_spawn.surface_name)
|
||||
|
||||
local total_spawn_width = storage.ocfg.spawn_general.spawn_radius_tiles +
|
||||
local spawn_config = storage.ocfg.surfaces_config[unique_spawn.surface_name].spawn_config
|
||||
|
||||
local total_spawn_width = (storage.ocfg.spawn_general.spawn_radius_tiles * spawn_config.radius_modifier) +
|
||||
storage.ocfg.spawn_general.moat_width_tiles
|
||||
|
||||
-- Check if it was near someone else's base. (Really just buddy base is possible I think?)
|
||||
nearOtherSpawn = false
|
||||
for player_index, spawn in pairs(storage.unique_spawns[primary_spawn.surface_name]) do
|
||||
for player_index, spawn in pairs(storage.unique_spawns[unique_spawn.surface_name]) do
|
||||
if ((player_index ~= player_name) and
|
||||
(util.distance(primary_spawn.position, spawn.position) < (total_spawn_width * 3))) then
|
||||
(util.distance(unique_spawn.position, spawn.position) < (total_spawn_width * 3))) then
|
||||
log("Won't remove base as it's close to another spawn: " .. player_index)
|
||||
nearOtherSpawn = true
|
||||
end
|
||||
@ -1030,26 +1049,20 @@ function UniqueSpawnCleanupRemove(player_name)
|
||||
|
||||
-- TODO: Possibly limit this based on playtime? If player is on for a long time then don't remove it?
|
||||
-- Use regrowth mod to cleanup the area.
|
||||
local spawn_position = primary_spawn.position
|
||||
local spawn_position = unique_spawn.position
|
||||
if (storage.ocfg.regrowth.enable_abandoned_base_cleanup and (not nearOtherSpawn)) then
|
||||
log("Removing base: " .. spawn_position.x .. "," .. spawn_position.y .. " on surface: " .. primary_spawn.surface_name)
|
||||
log("Removing base: " .. spawn_position.x .. "," .. spawn_position.y .. " on surface: " .. unique_spawn.surface_name)
|
||||
|
||||
-- Clear an area around the spawn that SHOULD not include any other bases.
|
||||
local clear_radius = storage.ocfg.gameplay.minimum_distance_to_existing_chunks - 2 -- Bring in a bit for safety.
|
||||
RegrowthMarkAreaForRemoval(primary_spawn.surface_name, spawn_position, clear_radius)
|
||||
RegrowthMarkAreaForRemoval(unique_spawn.surface_name, spawn_position, clear_radius)
|
||||
TriggerCleanup()
|
||||
-- Trigger event
|
||||
script.raise_event("oarc-mod-on-spawn-remove-request", {spawn_data = primary_spawn})
|
||||
script.raise_event("oarc-mod-on-spawn-remove-request", {spawn_data = unique_spawn})
|
||||
end
|
||||
|
||||
-- Remove ALL primary and secondary spawns where this player is the host.
|
||||
for surface_index, spawns in pairs(storage.unique_spawns) do
|
||||
for player_index, _ in pairs(spawns) do
|
||||
if (player_index == player_name) then
|
||||
storage.unique_spawns[surface_index][player_index] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Remove the spawn point from the global table.
|
||||
storage.unique_spawns[unique_spawn.surface_name][player_name] = nil
|
||||
end
|
||||
|
||||
---Cleans up all references to a player in the global tables.
|
||||
@ -1059,16 +1072,23 @@ function CleanupPlayerGlobals(player_name)
|
||||
|
||||
-- Clear the buddy pair IF one exists
|
||||
if (storage.buddy_pairs[player_name] ~= nil) then
|
||||
local buddyName = storage.buddy_pairs[player_name]
|
||||
local buddy_name = storage.buddy_pairs[player_name]
|
||||
storage.buddy_pairs[player_name] = nil
|
||||
storage.buddy_pairs[buddyName] = nil
|
||||
storage.buddy_pairs[buddy_name] = nil
|
||||
|
||||
-- Nil the buddy from any of the unique spawn entries
|
||||
for _,spawns in pairs(storage.unique_spawns) do
|
||||
if (spawns[buddy_name] ~= nil) then
|
||||
spawns[buddy_name].buddy_name = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Transfer or remove a shared spawn if player is owner
|
||||
local unique_spawn = FindPrimaryUniqueSpawn(player_name)
|
||||
if (unique_spawn ~= nil and #unique_spawn.joiners > 0) then
|
||||
local new_owner_name = table.remove(unique_spawn.joiners) -- Get 1 to use as new owner.
|
||||
TransferOwnershipOfSharedSpawn(unique_spawn, new_owner_name)
|
||||
TransferOwnershipOfAllSpawns(unique_spawn, new_owner_name)
|
||||
SendBroadcastMsg( {"oarc-host-left-new-host", player_name, new_owner_name})
|
||||
end
|
||||
|
||||
@ -1088,8 +1108,7 @@ function CleanupPlayerGlobals(player_name)
|
||||
storage.player_respawns[player_name] = nil
|
||||
end
|
||||
|
||||
-- Remove them from the delayed spawn queue if they are in it
|
||||
-- TODO: Check if there are others in the queue?
|
||||
-- Remove them from the delayed spawn queue if they are still the host
|
||||
for index, delayedSpawn in pairs(storage.delayed_spawns --[[@as OarcDelayedSpawnsTable]]) do
|
||||
if (player_name == delayedSpawn.host_name) then
|
||||
storage.delayed_spawns[index] = nil
|
||||
@ -1110,7 +1129,7 @@ end
|
||||
---@param primary_spawn OarcUniqueSpawn
|
||||
---@param new_host_name string
|
||||
---@return nil
|
||||
function TransferOwnershipOfSharedSpawn(primary_spawn, new_host_name)
|
||||
function TransferOwnershipOfAllSpawns(primary_spawn, new_host_name)
|
||||
|
||||
-- Transfer every primary AND secondary spawn.
|
||||
for surface_name, unique_spawns in pairs(storage.unique_spawns) do
|
||||
@ -1134,6 +1153,13 @@ function TransferOwnershipOfSharedSpawn(primary_spawn, new_host_name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Transfer any delayed_spawns
|
||||
for index, delayed_spawn in pairs(storage.delayed_spawns) do
|
||||
if (delayed_spawn.host_name == primary_spawn.host_name) then
|
||||
storage.delayed_spawns[index].host_name = new_host_name
|
||||
end
|
||||
end
|
||||
|
||||
game.players[new_host_name].print({ "oarc-new-owner-msg" })
|
||||
end
|
||||
|
||||
@ -1145,6 +1171,37 @@ end
|
||||
|
||||
--]]
|
||||
|
||||
---Queue a player whose character is nil when being sent to a new spawn.
|
||||
---A separate on_tick function will read this queue and send the player to the spawn point when they have a character again.
|
||||
---@param player_name string
|
||||
---@param surface_name string
|
||||
---@param first_spawn boolean
|
||||
---@return nil
|
||||
function QueueNilCharacterForNewSpawnTeleport(player_name, surface_name, first_spawn)
|
||||
if (storage.nil_character_teleport_queue[player_name] == nil) then
|
||||
storage.nil_character_teleport_queue[player_name] = { surface_name = surface_name, first_spawn = first_spawn }
|
||||
end
|
||||
end
|
||||
|
||||
---On tick function to process the nil character teleport queue.
|
||||
---@return nil
|
||||
function OnTickNilCharacterTeleportQueue()
|
||||
for player_name, data in pairs(storage.nil_character_teleport_queue) do
|
||||
local player = game.players[player_name]
|
||||
|
||||
-- If player is nil, remove them from the queue.
|
||||
if (player == nil) then
|
||||
storage.nil_character_teleport_queue[player_name] = nil
|
||||
|
||||
-- Else if they have a character, send them to the spawn point.
|
||||
-- And hope to high heaven this doesn't recurse infinitely.
|
||||
elseif (player.character ~= nil) then
|
||||
storage.nil_character_teleport_queue[player_name] = nil
|
||||
SendPlayerToNewSpawn(player_name, data.surface_name, data.first_spawn)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Finds and removes a player from a shared spawn join queue, and refreshes the host's GUI.
|
||||
---@param player_name string
|
||||
---@return boolean
|
||||
@ -1510,9 +1567,9 @@ end
|
||||
|
||||
---Creates and sends a player to a new secondary spawn, temporarily placing them in the holding pen.
|
||||
---@param player LuaPlayer
|
||||
---@param surface LuaSurface
|
||||
---@param surface_name string
|
||||
---@return nil
|
||||
function SecondarySpawn(player, surface)
|
||||
function SecondarySpawn(player, surface_name)
|
||||
|
||||
local player_name = player.name
|
||||
|
||||
@ -1527,8 +1584,6 @@ function SecondarySpawn(player, surface)
|
||||
return
|
||||
end
|
||||
|
||||
local surface_name = surface.name
|
||||
|
||||
-- Confirm there is no existing spawn point for this host on this surface
|
||||
if (storage.unique_spawns[surface_name] ~= nil and storage.unique_spawns[surface_name][host_name] ~= nil) then
|
||||
log("ERROR - SecondarySpawn - Host already has a spawn point on this surface: " .. host_name .. " on surface: " .. surface_name)
|
||||
@ -1536,7 +1591,7 @@ function SecondarySpawn(player, surface)
|
||||
end
|
||||
|
||||
-- Find a new spawn point
|
||||
local spawn_position = FindUngeneratedCoordinates(surface, spawn_choices.distance, 3)
|
||||
local spawn_position = FindUngeneratedCoordinates(surface_name, spawn_choices.distance, 3)
|
||||
-- If that fails, just throw a warning and don't spawn them. They can try again.
|
||||
if ((spawn_position.x == 0) and (spawn_position.y == 0)) then
|
||||
player.print({ "oarc-no-ungenerated-land-error" })
|
||||
@ -1552,7 +1607,7 @@ function SecondarySpawn(player, surface)
|
||||
local buddy_position = GetBuddySpawnPosition(spawn_position, surface_name, spawn_choices.moat)
|
||||
local buddy_choices = storage.spawn_choices[spawn_choices.buddy]
|
||||
|
||||
GenerateNewSpawn(host_name, surface_name, buddy_position, buddy_choices, false)
|
||||
GenerateNewSpawn(spawn_choices.buddy, surface_name, buddy_position, buddy_choices, false)
|
||||
SetPlayerRespawn(spawn_choices.buddy, surface_name, buddy_position, false)
|
||||
|
||||
-- Make sure host and joiners all have their new respawn position set for this surface.
|
||||
@ -1568,7 +1623,7 @@ function SecondarySpawn(player, surface)
|
||||
SafeTeleport(player, game.surfaces[HOLDING_PEN_SURFACE_NAME], {x=0,y=0})
|
||||
|
||||
-- Announce
|
||||
SendBroadcastMsg({"", { "oarc-player-new-secondary", player_name, surface.name }, " ", GetGPStext(surface.name, spawn_position)})
|
||||
SendBroadcastMsg({"", { "oarc-player-new-secondary", player_name, surface_name }, " ", GetGPStext(surface_name, spawn_position)})
|
||||
end
|
||||
|
||||
-- Check a table to see if there are any players waiting to spawn
|
||||
@ -1774,3 +1829,6 @@ SPAWN_TEAM_CHOICE = {
|
||||
|
||||
---Primary means a player can spawn for the first time on this surface, secondary they can land here and also receive a custom spawn area.
|
||||
---@alias OarcSurfaceSpawnSetting { primary: boolean, secondary: boolean}
|
||||
|
||||
---Entry for a nil_character_teleport_queue
|
||||
---@alias OarcNilCharacterTeleportQueueEntry { surface_name: string, first_spawn: boolean }
|
||||
|
@ -891,11 +891,8 @@ function PrimarySpawnRequest(player)
|
||||
storage.spawn_choices[player.name].host_name = nil
|
||||
storage.spawn_choices[player.name].buddy = nil
|
||||
|
||||
-- Cache some useful variables
|
||||
local surface = game.surfaces[spawn_choices.surface_name]
|
||||
|
||||
-- Find coordinates of a good place to spawn
|
||||
local spawn_position = FindUngeneratedCoordinates(surface, spawn_choices.distance, 3)
|
||||
local spawn_position = FindUngeneratedCoordinates(spawn_choices.surface_name, spawn_choices.distance, 3)
|
||||
|
||||
-- If that fails, just throw a warning and don't spawn them. They can try again.
|
||||
if ((spawn_position.x == 0) and (spawn_position.y == 0)) then
|
||||
@ -1145,7 +1142,7 @@ function AcceptBuddyRequest(player, requesting_buddy_name)
|
||||
local buddy_choices = storage.spawn_choices[player.name]
|
||||
|
||||
-- Find coordinates of a good place to spawn
|
||||
local spawn_position = FindUngeneratedCoordinates(surface, spawn_choices.distance, 3)
|
||||
local spawn_position = FindUngeneratedCoordinates(spawn_choices.surface_name, spawn_choices.distance, 3)
|
||||
|
||||
-- If that fails, just throw a warning and don't spawn them. They can try again.
|
||||
if ((spawn_position.x == 0) and (spawn_position.y == 0)) then
|
||||
@ -1176,8 +1173,8 @@ function AcceptBuddyRequest(player, requesting_buddy_name)
|
||||
|
||||
|
||||
-- Queue spawn generation for the requesting buddy FIRST. (left)
|
||||
local delayed_spawn = GenerateNewSpawn(player.name, spawn_choices.surface_name, spawn_position, spawn_choices, true)
|
||||
QueuePlayerForSpawn(player.name, delayed_spawn)
|
||||
local delayed_spawn = GenerateNewSpawn(requesting_buddy_name, spawn_choices.surface_name, spawn_position, spawn_choices, true)
|
||||
QueuePlayerForSpawn(requesting_buddy_name, delayed_spawn)
|
||||
|
||||
-- ORDER MATTERS! Otherwise sometimes chunks don't generate properly!
|
||||
-- Queue spawn generation for the accepting buddy SECOND. (right)
|
||||
|
391
lib/spawn_area_generation.lua
Normal file
391
lib/spawn_area_generation.lua
Normal file
@ -0,0 +1,391 @@
|
||||
-- --------------------------------------------------------------------------------
|
||||
-- -- Resource patch and starting area generation
|
||||
-- --------------------------------------------------------------------------------
|
||||
|
||||
---Circle spawn shape (handles land, trees and moat)
|
||||
---@param surface LuaSurface
|
||||
---@param unique_spawn OarcUniqueSpawn
|
||||
---@param chunk_area BoundingBox
|
||||
---@return nil
|
||||
function CreateCropCircle(surface, unique_spawn, chunk_area)
|
||||
--------------------------------------------
|
||||
local spawn_general = storage.ocfg.spawn_general
|
||||
local spawn_config = storage.ocfg.surfaces_config[surface.name].spawn_config
|
||||
|
||||
local spawn_pos = unique_spawn.position
|
||||
local tile_radius = spawn_general.spawn_radius_tiles * spawn_config.radius_modifier
|
||||
|
||||
local fill_tile = "landfill"
|
||||
if spawn_general.force_tiles then
|
||||
fill_tile = spawn_config.fill_tile
|
||||
end
|
||||
|
||||
local moat = unique_spawn.moat
|
||||
local bridge = storage.ocfg.gameplay.enable_moat_bridging
|
||||
|
||||
local liquid_tile = spawn_config.liquid_tile
|
||||
local fish_enabled = (liquid_tile == "water")
|
||||
|
||||
local moat_width = storage.ocfg.spawn_general.moat_width_tiles
|
||||
local tree_width = storage.ocfg.spawn_general.tree_width_tiles
|
||||
--------------------------------------------
|
||||
|
||||
local tile_radius_sqr = tile_radius ^ 2
|
||||
local moat_radius_sqr = ((tile_radius + moat_width) ^ 2)
|
||||
local tree_radius_sqr_inner = ((tile_radius - 1 - tree_width) ^ 2) -- 1 less to make sure trees are inside the spawn area
|
||||
local tree_radius_sqr_outer = ((tile_radius - 1) ^ 2)
|
||||
|
||||
|
||||
local dirtTiles = {}
|
||||
for i = chunk_area.left_top.x, chunk_area.right_bottom.x, 1 do
|
||||
for j = chunk_area.left_top.y, chunk_area.right_bottom.y, 1 do
|
||||
-- This ( X^2 + Y^2 ) is used to calculate if something is inside a circle area.
|
||||
-- We avoid using sqrt for performance reasons.
|
||||
local distSqr = math.floor((spawn_pos.x - i) ^ 2 + (spawn_pos.y - j) ^ 2)
|
||||
|
||||
-- Fill in all unexpected water (or force grass)
|
||||
if (distSqr <= tile_radius_sqr) then
|
||||
if (surface.get_tile(i, j).collides_with("water_tile") or
|
||||
storage.ocfg.spawn_general.force_tiles) then
|
||||
table.insert(dirtTiles, { name = fill_tile, position = { i, j } })
|
||||
end
|
||||
end
|
||||
|
||||
-- Fill moat with water.
|
||||
if (moat) then
|
||||
if (bridge and ((j == spawn_pos.y - 1) or (j == spawn_pos.y) or (j == spawn_pos.y + 1))) then
|
||||
-- This will leave the tiles "as is" on the left and right of the spawn which has the effect of creating
|
||||
-- land connections if the spawn is on or near land.
|
||||
elseif ((distSqr < moat_radius_sqr) and (distSqr > tile_radius_sqr)) then
|
||||
table.insert(dirtTiles, { name = liquid_tile, position = { i, j } })
|
||||
|
||||
--5% chance of fish in water
|
||||
if fish_enabled and (math.random(1, 20) == 1) then
|
||||
surface.create_entity({ name = "fish", position = { i + 0.5, j + 0.5 } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
surface.set_tiles(dirtTiles)
|
||||
|
||||
--Create trees (needs to be done after setting tiles!)
|
||||
local tree_entity = spawn_config.tree_entity
|
||||
if (tree_entity == nil) then return end
|
||||
|
||||
for i = chunk_area.left_top.x, chunk_area.right_bottom.x, 1 do
|
||||
for j = chunk_area.left_top.y, chunk_area.right_bottom.y, 1 do
|
||||
local distSqr = math.floor((spawn_pos.x - i) ^ 2 + (spawn_pos.y - j) ^ 2)
|
||||
if ((distSqr < tree_radius_sqr_outer) and (distSqr > tree_radius_sqr_inner)) then
|
||||
local pos = surface.find_non_colliding_position(tree_entity, { i, j }, 2, 0.5)
|
||||
if (pos ~= nil) then
|
||||
surface.create_entity({ name = tree_entity, position = pos })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Octagon spawn shape (handles land, trees and moat) (Curtesy of jvmguy)
|
||||
---@param surface LuaSurface
|
||||
---@param unique_spawn OarcUniqueSpawn
|
||||
---@param chunk_area BoundingBox
|
||||
---@return nil
|
||||
function CreateCropOctagon(surface, unique_spawn, chunk_area)
|
||||
--------------------------------------------
|
||||
local spawn_general = storage.ocfg.spawn_general
|
||||
local spawn_config = storage.ocfg.surfaces_config[surface.name].spawn_config
|
||||
|
||||
local spawn_pos = unique_spawn.position
|
||||
local tile_radius = spawn_general.spawn_radius_tiles * spawn_config.radius_modifier
|
||||
|
||||
local fill_tile = "landfill"
|
||||
if spawn_general.force_tiles then
|
||||
fill_tile = spawn_config.fill_tile
|
||||
end
|
||||
|
||||
local moat = unique_spawn.moat
|
||||
local bridge = storage.ocfg.gameplay.enable_moat_bridging
|
||||
|
||||
local liquid_tile = spawn_config.liquid_tile
|
||||
local fish_enabled = (liquid_tile == "water")
|
||||
|
||||
local moat_width = storage.ocfg.spawn_general.moat_width_tiles
|
||||
local tree_width = storage.ocfg.spawn_general.tree_width_tiles
|
||||
--------------------------------------------
|
||||
|
||||
local moat_width_outer = tile_radius + moat_width
|
||||
local tree_distance_inner = tile_radius - tree_width
|
||||
|
||||
local dirtTiles = {}
|
||||
for i = chunk_area.left_top.x, chunk_area.right_bottom.x, 1 do
|
||||
for j = chunk_area.left_top.y, chunk_area.right_bottom.y, 1 do
|
||||
local distVar1 = math.floor(math.max(math.abs(spawn_pos.x - i), math.abs(spawn_pos.y - j)))
|
||||
local distVar2 = math.floor(math.abs(spawn_pos.x - i) + math.abs(spawn_pos.y - j))
|
||||
local distVar = math.max(distVar1, distVar2 * 0.707);
|
||||
|
||||
-- Fill in all unexpected water (or force grass)
|
||||
if (distVar <= tile_radius) then
|
||||
if (surface.get_tile(i, j).collides_with("water_tile") or
|
||||
storage.ocfg.spawn_general.force_tiles) then
|
||||
table.insert(dirtTiles, { name = fill_tile, position = { i, j } })
|
||||
end
|
||||
end
|
||||
|
||||
-- Fill moat with water
|
||||
if (moat) then
|
||||
if (bridge and ((j == spawn_pos.y - 1) or (j == spawn_pos.y) or (j == spawn_pos.y + 1))) then
|
||||
-- This will leave the tiles "as is" on the left and right of the spawn which has the effect of creating
|
||||
-- land connections if the spawn is on or near land.
|
||||
elseif ((distVar > tile_radius) and (distVar <= moat_width_outer)) then
|
||||
table.insert(dirtTiles, { name = liquid_tile, position = { i, j } })
|
||||
|
||||
--5% chance of fish in water
|
||||
if fish_enabled and (math.random(1, 20) == 1) then
|
||||
surface.create_entity({ name = "fish", position = { i + 0.5, j + 0.5 } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
surface.set_tiles(dirtTiles)
|
||||
|
||||
|
||||
--Create trees (needs to be done after setting tiles!)
|
||||
local tree_entity = spawn_config.tree_entity
|
||||
if (tree_entity == nil) then return end
|
||||
|
||||
--Create trees (needs to be done after setting tiles!)
|
||||
for i = chunk_area.left_top.x, chunk_area.right_bottom.x, 1 do
|
||||
for j = chunk_area.left_top.y, chunk_area.right_bottom.y, 1 do
|
||||
local distVar1 = math.floor(math.max(math.abs(spawn_pos.x - i), math.abs(spawn_pos.y - j)))
|
||||
local distVar2 = math.floor(math.abs(spawn_pos.x - i) + math.abs(spawn_pos.y - j))
|
||||
local distVar = math.max(distVar1, distVar2 * 0.707);
|
||||
|
||||
if ((distVar < tile_radius) and (distVar >= tree_distance_inner)) then
|
||||
local pos = surface.find_non_colliding_position(tree_entity, { i, j }, 2, 0.5)
|
||||
if (pos ~= nil) then
|
||||
surface.create_entity({ name = tree_entity, position = pos })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Square spawn shape (handles land, trees and moat)
|
||||
---@param surface LuaSurface
|
||||
---@param unique_spawn OarcUniqueSpawn
|
||||
---@param chunk_area BoundingBox
|
||||
---@return nil
|
||||
function CreateCropSquare(surface, unique_spawn, chunk_area)
|
||||
--------------------------------------------
|
||||
local spawn_general = storage.ocfg.spawn_general
|
||||
local spawn_config = storage.ocfg.surfaces_config[surface.name].spawn_config
|
||||
|
||||
local spawn_pos = unique_spawn.position
|
||||
local tile_radius = spawn_general.spawn_radius_tiles * spawn_config.radius_modifier
|
||||
|
||||
local fill_tile = "landfill"
|
||||
if spawn_general.force_tiles then
|
||||
fill_tile = spawn_config.fill_tile
|
||||
end
|
||||
|
||||
local moat = unique_spawn.moat
|
||||
local bridge = storage.ocfg.gameplay.enable_moat_bridging
|
||||
|
||||
local liquid_tile = spawn_config.liquid_tile
|
||||
local fish_enabled = (liquid_tile == "water")
|
||||
|
||||
local moat_width = storage.ocfg.spawn_general.moat_width_tiles
|
||||
local tree_width = storage.ocfg.spawn_general.tree_width_tiles
|
||||
--------------------------------------------
|
||||
|
||||
local moat_width_outer = tile_radius + moat_width
|
||||
local tree_distance_inner = tile_radius - tree_width
|
||||
|
||||
local dirtTiles = {}
|
||||
for i = chunk_area.left_top.x, chunk_area.right_bottom.x, 1 do
|
||||
for j = chunk_area.left_top.y, chunk_area.right_bottom.y, 1 do
|
||||
-- Max distance from center (either x or y)
|
||||
local max_distance = math.max(math.abs(spawn_pos.x - i), math.abs(spawn_pos.y - j))
|
||||
|
||||
-- Fill in all unexpected water (or force grass)
|
||||
if (max_distance <= tile_radius) then
|
||||
if (surface.get_tile(i, j).collides_with("water_tile") or
|
||||
storage.ocfg.spawn_general.force_tiles) then
|
||||
table.insert(dirtTiles, { name = fill_tile, position = { i, j } })
|
||||
end
|
||||
end
|
||||
|
||||
-- Fill moat with water
|
||||
if (moat) then
|
||||
if (bridge and ((j == spawn_pos.y - 1) or (j == spawn_pos.y) or (j == spawn_pos.y + 1))) then
|
||||
-- This will leave the tiles "as is" on the left and right of the spawn which has the effect of creating
|
||||
-- land connections if the spawn is on or near land.
|
||||
elseif ((max_distance > tile_radius) and (max_distance <= moat_width_outer)) then
|
||||
table.insert(dirtTiles, { name = liquid_tile, position = { i, j } })
|
||||
|
||||
--5% chance of fish in water
|
||||
if fish_enabled and (math.random(1, 20) == 1) then
|
||||
surface.create_entity({ name = "fish", position = { i + 0.5, j + 0.5 } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
surface.set_tiles(dirtTiles)
|
||||
|
||||
--Create trees (needs to be done after setting tiles!)
|
||||
local tree_entity = spawn_config.tree_entity
|
||||
if (tree_entity == nil) then return end
|
||||
|
||||
--Create trees (needs to be done after setting tiles!)
|
||||
for i = chunk_area.left_top.x, chunk_area.right_bottom.x, 1 do
|
||||
for j = chunk_area.left_top.y, chunk_area.right_bottom.y, 1 do
|
||||
local max_distance = math.max(math.abs(spawn_pos.x - i), math.abs(spawn_pos.y - j))
|
||||
if ((max_distance < tile_radius) and (max_distance >= tree_distance_inner)) then
|
||||
local pos = surface.find_non_colliding_position(tree_entity, { i, j }, 2, 0.5)
|
||||
if (pos ~= nil) then
|
||||
surface.create_entity({ name = tree_entity, position = pos })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Add a circle of water
|
||||
---@param surface LuaSurface
|
||||
---@param centerPos MapPosition
|
||||
---@param chunkArea BoundingBox
|
||||
---@param tileRadius number
|
||||
---@param moatTile string
|
||||
---@param bridge boolean
|
||||
---@param shape SpawnShapeChoice
|
||||
---@return nil
|
||||
function CreateMoat(surface, centerPos, chunkArea, tileRadius, moatTile, bridge, shape)
|
||||
local tileRadSqr = tileRadius ^ 2
|
||||
|
||||
local tiles = {}
|
||||
for i = chunkArea.left_top.x, chunkArea.right_bottom.x, 1 do
|
||||
for j = chunkArea.left_top.y, chunkArea.right_bottom.y, 1 do
|
||||
if (bridge and ((j == centerPos.y - 1) or (j == centerPos.y) or (j == centerPos.y + 1))) then
|
||||
-- This will leave the tiles "as is" on the left and right of the spawn which has the effect of creating
|
||||
-- land connections if the spawn is on or near land.
|
||||
else
|
||||
-- This ( X^2 + Y^2 ) is used to calculate if something
|
||||
-- is inside a circle area.
|
||||
local distVar = math.floor((centerPos.x - i) ^ 2 + (centerPos.y - j) ^ 2)
|
||||
|
||||
-- Create a circle of water
|
||||
if ((distVar < tileRadSqr + (1500 * storage.ocfg.spawn_general.moat_width_tiles)) and
|
||||
(distVar > tileRadSqr)) then
|
||||
table.insert(tiles, { name = moatTile, position = { i, j } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
surface.set_tiles(tiles)
|
||||
end
|
||||
|
||||
-- Create a horizontal line of tiles (typically used for water)
|
||||
---@param surface LuaSurface
|
||||
---@param leftPos TilePosition
|
||||
---@param length integer
|
||||
---@param tile_name string
|
||||
---@return nil
|
||||
function CreateTileStrip(surface, leftPos, length, tile_name)
|
||||
local waterTiles = {}
|
||||
for i = 0, length - 1, 1 do
|
||||
table.insert(waterTiles, { name = tile_name, position = { leftPos.x + i, leftPos.y } })
|
||||
end
|
||||
surface.set_tiles(waterTiles)
|
||||
end
|
||||
|
||||
--- Function to generate a resource patch, of a certain size/amount at a pos.
|
||||
---@param surface LuaSurface
|
||||
---@param resourceName string
|
||||
---@param diameter integer
|
||||
---@param position TilePosition
|
||||
---@param amount integer
|
||||
function GenerateResourcePatch(surface, resourceName, diameter, position, amount)
|
||||
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)
|
||||
|
||||
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
|
||||
surface.create_entity({
|
||||
name = resourceName,
|
||||
amount = amount,
|
||||
position = { position.x + x, position.y + y }
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Function to generate a resource patch, of a certain size/amount at a pos.
|
||||
---@param surface LuaSurface
|
||||
---@param position MapPosition
|
||||
---@return nil
|
||||
function PlaceRandomEntities(surface, position)
|
||||
local spawn_config = storage.ocfg.surfaces_config[surface.name].spawn_config
|
||||
local random_entities = spawn_config.random_entities
|
||||
if (random_entities == nil) then return end
|
||||
|
||||
local tree_width = storage.ocfg.spawn_general.tree_width_tiles
|
||||
local radius = storage.ocfg.spawn_general.spawn_radius_tiles * spawn_config.radius_modifier - tree_width
|
||||
|
||||
--Iterate through the random entities and place them
|
||||
for _, entry in pairs(random_entities) do
|
||||
local entity_name = entry.name
|
||||
|
||||
for i = 1, entry.count do
|
||||
local random_pos = GetRandomPointWithinCircle(radius, position)
|
||||
local open_pos = surface.find_non_colliding_position(entity_name, random_pos, tree_width, 0.5)
|
||||
|
||||
if (open_pos ~= nil) then
|
||||
surface.create_entity({
|
||||
name = entity_name,
|
||||
position = open_pos
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Randomly place lightning attractors specific for Fulgora. This should space them out so they don't overlap too much.
|
||||
---@param surface LuaSurface
|
||||
---@param position MapPosition
|
||||
---@return nil
|
||||
function PlaceFulgoranLightningAttractors(surface, position, count)
|
||||
local spawn_config = storage.ocfg.surfaces_config[surface.name].spawn_config
|
||||
local radius = storage.ocfg.spawn_general.spawn_radius_tiles * spawn_config.radius_modifier
|
||||
|
||||
-- HARDCODED FOR NOW
|
||||
local ATTRACTOR_NAME = "fulgoran-ruin-attractor"
|
||||
local ATTRACTOR_RADIUS = 20
|
||||
|
||||
--Iterate through and place them and use the largest available entity
|
||||
for i = 1, count do
|
||||
local random_pos = GetRandomPointWithinCircle(radius, position)
|
||||
local open_pos = surface.find_non_colliding_position("crash-site-spaceship", random_pos, 1, 0.5)
|
||||
|
||||
if (open_pos ~= nil) then
|
||||
surface.create_entity({
|
||||
name = ATTRACTOR_NAME,
|
||||
position = open_pos,
|
||||
force = "player" -- Same as native game
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
@ -329,13 +329,13 @@ oarc-fluid-count=Anzahl
|
||||
oarc-fluid-amount=Menge
|
||||
|
||||
oarc-misc-config=Sonstiges-Konfiguration
|
||||
oarc-water=Wasser
|
||||
oarc-water-length=Wasserlänge
|
||||
oarc-water-length-tooltip=Dies ist die Länge in Kacheln des Wasserstreifens um den Spawn-Bereich.
|
||||
oarc-water-x-offset=Wasser X-Versatz
|
||||
oarc-water-x-offset-tooltip=Dies ist der X-Versatz in Kacheln, gemessen vom Norden des Spawn-Bereichs.
|
||||
oarc-water-y-offset=Wasser Y-Versatz
|
||||
oarc-water-y-offset-tooltip=Dies ist der Y-Versatz in Kacheln, gemessen vom Norden des Spawn-Bereichs.
|
||||
oarc-liquid=Wasser
|
||||
oarc-liquid-length=Wasserlänge
|
||||
oarc-liquid-length-tooltip=Dies ist die Länge in Kacheln des Wasserstreifens um den Spawn-Bereich.
|
||||
oarc-liquid-x-offset=Wasser X-Versatz
|
||||
oarc-liquid-x-offset-tooltip=Dies ist der X-Versatz in Kacheln, gemessen vom Norden des Spawn-Bereichs.
|
||||
oarc-liquid-y-offset=Wasser Y-Versatz
|
||||
oarc-liquid-y-offset-tooltip=Dies ist der Y-Versatz in Kacheln, gemessen vom Norden des Spawn-Bereichs.
|
||||
|
||||
oarc-shared-chest=Gemeinsame Truhe
|
||||
oarc-chest-x-offset=Truhe X-Versatz
|
||||
|
@ -30,7 +30,6 @@ oarc-mod-enable-friendly-fire=Enable friendly fire
|
||||
|
||||
oarc-mod-main-force-name=Main force name
|
||||
oarc-mod-default-surface=Default starting surface
|
||||
oarc-mod-enable-secondary-spawns=Enable secondary spawns
|
||||
|
||||
oarc-mod-scale-resources-around-spawns=Scale resources around spawns
|
||||
oarc-mod-modified-enemy-spawning=Scale enemies around spawns
|
||||
@ -51,7 +50,7 @@ oarc-mod-spawn-general-radius-tiles=Spawn area radius
|
||||
oarc-mod-spawn-general-moat-width-tiles=Spawn moat width
|
||||
oarc-mod-spawn-general-tree-width-tiles=Spawn tree ring width
|
||||
oarc-mod-spawn-general-enable-resources-circle-shape=Spawn resource deposits shape
|
||||
oarc-mod-spawn-general-enable-force-grass=Force spawn area grass
|
||||
oarc-mod-spawn-general-enable-force-tiles=Fill spawn area tiles
|
||||
oarc-mod-spawn-general-shape=Spawn area shape
|
||||
|
||||
oarc-mod-resource-placement-enabled=Starting resource auto placement
|
||||
@ -93,7 +92,6 @@ oarc-mod-enable-friendly-fire=Enables friendly fire. So you can shoot your chest
|
||||
|
||||
oarc-mod-main-force-name=The name of the main force. This is the default team that is created when the game starts.
|
||||
oarc-mod-default-surface=The default surface that players will spawn on if they join the main team or if spawning on other surfaces is not enabled.
|
||||
oarc-mod-enable-secondary-spawns=Enabling this will provide players with a secondary spawn point when they first move to a new surface/planet. This is only applicable if the other surface is enabled for separate spawns.
|
||||
|
||||
oarc-mod-scale-resources-around-spawns=This scales resources around every spawn area so far away spawns aren't immediately next to very rich deposits.
|
||||
oarc-mod-modified-enemy-spawning=This scales the enemy spawning globally based on the allowed spawn distances to avoid every spawn being surrounded by behemoth worms.
|
||||
@ -114,7 +112,7 @@ oarc-mod-spawn-general-radius-tiles=This is the radius of the spawn area in tile
|
||||
oarc-mod-spawn-general-moat-width-tiles=This is the width of the moat around the spawn area in tiles, if a moat is enabled and selected at spawn time.
|
||||
oarc-mod-spawn-general-tree-width-tiles=This is the width of the tree ring around the spawn area in tiles. It guarantees some trees near to spawn.
|
||||
oarc-mod-spawn-general-enable-resources-circle-shape=This is the shape of the starting area resource deposits.
|
||||
oarc-mod-spawn-general-enable-force-grass=Enabling this will make the entire spawn area pure grass. Disabling will use landfill as needed instead.
|
||||
oarc-mod-spawn-general-enable-force-tiles=Enabling this will fill the entire spawn area with a specific tile (grass on Nauvis). Otherwise, landfill will be used as needed to fill in any gaps instead.
|
||||
oarc-mod-spawn-general-shape=This is the shape of the spawn area.
|
||||
|
||||
oarc-mod-resource-placement-enabled=You should leave this enabled unless you are manually specifying resource placements in the custom scenario!
|
||||
|
@ -341,13 +341,13 @@ oarc-fluid-count=Count
|
||||
oarc-fluid-amount=Amount
|
||||
|
||||
oarc-misc-config=Misc Config
|
||||
oarc-water=Water
|
||||
oarc-water-length=Water Length
|
||||
oarc-water-length-tooltip=This is the length in tiles of the water strip around the spawn area.
|
||||
oarc-water-x-offset=Water X Offset
|
||||
oarc-water-x-offset-tooltip=This is the x_offset in tiles, from the north of the spawn area.
|
||||
oarc-water-y-offset=Water Y Offset
|
||||
oarc-water-y-offset-tooltip=This is the y_offset in tiles, from the north of the spawn area.
|
||||
oarc-liquid=Liquid
|
||||
oarc-liquid-length=Liquid Length
|
||||
oarc-liquid-length-tooltip=This is the length in tiles of the liquid strip in the spawn area. Only placed if there is no moat.
|
||||
oarc-liquid-x-offset=Liquid X Offset
|
||||
oarc-liquid-x-offset-tooltip=This is the x_offset in tiles, from the north of the spawn area.
|
||||
oarc-liquid-y-offset=Liquid Y Offset
|
||||
oarc-liquid-y-offset-tooltip=This is the y_offset in tiles, from the north of the spawn area.
|
||||
|
||||
oarc-shared-chest=Shared Chest
|
||||
oarc-chest-x-offset=Chest X Offset
|
||||
|
@ -30,7 +30,6 @@ oarc-mod-enable-friendly-fire=启用友军伤害
|
||||
|
||||
oarc-mod-main-force-name=主队伍名称
|
||||
oarc-mod-default-surface=默认起始空间(星球)
|
||||
oarc-mod-enable-secondary-spawns=启用次要基地
|
||||
|
||||
oarc-mod-scale-resources-around-spawns=根据基地缩放资源
|
||||
oarc-mod-modified-enemy-spawning=根据基地缩放敌人
|
||||
@ -51,7 +50,7 @@ oarc-mod-spawn-general-radius-tiles=基地半径
|
||||
oarc-mod-spawn-general-moat-width-tiles=基地护城河宽度
|
||||
oarc-mod-spawn-general-tree-width-tiles=基地树木环宽度
|
||||
oarc-mod-spawn-general-enable-resources-circle-shape=出生资源存放形状
|
||||
oarc-mod-spawn-general-enable-force-grass=强制基地为草地
|
||||
oarc-mod-spawn-general-enable-force-tiles=强制基地为草地
|
||||
oarc-mod-spawn-general-shape=基地形状
|
||||
|
||||
oarc-mod-resource-placement-enabled=起始资源自动放置
|
||||
@ -88,7 +87,6 @@ oarc-mod-number-of-players-per-shared-spawn=可以加入共享基地的玩家数
|
||||
oarc-mod-enable-friendly-fire=启用友军伤害。这样您可以射击自己的箱子(或用火车碾压朋友)。这允许您对自己的队伍造成伤害。
|
||||
oarc-mod-main-force-name=主队伍的名称。这是游戏开始时创建的默认队伍。
|
||||
oarc-mod-default-surface=如果玩家加入主队伍或不允许在其他空间(星球)出生,他们将在此默认空间(星球)出生。
|
||||
oarc-mod-enable-secondary-spawns=启用此选项将在玩家首次移动到新空间/星球时提供次要基地。仅在允许其他空间(星球)单独出生时适用。
|
||||
oarc-mod-scale-resources-around-spawns=这会根据每个出生区域缩放资源,以避免远处的基地紧邻非常丰富的矿藏。
|
||||
oarc-mod-modified-enemy-spawning=根据允许的出生距离全局缩放敌人生成,以避免每个基地都被巨型蠕虫包围。
|
||||
oarc-mod-minimum-online-time=玩家在离开前必须在线的最短时间,否则他们的出生区域将被清理。
|
||||
@ -104,7 +102,7 @@ oarc-mod-spawn-general-radius-tiles=这是出生区域的半径(以图块为
|
||||
oarc-mod-spawn-general-moat-width-tiles=如果启用并在出生时选择了护城河,这是出生区域周围护城河的宽度(以图块为单位)。
|
||||
oarc-mod-spawn-general-tree-width-tiles=这是出生区域周围树木环的宽度(以图块为单位)。它保证基地附近有一些树木。
|
||||
oarc-mod-spawn-general-enable-resources-circle-shape=这是起始区域资源存放的形状。
|
||||
oarc-mod-spawn-general-enable-force-grass=启用此选项将使整个出生区域变成纯草地。禁用将根据需要使用填海造地。
|
||||
oarc-mod-spawn-general-enable-force-tiles=启用此选项将使整个出生区域变成纯草地。禁用将根据需要使用填海造地。
|
||||
oarc-mod-spawn-general-shape=这是出生区域的形状。
|
||||
oarc-mod-resource-placement-enabled=除非您在自定义场景中手动指定资源放置,否则应保持此项启用!
|
||||
oarc-mod-resource-placement-distance-to-edge=这是资源放置距离出生区域边缘的距离。仅适用于圆形/八边形形状的基地。
|
||||
|
@ -343,13 +343,13 @@ oarc-fluid-amount=量
|
||||
|
||||
|
||||
oarc-misc-config=杂项配置
|
||||
oarc-water=水
|
||||
oarc-water-length=水的长度
|
||||
oarc-water-length-tooltip=这是基地周围水带的长度(单位:格)。
|
||||
oarc-water-x-offset=水的 X 偏移
|
||||
oarc-water-x-offset-tooltip=这是从基地北部的 x 轴偏移(单位:格)。
|
||||
oarc-water-y-offset=水的 Y 偏移
|
||||
oarc-water-y-offset-tooltip=这是从基地北部的 y 轴偏移(单位:格)。
|
||||
oarc-liquid=水
|
||||
oarc-liquid-length=水的长度
|
||||
oarc-liquid-length-tooltip=这是基地周围水带的长度(单位:格)。
|
||||
oarc-liquid-x-offset=水的 X 偏移
|
||||
oarc-liquid-x-offset-tooltip=这是从基地北部的 x 轴偏移(单位:格)。
|
||||
oarc-liquid-y-offset=水的 Y 偏移
|
||||
oarc-liquid-y-offset-tooltip=这是从基地北部的 y 轴偏移(单位:格)。
|
||||
|
||||
oarc-shared-chest=共享箱
|
||||
oarc-chest-x-offset=箱的 X 偏移
|
||||
|
10
migrations/oarc-mod-V2.1.10.lua
Normal file
10
migrations/oarc-mod-V2.1.10.lua
Normal file
@ -0,0 +1,10 @@
|
||||
--Migrate the force_grass to force_tiles new setting!
|
||||
if storage.ocfg.spawn_general.force_tiles == nil then
|
||||
storage.ocfg.spawn_general.force_tiles = true
|
||||
log("Updating spawn_general config with new 'force_tiles' setting.")
|
||||
end
|
||||
|
||||
--Make sure new planets get init'd. No harm in running this multiple times.
|
||||
SeparateSpawnsInitPlanets()
|
||||
|
||||
--Migrate surface config changes!
|
11
settings.lua
11
settings.lua
@ -177,13 +177,6 @@ data:extend({
|
||||
default_value = "nauvis",
|
||||
order = "e2"
|
||||
},
|
||||
{
|
||||
type = "bool-setting",
|
||||
name = "oarc-mod-enable-secondary-spawns",
|
||||
setting_type = "runtime-global",
|
||||
default_value = false,
|
||||
order = "e3"
|
||||
},
|
||||
|
||||
{
|
||||
type = "bool-setting",
|
||||
@ -328,9 +321,9 @@ data:extend({
|
||||
},
|
||||
{
|
||||
type = "bool-setting",
|
||||
name = "oarc-mod-spawn-general-enable-force-grass",
|
||||
name = "oarc-mod-spawn-general-enable-force-tiles",
|
||||
setting_type = "runtime-global",
|
||||
default_value = false,
|
||||
default_value = true,
|
||||
order = "h5"
|
||||
}, {
|
||||
type = "string-setting",
|
||||
|
Loading…
Reference in New Issue
Block a user