1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2025-03-05 14:45:19 +02:00

Found a few bugs in the old spawn validation logic, but were so rare as to not happen. Vanilla spawns is close to being done I think. Needs proper testing now.

This commit is contained in:
Oarcinae 2019-03-20 16:02:50 -04:00
parent d07f767389
commit 2afd833eff
5 changed files with 145 additions and 67 deletions

View File

@ -49,9 +49,6 @@ ENABLE_SEPARATE_SPAWNS = true
-- This scenario normally gives you a fixed circle with resources.
-- WORK IN PROGRESS
ENABLE_VANILLA_SPAWNS = true
VANILLA_SPAWN_COUNT = 8 -- num total spawns pre-assigned (minimum number)
VANILLA_SPAWN_SPACING = 2000 -- num tiles between each spawn.
-- This allows 2 players to spawn next to each other in the wilderness,
-- each with their own starting point. It adds more GUI selection options.
@ -162,6 +159,17 @@ NEAR_MAX_DIST = 50
FAR_MIN_DIST = 200
FAR_MAX_DIST = 300
---------------------------------------
-- Vanilla spawn point options
-- (only applicable if ENABLE_VANILLA_SPAWNS is enabled.)
---------------------------------------
-- Num total spawns pre-assigned (minimum number)
VANILLA_SPAWN_COUNT = 100
-- Num tiles between each spawn. (I recommend at least 1000)
VANILLA_SPAWN_SPACING = 2000
---------------------------------------
-- Resource & Spawn Circle Options
---------------------------------------
@ -396,7 +404,7 @@ SILO_POSITION = {x = 0, y = 100}
-- Set this to false so that you have to search for the silo's.
ENABLE_SILO_VISION = true
-- Add beacons around the silo (Philip's modm)
-- Add beacons around the silo (Philip's mod)
ENABLE_SILO_BEACONS = false
ENABLE_SILO_RADAR = false

View File

@ -77,6 +77,11 @@ local function CreateRocketSilo(surface, siloPosition, force)
silo.destructible = false
silo.minable = false
-- TAG it on the main force at least.
game.forces[MAIN_FORCE].add_chart_tag(game.surfaces[GAME_SURFACE_NAME],
{position=siloPosition, text="Rocket Silo",
icon={type="item",name="rocket-silo"}})
-- Make silo safe from being removed by regrowth
if ENABLE_REGROWTH then
OarcRegrowthOffLimits(siloPosition, 5)
@ -84,10 +89,10 @@ local function CreateRocketSilo(surface, siloPosition, force)
if ENABLE_SILO_BEACONS then
PhilipsBeaconsAndShit(surface, siloPosition, game.forces[MAIN_FORCE])
PhilipsBeacons(surface, siloPosition, game.forces[MAIN_FORCE])
end
if ENABLE_SILO_RADAR then
PhilipsRadarAndShit(surface, siloPosition, game.forces[MAIN_FORCE])
PhilipsRadar(surface, siloPosition, game.forces[MAIN_FORCE])
end
end
@ -174,145 +179,145 @@ function DelayedSiloCreationOnTick(surface)
end
function PhilipsBeaconsAndShit(surface, siloPos, force)
function PhilipsBeacons(surface, siloPos, force)
-- Add Beacons
-- x = right, left; y = up, down
-- top 1 left 1
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y-9}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- top 2
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-5, siloPos.y-9}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-5, siloPos.y-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- top 3
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-2, siloPos.y-9}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-2, siloPos.y-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- top 4
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+2, siloPos.y-9}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+2, siloPos.y-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- top 5
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+5, siloPos.y-9}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+5, siloPos.y-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- top 6 right 1
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y-9}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 2
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-6, siloPos.y-6}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y-5}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 3
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-6, siloPos.y-3}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y-2}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 4
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-6, siloPos.y}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y+2}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 5
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-6, siloPos.y+3}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y+5}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 6 bottom 1
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y+6}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-8, siloPos.y+8}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 7 bottom 2
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-5, siloPos.y+6}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-5, siloPos.y+8}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 2
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+6, siloPos.y-6}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y-5}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 3
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+6, siloPos.y-3}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y-2}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 4
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+6, siloPos.y}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y+2}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 5
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+6, siloPos.y+3}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y+5}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 6 bottom 3
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+5, siloPos.y+6}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+5, siloPos.y+8}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 7 bottom 4
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y+6}, force = force}
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+8, siloPos.y+8}, force = force}
beacon.destructible = false
beacon.minable = false
-- substations
-- top left
local substation = surface.create_entity{name = "substation", position = {siloPos.x-8, siloPos.y-6}, force = force}
local substation = surface.create_entity{name = "substation", position = {siloPos.x-5, siloPos.y-5}, force = force}
substation.destructible = false
substation.minable = false
-- top right
local substation = surface.create_entity{name = "substation", position = {siloPos.x+9, siloPos.y-6}, force = force}
local substation = surface.create_entity{name = "substation", position = {siloPos.x+6, siloPos.y-5}, force = force}
substation.destructible = false
substation.minable = false
-- bottom left
local substation = surface.create_entity{name = "substation", position = {siloPos.x-8, siloPos.y+4}, force = force}
local substation = surface.create_entity{name = "substation", position = {siloPos.x-5, siloPos.y+6}, force = force}
substation.destructible = false
substation.minable = false
-- bottom right
local substation = surface.create_entity{name = "substation", position = {siloPos.x+9, siloPos.y+4}, force = force}
local substation = surface.create_entity{name = "substation", position = {siloPos.x+6, siloPos.y+6}, force = force}
substation.destructible = false
substation.minable = false
-- end adding beacons
end
function PhilipsRadarAndShit(surface, siloPos, force)
function PhilipsRadar(surface, siloPos, force)
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-33, siloPos.y+3}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-43, siloPos.y+3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-33, siloPos.y-3}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-43, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-30, siloPos.y-6}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-40, siloPos.y-6}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-27, siloPos.y-6}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-37, siloPos.y-6}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-24, siloPos.y-6}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-34, siloPos.y-6}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-24, siloPos.y-3}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-34, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-24, siloPos.y}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-34, siloPos.y}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-24, siloPos.y+3}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-34, siloPos.y+3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-33, siloPos.y-6}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-43, siloPos.y-6}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-30, siloPos.y+3}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-40, siloPos.y+3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-27, siloPos.y+3}, force = force}
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-37, siloPos.y+3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "radar", position = {siloPos.x-33, siloPos.y}, force = force}
local radar = surface.create_entity{name = "radar", position = {siloPos.x-43, siloPos.y}, force = force}
radar.destructible = false
local substation = surface.create_entity{name = "substation", position = {siloPos.x-28, siloPos.y-1}, force = force}
local substation = surface.create_entity{name = "substation", position = {siloPos.x-38, siloPos.y-1}, force = force}
substation.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-30, siloPos.y-1}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-40, siloPos.y-1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-30, siloPos.y-3}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-40, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-30, siloPos.y+1}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-40, siloPos.y+1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-28, siloPos.y-3}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-38, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-28, siloPos.y+1}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-38, siloPos.y+1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-26, siloPos.y-1}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-36, siloPos.y-1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-26, siloPos.y-3}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-36, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-26, siloPos.y+1}, force = force}
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-36, siloPos.y+1}, force = force}
radar.destructible = false
end

