diff --git a/config.lua b/config.lua index 6116290..50d0737 100644 --- a/config.lua +++ b/config.lua @@ -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. @@ -161,7 +158,18 @@ NEAR_MAX_DIST = 50 -- Far Distance in chunks 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 diff --git a/lib/frontier_silo.lua b/lib/frontier_silo.lua index 1b85ec5..2d9a3a4 100644 --- a/lib/frontier_silo.lua +++ b/lib/frontier_silo.lua @@ -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 \ No newline at end of file diff --git a/lib/oarc_utils.lua b/lib/oarc_utils.lua index 35f6824..6fa243d 100644 --- a/lib/oarc_utils.lua +++ b/lib/oarc_utils.lua @@ -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 diff --git a/lib/separate_spawns.lua b/lib/separate_spawns.lua index 2d3582c..56fbed1 100644 --- a/lib/separate_spawns.lua +++ b/lib/separate_spawns.lua @@ -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 diff --git a/lib/separate_spawns_guis.lua b/lib/separate_spawns_guis.lua index f175002..4f9350b 100644 --- a/lib/separate_spawns_guis.lua +++ b/lib/separate_spawns_guis.lua @@ -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