View File

@ -401,6 +401,11 @@ function GetAreaAroundPos(pos, dist)
y=pos.y+dist}}
end
-- Gets chunk position of a tile.
function GetChunkPosFromTilePos(tile_pos)
return {x=math.floor(tile_pos.x/32), y=math.floor(tile_pos.y/32)}
end
-- Removes the entity type from the area given
function RemoveInArea(surface, area, type)
for key, entity in pairs(surface.find_entities_filtered({area=area, type= type})) do

View File

@ -84,6 +84,7 @@ function FindUnusedSpawns(event)
if (global.uniqueSpawns[player.name] ~= nil) then
local spawnPos = global.uniqueSpawns[player.name].pos
local isVanilla = global.uniqueSpawns[player.name].vanilla
-- Check if it was near someone else's base.
nearOtherSpawn = false
@ -100,6 +101,10 @@ function FindUnusedSpawns(event)
SendBroadcastMsg(player.name .. "'s base was marked for immediate clean up because they left within "..MIN_ONLINE_TIME_IN_MINUTES.." minutes of joining.")
OarcRegrowthMarkForRemoval(spawnPos, 10)
global.chunk_regrow.force_removal_flag = game.tick
if (isVanilla) then
table.insert(global.vanillaSpawns, spawnPos)
end
else
-- table.insert(global.unusedSpawns, global.uniqueSpawns[player.name]) -- Not used/implemented right now.
global.uniqueSpawns[player.name] = nil
@ -457,12 +462,12 @@ end
function QueuePlayerForDelayedSpawn(playerName, spawn, moatEnabled, vanillaSpawn)
-- If we get a valid spawn point, setup the area
if ((spawn.x ~= 0) and (spawn.y ~= 0)) then
if ((spawn.x ~= 0) or (spawn.y ~= 0)) then
global.uniqueSpawns[playerName] = {pos=spawn,moat=moatEnabled,vanilla=vanillaSpawn}
local delay_spawn_seconds = 5*(math.ceil(ENFORCE_LAND_AREA_TILE_DIST/CHUNK_SIZE))
game.players[playerName].print("Generating your spawn now, please wait a few for " .. delay_spawn_seconds .. " seconds...")
game.players[playerName].print("Generating your spawn now, please wait for at least " .. delay_spawn_seconds .. " seconds...")
game.players[playerName].surface.request_to_generate_chunks(spawn, 4)
delayedTick = game.tick + delay_spawn_seconds*TICKS_PER_SECOND
table.insert(global.delayedSpawns, {playerName=playerName, pos=spawn, moat=moatEnabled, vanilla=vanillaSpawn, delayedTick=delayedTick})
@ -646,3 +651,55 @@ function DeleteAllChunksExceptCenter(surface)
end
end
-- Find a vanilla spawn as close as possible to the given target_distance
function FindUnusedVanillaSpawn(surface, target_distance)
local best_key = nil
local best_distance = nil
for k,v in pairs(global.vanillaSpawns) do
-- Check if chunks nearby are not generated.
local chunk_pos = GetChunkPosFromTilePos(v)
if IsChunkAreaUngenerated(chunk_pos, 10, surface) then
-- Is this our first valid find?
if ((best_key == nil) or (best_distance == nil)) then
best_key = k
best_distance = math.abs(math.sqrt((v.x^2) + (v.y^2)) - target_distance)
-- Check if it is closer to target_distance than previous option.
else
local new_distance = math.abs(math.sqrt((v.x^2) + (v.y^2)) - target_distance)
if (new_distance < best_distance) then
best_key = k
best_distance = math.sqrt((v.x^2) + (v.y^2))
end
end
-- If it's not a valid spawn anymore, let's remove it.
else
table.remove(global.vanillaSpawns, k)
end
end
local spawn_pos = {x=0,y=0}
if ((best_key ~= nil) and (global.vanillaSpawns[best_key] ~= nil)) then
spawn_pos.x = global.vanillaSpawns[best_key].x
spawn_pos.y = global.vanillaSpawns[best_key].y
table.remove(global.vanillaSpawns, best_key)
end
DebugPrint("Found unused vanilla spawn: x=" .. spawn_pos.x .. ",y=" .. spawn_pos.y)
return spawn_pos
end
function ValidateVanillaSpawns(surface)
for k,v in pairs(global.vanillaSpawns) do
-- Check if chunks nearby are not generated.
local chunk_pos = GetChunkPosFromTilePos(v)
if not IsChunkAreaUngenerated(chunk_pos, 10, surface) then
table.remove(global.vanillaSpawns, k)
end
end
end

View File

@ -147,10 +147,10 @@ function DisplaySpawnOptions(player)
caption="Surround your spawn with a moat",
state=false}
end
if (ENABLE_VANILLA_SPAWNS) then
if (ENABLE_VANILLA_SPAWNS and (#global.vanillaSpawns > 0)) then
soloSpawnFlow.add{name = "isolated_spawn_vanilla_option_checkbox",
type = "checkbox",
caption="Use a pre-set vanilla spawn point",
caption="Use a pre-set vanilla spawn point. " .. #global.vanillaSpawns .. " available.",
state=false}
end
@ -291,13 +291,13 @@ function SpawnOptsGuiClick(event)
joinMainTeamRadio = true
joinOwnTeamRadio = false
end
if (SPAWN_MOAT_CHOICE_ENABLED) then
moatChoice =
pgcs.spawn_solo_flow.isolated_spawn_moat_option_checkbox.state
if (SPAWN_MOAT_CHOICE_ENABLED and
(pgcs.spawn_solo_flow.isolated_spawn_moat_option_checkbox ~= nil)) then
moatChoice = pgcs.spawn_solo_flow.isolated_spawn_moat_option_checkbox.state
end
if (ENABLE_VANILLA_SPAWNS) then
vanillaChoice =
pgcs.spawn_solo_flow.isolated_spawn_vanilla_option_checkbox.state
if (ENABLE_VANILLA_SPAWNS and
(pgcs.spawn_solo_flow.isolated_spawn_vanilla_option_checkbox ~= nil)) then
vanillaChoice = pgcs.spawn_solo_flow.isolated_spawn_vanilla_option_checkbox.state
end
pgcs.destroy()
else
@ -324,10 +324,13 @@ function SpawnOptsGuiClick(event)
-- Find an unused vanilla spawn
if (vanillaChoice) then
rand_index = math.random(#global.vanillaSpawns)
newSpawn.x = global.vanillaSpawns[rand_index].x
newSpawn.y = global.vanillaSpawns[rand_index].y
table.remove(global.vanillaSpawns, rand_index)
if (elemName == "isolated_spawn_far") then
newSpawn = FindUnusedVanillaSpawn(game.surfaces[GAME_SURFACE_NAME],
FAR_MAX_DIST*CHUNK_SIZE)
elseif (elemName == "isolated_spawn_near") then
newSpawn = FindUnusedVanillaSpawn(game.surfaces[GAME_SURFACE_NAME],
NEAR_MIN_DIST*CHUNK_SIZE)
end
-- Default OARC-type pre-set layout spawn.
else
@ -340,7 +343,7 @@ function SpawnOptsGuiClick(event)
end
-- If that fails, find a random map edge in a rand direction.
if ((newSpawn.x == 0) and (newSpawn.x == 0)) then
if ((newSpawn.x == 0) and (newSpawn.y == 0)) then
newSpawn = FindMapEdge(GetRandomVector(), player.surface)
DebugPrint("Resorting to find map edge! x=" .. newSpawn.x .. ",y=" .. newSpawn.y)
end