1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2025-02-01 12:57:49 +02:00

Merge pull request #105 from Oarcinae/dev_0.17

Merging 0.17 into Master
This commit is contained in:
Oarcinae 2019-09-24 18:33:38 -04:00 committed by GitHub
commit bc5e566e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 5980 additions and 6397 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
config.lua

View File

@ -1,81 +1,24 @@
# FactorioScenarioMultiplayerSpawn
A custom scenario for allowing separate spawn locations in multiplayer. Designed for Co-op and PvE.
0.17 is in a dev branch "dev_0.17". At this point it's basically stable. I will merge to master once 0.17 factorio is made stable.
0.16 is stable but will not receive any further updates.
## Instructions
### STEP 1
Download the zip.
Place it in your Factorio/scenarios/... folder.
It should look something like this (for my windows steam install location):
C:\Users\user\AppData\Roaming\Factorio\scenarios\FactorioScenarioMultiplayerSpawn\control.lua
### STEP 2
Go into config.lua and edit the strings to add your own server messages.
Rename the "FactorioScenarioMultiplayerSpawn" folder to something shorter and more convenient (optional).
### STEP 3
#### OPTION 1 (Client Hosted)
Start a multiplayer game on your client like normal.
#### OPTION 2 (Headless)
Generate a new map, use that save file to host if you want to.
#### OPTION 3 (Headless)
Place the scenario code in the game's scenario folder, typically something like "..\Factorio\scenarios\FactorioScenarioMultiplayerSpawn\\.."
Start a new game (generates a random map based on the config in config.lua) from the command line:
./factorio --start-server-load-scenario FactorioScenarioMultiplayerSpawn --server-settings my-server-settings.json
If you want to RESUME from this method, use something like this:
./factorio --start-server-load-latest --server-settings my-server-settings.json
## Configuration
Look in config.lua for some controls over the different modules.
Not all configurations have been fully tested so modify at your own risk.
If you want to change the RSO config, look for the rso_config and rso_resource_config files.
## TODO
I need to update this with more details about the implementation and explain some of the configuration options.
For now, just take a look at the source and it should be easy to understand I hope.
## Read the WIKI
The github wiki page will have the most up to date information. If you have questions, go there first, otherwise just ask.
## Stable Version (Factorio v0.17.69)
At this point master branch is basically stable, I'll help with bug fixes and minor features but I have no large changes planned.
## Credit
RSO is not my own creation. It was done by Orzelek. I requested permission to include it in my scenario.
https://mods.factorio.com/mods/orzelek/rso-mod
Several other portions of the code (tags, frontier style rocket silo) have also been adapted from other scenario code.
Credit to 3Ra for help as well: https://github.com/3RaGaming
Praise be to Mylon
## Random Notes
While it is an option to disable RSO, I would not recommend doing that. I can't guarantee any bugs or issues as I focus mostly on testing with RSO enabled.
Feel free to submit bugs/fixes/requests/pulls/forks whatever you want.
I do not plan on supporting PvP, but I will help anyone who wants to make it a configurable option.
## Contact
discord.gg/trnpcen
oarcinae@gmail.com

View File

@ -1,405 +0,0 @@
-- config.lua
-- Apr 2017
-- Configuration Options
--
-- You should be able to leave most of the settings here as defaults.
-- The only thing you definitely want to change are the welcome messages.
--------------------------------------------------------------------------------
-- Messages
-- You will want to change some of these to be your own.
-- Make sure SERVER_OWNER_IS_OARC = false
--------------------------------------------------------------------------------
-- This stuff is printed in the console. It's probably ignored most of the time.
WELCOME_MSG = "[INSERT SERVER OWNER MSG HERE!]"
GAME_MODE_MSG = "In the current game mode, a satellite must be launched from an existing far away rocket silo to win!"
MODULES_ENABLED = "Mods Enabled: Separate Spawns, RSO, Long-Reach, Autofill, Undecorator, Player List"
-- This stuff is shown in the welcome GUI. Make sure it's valid.
WELCOME_MSG_TITLE = "[INSERT SERVER OWNER MSG HERE!]"
SERVER_MSG = "Rules: Be polite. Ask before changing other players's stuff. Have fun!\n"..
"This server is running a custom scenario that changes spawn locations."
SCENARIO_INFO_MSG = "Latest updates in this scenario version:\n"..
"0.16 experimental release. Tweaks to fix spawn issues / text / difficulty.\n"..
"This scenario gives you and/or your friends your own starting area.\n"..
"You can be on the main team or your own. All teams are friendly.\n"..
"If you leave in the first 15 minutes, your base and character will be deleted!"
SPAWN_WARN_MSG = "Due to the way this scenario works, it may take some time for the land around your new spawn area to generate... Please wait for 10-20 seconds when you select your first spawn."
CONTACT_MSG = "Contact: SteamID:Oarc | oarcinae@gmail.com | discord.gg/TPYxRrS"
-- This should be false for you, it's just a convenience for me.
SERVER_OWNER_IS_OARC = false
--------------------------------------------------------------------------------
-- Module Enables
-- These enables are not fully tested! For example, disabling separate spawns
-- will probably break the frontier rocket silo mode
--------------------------------------------------------------------------------
-- Separate spawns
-- This is the core of the mod. Probably not a good idea to disable it.
ENABLE_SEPARATE_SPAWNS = true
-- 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.
ENABLE_BUDDY_SPAWN = true
-- RSO soft-mod (included in the scenario)
ENABLE_RSO = true
-- Frontier style rocket silo mode
FRONTIER_ROCKET_SILO_MODE = true
-- Enable Undecorator
-- Removes decorative items to reduce save file size.
ENABLE_UNDECORATOR = true
-- Enable Tags
ENABLE_TAGS = true
-- Enable Long Reach
ENABLE_LONGREACH = true
-- Enable Autofill
ENABLE_AUTOFILL = true
-- Enable Playerlist
ENABLE_PLAYER_LIST = true
PLAYER_LIST_OFFLINE_PLAYERS = true -- List offline players as well.
-- Enable Gravestone Chests
ENABLE_GRAVESTONE_ON_DEATH = false
-- Items dumped into chest when you leave.
ENABLE_GRAVESTONE_ON_LEAVING = false
-- If anyone leaves within first X minutes, items get dumped into chest.
ENABLE_GRAVESTONE_ON_LEAVING_TIME_MINS = 15
-- Enable quick start items
ENABLE_POWER_ARMOR_QUICK_START = false
-- Enable shared vision between teams (all teams are COOP regardless)
ENABLE_SHARED_TEAM_VISION = true
-- Enable map regrowth, see regrowth_map.lua for more info.
-- I'm not a fan of this anymore, but it helps keep the map size down
ENABLE_REGROWTH = false
-- If you have regrowth enabled, this should also be enabled.
-- It removes bases for players that join and leave the game quickly.
-- This can also be used without enabling regrowth.
ENABLE_ABANDONED_BASE_REMOVAL = true
--------------------------------------------------------------------------------
-- Spawn Options
--------------------------------------------------------------------------------
---------------------------------------
-- Starting Items
---------------------------------------
-- Items provided to the player the first time they join
PLAYER_SPAWN_START_ITEMS = {
{name="pistol", count=1},
{name="firearm-magazine", count=100},
{name="iron-plate", count=8},
{name="burner-mining-drill", count = 1},
{name="stone-furnace", count = 1},
-- {name="iron-plate", count=20},
-- {name="burner-mining-drill", count = 1},
-- {name="stone-furnace", count = 1},
-- {name="power-armor", count=1},
-- {name="fusion-reactor-equipment", count=1},
-- {name="battery-mk2-equipment", count=3},
-- {name="exoskeleton-equipment", count=1},
-- {name="personal-roboport-mk2-equipment", count=3},
-- {name="solar-panel-equipment", count=7},
-- {name="construction-robot", count=100},
-- {name="repair-pack", count=100},
-- {name="steel-axe", count=3},
}
-- Items provided after EVERY respawn (disabled by default)
PLAYER_RESPAWN_START_ITEMS = {
-- {name="pistol", count=1},
-- {name="firearm-magazine", count=100}
}
---------------------------------------
-- Distance Options
---------------------------------------
-- This is the radius, in chunks, that a spawn area is from any other generated
-- chunks. It ensures the spawn area isn't too near generated/explored/existing
-- area. The larger you make this, the further away players will spawn from
-- generated map area (even if it is not visible on the map!).
CHECK_SPAWN_UNGENERATED_CHUNKS_RADIUS = 5
-- Near Distance in chunks
NEAR_MIN_DIST = 0
NEAR_MAX_DIST = 50
-- Far Distance in chunks
FAR_MIN_DIST = 200
FAR_MAX_DIST = 300
---------------------------------------
-- Resource & Spawn Circle Options
---------------------------------------
-- Enable this to have a vanilla style starting spawn for all new spawns.
-- This scenario normally gives you a fixed circle with resources.
-- USE_VANILLA_STARTING_SPAWN = true
-- TODO - Requires pre-allocating spawns...
-- Allow players to choose to spawn with a moat
SPAWN_MOAT_CHOICE_ENABLED = true
-- If you change the spawn area size, you might have to adjust this as well
MOAT_SIZE_MODIFIER = 1
-- THIS IS WHAT SETS THE SPAWN CIRCLE SIZE!
-- Create a circle of land area for the spawn
-- If you make this much bigger than a few chunks, good luck.
ENFORCE_LAND_AREA_TILE_DIST = CHUNK_SIZE*1.8
-- Location of water strip (horizontal)
WATER_SPAWN_OFFSET_X = -4
WATER_SPAWN_OFFSET_Y = -38
WATER_SPAWN_LENGTH = 8
-- Start resource amounts (per tile/oil spot)
START_IRON_AMOUNT = 1500
START_COPPER_AMOUNT = 1500
START_STONE_AMOUNT = 1000
START_COAL_AMOUNT = 1500
START_URANIUM_AMOUNT = 1000
START_OIL_AMOUNT = 300000
-- Start resource shape
-- If this is true, it will be a circle
-- If false, it will be a square
ENABLE_RESOURCE_SHAPE_CIRCLE = true
-- Start resource position and size
-- Position is relative to player starting location
START_RESOURCE_STONE_POS_X = -27
START_RESOURCE_STONE_POS_Y = -34
START_RESOURCE_STONE_SIZE = 12
START_RESOURCE_COAL_POS_X = -27
START_RESOURCE_COAL_POS_Y = -20
START_RESOURCE_COAL_SIZE = 12
START_RESOURCE_COPPER_POS_X = -28
START_RESOURCE_COPPER_POS_Y = -3
START_RESOURCE_COPPER_SIZE = 14
START_RESOURCE_IRON_POS_X = -29
START_RESOURCE_IRON_POS_Y = 16
START_RESOURCE_IRON_SIZE = 16
START_RESOURCE_URANIUM_POS_X = 17
START_RESOURCE_URANIUM_POS_Y = -34
START_RESOURCE_URANIUM_SIZE = 0 -- Disabled by default.
-- Specify 2 oil spot locations for starting oil.
START_RESOURCE_OIL_NUM_PATCHES = 2
-- The first patch
START_RESOURCE_OIL_POS_X = -39
START_RESOURCE_OIL_POS_Y = -2
-- How far each patch is offset from the others and in which direction
-- Default (x=0, y=-4) means that patches spawn in a vertical row downwards.
START_RESOURCE_OIL_X_OFFSET = 0
START_RESOURCE_OIL_Y_OFFSET = -4
-- Force the land area circle at the spawn to be fully grass
ENABLE_SPAWN_FORCE_GRASS = true
-- Set this to true for the spawn area to be surrounded by a circle of trees
SPAWN_TREE_CIRCLE_ENABLED = true
-- Set this to true for the spawn area to be surrounded by an octagon of trees
-- I don't recommend using this with moatsm
SPAWN_TREE_OCTAGON_ENABLED = true
---------------------------------------
-- Safe Spawn Area Options
---------------------------------------
-- Safe area has no aliens
-- +/- this in x and y direction
SAFE_AREA_TILE_DIST = CHUNK_SIZE*5
-- Warning area has reduced aliens
-- +/- this in x and y direction
WARNING_AREA_TILE_DIST = CHUNK_SIZE*10
-- 1 : X (spawners alive : spawners destroyed) in this area
WARN_AREA_REDUCTION_RATIO = 10
---------------------------------------
-- Other Forces/Teams Options
---------------------------------------
-- Separate teams
-- This allows you to join your own force/team. Everyone is still COOP/PvE, all
-- teams are friendly and cease-fire.
ENABLE_SEPARATE_TEAMS = true
-- Main force is what default players join
MAIN_FORCE = "Main Force"
-- Enable if people can spawn at the main base
-- THIS CURRENTLY IS BROKEN! YOU WILL NOT GET ANY RESOURCES IF YOU USE RSO!
ENABLE_DEFAULT_SPAWN = false -- DON'T USE THIS
-- Enable if people can allow others to join their base
ENABLE_SHARED_SPAWNS = true
MAX_ONLINE_PLAYERS_AT_SHARED_SPAWN = 0
-- Share local team chat with all teams
-- This makes it so you don't have to use /s
-- but it means you can't talk privately with your own team.
ENABLE_SHARED_TEAM_CHAT = true
---------------------------------------
-- Special Action Cooldowns
---------------------------------------
RESPAWN_COOLDOWN_IN_MINUTES = 15
RESPAWN_COOLDOWN_TICKS = TICKS_PER_MINUTE * RESPAWN_COOLDOWN_IN_MINUTES
-- Require playes to be online for at least 5 minutes
-- Else their character is removed and their spawn point is freed up for use
MIN_ONLINE_TIME_IN_MINUTES = 15
MIN_ONLINE_TIME = TICKS_PER_MINUTE * MIN_ONLINE_TIME_IN_MINUTES
--------------------------------------------------------------------------------
-- Alien Options
--------------------------------------------------------------------------------
-- Enable/Disable enemy expansion
ENEMY_EXPANSION = true
-- Divide the alien evolution factors by this number to reduce it (or multiply if < 1)
ENEMY_TIME_FACTOR_DISABLE = false -- Set this to true to disable time based evolution completely.
ENEMY_TIME_FACTOR_DIVISOR = 10
ENEMY_POLLUTION_FACTOR_DISABLE = false -- Set this to true to disable pollution based evolution completely.
ENEMY_POLLUTION_FACTOR_DIVISOR = 10
ENEMY_DESTROY_FACTOR_DISABLE = false -- Set this to true to disable spawner destruction based evolution completely.
ENEMY_DESTROY_FACTOR_DIVISOR = 1
--------------------------------------------------------------------------------
-- Frontier Rocket Silo Options
--------------------------------------------------------------------------------
-- Number of silos found in the wild.
-- These will spawn in a circle at given distance from the center of the map
-- If you set this number too high, you'll have a lot of delay at the start of the game.
SILO_NUM_SPAWNS = 3
-- How many chunks away from the center of the map should the silo be spawned
SILO_CHUNK_DISTANCE = 200
-- If this is enabled, you get ONE silo at the location specified below.
SILO_FIXED_POSITION = false
-- If you want to set a fixed spawn location for a single silo
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)
ENABLE_SILO_BEACONS = false
ENABLE_SILO_RADAR = false
--------------------------------------------------------------------------------
-- Long Reach Options
--------------------------------------------------------------------------------
BUILD_DIST_BONUS = 64
REACH_DIST_BONUS = BUILD_DIST_BONUS
RESOURCE_DIST_BONUS = 2
--------------------------------------------------------------------------------
-- Autofill Options
--------------------------------------------------------------------------------
AUTOFILL_TURRET_AMMO_QUANTITY = 10
--------------------------------------------------------------------------------
-- RSO Soft-Mod Configurations
-- Configure these to tweak the RSO values.
--------------------------------------------------------------------------------
-- CONFIGURE STUFF INSIDE rso_config.lua
-- RSO resources can be very lucky/unlucky...
-- don't complain if you can't find a resource.
--------------------------------------------------------------------------------
-- MAP CONFIGURATION OPTIONS
-- Configure these if you are running headless since there is no way to set
-- resources otherwise.
--------------------------------------------------------------------------------
-- Set this to true if you are creating the scenario at the cmd line.
CMD_LINE_MAP_GEN = true
-- Adjust settings here to set your map stuff.
-- "Sizes can be specified as none, very-low, low, normal, high, very-high"
global.clMapGen = {}
global.clMapGen.terrain_segmentation="normal"
global.clMapGen.water="normal"
global.clMapGen.starting_area="low"
global.clMapGen.peaceful_mode=false
global.clMapGen.seed=nil;
-- These are my go to default vanilla settings, it's not RSO, but it's okay.
global.clMapGen.autoplace_controls = {
-- Resources and enemies only matter if you are NOT using RSO.
["coal"]={frequency="very-low", size= "low", richness= "high"},
["copper-ore"]={frequency= "very-low", size= "low", richness= "high"},
["crude-oil"]={frequency= "low", size= "low", richness= "high"},
["enemy-base"]={frequency= "low", size= "normal", richness= "normal"},
["iron-ore"]={frequency= "very-low", size= "low", richness= "high"},
["stone"]={frequency= "very-low", size= "low", richness= "high"},
["uranium-ore"]={frequency= "low", size= "low", richness= "high"},
["desert"]={frequency= "low", size= "low", richness= "low"},
["dirt"]={frequency= "low", size= "low", richness= "low"},
["grass"]={frequency= "normal", size= "normal", richness= "normal"},
["sand"]={frequency= "low", size= "low", richness= "low"},
["trees"]={frequency= "normal", size= "normal", richness= "normal"}
}
-- Cliff defaults are 10 and 10, set both to 0 to turn cliffs off I think?
global.clMapGen.cliff_settings={cliff_elevation_0=10, cliff_elevation_interval=10, name="cliff"}
--------------------------------------------------------------------------------
-- ANTI-Griefing stuff ( I don't personally maintain this as I don't care for it.)
-- These things were added from other people's requests/changes and are disabled by default.
--------------------------------------------------------------------------------
-- Enable this to disable some basic things like friendly fire, deconstructing from map view, etc.
ENABLE_ANTI_GRIEFING = false
-- Makes blueprint ghosts dissapear if they have been placed longer than this
GHOST_TIME_TO_LIVE = 0 * TICKS_PER_MINUTE -- set to 0 for infinite ghost life
-------------------------------------------------------------------------------
-- DEBUG / Custom stuff
--------------------------------------------------------------------------------
OARC_DIFFICULTY_CUSTOM = false
-- DEBUG prints for me
global.oarcDebugEnabled = false
-- These are my specific welcome messages that get used only if I am the user
-- that creates the game.
WELCOME_MSG_OARC = "Welcome to Oarc's official server! Join the discord here: discord.gg/TPYxRrS"
WELCOME_MSG_TITLE_OARC = "Welcome to Oarc's Server!"

View File

@ -1,14 +1,13 @@
-- control.lua
-- Apr 2017
-- Mar 2019
-- Oarc's Separated Spawn Scenario
--
--
-- I wanted to create a scenario that allows you to spawn in separate locations
-- From there, I ended up adding a bunch of other minor/major features
--
--
-- Credit:
-- RSO mod to RSO author - Orzelek - I contacted him via the forum
-- Tags - Taken from WOGs scenario
-- Tags - Taken from WOGs scenario
-- Rocket Silo - Taken from Frontier as an idea
--
-- Feel free to re-use anything you want. It would be nice to give me credit
@ -16,124 +15,99 @@
-- To keep the scenario more manageable I have done the following:
-- To keep the scenario more manageable (for myself) I have done the following:
-- 1. Keep all event calls in control.lua (here)
-- 2. Put all config options in config.lua
-- 3. Put mods into their own files where possible (RSO has multiple)
-- 2. Put all config options in config.lua and provided an example-config.lua file too.
-- 3. Put other stuff into their own files where possible.
-- 4. Put all other files into lib folder
-- 5. Provided an examples folder for example/recommended map gen settings
-- Generic Utility Includes
require("locale/oarc_utils")
require("locale/rso/rso_control")
require("locale/frontier_silo")
require("locale/tag")
require("locale/game_opts")
require("lib/oarc_utils")
-- Other soft-mod type features.
require("lib/frontier_silo")
require("lib/tag")
require("lib/game_opts")
require("lib/player_list")
require("lib/rocket_launch")
require("lib/admin_commands")
require("lib/regrowth_map")
-- For Philip. I currently do not use this and need to add proper support for
-- commands like this in the future.
require("locale/temp/rgcommand")
require("locale/temp/helper_commands")
-- require("lib/rgcommand")
-- require("lib/helper_commands")
-- Main Configuration File
require("config")
-- Save all config settings to global table.
require("lib/oarc_global_cfg.lua")
-- Scenario Specific Includes
require("separate_spawns")
require("separate_spawns_guis")
require("regrowth_map")
require("lib/separate_spawns")
require("lib/separate_spawns_guis")
--------------------------------------------------------------------------------
-- Rocket Launch Event Code
-- Controls the "win condition"
--------------------------------------------------------------------------------
function RocketLaunchEvent(event)
local force = event.rocket.force
if event.rocket.get_item_count("satellite") == 0 then
for index, player in pairs(force.players) do
player.print("You launched the rocket, but you didn't put a satellite inside.")
end
return
end
require("lib/oarc_gui_tabs")
if not global.satellite_sent then
global.satellite_sent = {}
end
-- Create a new surface so we can modify map settings at the start.
GAME_SURFACE_NAME="oarc"
if global.satellite_sent[force.name] then
global.satellite_sent[force.name] = global.satellite_sent[force.name] + 1
else
game.set_game_state{game_finished=true, player_won=true, can_continue=true}
global.satellite_sent[force.name] = 1
end
for index, player in pairs(force.players) do
if player.gui.left.rocket_score then
player.gui.left.rocket_score.rocket_count.caption = tostring(global.satellite_sent[force.name])
else
local frame = player.gui.left.add{name = "rocket_score", type = "frame", direction = "horizontal", caption="Score"}
frame.add{name="rocket_count_label", type = "label", caption={"", "Satellites launched", ":"}}
frame.add{name="rocket_count", type = "label", caption=tostring(global.satellite_sent[force.name])}
end
end
end
-- I'm reverting my decision to turn the regrowth thing into a mod.
remote.add_interface("oarc_regrowth",
{area_offlimits_chunkpos = MarkAreaSafeGivenChunkPos,
area_offlimits_tilepos = MarkAreaSafeGivenTilePos,
area_removal_tilepos = MarkAreaForRemoval,
trigger_immediate_cleanup = TriggerCleanup,
add_surface = RegrowthAddSurface})
commands.add_command("trigger-map-cleanup",
"Force immediate removal of all expired chunks (unused chunk removal mod)",
ForceRemoveChunksCmd)
--------------------------------------------------------------------------------
-- ALL EVENT HANLDERS ARE HERE IN ONE PLACE!
--------------------------------------------------------------------------------
----------------------------------------
-- On Init - only runs once the first
-- On Init - only runs once the first
-- time the game starts
----------------------------------------
script.on_init(function(event)
-- CreateLobbySurface() -- Currently unused, but have plans for future.
-- Configures the map settings for enemies
-- This controls evolution growth factors and enemy expansion settings.
ConfigureAlienStartingParams()
-- FIRST
InitOarcConfig()
-- Here I create the game surface. I do this so that I don't have to worry
-- about the game menu settings and I can now generate a map from the command
-- line more easily!
if ENABLE_RSO then
CreateGameSurface(RSO_MODE)
else
CreateGameSurface(VANILLA_MODE)
end
if ENABLE_SEPARATE_SPAWNS then
InitSpawnGlobalsAndForces()
end
if SILO_FIXED_POSITION then
SetFixedSiloPosition(SILO_POSITION)
else
SetRandomSiloPosition(SILO_NUM_SPAWNS)
end
if FRONTIER_ROCKET_SILO_MODE then
GenerateRocketSiloAreas(game.surfaces[GAME_SURFACE_NAME])
end
SetServerWelcomeMessages()
if ENABLE_REGROWTH or ENABLE_ABANDONED_BASE_REMOVAL then
OarcRegrowthInit()
-- Regrowth (always init so we can enable during play.)
RegrowthInit()
-- Create new game surface
CreateGameSurface()
-- MUST be before other stuff, but after surface creation.
InitSpawnGlobalsAndForces()
-- Frontier Silo Area Generation
if (global.ocfg.frontier_rocket_silo) then
SpawnSilosAndGenerateSiloAreas()
end
-- Everyone do the shuffle. Helps avoid always starting at the same location.
global.vanillaSpawns = FYShuffle(global.vanillaSpawns)
log("Vanilla spawns:")
log(serpent.block(global.vanillaSpawns))
end)
----------------------------------------
-- Freeplay rocket launch info
-- Slightly modified for my purposes
-- Rocket launch event
-- Used for end game win conditions / unlocking late game stuff
----------------------------------------
script.on_event(defines.events.on_rocket_launched, function(event)
if FRONTIER_ROCKET_SILO_MODE then
if global.ocfg.frontier_rocket_silo then
RocketLaunchEvent(event)
end
end)
@ -143,29 +117,21 @@ end)
-- Chunk Generation
----------------------------------------
script.on_event(defines.events.on_chunk_generated, function(event)
if ENABLE_REGROWTH then
OarcRegrowthChunkGenerate(event.area.left_top)
end
if ENABLE_UNDECORATOR then
if global.ocfg.enable_regrowth then
RegrowthChunkGenerate(event)
end
if global.ocfg.enable_undecorator then
UndecorateOnChunkGenerate(event)
end
if ENABLE_RSO then
RSO_ChunkGenerated(event)
end
if FRONTIER_ROCKET_SILO_MODE then
if global.ocfg.frontier_rocket_silo then
GenerateRocketSiloChunk(event)
end
if ENABLE_SEPARATE_SPAWNS and not USE_VANILLA_STARTING_SPAWN then
SeparateSpawnsGenerateChunk(event)
end
SeparateSpawnsGenerateChunk(event)
if not ENABLE_DEFAULT_SPAWN then
CreateHoldingPen(event.surface, event.area, 16, false)
end
CreateHoldingPen(event.surface, event.area, 16, 32)
end)
@ -173,176 +139,176 @@ end)
-- Gui Click
----------------------------------------
script.on_event(defines.events.on_gui_click, function(event)
if ENABLE_TAGS then
-- Don't interfere with other mod related stuff.
if (event.element.get_mod() ~= nil) then return end
if global.ocfg.enable_tags then
TagGuiClick(event)
end
if ENABLE_PLAYER_LIST then
if global.ocfg.enable_player_list then
PlayerListGuiClick(event)
end
if ENABLE_SEPARATE_SPAWNS then
WelcomeTextGuiClick(event)
SpawnOptsGuiClick(event)
SpawnCtrlGuiClick(event)
SharedSpwnOptsGuiClick(event)
BuddySpawnOptsGuiClick(event)
BuddySpawnWaitMenuClick(event)
BuddySpawnRequestMenuClick(event)
SharedSpawnJoinWaitMenuClick(event)
end
WelcomeTextGuiClick(event)
SpawnOptsGuiClick(event)
SpawnCtrlGuiClick(event)
SharedSpwnOptsGuiClick(event)
BuddySpawnOptsGuiClick(event)
BuddySpawnWaitMenuClick(event)
BuddySpawnRequestMenuClick(event)
SharedSpawnJoinWaitMenuClick(event)
ClickOarcGuiButton(event)
GameOptionsGuiClick(event)
end)
script.on_event(defines.events.on_gui_checked_state_changed, function (event)
if ENABLE_SEPARATE_SPAWNS then
SpawnOptsRadioSelect(event)
SpawnCtrlGuiOptionsSelect(event)
end
SpawnOptsRadioSelect(event)
SpawnCtrlGuiOptionsSelect(event)
end)
script.on_event(defines.events.on_gui_selected_tab_changed, function (event)
TabChangeOarcGui(event)
end)
----------------------------------------
-- Player Events
----------------------------------------
script.on_event(defines.events.on_player_joined_game, function(event)
CreateGameOptionsGui(event)
PlayerJoinedMessages(event)
if ENABLE_PLAYER_LIST then
CreatePlayerListGui(event)
end
if ENABLE_TAGS then
CreateTagGui(event)
end
ServerWriteFile("player_events", game.players[event.player_index].name .. " joined the game." .. "\n")
end)
script.on_event(defines.events.on_player_created, function(event)
local player = game.players[event.player_index]
-- Move the player to the game surface immediately.
-- May change this to Lobby in the future.
game.players[event.player_index].teleport(game.forces[MAIN_FORCE].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME)
player.teleport({x=0,y=0}, GAME_SURFACE_NAME)
if ENABLE_LONGREACH then
GivePlayerLongReach(game.players[event.player_index])
if global.ocfg.enable_long_reach then
GivePlayerLongReach(player)
end
if not ENABLE_SEPARATE_SPAWNS then
PlayerSpawnItems(event)
else
SeparateSpawnsPlayerCreated(event)
end
SeparateSpawnsPlayerCreated(event.player_index)
InitOarcGuiTabs(player)
end)
script.on_event(defines.events.on_player_respawned, function(event)
if ENABLE_SEPARATE_SPAWNS then
SeparateSpawnsPlayerRespawned(event)
end
SeparateSpawnsPlayerRespawned(event)
PlayerRespawnItems(event)
if ENABLE_LONGREACH then
if global.ocfg.enable_long_reach then
GivePlayerLongReach(game.players[event.player_index])
end
end)
script.on_event(defines.events.on_pre_player_died, function(event)
if ENABLE_GRAVESTONE_ON_DEATH then
DropGravestoneChests(game.players[event.player_index])
end
end)
script.on_event(defines.events.on_player_left_game, function(event)
if ENABLE_GRAVESTONE_ON_LEAVING then
if (game.players[event.player_index].online_time <
ENABLE_GRAVESTONE_ON_LEAVING_TIME_MINS) then
DropGravestoneChests(game.players[event.player_index])
end
end
if ENABLE_SEPARATE_SPAWNS then
FindUnusedSpawns(event)
end
ServerWriteFile("player_events", game.players[event.player_index].name .. " left the game." .. "\n")
FindUnusedSpawns(game.players[event.player_index], true)
end)
----------------------------------------
-- On BUILD entity. Don't forget on_robot_built_entity too!
----------------------------------------
script.on_event(defines.events.on_built_entity, function(event)
if ENABLE_AUTOFILL then
if global.ocfg.enable_autofill then
Autofill(event)
end
if ENABLE_REGROWTH then
OarcRegrowthOffLimitsChunk(event.created_entity.position)
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
GAME_SURFACE_NAME,
event.created_entity.position,
2)
end
if ENABLE_ANTI_GRIEFING then
SetItemBlueprintTimeToLive(event)
end
if global.ocfg.frontier_rocket_silo then
BuildSiloAttempt(event)
end
end)
----------------------------------------
-- Shared vision, charts a small area around other players
-- On script_raised_built. This should help catch mods that
-- place items that don't count as player_built and robot_built.
-- Specifically FARL.
----------------------------------------
script.on_event(defines.events.script_raised_built, function(event)
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
GAME_SURFACE_NAME,
event.entity.position,
2)
end
end)
----------------------------------------
-- On tick events. Stuff that needs to happen at regular intervals.
-- Delayed events, delayed spawns, ...
----------------------------------------
script.on_event(defines.events.on_tick, function(event)
if ENABLE_REGROWTH then
OarcRegrowthOnTick()
if global.ocfg.enable_regrowth then
RegrowthOnTick()
RegrowthForceRemovalOnTick()
end
if ENABLE_ABANDONED_BASE_REMOVAL then
OarcRegrowthForceRemovalOnTick()
end
DelayedSpawnOnTick()
if ENABLE_SEPARATE_SPAWNS then
DelayedSpawnOnTick()
end
if FRONTIER_ROCKET_SILO_MODE then
DelayedSiloCreationOnTick()
if global.ocfg.frontier_rocket_silo then
DelayedSiloCreationOnTick(game.surfaces[GAME_SURFACE_NAME])
end
end)
script.on_event(defines.events.on_sector_scanned, function (event)
if ENABLE_REGROWTH then
OarcRegrowthSectorScan(event)
if global.ocfg.enable_regrowth then
RegrowthSectorScan(event)
end
end)
-- script.on_event(defines.events.on_sector_scanned, function (event)
-- end)
----------------------------------------
-- Refreshes regrowth timers around an active timer
-- Refresh areas where stuff is built, and mark any chunks with player
-- built stuff as permanent.
--
----------------------------------------
if ENABLE_REGROWTH then
script.on_event(defines.events.on_robot_built_entity, function (event)
OarcRegrowthOffLimitsChunk(event.created_entity.position)
end)
script.on_event(defines.events.on_player_mined_entity, function(event)
OarcRegrowthCheckChunkEmpty(event)
end)
script.on_event(defines.events.on_robot_mined_entity, function(event)
OarcRegrowthCheckChunkEmpty(event)
end)
end
script.on_event(defines.events.on_robot_built_entity, function (event)
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
GAME_SURFACE_NAME,
event.created_entity.position,
2)
end
if global.ocfg.frontier_rocket_silo then
BuildSiloAttempt(event)
end
end)
----------------------------------------
-- Shared chat, so you don't have to type /s
-- But you do lose your player colors across forces.
----------------------------------------
script.on_event(defines.events.on_console_chat, function(event)
if (ENABLE_SHARED_TEAM_CHAT) then
if (event.player_index) then
ServerWriteFile("server_chat", game.players[event.player_index].name .. ": " .. event.message .. "\n")
end
if (global.ocfg.enable_shared_chat) then
if (event.player_index ~= nil) then
ShareChatBetweenForces(game.players[event.player_index], event.message)
end
@ -354,8 +320,43 @@ end)
-- This is where you can permanently remove researched techs
----------------------------------------
script.on_event(defines.events.on_research_finished, function(event)
if FRONTIER_ROCKET_SILO_MODE then
-- Never allows players to build rocket-silos in "frontier" mode.
if global.ocfg.frontier_rocket_silo and not global.ocfg.frontier_allow_build then
RemoveRecipe(event.research.force, "rocket-silo")
end
if global.ocfg.lock_goodies_rocket_launch and
(not global.satellite_sent or not global.satellite_sent[event.research.force.name]) then
RemoveRecipe(event.research.force, "productivity-module-3")
RemoveRecipe(event.research.force, "speed-module-3")
end
if global.ocfg.enable_loaders then
EnableLoaders(event)
end
end)
----------------------------------------
-- On Entity Spawned and On Biter Base Built
-- This is where I modify biter spawning based on location and other factors.
----------------------------------------
script.on_event(defines.events.on_entity_spawned, function(event)
if (global.ocfg.modified_enemy_spawning) then
ModifyEnemySpawnsNearPlayerStartingAreas(event)
end
end)
script.on_event(defines.events.on_biter_base_built, function(event)
if (global.ocfg.modified_enemy_spawning) then
ModifyEnemySpawnsNearPlayerStartingAreas(event)
end
end)
----------------------------------------
-- On Corpse Timed Out
-- Save player's stuff so they don't lose it if they can't get to the corpse fast enough.
----------------------------------------
script.on_event(defines.events.on_character_corpse_expired, function(event)
DropGravestoneChestFromCorpse(event.corpse)
end)

423
example-config.lua Normal file
View File

@ -0,0 +1,423 @@
-- example-config.lua (Rename this file to config.lua to use it)
-- Sep 24 2019 (updated on)
-- Configuration Options
--
-- You should be able to leave most of the settings here as defaults.
-- The only thing you definitely want to change are the welcome messages.
--------------------------------------------------------------------------------
-- Messages
-- You will want to change some of these to be your own.
--------------------------------------------------------------------------------
-- This stuff is shown in the welcome GUI and Info panel. Make sure it's valid.
WELCOME_MSG_TITLE = "[INSERT SERVER OWNER MSG HERE test title!]"
WELCOME_MSG = "[INSERT SERVER OWNER MSG HERE test msg!]" -- Printed to player on join as well.
SERVER_MSG = "Rules: Be polite. Ask before changing other players's stuff. Have fun!\n"..
"This server is running a custom scenario that allows individual starting areas on the map."
SCENARIO_INFO_MSG = "Latest updates in this scenario version:\n"..
"0.17 stable release. Regrowth back to softmod!\n"..
"This scenario gives you and/or your friends your own starting area.\n"..
"You can be on the main team or your own. All teams are friendly.\n"..
"If you leave in the first 15 minutes, your base and character will be deleted!"
CONTACT_MSG = "Contact: SteamID:Oarc | oarcinae@gmail.com | discord.gg/trnpcen"
--------------------------------------------------------------------------------
-- Module Enables
--------------------------------------------------------------------------------
-- Enable this to have a vanilla style starting spawn.
-- This changes the experience pretty drastically.
-- If you enable this, you will NOT get the option to spawn using the "pre-fab"
-- fixed layout spawns. This is because the spawn types just don't balance well with
-- each other.
ENABLE_VANILLA_SPAWNS = false
-- 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.
ENABLE_BUDDY_SPAWN = true
-- Frontier style rocket silo mode
-- This means you can't build silos, but some spawn out in the wild for you to use.
FRONTIER_ROCKET_SILO_MODE = true
-- Silo Islands
-- This options is only valid when used with ENABLE_VANILLA_SPAWNS and FRONTIER_ROCKET_SILO_MODE!
-- This spreads out rocket silos on every OTHER island/vanilla spawn
SILO_ISLANDS_MODE = false
-- Enable Undecorator
-- Removes decorative items to reduce save file size.
ENABLE_UNDECORATOR = true
-- Enable Tags
ENABLE_TAGS = true
-- Enable Long Reach
ENABLE_LONGREACH = true
-- Enable Autofill
ENABLE_AUTOFILL = true
-- Enable vanilla loaders
ENABLE_LOADERS = true
-- Enable Playerlist
ENABLE_PLAYER_LIST = true
PLAYER_LIST_OFFLINE_PLAYERS = true -- List offline players as well.
-- Enable shared vision between teams (all teams are COOP regardless)
ENABLE_SHARED_TEAM_VISION = true
-- Cleans up unused chunks periodically. Helps keep map size down.
ENABLE_REGROWTH = true
-- Only works if you have the Unused Chunk Removal mod installed.
ENABLE_ABANDONED_BASE_REMOVAL = true
-- Enable the new 0.17 research queue by default for all forces.
ENABLE_RESEARCH_QUEUE = true
-- Lock power armor mk2, atomic bombs and artillery until you launch a rocket.
-- Also lock speed/prod module-3s
LOCK_GOODIES_UNTIL_ROCKET_LAUNCH = false
--------------------------------------------------------------------------------
-- MAP CONFIGURATION OPTIONS
-- In past versions I had a way to config map settings here to be used for cmd
-- line launching, but now you should just be using --map-gen-settings and
-- --map-settings option since it works with --start-server-load-scenario
-- Read the README.md file for instructions.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Alien Options
--------------------------------------------------------------------------------
-- 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.
-- If you're trying out the vanilla spawning, you might want to disable this.
OARC_MODIFIED_ENEMY_SPAWNING = true
---------------------------------------
-- Starting Items
---------------------------------------
-- Items provided to the player the first time they join
PLAYER_SPAWN_START_ITEMS = {
{name="pistol", count=1},
{name="firearm-magazine", count=200},
{name="iron-plate", count=16},
{name="burner-mining-drill", count = 2},
{name="stone-furnace", count = 2},
-- {name="iron-plate", count=20},
-- {name="burner-mining-drill", count = 1},
-- {name="stone-furnace", count = 1},
-- {name="power-armor", count=1},
-- {name="fusion-reactor-equipment", count=1},
-- {name="battery-mk2-equipment", count=3},
-- {name="exoskeleton-equipment", count=1},
-- {name="personal-roboport-mk2-equipment", count=3},
-- {name="solar-panel-equipment", count=7},
-- {name="construction-robot", count=100},
-- {name="repair-pack", count=100},
-- {name="steel-axe", count=3},
}
-- Items provided after EVERY respawn (disabled by default)
PLAYER_RESPAWN_START_ITEMS = {
-- {name="pistol", count=1},
-- {name="firearm-magazine", count=100}
}
---------------------------------------
-- Distance Options
---------------------------------------
-- This is the radius, in chunks, that a spawn area is from any other generated
-- chunks. It ensures the spawn area isn't too near generated/explored/existing
-- area. The larger you make this, the further away players will spawn from
-- generated map area (even if it is not visible on the map!).
CHECK_SPAWN_UNGENERATED_CHUNKS_RADIUS = 10
-- Near Distance in chunks
-- When a player selects "near" spawn, they will be in or as close to this range as possible.
NEAR_MIN_DIST = 0
NEAR_MAX_DIST = 50
-- Far Distance in chunks
-- When a player selects "far" spawn, they will be at least this distance away.
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)
-- There is currently a bug in factorio that can cause desyncs if this number is much higher.
-- https://forums.factorio.com/viewtopic.php?f=7&t=68657
-- Not sure you need that much anyways....
-- Points are in an even grid layout.
VANILLA_SPAWN_COUNT = 60
-- Num tiles between each spawn. (I recommend at least 1000)
VANILLA_SPAWN_SPACING = 2000
---------------------------------------
-- Resource & Spawn Circle Options
---------------------------------------
-- This is where you can modify what resources spawn, how much, where, etc.
-- Once you have a config you like, it's a good idea to save it for later use
-- so you don't lost it if you update the scenario.
OARC_CFG = {
-- Misc spawn related config.
gen_settings = {
-- THIS IS WHAT SETS THE SPAWN CIRCLE SIZE!
-- Create a circle of land area for the spawn
-- If you make this much bigger than a few chunks, good luck.
land_area_tiles = CHUNK_SIZE*1.8,
-- Allow players to choose to spawn with a moat
moat_choice_enabled = true,
-- If you change the spawn area size, you might have to adjust this as well
moat_size_modifier = 1,
-- Start resource shape. true = circle, false = square.
resources_circle_shape = true,
-- Force the land area circle at the spawn to be fully grass
force_grass = true,
-- Spawn a circle/octagon of trees around the base outline.
tree_circle = true,
tree_octagon = false,
},
-- Safe Spawn Area Options
-- The default settings here are balanced for my recommended map gen settings (close to train world).
safe_area =
{
-- Safe area has no aliens
-- This is the radius in tiles of safe area.
safe_radius = CHUNK_SIZE*8,
-- Warning area has significantly reduced aliens
-- This is the radius in tiles of warning area.
warn_radius = CHUNK_SIZE*16,
-- 1 : X (spawners alive : spawners destroyed) in this area
warn_reduction = 20,
-- Danger area has slightly reduce aliens
-- This is the radius in tiles of danger area.
danger_radius = CHUNK_SIZE*32,
-- 1 : X (spawners alive : spawners destroyed) in this area
danger_reduction = 5,
},
-- Location of water strip (horizontal)
water = {
x_offset = -4,
y_offset = -48,
length = 8
},
-- Handle placement of starting resources
resource_rand_pos_settings =
{
-- Autoplace resources (randomly in circle)
-- This will ignore the fixed x_offset/y_offset values in resource_tiles.
-- Only works for resource_tiles at the moment, not oil patches/water.
enabled = true,
-- Distance from center of spawn that resources are placed.
radius = 44,
-- At what angle (in radians) do resources start.
-- 0 means starts directly east.
-- Resources are placed clockwise from there.
angle_offset = 2.32, -- 2.32 is approx SSW.
-- At what andle do we place the last resource.
-- angle_offset and angle_final determine spacing and placement.
angle_final = 4.46 -- 4.46 is approx NNW.
},
-- Resource tiles
-- If you are running with mods like bobs/angels, you'll want to customize this.
resource_tiles =
{
["iron-ore"] =
{
amount = 1800,
size = 16,
x_offset = -29,
y_offset = 16
},
["copper-ore"] =
{
amount = 1500,
size = 14,
x_offset = -28,
y_offset = -3
},
["stone"] =
{
amount = 1000,
size = 12,
x_offset = -27,
y_offset = -34
},
["coal"] =
{
amount = 1500,
size = 12,
x_offset = -27,
y_offset = -20
}--,
-- ["uranium-ore"] =
-- {
-- amount = 0,
-- size = 0,
-- x_offset = 17,
-- y_offset = -34
-- }
-- ####### Bobs + Angels #######
-- DISABLE STARTING OIL PATCHES!
-- Coal = coal
-- Saphirite = angels-ore1
-- Stiratite = angels-ore3
-- Rubyte = angels-ore5
-- Bobmonium = angels-ore6
-- ########## Bobs Ore ##########
-- Iron = iron-ore
-- Copper = copper-ore
-- Coal = coal
-- Stone = stone
-- Tin = tin-ore
-- Lead (Galena) = lead-ore
-- See https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn/issues/11#issuecomment-479724909
-- for full examples.
},
-- Special resource patches like oil
resource_patches =
{
["crude-oil"] =
{
num_patches = 2,
amount = 900000,
x_offset_start = -3,
y_offset_start = 48,
x_offset_next = 6,
y_offset_next = 0
}
},
}
---------------------------------------
-- Other Forces/Teams Options
---------------------------------------
-- Separate teams
-- This allows you to join your own force/team. Everyone is still COOP/PvE, all
-- teams are friendly and cease-fire.
ENABLE_SEPARATE_TEAMS = true
-- Main force is what default players join
MAIN_FORCE = "Main Force"
-- Enable if players can allow others to join their base.
-- And specify how many including the host are allowed.
ENABLE_SHARED_SPAWNS = true
MAX_PLAYERS_AT_SHARED_SPAWN = 3
-- Share local team chat with all teams
-- This makes it so you don't have to use /s
-- But it also means you can't talk privately with your own team.
ENABLE_SHARED_TEAM_CHAT = true
---------------------------------------
-- Special Action Cooldowns
---------------------------------------
RESPAWN_COOLDOWN_IN_MINUTES = 15
-- Require playes to be online for at least X minutes
-- Else their character is removed and their spawn point is freed up for use
MIN_ONLINE_TIME_IN_MINUTES = 15
--------------------------------------------------------------------------------
-- Frontier Rocket Silo Options
--------------------------------------------------------------------------------
-- Number of silos found in the wild.
-- These will spawn in a circle at given distance from the center of the map
-- If you set this number too high, you'll have a lot of delay at the start of the game.
SILO_NUM_SPAWNS = 5
-- How many chunks away from the center of the map should the silo be spawned
SILO_CHUNK_DISTANCE = 200
-- If this is enabled, you get silos at the positions specified below.
-- (The other settings above are ignored in this case.)
SILO_FIXED_POSITION = false
-- If you want to set fixed spawn locations for some silos.
SILO_POSITIONS = {{x = -1000, y = -1000},
{x = -1000, y = 1000},
{x = 1000, y = -1000},
{x = 1000, y = 1000}}
-- 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 mod)
ENABLE_SILO_BEACONS = false
ENABLE_SILO_RADAR = false
-- Allow silos to be built by the player, but forces them to build in
-- the fixed locations. If this is false, silos are built and assigned
-- only to the main force. This can cause a problem for non main forces
-- when playing with LOCK_GOODIES_UNTIL_ROCKET_LAUNCH enabled.
ENABLE_SILO_PLAYER_BUILD = true
--------------------------------------------------------------------------------
-- Long Reach Options
--------------------------------------------------------------------------------
BUILD_DIST_BONUS = 64
REACH_DIST_BONUS = BUILD_DIST_BONUS
RESOURCE_DIST_BONUS = 2
--------------------------------------------------------------------------------
-- Autofill Options
--------------------------------------------------------------------------------
AUTOFILL_TURRET_AMMO_QUANTITY = 10
--------------------------------------------------------------------------------
-- ANTI-Griefing stuff ( I don't personally maintain this as I don't care for it.)
-- These things were added from other people's requests/changes and are disabled by default.
--------------------------------------------------------------------------------
-- Enable this to disable deconstructing from map view, and setting a time limit
-- on ghost placements.
ENABLE_ANTI_GRIEFING = false
-- Makes blueprint ghosts dissapear if they have been placed longer than this
-- ONLY has an effect if ENABLE_ANTI_GRIEFING is true!
GHOST_TIME_TO_LIVE = 10 * TICKS_PER_MINUTE
--------------------------------------------------------------------------------
-- This turns on writing chat and certain events to specific files so that I can
-- use that for discord integration. I suggest you leave this off unless you
-- know what you are doing.
--------------------------------------------------------------------------------
ENABLE_SERVER_WRITE_FILES = false

View File

@ -0,0 +1,72 @@
{
"_terrain_segmentation_comment": "Inverse of map scale",
"terrain_segmentation": 1,
"_water_comment":
[
"Multiplier for water 'coverage' - higher increases the water level.",
"Water level = 10 * log2(this value)"
],
"water": 1,
"_comment_width+height": "Width and height of map, in tiles; 0 means infinite",
"width": 0,
"height": 0,
"_starting_area_comment": "Multiplier for 'biter free zone radius'",
"starting_area": 1,
"peaceful_mode": false,
"autoplace_controls":
{
"coal" : {"frequency" : 0.20, "richness" : 0.50, "size" : 1.50},
"copper-ore" : {"frequency" : 0.20, "richness" : 0.50, "size" : 1.50},
"crude-oil" : {"frequency" : 0.20, "richness" : 0.50, "size" : 1.50},
"enemy-base" : {"frequency" : 0.20, "richness" : 0.50, "size" : 0.50},
"iron-ore" : {"frequency" : 0.20, "richness" : 0.50, "size" : 1.50},
"stone" : {"frequency" : 0.20, "richness" : 0.50, "size" : 1.50},
"trees" : {"frequency" : 0.50, "richness" : 1.00, "size" : 1.50},
"uranium-ore" : {"frequency" : 0.20, "richness" : 0.50, "size" : 1.50}
},
"cliff_settings":
{
"_name_comment": "Name of the cliff prototype",
"name": "cliff",
"_cliff_elevation_0_comment": "Elevation of first row of cliffs",
"cliff_elevation_0": 10,
"_cliff_elevation_interval_comment": "Elevation difference between successive rows of cliffs",
"cliff_elevation_interval": 10,
"_richness_comment": "Multiplier for cliff continuity; 0 will result in no cliffs, 10 will make all cliff rows completely solid",
"richness": 1
},
"_property_expression_names_comment":
[
"Overrides for property value generators",
"Elevation influences water and cliff placement.",
"Leave it blank to get 'normal' terrain.",
"Use '0_16-elevation' to reproduce terrain from 0.16.",
"Use '0_17-island' to get an island.",
"elevation'': ''0_17-island"
],
"property_expression_names":
{
"control-setting:aux:bias": "0.00",
"control-setting:aux:frequency:multiplier": "1.00",
"control-setting:moisture:bias": "0.00",
"control-setting:moisture:frequency:multiplier": "1.00"
},
"starting_points":
[
{"x": 0, "y": 0}
],
"_seed_comment": "Use null for a random seed, number for a specific seed.",
"seed": null
}

View File

@ -0,0 +1,113 @@
{
"difficulty_settings":
{
"recipe_difficulty": 0,
"technology_difficulty": 0,
"technology_price_multiplier": 1
},
"pollution":
{
"enabled": true,
"_comment_min_to_diffuse_1": "these are values for 60 ticks (1 simulated second)",
"_comment_min_to_diffuse_2": "amount that is diffused to neighboring chunk",
"diffusion_ratio":0.02,
"min_to_diffuse":15,
"ageing":1,
"expected_max_per_chunk":7000,
"min_to_show_per_chunk":700,
"min_pollution_to_damage_trees": 3500,
"pollution_with_max_forest_damage": 10000,
"pollution_per_tree_damage": 2000,
"pollution_restored_per_tree_damage": 500,
"max_pollution_to_restore_trees": 1000
},
"enemy_evolution":
{
"enabled": true,
"time_factor": 0,
"destroy_factor": 0.001,
"pollution_factor": 0.000010
},
"enemy_expansion":
{
"enabled": true,
"min_base_spacing": 5,
"max_expansion_distance": 20,
"friendly_base_influence_radius": 2,
"enemy_building_influence_radius": 2,
"building_coefficient": 0.1,
"other_base_coefficient": 2.0,
"neighbouring_chunk_coefficient": 0.5,
"neighbouring_base_chunk_coefficient": 0.4,
"max_colliding_tiles_coefficient": 0.9,
"settler_group_min_size": 2,
"settler_group_max_size": 10,
"min_expansion_cooldown": 54000,
"max_expansion_cooldown": 216000
},
"unit_group":
{
"min_group_gathering_time": 3600,
"max_group_gathering_time": 14400,
"max_wait_time_for_late_members": 3600,
"max_group_radius": 30.0,
"min_group_radius": 5.0,
"max_member_speedup_when_behind": 1.4,
"max_member_slowdown_when_ahead": 0.6,
"max_group_slowdown_factor": 0.3,
"max_group_member_fallback_factor": 3,
"member_disown_distance": 10,
"tick_tolerance_when_member_arrives": 60,
"max_gathering_unit_groups": 30,
"max_unit_group_size": 20
},
"steering":
{
"default":
{
"radius": 1.2,
"separation_force": 0.005,
"separation_factor": 1.2,
"force_unit_fuzzy_goto_behavior": false
},
"moving":
{
"radius": 3,
"separation_force": 0.01,
"separation_factor": 3,
"force_unit_fuzzy_goto_behavior": false
}
},
"path_finder":
{
"fwd2bwd_ratio": 5,
"goal_pressure_ratio": 2,
"max_steps_worked_per_tick": 100,
"use_path_cache": true,
"short_cache_size": 5,
"long_cache_size": 25,
"short_cache_min_cacheable_distance": 10,
"short_cache_min_algo_steps_to_cache": 50,
"long_cache_min_cacheable_distance": 30,
"cache_max_connect_to_cache_steps_multiplier": 100,
"cache_accept_path_start_distance_ratio": 0.2,
"cache_accept_path_end_distance_ratio": 0.15,
"negative_cache_accept_path_start_distance_ratio": 0.3,
"negative_cache_accept_path_end_distance_ratio": 0.3,
"cache_path_start_distance_rating_multiplier": 10,
"cache_path_end_distance_rating_multiplier": 20,
"stale_enemy_with_same_destination_collision_penalty": 30,
"ignore_moving_enemy_collision_distance": 5,
"enemy_with_different_destination_collision_penalty": 30,
"general_entity_collision_penalty": 10,
"general_entity_subsequent_collision_penalty": 3,
"max_clients_to_accept_any_new_request": 10,
"max_clients_to_accept_short_new_request": 100,
"direct_distance_to_consider_short_request": 100,
"short_request_max_steps": 1000,
"short_request_ratio": 0.5,
"min_steps_to_check_path_find_termination": 2000,
"start_to_goal_cost_multiplier_to_terminate_path_find": 500.0
},
"max_failed_behavior_count": 3
}

28
lib/admin_commands.lua Normal file
View File

@ -0,0 +1,28 @@
-- admin_commands.lua
-- May 2019
--
-- Yay, admin commands!
require("lib/oarc_utils")
-- Give yourself or another player, power armor
commands.add_command("powerstart", "give a start kit", function(command)
local player = game.players[command.player_index]
local target = player
if player ~= nil and player.admin then
if (command.parameter ~= nil) then
if game.players[command.parameter] ~= nil then
target = game.players[command.parameter]
else
target.print("Invalid player target. Double check the player name?")
return
end
end
GiveQuickStartPowerArmor(target)
player.print("Gave a powerstart kit to " .. target.name)
target.print("You have been given a power armor starting kit!")
end
end)

View File

@ -1,318 +1,408 @@
-- frontier_silo.lua
-- Jan 2018
-- My take on frontier silos for my Oarc scenario
require("config")
require("locale/oarc_utils")
--------------------------------------------------------------------------------
-- Frontier style rocket silo stuff
--------------------------------------------------------------------------------
-- This creates a random silo position, stored to global.siloPosition
-- It uses the config setting SILO_CHUNK_DISTANCE and spawns the silo somewhere
-- on a circle edge with radius using that distance.
function SetRandomSiloPosition(num_silos)
if (global.siloPosition == nil) then
global.siloPosition = {}
random_angle_offset = math.random(0, math.pi * 2)
for i=1,num_silos do
theta = ((math.pi * 2) / num_silos);
angle = (theta * i) + random_angle_offset;
tx = (SILO_CHUNK_DISTANCE*CHUNK_SIZE * math.cos(angle))
ty = (SILO_CHUNK_DISTANCE*CHUNK_SIZE * math.sin(angle))
table.insert(global.siloPosition, {x=math.floor(tx), y=math.floor(ty)})
log("Silo position: " .. tx .. ", " .. ty .. ", " .. angle)
end
end
end
-- Sets the global.siloPosition var to the set in the config file
function SetFixedSiloPosition(pos)
if (global.siloPosition == nil) then
global.siloPosition = {}
table.insert(global.siloPosition, SILO_POSITION)
end
end
-- Create a rocket silo at the specified positionmmmm
-- Also makes sure tiles and entities are cleared if required.
local function CreateRocketSilo(surface, siloPosition, force)
-- Delete any entities beneath the silo?
for _, entity in pairs(surface.find_entities_filtered{area = {{siloPosition.x-5,
siloPosition.y-6},
{siloPosition.x+6,
siloPosition.y+6}}}) do
entity.destroy()
end
-- Remove nearby enemies again
for _, entity in pairs(surface.find_entities_filtered{area = {{siloPosition.x-(CHUNK_SIZE*4),
siloPosition.y-(CHUNK_SIZE*4)},
{siloPosition.x+(CHUNK_SIZE*4),
siloPosition.y+(CHUNK_SIZE*4)}}, force = "enemy"}) do
entity.destroy()
end
-- Set tiles below the silo
tiles = {}
i = 1
for dx = -5,5 do
for dy = -6,5 do
tiles[i] = {name = "concrete", position = {siloPosition.x+dx, siloPosition.y+dy}}
i=i+1
end
end
surface.set_tiles(tiles, true)
-- Create indestructible silo and assign to a force
local silo = surface.create_entity{name = "rocket-silo", position = {siloPosition.x+0.5, siloPosition.y}, force = force}
silo.destructible = false
silo.minable = false
-- Make silo safe from being removed by regrowth
if ENABLE_REGROWTH then
OarcRegrowthOffLimits(siloPosition, 5)
end
if ENABLE_SILO_BEACONS then
PhilipsBeaconsAndShit(surface, siloPosition, game.forces[MAIN_FORCE])
end
if ENABLE_SILO_RADAR then
PhilipsRadarAndShit(surface, siloPosition, game.forces[MAIN_FORCE])
end
end
-- Generates all rocket silos, should be called after the areas are generated
-- Includes a crop circle
function GenerateAllSilos(surface)
-- Create each silo in the list
for idx,siloPos in pairs(global.siloPosition) do
CreateRocketSilo(surface, siloPos, MAIN_FORCE)
end
end
-- Generate clean land and trees around silo area on chunk generate event
function GenerateRocketSiloChunk(event)
-- Silo generation can take awhile depending on the number of silos.
if (game.tick < SILO_NUM_SPAWNS*10*TICKS_PER_SECOND) then
local surface = event.surface
local chunkArea = event.area
local chunkAreaCenter = {x=chunkArea.left_top.x+(CHUNK_SIZE/2),
y=chunkArea.left_top.y+(CHUNK_SIZE/2)}
for idx,siloPos in pairs(global.siloPosition) do
local safeArea = {left_top=
{x=siloPos.x-(CHUNK_SIZE*4),
y=siloPos.y-(CHUNK_SIZE*4)},
right_bottom=
{x=siloPos.x+(CHUNK_SIZE*4),
y=siloPos.y+(CHUNK_SIZE*4)}}
-- Clear enemies directly next to the rocket
if CheckIfInArea(chunkAreaCenter,safeArea) then
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, force = "enemy"}) do
entity.destroy()
end
-- Remove trees/resources inside the spawn area
RemoveInCircle(surface, chunkArea, "tree", siloPos, ENFORCE_LAND_AREA_TILE_DIST+5)
RemoveInCircle(surface, chunkArea, "resource", siloPos, ENFORCE_LAND_AREA_TILE_DIST+5)
RemoveInCircle(surface, chunkArea, "cliff", siloPos, ENFORCE_LAND_AREA_TILE_DIST+5)
RemoveDecorationsArea(surface, chunkArea)
-- Create rocket silo
CreateCropOctagon(surface, siloPos, chunkArea, CHUNK_SIZE*2)
end
end
end
end
-- Generate chunks where we plan to place the rocket silos.
function GenerateRocketSiloAreas(surface)
for idx,siloPos in pairs(global.siloPosition) do
if (ENABLE_SILO_VISION) then
ChartRocketSiloAreas(surface, game.forces[MAIN_FORCE])
end
surface.request_to_generate_chunks({siloPos.x, siloPos.y}, 3)
end
end
-- Chart chunks where we plan to place the rocket silos.
function ChartRocketSiloAreas(surface, force)
for idx,siloPos in pairs(global.siloPosition) do
force.chart(surface, {{siloPos.x-(CHUNK_SIZE*2),
siloPos.y-(CHUNK_SIZE*2)},
{siloPos.x+(CHUNK_SIZE*2),
siloPos.y+(CHUNK_SIZE*2)}})
end
end
global.oarc_silos_generated = false
function DelayedSiloCreationOnTick(event)
-- Delay the creation of the silos so we place them on already generated lands.
if (not global.oarc_silos_generated and (game.tick >= SILO_NUM_SPAWNS*10*TICKS_PER_SECOND)) then
DebugPrint("Frontier silos generated!")
global.oarc_silos_generated = true
GenerateAllSilos(game.surfaces[GAME_SURFACE_NAME])
end
end
function PhilipsBeaconsAndShit(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}
beacon.destructible = false
beacon.minable = false
-- top 2
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-5, siloPos.y-9}, 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}
beacon.destructible = false
beacon.minable = false
-- top 4
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+2, siloPos.y-9}, 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}
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}
beacon.destructible = false
beacon.minable = false
-- left 2
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-6, siloPos.y-6}, 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}
beacon.destructible = false
beacon.minable = false
-- left 4
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x-6, siloPos.y}, 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}
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}
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}
beacon.destructible = false
beacon.minable = false
-- right 2
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+6, siloPos.y-6}, 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}
beacon.destructible = false
beacon.minable = false
-- right 4
local beacon = surface.create_entity{name = "beacon", position = {siloPos.x+6, siloPos.y}, 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}
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}
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}
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}
substation.destructible = false
substation.minable = false
-- top right
local substation = surface.create_entity{name = "substation", position = {siloPos.x+9, siloPos.y-6}, 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}
substation.destructible = false
substation.minable = false
-- bottom right
local substation = surface.create_entity{name = "substation", position = {siloPos.x+9, siloPos.y+4}, force = force}
substation.destructible = false
substation.minable = false
-- end adding beacons
end
function PhilipsRadarAndShit(surface, siloPos, force)
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-33, 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}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-30, 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}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-24, 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}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-24, siloPos.y}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-24, 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}
radar.destructible = false
local radar = surface.create_entity{name = "solar-panel", position = {siloPos.x-30, 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}
radar.destructible = false
local radar = surface.create_entity{name = "radar", position = {siloPos.x-33, siloPos.y}, force = force}
radar.destructible = false
local substation = surface.create_entity{name = "substation", position = {siloPos.x-28, siloPos.y-1}, force = force}
substation.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-30, siloPos.y-1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-30, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-30, siloPos.y+1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-28, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-28, siloPos.y+1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-26, siloPos.y-1}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-26, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-26, siloPos.y+1}, force = force}
radar.destructible = false
-- frontier_silo.lua
-- Jan 2018
-- My take on frontier silos for my Oarc scenario
require("config")
require("lib/oarc_utils")
--------------------------------------------------------------------------------
-- Frontier style rocket silo stuff
--------------------------------------------------------------------------------
function SpawnSilosAndGenerateSiloAreas()
-- Special silo islands mode "boogaloo"
if (global.ocfg.silo_islands) then
local num_spawns = #global.vanillaSpawns
local new_spawn_list = {}
-- Pick out every OTHER vanilla spawn for the rocket silos.
for k,v in pairs(global.vanillaSpawns) do
if ((k <= num_spawns/2) and (k%2==1)) then
SetFixedSiloPosition({x=v.x,y=v.y})
elseif ((k > num_spawns/2) and (k%2==0)) then
SetFixedSiloPosition({x=v.x,y=v.y})
else
table.insert(new_spawn_list, v)
end
end
global.vanillaSpawns = new_spawn_list
-- A set of fixed silo positions
elseif (global.ocfg.frontier_fixed_pos) then
for k,v in pairs(global.ocfg.frontier_pos_table) do
SetFixedSiloPosition(v)
end
-- Random locations on a circle.
else
SetRandomSiloPosition(global.ocfg.frontier_silo_count)
end
-- Freezes the game at the start to generate all the chunks.
GenerateRocketSiloAreas(game.surfaces[GAME_SURFACE_NAME])
end
-- This creates a random silo position, stored to global.siloPosition
-- It uses the config setting global.ocfg.frontier_silo_distance and spawns the
-- silo somewhere on a circle edge with radius using that distance.
function SetRandomSiloPosition(num_silos)
if (global.siloPosition == nil) then
global.siloPosition = {}
end
random_angle_offset = math.random(0, math.pi * 2)
for i=1,num_silos do
theta = ((math.pi * 2) / num_silos);
angle = (theta * i) + random_angle_offset;
tx = (global.ocfg.frontier_silo_distance*CHUNK_SIZE * math.cos(angle))
ty = (global.ocfg.frontier_silo_distance*CHUNK_SIZE * math.sin(angle))
table.insert(global.siloPosition, {x=math.floor(tx), y=math.floor(ty)})
log("Silo position: " .. tx .. ", " .. ty .. ", " .. angle)
end
end
-- Sets the global.siloPosition var to the set in the config file
function SetFixedSiloPosition(pos)
table.insert(global.siloPosition, pos)
end
-- Create a rocket silo at the specified positionmmmm
-- Also makes sure tiles and entities are cleared if required.
local function CreateRocketSilo(surface, siloPosition, force)
-- Delete any entities beneath the silo?
for _, entity in pairs(surface.find_entities_filtered{area = {{siloPosition.x-5,
siloPosition.y-6},
{siloPosition.x+6,
siloPosition.y+6}}}) do
entity.destroy()
end
-- Remove nearby enemies again
for _, entity in pairs(surface.find_entities_filtered{area = {{siloPosition.x-(CHUNK_SIZE*4),
siloPosition.y-(CHUNK_SIZE*4)},
{siloPosition.x+(CHUNK_SIZE*4),
siloPosition.y+(CHUNK_SIZE*4)}}, force = "enemy"}) do
entity.destroy()
end
-- Set tiles below the silo
tiles = {}
for dx = -10,10 do
for dy = -10,10 do
if (game.active_mods["oarc-restricted-build"]) then
table.insert(tiles, {name = global.ocfg.locked_build_area_tile,
position = {siloPosition.x+dx, siloPosition.y+dy}})
else
if ((dx % 2 == 0) or (dx % 2 == 0)) then
table.insert(tiles, {name = "concrete",
position = {siloPosition.x+dx, siloPosition.y+dy}})
else
table.insert(tiles, {name = "hazard-concrete-left",
position = {siloPosition.x+dx, siloPosition.y+dy}})
end
end
end
end
surface.set_tiles(tiles, true)
-- Create indestructible silo and assign to a force
if not global.ocfg.frontier_allow_build then
local silo = surface.create_entity{name = "rocket-silo", position = {siloPosition.x+0.5, siloPosition.y}, force = force}
silo.destructible = false
silo.minable = false
end
-- TAG it on the main force at least.
game.forces[global.ocfg.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.
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
surface.index,
siloPosition,
5)
end
if ENABLE_SILO_BEACONS then
PhilipsBeacons(surface, siloPosition, game.forces[global.ocfg.main_force])
end
if ENABLE_SILO_RADAR then
PhilipsRadar(surface, siloPosition, game.forces[global.ocfg.main_force])
end
end
-- Generates all rocket silos, should be called after the areas are generated
-- Includes a crop circle
function GenerateAllSilos(surface)
-- Create each silo in the list
for idx,siloPos in pairs(global.siloPosition) do
CreateRocketSilo(surface, siloPos, global.ocfg.main_force)
end
end
-- Validates any attempt to build a silo.
-- Should be call in on_built_entity and on_robot_built_entity
function BuildSiloAttempt(event)
-- Validation
if (event.created_entity == nil) then return end
local e_name = event.created_entity.name
if (event.created_entity.name == "entity-ghost") then
e_name =event.created_entity.ghost_name
end
if (e_name ~= "rocket-silo") then return end
-- Check if it's in the right area.
local epos = event.created_entity.position
for k,v in pairs(global.siloPosition) do
if (getDistance(epos, v) < 5) then
SendBroadcastMsg("Rocket silo has been built!")
return
end
end
-- If we get here, means it wasn't in a valid position. Need to remove it.
if (event.created_entity.last_user ~= nil) then
FlyingText("Can't build silo here! Check the map!", epos, my_color_red, event.created_entity.surface)
if (event.created_entity.name == "entity-ghost") then
event.created_entity.destroy()
else
event.created_entity.last_user.mine_entity(event.created_entity, true)
end
else
log("ERROR! Rocket-silo had no valid last user?!?!")
end
end
-- Generate clean land and trees around silo area on chunk generate event
function GenerateRocketSiloChunk(event)
-- Silo generation can take awhile depending on the number of silos.
if (game.tick < #global.siloPosition*10*TICKS_PER_SECOND) then
local surface = event.surface
local chunkArea = event.area
local chunkAreaCenter = {x=chunkArea.left_top.x+(CHUNK_SIZE/2),
y=chunkArea.left_top.y+(CHUNK_SIZE/2)}
for idx,siloPos in pairs(global.siloPosition) do
local safeArea = {left_top=
{x=siloPos.x-(CHUNK_SIZE*4),
y=siloPos.y-(CHUNK_SIZE*4)},
right_bottom=
{x=siloPos.x+(CHUNK_SIZE*4),
y=siloPos.y+(CHUNK_SIZE*4)}}
-- Clear enemies directly next to the rocket
if CheckIfInArea(chunkAreaCenter,safeArea) then
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, force = "enemy"}) do
entity.destroy()
end
-- Remove trees/resources inside the spawn area
RemoveInCircle(surface, chunkArea, "tree", siloPos, global.ocfg.spawn_config.gen_settings.land_area_tiles+5)
RemoveInCircle(surface, chunkArea, "resource", siloPos, global.ocfg.spawn_config.gen_settings.land_area_tiles+5)
RemoveInCircle(surface, chunkArea, "cliff", siloPos, global.ocfg.spawn_config.gen_settings.land_area_tiles+5)
RemoveDecorationsArea(surface, chunkArea)
-- Create rocket silo
CreateCropOctagon(surface, siloPos, chunkArea, CHUNK_SIZE*2, "grass-1")
end
end
end
end
-- Generate chunks where we plan to place the rocket silos.
function GenerateRocketSiloAreas(surface)
for idx,siloPos in pairs(global.siloPosition) do
surface.request_to_generate_chunks({siloPos.x, siloPos.y}, 3)
end
if (global.ocfg.frontier_silo_vision) then
ChartRocketSiloAreas(surface, game.forces[global.ocfg.main_force])
end
end
-- Chart chunks where we plan to place the rocket silos.
function ChartRocketSiloAreas(surface, force)
for idx,siloPos in pairs(global.siloPosition) do
force.chart(surface, {{siloPos.x-(CHUNK_SIZE*2),
siloPos.y-(CHUNK_SIZE*2)},
{siloPos.x+(CHUNK_SIZE*2),
siloPos.y+(CHUNK_SIZE*2)}})
end
end
global.oarc_silos_generated = false
function DelayedSiloCreationOnTick(surface)
-- Delay the creation of the silos so we place them on already generated lands.
if (not global.oarc_silos_generated and (game.tick >= #global.siloPosition*10*TICKS_PER_SECOND)) then
log("Frontier silos generated!")
SendBroadcastMsg("Rocket silos are now available!")
global.oarc_silos_generated = true
GenerateAllSilos(surface)
end
end
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-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- top 2
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-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- top 4
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-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-8}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 2
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-8, siloPos.y-2}, force = force}
beacon.destructible = false
beacon.minable = false
-- left 4
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-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+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+8}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 2
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+8, siloPos.y-2}, force = force}
beacon.destructible = false
beacon.minable = false
-- right 4
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+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+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+8}, force = force}
beacon.destructible = false
beacon.minable = false
-- substations
-- top left
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+6, siloPos.y-5}, force = force}
substation.destructible = false
substation.minable = false
-- bottom left
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+6, siloPos.y+6}, force = force}
substation.destructible = false
substation.minable = false
-- end adding beacons
end
function PhilipsRadar(surface, siloPos, 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-43, siloPos.y-3}, force = force}
radar.destructible = false
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-37, siloPos.y-6}, force = force}
radar.destructible = false
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-34, siloPos.y-3}, force = force}
radar.destructible = false
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-34, siloPos.y+3}, force = force}
radar.destructible = false
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-40, siloPos.y+3}, force = force}
radar.destructible = false
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-43, siloPos.y}, force = force}
radar.destructible = false
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-40, siloPos.y-1}, force = force}
radar.destructible = false
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-40, siloPos.y+1}, force = force}
radar.destructible = false
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-38, siloPos.y+1}, force = force}
radar.destructible = false
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-36, siloPos.y-3}, force = force}
radar.destructible = false
local radar = surface.create_entity{name = "accumulator", position = {siloPos.x-36, siloPos.y+1}, force = force}
radar.destructible = false
end

144
lib/game_opts.lua Normal file
View File

@ -0,0 +1,144 @@
-- game_opts.lua
-- Jan 2018
-- Display current game options, maybe have some admin controls here
-- Main Configuration File
require("config")
require("lib/oarc_utils")
require("lib/separate_spawns")
function GameOptionsGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local name = event.element.name
if (name == "ban_player") then
local pIndex = event.element.parent.ban_players_dropdown.selected_index
if (pIndex ~= 0) then
local banPlayer = event.element.parent.ban_players_dropdown.get_item(pIndex)
if (game.players[banPlayer]) then
game.ban_player(banPlayer, "Banned from admin panel.")
log("Banning " .. banPlayer)
end
end
end
if (name == "restart_player") then
local pIndex = event.element.parent.ban_players_dropdown.selected_index
if (pIndex ~= 0) then
local resetPlayer = event.element.parent.ban_players_dropdown.get_item(pIndex)
if (game.players[resetPlayer]) then
SeparateSpawnsPlayerCreated(resetPlayer)
log("Resetting " .. resetPlayer)
end
end
end
end
-- Used by AddOarcGuiTab
function CreateGameOptionsTab(tab_container, player)
-- General Server Info:
AddLabel(tab_container, "info_1", global.ocfg.welcome_msg, my_longer_label_style)
AddLabel(tab_container, "info_2", global.ocfg.server_rules, my_longer_label_style)
AddLabel(tab_container, "info_3", global.ocfg.server_contact, my_longer_label_style)
AddSpacerLine(tab_container)
-- Enemy Settings:
local enemy_expansion_txt = "disabled"
if game.map_settings.enemy_expansion.enabled then enemy_expansion_txt = "enabled" end
local enemy_text="Server Run Time: " .. formattime_hours_mins(game.tick) .. "\n" ..
"Current Evolution: " .. string.format("%.4f", game.forces["enemy"].evolution_factor) .. "\n" ..
"Enemy evolution time factor: " .. game.map_settings.enemy_evolution.time_factor .. "\n" ..
"Enemy evolution pollution factor: " .. game.map_settings.enemy_evolution.pollution_factor .. "\n" ..
"Enemy evolution destroy factor: " .. game.map_settings.enemy_evolution.destroy_factor .. "\n" ..
"Enemy expansion is " .. enemy_expansion_txt
AddLabel(tab_container, "enemy_info", enemy_text, my_longer_label_style)
AddSpacerLine(tab_container)
-- Game Mode:
AddLabel(tab_container, "core_mod_en", "Core game mode (separate spawns) is enabled.", my_longer_label_style)
-- Soft Mods:
local soft_mods_string = "Oarc Core"
if (global.ocfg.enable_undecorator) then
soft_mods_string = soft_mods_string .. ", Undecorator"
end
if (global.ocfg.enable_tags) then
soft_mods_string = soft_mods_string .. ", Tags"
end
if (global.ocfg.enable_long_reach) then
soft_mods_string = soft_mods_string .. ", Long Reach"
end
if (global.ocfg.enable_autofill) then
soft_mods_string = soft_mods_string .. ", Auto Fill"
end
if (global.ocfg.enable_player_list) then
soft_mods_string = soft_mods_string .. ", Player List"
end
if (global.ocfg.enable_regrowth) then
soft_mods_string = soft_mods_string .. ", Regrowth"
end
local game_info_str = "Soft Mods Enabled: " .. soft_mods_string
-- Spawn options:
if (global.ocfg.enable_separate_teams) then
game_info_str = game_info_str.."\n".."You are allowed to spawn on your own team (have your own research tree). All teams are friendly!"
end
if (global.ocfg.enable_vanilla_spawns) then
game_info_str = game_info_str.."\n".."You are spawned in a default style starting area."
else
game_info_str = game_info_str.."\n".."You are spawned with a fix set of starting resources."
if (global.ocfg.enable_buddy_spawn) then
game_info_str = game_info_str.."\n".."You can chose to spawn alongside a buddy if you spawn together at the same time."
end
end
if (global.ocfg.enable_shared_spawns) then
game_info_str = game_info_str.."\n".."Spawn hosts may choose to share their spawn and allow other players to join them."
end
if (global.ocfg.enable_separate_teams and global.ocfg.enable_shared_team_vision) then
game_info_str = game_info_str.."\n".."Everyone (all teams) have shared vision."
end
if (global.ocfg.frontier_rocket_silo) then
game_info_str = game_info_str.."\n".."Silos are only placeable in certain areas on the map!"
end
if (global.ocfg.enable_regrowth) then
game_info_str = game_info_str.."\n".."Old parts of the map will slowly be deleted over time (chunks without any player buildings)."
end
if (ENABLE_POWER_ARMOR_QUICK_START) then
game_info_str = game_info_str.."\n".."Power armor quick start enabled."
end
if (global.ocfg.lock_goodies_rocket_launch) then
game_info_str = game_info_str.."\n".."Artillery/Nukes/ArmorMK2 tech and Prod/Speed 3 module recipes are locked until you launch a rocket!"
end
AddLabel(tab_container, "game_info_label", game_info_str, my_longer_label_style)
if (global.ocfg.enable_abandoned_base_removal) then
AddLabel(tab_container, "leave_warning_msg", "If you leave within " .. global.ocfg.minimum_online_time .. " minutes of joining, your base and character will be deleted.", my_longer_label_style)
tab_container.leave_warning_msg.style.font_color=my_color_red
end
-- Ending Spacer
AddSpacerLine(tab_container)
-- ADMIN CONTROLS
if (player.admin) then
player_list = {}
for _,player in pairs(game.connected_players) do
table.insert(player_list, player.name)
end
tab_container.add{name = "ban_players_dropdown",
type = "drop-down",
items = player_list}
tab_container.add{name="ban_player", type="button", caption="Ban Player"}
tab_container.add{name="restart_player", type="button", caption="Restart Player"}
end
end

View File

@ -2,7 +2,7 @@
-- Jan 2018
-- None of this is my code.
require("locale/oarc_utils")
require("lib/oarc_utils")
commands.add_command("run", "change player speed bonus", function(command)
local player = game.players[command.player_index];

211
lib/oarc_global_cfg.lua Normal file
View File

@ -0,0 +1,211 @@
-- oarc_global_cfg.lua
-- April 2019
--
-- Here is where we store/init config values to the global table.
-- Allows runtime modification of game settings if we want it.
-- Also allows supporting both MOD and SCENARIO versions.
-- DON'T JUDGE ME
-- That's a LOT of settings.
function InitOarcConfig()
global.ocfg = {}
if (game.active_mods["clean-tutorial-grid"]) then
global.ocfg.locked_build_area_tile = "clean-tutorial-grid"
else
global.ocfg.locked_build_area_tile = "tutorial-grid"
end
-- SCENARIO VERSION
if (not game.active_mods["oarc-mod"]) then
global.ocfg.welcome_title = WELCOME_MSG_TITLE
global.ocfg.welcome_msg = WELCOME_MSG
global.ocfg.server_rules = SERVER_MSG
global.ocfg.minimum_online_time = MIN_ONLINE_TIME_IN_MINUTES
global.ocfg.server_contact = CONTACT_MSG
global.ocfg.enable_vanilla_spawns = ENABLE_VANILLA_SPAWNS
global.ocfg.enable_buddy_spawn = ENABLE_BUDDY_SPAWN
global.ocfg.frontier_rocket_silo = FRONTIER_ROCKET_SILO_MODE
global.ocfg.silo_islands = SILO_ISLANDS_MODE
global.ocfg.enable_undecorator = ENABLE_UNDECORATOR
global.ocfg.enable_tags = ENABLE_TAGS
global.ocfg.enable_long_reach = ENABLE_LONGREACH
global.ocfg.enable_autofill = ENABLE_AUTOFILL
global.ocfg.enable_loaders = ENABLE_LOADERS
global.ocfg.enable_player_list = ENABLE_PLAYER_LIST
global.ocfg.list_offline_players = PLAYER_LIST_OFFLINE_PLAYERS
global.ocfg.enable_shared_team_vision = ENABLE_SHARED_TEAM_VISION
global.ocfg.enable_regrowth = ENABLE_REGROWTH
global.ocfg.enable_abandoned_base_removal = ENABLE_ABANDONED_BASE_REMOVAL
global.ocfg.enable_research_queue = ENABLE_RESEARCH_QUEUE
global.ocfg.lock_goodies_rocket_launch = LOCK_GOODIES_UNTIL_ROCKET_LAUNCH
global.ocfg.modified_enemy_spawning = OARC_MODIFIED_ENEMY_SPAWNING
global.ocfg.near_dist_start = NEAR_MIN_DIST
global.ocfg.near_dist_end = NEAR_MAX_DIST
global.ocfg.far_dist_start = FAR_MIN_DIST
global.ocfg.far_dist_end = FAR_MAX_DIST
global.ocfg.vanilla_spawn_count = VANILLA_SPAWN_COUNT
global.ocfg.vanilla_spawn_spacing = VANILLA_SPAWN_SPACING
global.ocfg.spawn_config = OARC_CFG
global.ocfg.enable_separate_teams = ENABLE_SEPARATE_TEAMS
global.ocfg.main_force = MAIN_FORCE
global.ocfg.enable_shared_spawns = ENABLE_SHARED_SPAWNS
global.ocfg.max_players_shared_spawn = MAX_PLAYERS_AT_SHARED_SPAWN
global.ocfg.enable_shared_chat = ENABLE_SHARED_TEAM_CHAT
global.ocfg.respawn_cooldown_min = RESPAWN_COOLDOWN_IN_MINUTES
global.ocfg.frontier_silo_count = SILO_NUM_SPAWNS
global.ocfg.frontier_silo_distance = SILO_CHUNK_DISTANCE
global.ocfg.frontier_fixed_pos = SILO_FIXED_POSITION
global.ocfg.frontier_pos_table = SILO_POSITIONS
global.ocfg.frontier_silo_vision = ENABLE_SILO_VISION
global.ocfg.frontier_allow_build = ENABLE_SILO_PLAYER_BUILD
global.ocfg.enable_server_write_files = ENABLE_SERVER_WRITE_FILES
-- MOD VERSION
else
log("Oarc MOD! Version: " .. game.active_mods["oarc-mod"].version)
global.ocfg.welcome_title = settings.global["oarc-welcome-title"].value
global.ocfg.welcome_msg = settings.global["oarc-welcome-msg"].value
global.ocfg.server_rules = settings.global["oarc-server-rules"].value
global.ocfg.minimum_online_time = settings.global["oarc-minimum-online-time"].value
global.ocfg.server_contact = settings.global["oarc-server-contact"].value
global.ocfg.enable_vanilla_spawns = settings.global["oarc-enable-vanilla-spawns"].value
global.ocfg.enable_buddy_spawn = settings.global["oarc-enable-buddy-spawn"].value
global.ocfg.frontier_rocket_silo = settings.global["oarc-frontier-rocket-silo"].value
global.ocfg.enable_undecorator = settings.global["oarc-enable-undecorator"].value
global.ocfg.enable_tags = settings.global["oarc-enable-tags"].value
global.ocfg.enable_long_reach = settings.global["oarc-enable-long-reach"].value
global.ocfg.enable_autofill = settings.global["oarc-enable-autofill"].value
global.ocfg.enable_loaders = false
global.ocfg.enable_player_list = settings.global["oarc-enable-player-list"].value
global.ocfg.list_offline_players = settings.global["oarc-list-offline-players"].value
global.ocfg.enable_shared_team_vision = settings.global["oarc-enable-shared-team-vision"].value
global.ocfg.enable_regrowth = settings.global["oarc-enable-regrowth"].value
global.ocfg.enable_research_queue = settings.global["oarc-enable-research-queue"].value
global.ocfg.lock_goodies_rocket_launch = false
global.ocfg.modified_enemy_spawning = settings.global["oarc-modified-enemy-spawning"].value
global.ocfg.near_dist_start = settings.global["oarc-near-dist-start"].value
global.ocfg.near_dist_end = settings.global["oarc-near-dist-end"].value
global.ocfg.far_dist_start = settings.global["oarc-far-dist-start"].value
global.ocfg.far_dist_end = settings.global["oarc-far-dist-end"].value
global.ocfg.vanilla_spawn_count = settings.global["oarc-vanilla-spawn-count"].value
global.ocfg.vanilla_spawn_spacing = settings.global["oarc-vanilla-spawn-spacing"].value
global.ocfg.spawn_config = {
gen_settings = {
land_area_tiles = settings.global["oarc-enforce-land-area-tile-dist"].value,
moat_choice_enabled = settings.global["oarc-allow-moat-choice"].value,
moat_size_modifier = settings.global["oarc-moat-size-mod"].value,
resources_circle_shape = settings.global["oarc-resource-shape-circle"].value,
force_grass = settings.global["oarc-force-grass"].value,
tree_circle = settings.global["oarc-tree-circle"].value,
tree_octagon = settings.global["oarc-tree-octagon"].value,
},
safe_area =
{
safe_radius = CHUNK_SIZE*10,
warn_radius = CHUNK_SIZE*20,
warn_reduction = 20,
danger_radius = CHUNK_SIZE*50,
danger_reduction = 5,
},
water = {
x_offset = settings.global["oarc-water-x-offset"].value,
y_offset = settings.global["oarc-water-y-offset"].value,
length = settings.global["oarc-water-length"].value,
},
resource_rand_pos_settings =
{
enabled = settings.global["oarc-resource-rand-pos-enabled"].value,
radius = settings.global["oarc-resource-rand-pos-radius"].value,
angle_offset = settings.global["oarc-resource-rand-pos-angle-offset"].value,
angle_final = settings.global["oarc-resource-rand-pos-angle-final"].value,
},
resource_tiles =
{
[settings.global["oarc-resource-1-name"].value] =
{
amount = settings.global["oarc-resource-1-amount"].value,
size = settings.global["oarc-resource-1-size"].value,
x_offset = -29,
y_offset = 16
},
[settings.global["oarc-resource-2-name"].value] =
{
amount = settings.global["oarc-resource-2-amount"].value,
size = settings.global["oarc-resource-2-size"].value,
x_offset = -28,
y_offset = -3
},
[settings.global["oarc-resource-3-name"].value] =
{
amount = settings.global["oarc-resource-3-amount"].value,
size = settings.global["oarc-resource-3-size"].value,
x_offset = -27,
y_offset = -34
},
[settings.global["oarc-resource-4-name"].value] =
{
amount = settings.global["oarc-resource-4-amount"].value,
size = settings.global["oarc-resource-4-size"].value,
x_offset = -27,
y_offset = -20
}
-- [settings.global["oarc-resource-5-name"].value] =
-- {
-- amount = settings.global["oarc-resource-5-amount"].value,
-- size = settings.global["oarc-resource-5-size"].value,
-- x_offset = -27,
-- y_offset = -20
-- }
},
resource_patches =
{
[settings.global["oarc-resource-patch-1-name"].value] =
{
num_patches = settings.global["oarc-resource-patch-1-count"].value,
amount = settings.global["oarc-resource-patch-1-amount"].value,
x_offset_start = 0,
y_offset_start = 48,
x_offset_next = 4,
y_offset_next = 0
}
},
}
global.ocfg.enable_separate_teams = settings.global["oarc-enable-separate-teams"].value
global.ocfg.main_force = settings.global["oarc-main-force"].value
global.ocfg.enable_shared_spawns = settings.global["oarc-enable-shared-spawns"].value
global.ocfg.max_players_shared_spawn = settings.global["oarc-max-players-shared-spawn"].value
global.ocfg.enable_shared_chat = settings.global["oarc-enable-shared-chat"].value
global.ocfg.respawn_cooldown_min = settings.global["oarc-respawn-cooldown-min"].value
global.ocfg.frontier_silo_count = settings.global["oarc-frontier-silo-count"].value
global.ocfg.frontier_silo_distance = settings.global["oarc-frontier-silo-distance"].value
global.ocfg.frontier_fixed_pos = false
global.ocfg.frontier_pos_table = {{x = 0, y = 100}}
global.ocfg.frontier_silo_vision = settings.global["oarc-frontier-silo-vision"].value
global.ocfg.frontier_allow_build = true
end
-----------------------
-- VALIDATION CHECKS --
-----------------------
if (not global.ocfg.frontier_rocket_silo or not global.ocfg.enable_vanilla_spawns) then
global.ocfg.silo_islands = false
end
if (global.ocfg.enable_vanilla_spawns) then
global.ocfg.enable_buddy_spawn = false
end
end

246
lib/oarc_gui_tabs.lua Normal file
View File

@ -0,0 +1,246 @@
-- oarc_gui_tabs.lua
--------------------------------------------------------------------------------
-- GUI Tab Handler
--------------------------------------------------------------------------------
-- NAME of the top level element (outer frame)
local OARC_GUI = "oarc_gui"
-- LIST of all implemented tabs and their content Functions
OARC_GAME_OPTS_GUI_TAB_NAME = "Server Info"
OARC_SPAWN_CTRL_GUI_NAME = "Spawn Controls"
OARC_PLAYER_LIST_GUI_TAB_NAME = "Players"
OARC_TAGS_GUI_TAB_NAME = "Name Tags"
OARC_ROCKETS_GUI_TAB_NAME = "Rockets"
local OARC_GUI_TAB_CONTENT_FUNCTIONS = {}
OARC_GUI_TAB_CONTENT_FUNCTIONS["Server Info"] = CreateGameOptionsTab
OARC_GUI_TAB_CONTENT_FUNCTIONS["Spawn Controls"] = CreateSpawnCtrlGuiTab
OARC_GUI_TAB_CONTENT_FUNCTIONS["Players"] = CreatePlayerListGuiTab
OARC_GUI_TAB_CONTENT_FUNCTIONS["Name Tags"] = CreateTagGuiTab
OARC_GUI_TAB_CONTENT_FUNCTIONS["Rockets"] = CreateRocketGuiTab
function InitOarcGuiTabs(player)
CreateOarcGuiButton(player)
-- Add general info tab
AddOarcGuiTab(player, OARC_GAME_OPTS_GUI_TAB_NAME)
SetOarcGuiTabEnabled(player, OARC_GAME_OPTS_GUI_TAB_NAME, true)
-- Spawn control tab, disabled by default
AddOarcGuiTab(player, OARC_SPAWN_CTRL_GUI_NAME)
-- If player list is enabled, create that
if global.ocfg.enable_player_list then
AddOarcGuiTab(player, OARC_PLAYER_LIST_GUI_TAB_NAME)
SetOarcGuiTabEnabled(player, OARC_PLAYER_LIST_GUI_TAB_NAME, true)
end
-- Player tags
if global.ocfg.enable_tags then
AddOarcGuiTab(player, OARC_TAGS_GUI_TAB_NAME)
SetOarcGuiTabEnabled(player, OARC_TAGS_GUI_TAB_NAME, true)
end
-- Rockets tab, only enable if one has been launched already
AddOarcGuiTab(player, OARC_ROCKETS_GUI_TAB_NAME)
if (global.satellite_sent) then
SetOarcGuiTabEnabled(player, OARC_ROCKETS_GUI_TAB_NAME, true)
end
end
function CreateOarcGuiButton(player)
if (mod_gui.get_button_flow(player).oarc_button == nil) then
local b = mod_gui.get_button_flow(player).add{name="oarc_button",
type="sprite-button",
sprite="utility/expand_dots",
style=mod_gui.button_style}
b.style.padding=2
b.style.width=20
end
end
function DoesOarcGuiExist(player)
return (mod_gui.get_frame_flow(player)[OARC_GUI] ~= nil)
end
function ToggleOarcGuiVisible(player)
local of = mod_gui.get_frame_flow(player)[OARC_GUI]
if (of ~= nil) then
of.visible = not of.visible
end
end
function GetOarcGuiTabsPane(player)
if (mod_gui.get_frame_flow(player)[OARC_GUI] == nil) then
return nil
else
return mod_gui.get_frame_flow(player)[OARC_GUI].oarc_if.oarc_tabs
end
end
function ClickOarcGuiButton(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local name = event.element.name
if (name ~= "oarc_button") then return end
if (not DoesOarcGuiExist(player)) then
CreateOarcGuiTabsPane(player)
else
ToggleOarcGuiVisible(player)
FakeTabChangeEventOarcGui(player)
end
end
function TabChangeOarcGui(event)
if (event.element.name ~= "oarc_tabs") then return end
local player = game.players[event.player_index]
local otabs = event.element
local selected_tab_name = otabs.tabs[otabs.selected_tab_index].tab.name
-- Clear all tab contents
for i,t in pairs(otabs.tabs) do
t.content.clear()
end
SetOarGuiTabContent(player, selected_tab_name)
end
function FakeTabChangeEventOarcGui(player)
local event = {}
event.element = GetOarcGuiTabsPane(player)
event.player_index = player.index
TabChangeOarcGui(event)
end
function CreateOarcGuiTabsPane(player)
if (mod_gui.get_frame_flow(player)[OARC_GUI] == nil) then
-- OUTER FRAME (TOP GUI ELEMENT)
local frame = mod_gui.get_frame_flow(player).add{
type = 'frame',
name = OARC_GUI,
direction = "vertical"}
frame.style.padding = 5
-- INNER FRAME
local inside_frame = frame.add{
type = "frame",
name = "oarc_if",
style = "inside_deep_frame",
direction = "vertical"
}
-- SUB HEADING w/ LABEL
local subhead = inside_frame.add{
type="frame",
name="sub_header",
style = "changelog_subheader_frame"}
AddLabel(subhead, "scen_info", "Scenario Info and Controls", "subheader_caption_label")
-- TABBED PANE
local oarc_tabs = inside_frame.add{
name="oarc_tabs",
type="tabbed-pane",
style="tabbed_pane"}
oarc_tabs.style.top_padding = 8
end
end
-- Function creates a new tab.
-- It adds whatever it wants to the provided scroll-pane.
-- content_function takes a content holder GUI and player
function AddOarcGuiTab(player, tab_name, content_function)
if (not DoesOarcGuiExist(player)) then
CreateOarcGuiTabsPane(player)
ToggleOarcGuiVisible(player)
end
-- Get the tabbed pane
local otabs = GetOarcGuiTabsPane(player)
-- Create new tab
local new_tab = otabs.add{
type="tab",
name=tab_name,
caption=tab_name}
-- Create inside frame for content
local tab_inside_frame = otabs.add{
type="frame",
name=tab_name.."_if",
style = "inside_deep_frame",
direction="vertical"}
tab_inside_frame.style.left_margin = 10
tab_inside_frame.style.right_margin = 10
tab_inside_frame.style.top_margin = 4
tab_inside_frame.style.bottom_margin = 4
tab_inside_frame.style.padding = 5
tab_inside_frame.style.horizontally_stretchable = true
-- tab_inside_frame.style.vertically_stretchable = true
-- tab_inside_frame.style.horizontally_squashable = true
-- tab_inside_frame.style.vertically_squashable = true
-- Add the whole thing to the tab now.
otabs.add_tab(new_tab, tab_inside_frame)
-- Disable all new tabs by default
new_tab.enabled = false
-- If no other tabs are selected, select the first one.
if (otabs.selected_tab_index == nil) then
otabs.selected_tab_index = 1
end
-- if (global.oarc_gui_tab_funcs == nil) then
-- global.oarc_gui_tab_funcs = {}
-- end
-- global.oarc_gui_tab_funcs[tab_name] = content_function
end
function SetOarGuiTabContent(player, tab_name)
if (not DoesOarcGuiExist(player)) then return end
local otabs = GetOarcGuiTabsPane(player)
for _,t in ipairs(otabs.tabs) do
if (t.tab.name == tab_name) then
t.content.clear()
OARC_GUI_TAB_CONTENT_FUNCTIONS[tab_name](t.content, player)
return
end
end
end
function SetOarcGuiTabEnabled(player, tab_name, enable)
if (not DoesOarcGuiExist(player)) then return end
local otabs = GetOarcGuiTabsPane(player)
for _,t in ipairs(otabs.tabs) do
if (t.tab.name == tab_name) then
t.tab.enabled = enable
return
end
end
end
function SwitchOarcGuiTab(player, tab_name)
if (not DoesOarcGuiExist(player)) then return end
local otabs = GetOarcGuiTabsPane(player)
for i,t in pairs(otabs.tabs) do
if (t.tab.name == tab_name) then
otabs.selected_tab_index = i
FakeTabChangeEventOarcGui(player)
return
end
end
end

137
lib/oarc_gui_utils.lua Normal file
View File

@ -0,0 +1,137 @@
-- oarc_gui_utils.lua
-- Mar 2019
-- Generic GUI stuff goes here.
--------------------------------------------------------------------------------
-- GUI Styles
--------------------------------------------------------------------------------
my_fixed_width_style = {
minimal_width = 450,
maximal_width = 450
}
my_label_style = {
-- minimal_width = 450,
-- maximal_width = 50,
single_line = false,
font_color = {r=1,g=1,b=1},
top_padding = 0,
bottom_padding = 0
}
my_label_header_style = {
single_line = false,
font = "heading-1",
font_color = {r=1,g=1,b=1},
top_padding = 0,
bottom_padding = 0
}
my_label_header_grey_style = {
single_line = false,
font = "heading-1",
font_color = {r=0.6,g=0.6,b=0.6},
top_padding = 0,
bottom_padding = 0
}
my_note_style = {
-- minimal_width = 450,
single_line = false,
font = "default-small-semibold",
font_color = {r=1,g=0.5,b=0.5},
top_padding = 0,
bottom_padding = 0
}
my_warning_style = {
-- minimal_width = 450,
-- maximal_width = 450,
single_line = false,
font_color = {r=1,g=0.1,b=0.1},
top_padding = 0,
bottom_padding = 0
}
my_spacer_style = {
minimal_height = 10,
top_padding = 0,
bottom_padding = 0
}
my_small_button_style = {
font = "default-small-semibold"
}
my_player_list_fixed_width_style = {
minimal_width = 200,
maximal_width = 400,
maximal_height = 200
}
my_player_list_admin_style = {
font = "default-semibold",
font_color = {r=1,g=0.5,b=0.5},
minimal_width = 200,
top_padding = 0,
bottom_padding = 0,
single_line = false,
}
my_player_list_style = {
font = "default-semibold",
minimal_width = 200,
top_padding = 0,
bottom_padding = 0,
single_line = false,
}
my_player_list_offline_style = {
-- font = "default-semibold",
font_color = {r=0.5,g=0.5,b=0.5},
minimal_width = 200,
top_padding = 0,
bottom_padding = 0,
single_line = false,
}
my_player_list_style_spacer = {
minimal_height = 20,
}
my_color_red = {r=1,g=0.1,b=0.1}
my_longer_label_style = {
maximal_width = 600,
single_line = false,
font_color = {r=1,g=1,b=1},
top_padding = 0,
bottom_padding = 0
}
my_longer_warning_style = {
maximal_width = 600,
single_line = false,
font_color = {r=1,g=0.1,b=0.1},
top_padding = 0,
bottom_padding = 0
}
--------------------------------------------------------------------------------
-- GUI Functions
--------------------------------------------------------------------------------
-- Apply a style option to a GUI
function ApplyStyle (guiIn, styleIn)
for k,v in pairs(styleIn) do
guiIn.style[k]=v
end
end
-- Shorter way to add a label with a style
function AddLabel(guiIn, name, message, style)
local g = guiIn.add{name = name, type = "label",
caption=message}
if (type(style) == "table") then
ApplyStyle(g, style)
else
g.style = style
end
end
-- Shorter way to add a spacer
function AddSpacer(guiIn)
ApplyStyle(guiIn.add{type = "label", caption=" "}, my_spacer_style)
end
function AddSpacerLine(guiIn)
ApplyStyle(guiIn.add{type = "line", direction="horizontal"}, my_spacer_style)
end

1064
lib/oarc_utils.lua Normal file

File diff suppressed because it is too large Load Diff

46
lib/player_list.lua Normal file
View File

@ -0,0 +1,46 @@
-- oarc_player_list.lua
-- Mar 2019
--------------------------------------------------------------------------------
-- Player List GUI - My own version
--------------------------------------------------------------------------------
function CreatePlayerListGuiTab(tab_container, player)
local scrollFrame = tab_container.add{type="scroll-pane",
name="playerList-panel",
direction = "vertical"}
ApplyStyle(scrollFrame, my_player_list_fixed_width_style)
scrollFrame.horizontal_scroll_policy = "never"
AddLabel(scrollFrame, "online_title_msg", "Online Players:", my_label_header_style)
for _,player in pairs(game.connected_players) do
local caption_str = player.name.." ["..player.force.name.."]".." ("..formattime_hours_mins(player.online_time)..")"
if (player.admin) then
AddLabel(scrollFrame, player.name.."_plist", caption_str, my_player_list_admin_style)
else
AddLabel(scrollFrame, player.name.."_plist", caption_str, my_player_list_style)
end
end
-- List offline players
if (global.ocfg.list_offline_players) then
AddSpacerLine(scrollFrame)
AddLabel(scrollFrame, "offline_title_msg", "Offline Players:", my_label_header_grey_style)
for _,player in pairs(game.players) do
if (not player.connected) then
local caption_str = player.name.." ["..player.force.name.."]".." ("..formattime_hours_mins(player.online_time)..")"
local text = scrollFrame.add{type="label", caption=caption_str, name=player.name.."_plist"}
ApplyStyle(text, my_player_list_offline_style)
end
end
end
end
function PlayerListGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local name = event.element.name
if (name == "playerList") then
ExpandPlayerListGui(player)
end
end

382
lib/regrowth_map.lua Normal file
View File

@ -0,0 +1,382 @@
-- regrowth_map.lua
-- Sep 2019
-- REVERTED BACK TO SOFT MOD
-- Code tracks all chunks generated and allows for deleting of inactive chunks.
--
-- Basic rules of regrowth:
-- 1. Area around player is safe for quite a large distance.
-- 2. Chunks with pollution won't be deleted.
-- 3. Chunks with any player buildings won't be deleted.
-- 4. Anything within radar range won't be deleted, but radar MUST be active.
-- -- This works by refreshing all chunk timers within radar range using
-- the on_sector_scanned event.
-- 5. Chunks timeout after 1 hour-ish, configurable
require("lib/oarc_utils")
require("config")
REGROWTH_TIMEOUT_TICKS = TICKS_PER_HOUR
-- Init globals and set player join area to be off limits.
function RegrowthInit()
if (global.rg == nil) then
global.rg = {}
global.rg.surfaces_index = 1
global.rg.player_refresh_index = 1
global.rg.force_removal_flag = -1000
global.rg.active_surfaces = {}
end
end
function TriggerCleanup()
global.rg.force_removal_flag = game.tick
end
function ForceRemoveChunksCmd(cmd_table)
if (game.players[cmd_table.player_index].admin) then
TriggerCleanup()
end
end
function RegrowthAddSurface(s_index)
RegrowthInit()
if (global.rg[s_index] ~= nil) then
log("ERROR - Tried to add surface that was already added?")
return
end
log("Oarc Regrowth - ADD SURFACE " .. game.surfaces[s_index].name)
global.rg[s_index] = {}
table.insert(global.rg.active_surfaces, s_index)
global.rg[s_index].map = {}
global.rg[s_index].removal_list = {}
global.rg[s_index].min_x = 0
global.rg[s_index].max_x = 0
global.rg[s_index].x_index = 0
global.rg[s_index].min_y = 0
global.rg[s_index].max_y = 0
global.rg[s_index].y_index = 0
-- MarkAreaSafeGivenTilePos({x=0,y=0}, 10)
end
-- Adds new chunks to the global table to track them.
-- This should always be called first in the chunk generate sequence
-- (Compared to other RSO & Oarc related functions...)
function RegrowthChunkGenerate(event)
local s_index = event.surface.index
local c_pos = GetChunkPosFromTilePos(event.area.left_top)
-- Surface must be "added" first.
if (global.rg[s_index] == nil) then return end
-- If this is the first chunk in that row:
if (global.rg[s_index].map[c_pos.x] == nil) then
global.rg[s_index].map[c_pos.x] = {}
end
-- Confirm the chunk doesn't already have a value set:
if (global.rg[s_index].map[c_pos.x][c_pos.y] == nil) then
global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick
end
-- Store min/max values for x/y dimensions:
if (c_pos.x < global.rg[s_index].min_x) then
global.rg[s_index].min_x = c_pos.x
end
if (c_pos.x > global.rg[s_index].max_x) then
global.rg[s_index].max_x = c_pos.x
end
if (c_pos.y < global.rg[s_index].min_y) then
global.rg[s_index].min_y = c_pos.y
end
if (c_pos.y > global.rg[s_index].max_y) then
global.rg[s_index].max_y = c_pos.y
end
end
-- Mark an area for "immediate" forced removal
function MarkAreaForRemoval(s_index, pos, chunk_radius)
local c_pos = GetChunkPosFromTilePos(pos)
for i=-chunk_radius,chunk_radius do
for k=-chunk_radius,chunk_radius do
local x = c_pos.x+i
local y = c_pos.y+k
if (global.rg[s_index].map[x] == nil) then
global.rg[s_index].map[x] = {}
end
global.rg[s_index].map[x][y] = nil
table.insert(global.rg[s_index].removal_list,
{pos={x=x,y=y},force=true})
end
end
end
-- Marks a chunk containing a position that won't ever be deleted.
function MarkChunkSafe(s_index, c_pos)
if (global.rg[s_index].map[c_pos.x] == nil) then
global.rg[s_index].map[c_pos.x] = {}
end
global.rg[s_index].map[c_pos.x][c_pos.y] = -1
end
-- Marks a safe area around a TILE position that won't ever be deleted.
function MarkAreaSafeGivenTilePos(s_index, pos, chunk_radius)
if (global.rg[s_index] == nil) then return end
local c_pos = GetChunkPosFromTilePos(pos)
MarkAreaSafeGivenChunkPos(s_index, c_pos, chunk_radius)
end
-- Marks a safe area around a CHUNK position that won't ever be deleted.
function MarkAreaSafeGivenChunkPos(s_index, c_pos, chunk_radius)
if (global.rg[s_index] == nil) then return end
for i=-chunk_radius,chunk_radius do
for j=-chunk_radius,chunk_radius do
MarkChunkSafe(s_index, {x=c_pos.x+i,y=c_pos.y+j})
end
end
end
-- Refreshes timers on a chunk containing position
function RefreshChunkTimer(s_index, pos, bonus_time)
local c_pos = GetChunkPosFromTilePos(pos)
if (global.rg[s_index].map[c_pos.x] == nil) then
global.rg[s_index].map[c_pos.x] = {}
end
if (global.rg[s_index].map[c_pos.x][c_pos.y] ~= -1) then
global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick + bonus_time
end
end
-- Forcefully refreshes timers on a chunk containing position
-- Will overwrite -1 flag.
-- function OarcRegrowthForceRefreshChunk(s_index, pos, bonus_time)
-- local c_pos = GetChunkPosFromTilePos(pos)
-- if (global.rg[s_index].map[c_pos.x] == nil) then
-- global.rg[s_index].map[c_pos.x] = {}
-- end
-- global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick + bonus_time
-- end
-- Refreshes timers on all chunks around a certain area
function RefreshArea(s_index, pos, chunk_radius, bonus_time)
local c_pos = GetChunkPosFromTilePos(pos)
for i=-chunk_radius,chunk_radius do
for k=-chunk_radius,chunk_radius do
local x = c_pos.x+i
local y = c_pos.y+k
if (global.rg[s_index].map[x] == nil) then
global.rg[s_index].map[x] = {}
end
if (global.rg[s_index].map[x][y] ~= -1) then
global.rg[s_index].map[x][y] = game.tick + bonus_time
end
end
end
end
-- Refreshes timers on all chunks near an ACTIVE radar
function RegrowthSectorScan(event)
local s_index = event.radar.surface.index
if (global.rg[s_index] == nil) then return end
RefreshArea(s_index, event.radar.position, 14, 0)
RefreshChunkTimer(s_index, event.chunk_position, 0)
end
-- Refresh all chunks near a single player. Cyles through all connected players.
function RefreshPlayerArea()
global.rg.player_refresh_index = global.rg.player_refresh_index + 1
if (global.rg.player_refresh_index > #game.connected_players) then
global.rg.player_refresh_index = 1
end
if (game.connected_players[global.rg.player_refresh_index]) then
local player = game.connected_players[global.rg.player_refresh_index]
if (not player.character) then return end
local s_index = player.character.surface.index
if (global.rg[s_index] == nil) then return end
RefreshArea(s_index, player.position, 4, 0)
end
end
-- Gets the next chunk the array map and checks to see if it has timed out.
-- Adds it to the removal list if it has.
function RegrowthSingleStepArray(s_index)
-- Increment X and reset when we hit the end.
if (global.rg[s_index].x_index > global.rg[s_index].max_x) then
global.rg[s_index].x_index = global.rg[s_index].min_x
-- Increment Y and reset when we hit the end.
if (global.rg[s_index].y_index > global.rg[s_index].max_y) then
global.rg[s_index].y_index = global.rg[s_index].min_y
-- log("Finished checking regrowth array. "..
-- game.surfaces[s_index].name.." "..
-- global.rg[s_index].min_x.." "..
-- global.rg[s_index].max_x.." "..
-- global.rg[s_index].min_y.." "..
-- global.rg[s_index].max_y)
else
global.rg[s_index].y_index = global.rg[s_index].y_index + 1
end
else
global.rg[s_index].x_index = global.rg[s_index].x_index + 1
end
local xidx = global.rg[s_index].x_index
local yidx = global.rg[s_index].y_index
if (not xidx or not yidx) then
log("ERROR - xidx or yidx is nil?")
end
-- Check row exists, otherwise make one.
if (global.rg[s_index].map[xidx] == nil) then
global.rg[s_index].map[xidx] = {}
end
-- If the chunk has timed out, add it to the removal list
local c_timer = global.rg[s_index].map[xidx][yidx]
if ((c_timer ~= nil) and (c_timer ~= -1) and
((c_timer + REGROWTH_TIMEOUT_TICKS) < game.tick)) then
-- Check chunk actually exists
if (game.surfaces[s_index].is_chunk_generated({x=xidx, y=yidx})) then
table.insert(global.rg[s_index].removal_list, {pos={x=xidx,
y=yidx},
force=false})
global.rg[s_index].map[xidx][yidx] = nil
end
end
end
-- Remove all chunks at same time to reduce impact to FPS/UPS
function OarcRegrowthRemoveAllChunks()
for _,s_index in pairs(global.rg.active_surfaces) do
print(k,v)
while (#global.rg[s_index].removal_list > 0) do
local c_remove = table.remove(global.rg[s_index].removal_list)
local c_pos = c_remove.pos
local c_timer = global.rg[s_index].map[c_pos.x][c_pos.y]
if (game.surfaces[s_index] == nil) then
log("Error! game.surfaces[name] is nil?? WTF?")
return
end
-- Confirm chunk is still expired
if (c_timer == nil) then
-- If it is FORCE removal, then remove it regardless of pollution.
if (c_remove.force) then
game.surfaces[s_index].delete_chunk(c_pos)
global.rg[s_index].map[c_pos.x][c_pos.y] = nil
-- If it is a normal timeout removal, don't do it if there is pollution in the chunk.
elseif (game.surfaces[s_index].get_pollution({c_pos.x*32,c_pos.y*32}) > 0) then
global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick
-- Else delete the chunk
else
game.surfaces[s_index].delete_chunk(c_pos)
global.rg[s_index].map[c_pos.x][c_pos.y] = nil
end
end
end
end
end
-- This is the main work function, it checks a single chunk in the list
-- per tick. It works according to the rules listed in the header of this
-- file.
function RegrowthOnTick()
if (#global.rg.active_surfaces == 0) then return end
-- Every half a second, refresh all chunks near a single player
-- Cyles through all players. Tick is offset by 2
if ((game.tick % (30)) == 2) then
RefreshPlayerArea()
end
-- Iterate through the active surfaces.
if (global.rg.surfaces_index > #global.rg.active_surfaces) then
global.rg.surfaces_index = 1
end
local s_index = global.rg.active_surfaces[global.rg.surfaces_index]
global.rg.surfaces_index = global.rg.surfaces_index+1
if (s_index == nil) then
log("ERROR - s_index = nil in OarcRegrowthOnTick?")
return
end
-- Every tick, check a few points in the 2d array of one of the active surfaces
-- According to /measured-command this shouldn't take more
-- than 0.1ms on average
for i=1,20 do
RegrowthSingleStepArray(s_index)
end
-- Allow enable/disable of auto cleanup, can change during runtime.
if (global.ocfg.enable_regrowth) then
local interval_ticks = REGROWTH_TIMEOUT_TICKS
-- Send a broadcast warning before it happens.
if ((game.tick % interval_ticks) == interval_ticks-601) then
if (#global.rg[s_index].removal_list > 100) then
SendBroadcastMsg("Map cleanup in 10 seconds... Unused and old map chunks will be deleted!")
end
end
-- Delete all listed chunks across all active surfaces
if ((game.tick % interval_ticks) == interval_ticks-1) then
if (#global.rg[s_index].removal_list > 100) then
OarcRegrowthRemoveAllChunks()
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
end
end
end
end
-- This function removes any chunks flagged but on demand.
-- Controlled by the global.rg.force_removal_flag
-- This function may be used outside of the normal regrowth modse.
function RegrowthForceRemovalOnTick()
-- Catch force remove flag
if (game.tick == global.rg.force_removal_flag+60) then
SendBroadcastMsg("Map cleanup (forced) in 10 seconds... Unused and old map chunks will be deleted!")
end
if (game.tick == global.rg.force_removal_flag+660) then
OarcRegrowthRemoveAllChunks()
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
end
end
-- Broadcast messages to all connected players
function SendBroadcastMsg(msg)
for name,player in pairs(game.connected_players) do
player.print(msg)
end
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

80
lib/rocket_launch.lua Normal file
View File

@ -0,0 +1,80 @@
-- rocket_launch.lua
-- May 2019
-- This is meant to extract out any rocket launch related logic to support my oarc scenario designs.
require("lib/oarc_utils")
require("config")
--------------------------------------------------------------------------------
-- Rocket Launch Event Code
-- Controls the "win condition"
--------------------------------------------------------------------------------
function RocketLaunchEvent(event)
local force = event.rocket.force
-- Notify players on force if rocket was launched without sat.
if event.rocket.get_item_count("satellite") == 0 then
for index, player in pairs(force.players) do
player.print("You launched the rocket, but you didn't put a satellite inside.")
end
return
end
-- First ever sat launch
if not global.satellite_sent then
global.satellite_sent = {}
SendBroadcastMsg("Team " .. event.rocket.force.name .. " was the first to launch a rocket!")
ServerWriteFile("rocket_events", "Team " .. event.rocket.force.name .. " was the first to launch a rocket!" .. "\n")
for name,player in pairs(game.players) do
SetOarcGuiTabEnabled(player, OARC_ROCKETS_GUI_TAB_NAME, true)
end
end
-- Track additional satellites launched by this force
if global.satellite_sent[force.name] then
global.satellite_sent[force.name] = global.satellite_sent[force.name] + 1
SendBroadcastMsg("Team " .. event.rocket.force.name .. " launched another rocket. Total " .. global.satellite_sent[force.name])
ServerWriteFile("rocket_events", "Team " .. event.rocket.force.name .. " launched another rocket. Total " .. global.satellite_sent[force.name] .. "\n")
-- First sat launch for this force.
else
-- game.set_game_state{game_finished=true, player_won=true, can_continue=true}
global.satellite_sent[force.name] = 1
SendBroadcastMsg("Team " .. event.rocket.force.name .. " launched their first rocket!")
ServerWriteFile("rocket_events", "Team " .. event.rocket.force.name .. " launched their first rocket!" .. "\n")
-- Unlock research
if global.ocfg.lock_goodies_rocket_launch then
EnableTech(force, "atomic-bomb")
EnableTech(force, "power-armor-mk2")
EnableTech(force, "artillery")
if (force.technologies["speed-module-3"].researched) then
AddRecipe(force, "speed-module-3")
end
if (force.technologies["productivity-module-3"].researched) then
AddRecipe(force, "productivity-module-3")
end
end
end
end
function CreateRocketGuiTab(tab_container, player)
-- local frame = tab_container.add{type="frame", name="rocket-panel", caption="Satellites Launched:", direction = "vertical"}
AddLabel(tab_container, nil, "Satellites Launched:", my_label_header_style)
if (global.satellite_sent == nil) then
AddLabel(tab_container, nil, "No launches yet.", my_label_style)
else
for force_name,sat_count in pairs(global.satellite_sent) do
AddLabel(tab_container,
"rc_"..force_name,
"Team " .. force_name .. ": " .. tostring(sat_count),
my_label_style)
end
end
end

800
lib/separate_spawns.lua Normal file
View File

@ -0,0 +1,800 @@
-- separate_spawns.lua
-- Nov 2016
--
-- Code that handles everything regarding giving each player a separate spawn
-- Includes the GUI stuff
require("lib/oarc_utils")
require("config")
--------------------------------------------------------------------------------
-- EVENT RELATED FUNCTIONS
--------------------------------------------------------------------------------
-- When a new player is created, present the spawn options
-- Assign them to the main force so they can communicate with the team
-- without shouting.
function SeparateSpawnsPlayerCreated(player_index)
local player = game.players[player_index]
-- Make sure spawn control tab is disabled
SetOarcGuiTabEnabled(player, OARC_SPAWN_CTRL_GUI_NAME, false)
SwitchOarcGuiTab(player, OARC_GAME_OPTS_GUI_TAB_NAME)
-- This checks if they have just joined the server.
-- No assigned force yet.
if (player.force.name ~= "player") then
FindUnusedSpawns(player, false)
end
player.force = global.ocfg.main_force
DisplayWelcomeTextGui(player)
end
-- Check if the player has a different spawn point than the default one
-- Make sure to give the default starting items
function SeparateSpawnsPlayerRespawned(event)
local player = game.players[event.player_index]
SendPlayerToSpawn(player)
end
-- This is the main function that creates the spawn area
-- Provides resources, land and a safe zone
function SeparateSpawnsGenerateChunk(event)
local surface = event.surface
local chunkArea = event.area
-- Modify enemies first.
if global.ocfg.modified_enemy_spawning then
DowngradeWormsDistanceBasedOnChunkGenerate(event)
end
-- This handles chunk generation near player spawns
-- If it is near a player spawn, it does a few things like make the area
-- safe and provide a guaranteed area of land and water tiles.
SetupAndClearSpawnAreas(surface, chunkArea)
end
-- Call this if a player leaves the game or is reset
function FindUnusedSpawns(player, remove_player)
if not player then
log("ERROR - FindUnusedSpawns on NIL Player!")
return
end
if (player.online_time < (global.ocfg.minimum_online_time * TICKS_PER_MINUTE)) then
-- If this player is staying in the game, lets make sure we don't delete them
-- along with the map chunks being cleared.
player.teleport({x=0,y=0}, GAME_SURFACE_NAME)
-- Clear out global variables for that player
if (global.playerSpawns[player.name] ~= nil) then
global.playerSpawns[player.name] = nil
end
-- Remove them from the delayed spawn queue if they are in it
for i=#global.delayedSpawns,1,-1 do
delayedSpawn = global.delayedSpawns[i]
if (player.name == delayedSpawn.playerName) then
if (delayedSpawn.vanilla) then
log("Returning a vanilla spawn back to available.")
table.insert(global.vanillaSpawns, {x=delayedSpawn.pos.x,y=delayedSpawn.pos.y})
end
table.remove(global.delayedSpawns, i)
log("Removing player from delayed spawn queue: " .. player.name)
end
end
-- Transfer or remove a shared spawn if player is owner
if (global.sharedSpawns[player.name] ~= nil) then
local teamMates = global.sharedSpawns[player.name].players
if (#teamMates >= 1) then
local newOwnerName = table.remove(teamMates)
TransferOwnershipOfSharedSpawn(player.name, newOwnerName)
else
global.sharedSpawns[player.name] = nil
end
end
-- If a uniqueSpawn was created for the player, mark it as unused.
if (global.uniqueSpawns[player.name] ~= nil) then
local spawnPos = global.uniqueSpawns[player.name].pos
-- Check if it was near someone else's base.
nearOtherSpawn = false
for spawnPlayerName,otherSpawnPos in pairs(global.uniqueSpawns) do
if ((spawnPlayerName ~= player.name) and (getDistance(spawnPos, otherSpawnPos.pos) < (global.ocfg.spawn_config.gen_settings.land_area_tiles*3))) then
log("Won't remove base as it's close to another spawn: " .. spawnPlayerName)
nearOtherSpawn = true
end
end
-- Unused Chunk Removal mod (aka regrowth)
if (global.ocfg.enable_abandoned_base_removal and
(not nearOtherSpawn) and
global.ocfg.enable_regrowth) then
if (global.uniqueSpawns[player.name].vanilla) then
log("Returning a vanilla spawn back to available.")
table.insert(global.vanillaSpawns, {x=spawnPos.x,y=spawnPos.y})
end
global.uniqueSpawns[player.name] = nil
log("Removing base: " .. spawnPos.x .. "," .. spawnPos.y)
remote.call("oarc_regrowth",
"area_removal_tilepos",
game.surfaces[GAME_SURFACE_NAME].index,
spawnPos,
CHECK_SPAWN_UNGENERATED_CHUNKS_RADIUS)
remote.call("oarc_regrowth",
"trigger_immediate_cleanup")
SendBroadcastMsg(player.name .. "'s base was marked for immediate clean up because they left within "..global.ocfg.minimum_online_time.." minutes of joining.")
else
-- table.insert(global.unusedSpawns, global.uniqueSpawns[player.name]) -- Not used/implemented right now.
global.uniqueSpawns[player.name] = nil
SendBroadcastMsg(player.name .. " base was freed up because they left within "..global.ocfg.minimum_online_time.." minutes of joining.")
end
end
-- remove that player's cooldown setting
if (global.playerCooldowns[player.name] ~= nil) then
global.playerCooldowns[player.name] = nil
end
-- Remove from shared spawn player slots (need to search all)
for _,sharedSpawn in pairs(global.sharedSpawns) do
for key,playerName in pairs(sharedSpawn.players) do
if (player.name == playerName) then
sharedSpawn.players[key] = nil;
end
end
end
-- Remove a force if this player created it and they are the only one on it
if ((#player.force.players <= 1) and (player.force.name ~= global.ocfg.main_force)) then
game.merge_forces(player.force, global.ocfg.main_force)
end
-- Remove the character completely
if (remove_player) then
game.remove_offline_players({player})
end
end
end
-- Clear the spawn areas.
-- This should be run inside the chunk generate event and be given a list of all
-- unique spawn points.
-- This clears enemies in the immediate area, creates a slightly safe area around it,
-- It no LONGER generates the resources though as that is now handled in a delayed event!
function SetupAndClearSpawnAreas(surface, chunkArea)
for name,spawn in pairs(global.uniqueSpawns) do
-- Create a bunch of useful area and position variables
local landArea = GetAreaAroundPos(spawn.pos, global.ocfg.spawn_config.gen_settings.land_area_tiles+CHUNK_SIZE)
local safeArea = GetAreaAroundPos(spawn.pos, global.ocfg.spawn_config.safe_area.safe_radius)
local warningArea = GetAreaAroundPos(spawn.pos, global.ocfg.spawn_config.safe_area.warn_radius)
local reducedArea = GetAreaAroundPos(spawn.pos, global.ocfg.spawn_config.safe_area.danger_radius)
local chunkAreaCenter = {x=chunkArea.left_top.x+(CHUNK_SIZE/2),
y=chunkArea.left_top.y+(CHUNK_SIZE/2)}
local spawnPosOffset = {x=spawn.pos.x+global.ocfg.spawn_config.gen_settings.land_area_tiles,
y=spawn.pos.y+global.ocfg.spawn_config.gen_settings.land_area_tiles}
-- Make chunks near a spawn safe by removing enemies
if CheckIfInArea(chunkAreaCenter,safeArea) then
RemoveAliensInArea(surface, chunkArea)
-- Create a warning area with heavily reduced enemies
elseif CheckIfInArea(chunkAreaCenter,warningArea) then
ReduceAliensInArea(surface, chunkArea, global.ocfg.spawn_config.safe_area.warn_reduction)
-- DowngradeWormsInArea(surface, chunkArea, 100, 100, 100)
RemoveWormsInArea(surface, chunkArea, false, true, true, true) -- remove all non-small worms.
-- Create a third area with moderatly reduced enemies
elseif CheckIfInArea(chunkAreaCenter,reducedArea) then
ReduceAliensInArea(surface, chunkArea, global.ocfg.spawn_config.safe_area.danger_reduction)
-- DowngradeWormsInArea(surface, chunkArea, 50, 100, 100)
RemoveWormsInArea(surface, chunkArea, false, false, true, true) -- remove all huge/behemoth worms.
end
if (not spawn.vanilla) then
-- 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)
if CheckIfInArea(chunkAreaCenter,landArea) then
-- Remove trees/resources inside the spawn area
RemoveInCircle(surface, chunkArea, "tree", spawn.pos, global.ocfg.spawn_config.gen_settings.land_area_tiles)
RemoveInCircle(surface, chunkArea, "resource", spawn.pos, global.ocfg.spawn_config.gen_settings.land_area_tiles+5)
RemoveInCircle(surface, chunkArea, "cliff", spawn.pos, global.ocfg.spawn_config.gen_settings.land_area_tiles+5)
RemoveDecorationsArea(surface, chunkArea)
local fill_tile = "grass-1"
if (game.active_mods["oarc-restricted-build"]) then
fill_tile = global.ocfg.locked_build_area_tile
end
if (global.ocfg.spawn_config.gen_settings.tree_circle) then
CreateCropCircle(surface, spawn.pos, chunkArea, global.ocfg.spawn_config.gen_settings.land_area_tiles, fill_tile)
end
if (global.ocfg.spawn_config.gen_settings.tree_octagon) then
CreateCropOctagon(surface, spawn.pos, chunkArea, global.ocfg.spawn_config.gen_settings.land_area_tiles, fill_tile)
end
if (global.ocfg.spawn_config.gen_settings.moat_choice_enabled) then
if (spawn.moat) then
CreateMoat(surface, spawn.pos, chunkArea, global.ocfg.spawn_config.gen_settings.land_area_tiles, fill_tile)
end
end
end
end
end
end
-- Same as GetClosestPosFromTable but specific to global.uniqueSpawns
function GetClosestUniqueSpawn(pos)
local closest_dist = nil
local closest_key = nil
for k,s in pairs(global.uniqueSpawns) do
local new_dist = getDistance(pos, s.pos)
if (closest_dist == nil) then
closest_dist = new_dist
closest_key = k
elseif (closest_dist > new_dist) then
closest_dist = new_dist
closest_key = k
end
end
if (closest_key == nil) then
-- log("GetClosestUniqueSpawn ERROR - None found?")
return nil
end
return global.uniqueSpawns[closest_key]
end
-- I wrote this to ensure everyone gets safer spawns regardless of evolution level.
-- This is intended to downgrade any biters/spitters spawning near player bases.
-- I'm not sure the performance impact of this but I'm hoping it's not bad.
function ModifyEnemySpawnsNearPlayerStartingAreas(event)
if (not event.entity or not (event.entity.force.name == "enemy") or not event.entity.position) then
log("ModifyBiterSpawns - Unexpected use.")
return
end
local enemy_pos = event.entity.position
local surface = event.entity.surface
local enemy_name = event.entity.name
local closest_spawn = GetClosestUniqueSpawn(enemy_pos)
if (closest_spawn == nil) then
-- log("GetClosestUniqueSpawn ERROR - None found?")
return
end
-- No enemies inside safe radius!
if (getDistance(enemy_pos, closest_spawn.pos) < global.ocfg.spawn_config.safe_area.safe_radius) then
event.entity.destroy()
-- Warn distance is all SMALL only.
elseif (getDistance(enemy_pos, closest_spawn.pos) < global.ocfg.spawn_config.safe_area.warn_radius) then
if ((enemy_name == "big-biter") or (enemy_name == "behemoth-biter") or (enemy_name == "medium-biter")) then
event.entity.destroy()
surface.create_entity{name = "small-biter", position = enemy_pos, force = game.forces.enemy}
-- log("Downgraded biter close to spawn.")
elseif ((enemy_name == "big-spitter") or (enemy_name == "behemoth-spitter") or (enemy_name == "medium-spitter")) then
event.entity.destroy()
surface.create_entity{name = "small-spitter", position = enemy_pos, force = game.forces.enemy}
-- log("Downgraded spitter close to spawn.")
elseif ((enemy_name == "big-worm-turret") or (enemy_name == "behemoth-worm-turret") or (enemy_name == "medium-worm-turret")) then
event.entity.destroy()
surface.create_entity{name = "small-worm-turret", position = enemy_pos, force = game.forces.enemy}
-- log("Downgraded worm close to spawn.")
end
-- Danger distance is MEDIUM max.
elseif (getDistance(enemy_pos, closest_spawn.pos) < global.ocfg.spawn_config.safe_area.danger_radius) then
if ((enemy_name == "big-biter") or (enemy_name == "behemoth-biter")) then
event.entity.destroy()
surface.create_entity{name = "medium-biter", position = enemy_pos, force = game.forces.enemy}
-- log("Downgraded biter further from spawn.")
elseif ((enemy_name == "big-spitter") or (enemy_name == "behemoth-spitter")) then
event.entity.destroy()
surface.create_entity{name = "medium-spitter", position = enemy_pos, force = game.forces.enemy}
-- log("Downgraded spitter further from spawn
elseif ((enemy_name == "big-worm-turret") or (enemy_name == "behemoth-worm-turret")) then
event.entity.destroy()
surface.create_entity{name = "medium-worm-turret", position = enemy_pos, force = game.forces.enemy}
-- log("Downgraded worm further from spawn.")
end
end
end
--------------------------------------------------------------------------------
-- NON-EVENT RELATED FUNCTIONS
--------------------------------------------------------------------------------
-- Generate the basic starter resource around a given location.
function GenerateStartingResources(surface, pos)
local rand_settings = global.ocfg.spawn_config.resource_rand_pos_settings
-- Generate all resource tile patches
if (not rand_settings.enabled) then
for t_name,t_data in pairs (global.ocfg.spawn_config.resource_tiles) do
local pos = {x=pos.x+t_data.x_offset, y=pos.y+t_data.y_offset}
GenerateResourcePatch(surface, t_name, t_data.size, pos, t_data.amount)
end
else
-- Create list of resource tiles
local r_list = {}
for k,_ in pairs(global.ocfg.spawn_config.resource_tiles) do
if (k ~= "") then
table.insert(r_list, k)
end
end
local shuffled_list = FYShuffle(r_list)
-- This places resources in a semi-circle
-- Tweak in config.lua
local angle_offset = rand_settings.angle_offset
local num_resources = TableLength(global.ocfg.spawn_config.resource_tiles)
local theta = ((rand_settings.angle_final - rand_settings.angle_offset) / num_resources);
local count = 0
for _,k_name in pairs (shuffled_list) do
local angle = (theta * count) + angle_offset;
local tx = (rand_settings.radius * math.cos(angle)) + pos.x
local ty = (rand_settings.radius * math.sin(angle)) + pos.y
local pos = {x=math.floor(tx), y=math.floor(ty)}
GenerateResourcePatch(surface, k_name, global.ocfg.spawn_config.resource_tiles[k_name].size, pos, global.ocfg.spawn_config.resource_tiles[k_name].amount)
count = count+1
end
end
-- Generate special resource patches (oil)
for p_name,p_data in pairs (global.ocfg.spawn_config.resource_patches) do
local oil_patch_x=pos.x+p_data.x_offset_start
local oil_patch_y=pos.y+p_data.y_offset_start
for i=1,p_data.num_patches do
surface.create_entity({name=p_name, amount=p_data.amount,
position={oil_patch_x, oil_patch_y}})
oil_patch_x=oil_patch_x+p_data.x_offset_next
oil_patch_y=oil_patch_y+p_data.y_offset_next
end
end
end
-- Add a spawn to the shared spawn global
-- Used for tracking which players are assigned to it, where it is and if
-- it is open for new players to join
function CreateNewSharedSpawn(player)
global.sharedSpawns[player.name] = {openAccess=true,
position=global.playerSpawns[player.name],
players={}}
end
function TransferOwnershipOfSharedSpawn(prevOwnerName, newOwnerName)
-- Transfer the shared spawn global
global.sharedSpawns[newOwnerName] = global.sharedSpawns[prevOwnerName]
global.sharedSpawns[newOwnerName].openAccess = false
global.sharedSpawns[prevOwnerName] = nil
-- Transfer the unique spawn global
global.uniqueSpawns[newOwnerName] = global.uniqueSpawns[prevOwnerName]
global.uniqueSpawns[prevOwnerName] = nil
game.players[newOwnerName].print("You have been given ownership of this base!")
end
-- Returns the number of players currently online at the shared spawn
function GetOnlinePlayersAtSharedSpawn(ownerName)
if (global.sharedSpawns[ownerName] ~= nil) then
-- Does not count base owner
local count = 0
-- For each player in the shared spawn, check if online and add to count.
for _,player in pairs(game.connected_players) do
if (ownerName == player.name) then
count = count + 1
end
for _,playerName in pairs(global.sharedSpawns[ownerName].players) do
if (playerName == player.name) then
count = count + 1
end
end
end
return count
else
return 0
end
end
-- Get the number of currently available shared spawns
-- This means the base owner has enabled access AND the number of online players
-- is below the threshold.
function GetNumberOfAvailableSharedSpawns()
local count = 0
for ownerName,sharedSpawn in pairs(global.sharedSpawns) do
if (sharedSpawn.openAccess and
(game.players[ownerName] ~= nil) and
game.players[ownerName].connected) then
if ((global.ocfg.max_players_shared_spawn == 0) or
(#global.sharedSpawns[ownerName].players < global.ocfg.max_players_shared_spawn)) then
count = count+1
end
end
end
return count
end
-- Initializes the globals used to track the special spawn and player
-- status information
function InitSpawnGlobalsAndForces()
-- This contains each player's spawn point. Literally where they will respawn.
-- There is a way in game to change this under one of the little menu features I added.
if (global.playerSpawns == nil) then
global.playerSpawns = {}
end
-- This is the most important table. It is a list of all the unique spawn points.
-- This is what chunk generation checks against.
-- Each entry looks like this: {pos={x,y},moat=bool,vanilla=bool}
if (global.uniqueSpawns == nil) then
global.uniqueSpawns = {}
end
-- List of available vanilla spawns
if (global.vanillaSpawns == nil) then
global.vanillaSpawns = {}
end
-- This keeps a list of any player that has shared their base.
-- Each entry contains information about if it's open, spawn pos, and players in the group.
if (global.sharedSpawns == nil) then
global.sharedSpawns = {}
end
-- This seems to be unused right now, but I had plans to re-use spawn points in the past.
-- if (global.unusedSpawns == nil) then
-- global.unusedSpawns = {}
-- end
-- Each player has an option to change their respawn which has a cooldown when used.
-- Other similar abilities/functions that require cooldowns could be added here.
if (global.playerCooldowns == nil) then
global.playerCooldowns = {}
end
-- List of players in the "waiting room" for a buddy spawn.
-- They show up in the list to select when doing a buddy spawn.
if (global.waitingBuddies == nil) then
global.waitingBuddies = {}
end
-- Players who have made a spawn choice get put into this list while waiting.
-- An on_tick event checks when it expires and then places down the base resources, and teleports the player.
-- Go look at DelayedSpawnOnTick() for more info.
if (global.delayedSpawns == nil) then
global.delayedSpawns = {}
end
-- This is what I use to communicate a buddy spawn request between the buddies.
-- This contains information of who is asking, and what options were selected.
if (global.buddySpawnOptions == nil) then
global.buddySpawnOptions = {}
end
-- Silo info
if (global.siloPosition == nil) then
global.siloPosition = {}
end
-- Name a new force to be the default force.
-- This is what any new player is assigned to when they join, even before they spawn.
local main_force = CreateForce(global.ocfg.main_force)
main_force.set_spawn_position({x=0,y=0}, GAME_SURFACE_NAME)
end
function DoesPlayerHaveCustomSpawn(player)
for name,spawnPos in pairs(global.playerSpawns) do
if (player.name == name) then
return true
end
end
return false
end
function ChangePlayerSpawn(player, pos)
global.playerSpawns[player.name] = pos
global.playerCooldowns[player.name] = {setRespawn=game.tick}
end
function QueuePlayerForDelayedSpawn(playerName, spawn, moatEnabled, vanillaSpawn)
-- If we get a valid spawn point, setup the area
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(global.ocfg.spawn_config.gen_settings.land_area_tiles/CHUNK_SIZE))
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})
DisplayPleaseWaitForSpawnDialog(game.players[playerName], delay_spawn_seconds)
else
log("THIS SHOULD NOT EVER HAPPEN! Spawn failed!")
SendBroadcastMsg("ERROR!! Failed to create spawn point for: " .. playerName)
end
end
-- Check a table to see if there are any players waiting to spawn
-- Check if we are past the delayed tick count
-- Spawn the players and remove them from the table.
function DelayedSpawnOnTick()
if ((game.tick % (30)) == 1) then
if ((global.delayedSpawns ~= nil) and (#global.delayedSpawns > 0)) then
for i=#global.delayedSpawns,1,-1 do
delayedSpawn = global.delayedSpawns[i]
if (delayedSpawn.delayedTick < game.tick) then
-- TODO, add check here for if chunks around spawn are generated surface.is_chunk_generated(chunkPos)
if (game.players[delayedSpawn.playerName] ~= nil) then
SendPlayerToNewSpawnAndCreateIt(delayedSpawn)
end
table.remove(global.delayedSpawns, i)
end
end
end
end
end
function SendPlayerToNewSpawnAndCreateIt(delayedSpawn)
-- DOUBLE CHECK and make sure the area is super safe.
ClearNearbyEnemies(delayedSpawn.pos, global.ocfg.spawn_config.safe_area.safe_radius, game.surfaces[GAME_SURFACE_NAME])
if (not delayedSpawn.vanilla) then
-- Create the spawn resources here
local water_data = global.ocfg.spawn_config.water
CreateWaterStrip(game.surfaces[GAME_SURFACE_NAME],
{x=delayedSpawn.pos.x+water_data.x_offset, y=delayedSpawn.pos.y+water_data.y_offset},
water_data.length)
CreateWaterStrip(game.surfaces[GAME_SURFACE_NAME],
{x=delayedSpawn.pos.x+water_data.x_offset, y=delayedSpawn.pos.y+water_data.y_offset+1},
water_data.length)
GenerateStartingResources(game.surfaces[GAME_SURFACE_NAME], delayedSpawn.pos)
end
-- Send the player to that position
local player = game.players[delayedSpawn.playerName]
player.teleport(delayedSpawn.pos, GAME_SURFACE_NAME)
GivePlayerStarterItems(game.players[delayedSpawn.playerName])
-- Chart the area.
ChartArea(player.force, delayedSpawn.pos, math.ceil(global.ocfg.spawn_config.gen_settings.land_area_tiles/CHUNK_SIZE), player.surface)
if (player.gui.screen.wait_for_spawn_dialog ~= nil) then
player.gui.screen.wait_for_spawn_dialog.destroy()
end
end
function SendPlayerToSpawn(player)
if (DoesPlayerHaveCustomSpawn(player)) then
player.teleport(global.playerSpawns[player.name], GAME_SURFACE_NAME)
else
player.teleport(game.forces[global.ocfg.main_force].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME)
end
end
function SendPlayerToRandomSpawn(player)
local numSpawns = TableLength(global.uniqueSpawns)
local rndSpawn = math.random(0,numSpawns)
local counter = 0
if (rndSpawn == 0) then
player.teleport(game.forces[global.ocfg.main_force].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME)
else
counter = counter + 1
for name,spawn in pairs(global.uniqueSpawns) do
if (counter == rndSpawn) then
player.teleport(spawn.pos)
break
end
counter = counter + 1
end
end
end
function CreateForce(force_name)
local newForce = nil
-- Check if force already exists
if (game.forces[force_name] ~= nil) then
log("Force already exists!")
return game.forces[global.ocfg.main_force]
-- Create a new force
elseif (TableLength(game.forces) < MAX_FORCES) then
newForce = game.create_force(force_name)
if global.ocfg.enable_shared_team_vision then
newForce.share_chart = true
end
if global.ocfg.enable_research_queue then
newForce.research_queue_enabled = true
end
-- Chart silo areas if necessary
if global.ocfg.frontier_rocket_silo and global.ocfg.frontier_silo_vision then
ChartRocketSiloAreas(game.surfaces[GAME_SURFACE_NAME], newForce)
end
SetCeaseFireBetweenAllForces()
SetFriendlyBetweenAllForces()
newForce.friendly_fire=false
if (ENABLE_ANTI_GRIEFING) then
AntiGriefing(newForce)
end
if global.ocfg.lock_goodies_rocket_launch and not global.satellite_sent then
DisableTech(newForce, "atomic-bomb")
DisableTech(newForce, "power-armor-mk2")
DisableTech(newForce, "artillery")
end
else
log("TOO MANY FORCES!!! - CreateForce()")
end
return newForce
end
function CreatePlayerCustomForce(player)
local newForce = CreateForce(player.name)
player.force = newForce
if (newForce.name == player.name) then
SendBroadcastMsg(player.name.." has started their own team!")
else
player.print("Sorry, no new teams can be created. You were assigned to the default team instead.")
end
return newForce
end
-- Function to generate some map_gen_settings.starting_points
-- You should only use this at the start of the game really.
function CreateVanillaSpawns(count, spacing)
local points = {}
-- Get an ODD number from the square of the input count.
-- Always rounding up so we don't end up with less points that requested.
local sqrt_count = math.ceil(math.sqrt(count))
if (sqrt_count % 2 == 0) then
sqrt_count = sqrt_count + 1
end
-- Need to know how much to offset the grid.
local sqrt_half = math.floor((sqrt_count-1)/2)
if (sqrt_count < 1) then
log("CreateVanillaSpawns less than 1!!")
return
end
if (global.vanillaSpawns == nil) then
global.vanillaSpawns = {}
end
-- This should give me points centered around 0,0 I think.
for i=-sqrt_half,sqrt_half,1 do
for j=-sqrt_half,sqrt_half,1 do
if (i~=0 or j~=0) then -- EXCEPT don't put 0,0
table.insert(points, {x=i*spacing,y=j*spacing})
table.insert(global.vanillaSpawns, {x=i*spacing,y=j*spacing})
end
end
end
-- Do something with the return value.
return points
end
-- Useful when combined with something like CreateVanillaSpawns
-- Where it helps ensure ALL chunks generated use new map_gen_settings.
function DeleteAllChunksExceptCenter(surface)
-- Delete the starting chunks that make it into the game before settings are changed.
for chunk in surface.get_chunks() do
-- Don't delete the chunk that might contain players lol.
-- This is really only a problem for launching AS the host. Not headless
if ((chunk.x ~= 0) and (chunk.y ~= 0)) then
surface.delete_chunk({chunk.x, chunk.y})
end
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, CHECK_SPAWN_UNGENERATED_CHUNKS_RADIUS+15, 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 = new_distance
end
end
-- If it's not a valid spawn anymore, let's remove it.
else
log("Removing vanilla spawn due to chunks generated: x=" .. v.x .. ",y=" .. v.y)
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
log("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, CHECK_SPAWN_UNGENERATED_CHUNKS_RADIUS+15, surface) then
log("Removing vanilla spawn due to chunks generated: x=" .. v.x .. ",y=" .. v.y)
table.remove(global.vanillaSpawns, k)
end
end
end

2398
separate_spawns_guis.lua → lib/separate_spawns_guis.lua Executable file → Normal file

File diff suppressed because it is too large Load Diff

52
lib/tag.lua Normal file
View File

@ -0,0 +1,52 @@
-- tag.lua
-- Apr 2017
-- Allows adding play tags
-- Tag list
local roles = {
{display_name = "[Solo]"},
{display_name = "[Mining]"},
{display_name = "[Power]"},
{display_name = "[Oil]"},
{display_name = "[Smelt]"},
{display_name = "[Rail]"},
{display_name = "[Defense]"},
{display_name = "[Circuits]"},
{display_name = "[Science!]"},
{display_name = "[Logistics]"},
{display_name = "[Misc]"},
{display_name = "[Aliens]"},
{display_name = "[Rocket]"},
{display_name = "[AFK]"}}
function CreateTagGuiTab(tab_container, player)
for i,role in ipairs(roles) do
tab_container.add{type="button", caption=role.display_name, name=role.display_name}
end
if (player.admin) then
tab_container.add{type="button", caption="[Admin]", name="admin"}
tab_container.add{type="button", caption="[Moderator]", name="moderator"}
end
tab_container.add{type="button", caption="Clear", name="clear_btn"}
end
function TagGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local name = event.element.name
if (name == "clear_btn") then
player.tag = ""
return
end
for i,role in ipairs(roles) do
if (name == role.display_name) then
player.tag = role.display_name
elseif (name == "admin") then
player.tag = "[Admin]"
elseif (name == "moderator") then
player.tag = "[Moderator]"
end
end
end

1
lib/test_lib_file.lua Normal file
View File

@ -0,0 +1 @@
-- test_lib_file.lua

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 Oarcinae
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

113
locale/de/locale.cfg Normal file
View File

@ -0,0 +1,113 @@
oarc-spawn-time-warning-msg=Aufgrund der Funktionsweise dieses Szenarios kann es einige Zeit dauern, bis das Land um deinen neuen Spawn herum generiert wurde. Bitte warte 10-20 Sekunden, nachdem du deinen Spawn ausgewählt hast.
oarc-i-understand=Ich verstehe
oarc-spawn-options=Spawn Optionen
oarc-click-info-btn-help=Klick oben links auf die Schaltfläche INFO, um mehr über dieses Szenario zu erfahren! Dies ist deine einzige Chance, eine Spawn-Option zu wählen. Wähle sorgfältig...
oarc-vanilla-spawn=Vanilla Spawn
oarc-default-spawn-behavior=Dies ist das standardmäßige Spawn-Verhalten eines Vanilla-Spiels. Du trittst dem Standardteam in der Mitte der Karte bei.
oarc-join-main-team-radio=Dem Standardteam beitreten (gemeinsame Forschung)
oarc-create-own-team-radio=Erstelle dein eigenes Team (eigene Forschung)
oarc-moat-option=Umgib deinen Spawn mit einem Graben.
oarc-solo-spawn-near=Allein spawnen (nah)
oarc-solo-spawn-far=Allein spawnen (fern)
oarc-starting-area-vanilla=Du spawnst in deinem eigenen Startbereich (wie im Vanilla-Spiel).
oarc-vanilla-spawns-available=Es steht __1__ Vanilla-Spawn zur Verfügung.
oarc-starting-area-normal=Du spawnst in einem neuen Gebiet mit voreingestellten Startressourcen.
oarc-join-someone-avail=Jemandem beitreten (__1__ verfügbar)
oarc-join-someone-info=Du wirst in der Basis von jemand anderem spawnen. Dies erfordert, dass mindestens eine Person Zugang zu seiner Basis gewährt hat. Diese Wahl ist endgültig und du wirst später nicht mehr in der Lage sein, deinen eigenen Spawn zu erstellen.
oarc-no-shared-avail=Es gibt derzeit keine freigegebenen Basen, in denen man spawnen kann.
oarc-join-check-again=Erneut prüfen
oarc-shared-spawn-disabled=Gemeinsame Spawns sind in diesem Modus deaktiviert.
oarc-buddy-spawn=Buddy Spawn
oarc-buddy-spawn-info=Das Buddy-System erfordert 2 Spieler in diesem Menü gleichzeitig, sie spawnen nebeneinander, jeder mit seinen eigenen Ressourcen.
oarc-max-players-shared-spawn=Wenn du deinen eigenen Spawn-Punkt erstellst, kann bis zu __1__ anderer Online-Spieler teilnehmen.
oarc-spawn-dist-notes=Der nahe Spawn liegt zwischen __1__-__2__ Chunks von der Mitte der Karte entfernt.\nDer ferne Spawn liegt zwischen __3__-__4__ Chunks von der Mitte der Karte entfernt.\nAlleine Spawnen ist gefährlich! Du wirst kämpfen müssen, um andere Spieler erreichen zu können.
oarc-player-is-joining-main-force=__1__ tritt dem Standardteam bei!
oarc-player-is-joining-near=__1__ nimmt aus der Ferne am Spiel teil!
oarc-player-is-joining-far=__1__ nimmt aus großer Entfernung am Spiel teil!
oarc-please-wait=BITTE WARTE, BIS DEIN SPAWN-PUNKT GENERIERT IST!
oarc-looking-for-buddy=__1__ sucht nach einem Buddy.
oarc-avail-bases-join=Verfügbare Basen zum Beitreten:
oarc-spawn-spots-remaining=__1__ (__2__ verbleibende Plätze)
oarc-cancel-return-to-previous=Abbrechen (zurück zu den vorherigen Optionen)
oarc-player-requesting-join-you=__1__ bittet darum, deiner Basis beizutreten!
oarc-waiting-for-spawn-owner=Warte auf die Antwort des Spawn-Besitzers...
oarc-you-will-spawn-once-host=Du wirst spawnen, sobald der Host ja gewählt hat...
oarc-player-cancel-join-request=__1__ hat die Anfrage zum Beitritt zu deinem Spawn abgebrochen.
oarc-spawn-ctrl=Spawn-Einst.
oarc-spawn-controls=Spawn Einstellungen:
oarc-spawn-allow-joiners=Erlaube anderen, deiner Basis beizutreten.
oarc-set-respawn-loc=Setze neuen Spawn-Punkt (1 Stunde Abklingzeit)
oarc-set-respawn-loc-cooldown=Set Respawn Cooldown Remaining: __1__
oarc-set-respawn-note=Das setzt deinen Spawn-Punkt an deine aktuelle Position.
oarc-select-player-join-queue=Wähle einen Spieler aus der Beitrittswarteschlange aus:
oarc-accept=Akzeptieren
oarc-reject=Ablehnen
oarc-no-player-join-reqs=Du hast keine Anfragen von Spielern, deiner Base beizutreten.
oarc-start-shared-base=Neue Spieler können nun __1__'s Base beitreten!
oarc-stop-shared-base=Neue Spieler können nicht länger der Base von __1__ beitreten!
oarc-spawn-point-updated=Re-Spawn Punkt aktualisiert!
oarc-selected-player-not-wait=Der ausgewählte Spieler wartet nicht mehr auf den Beitritt!
oarc-reject-joiner=Du lehnst __1__'s Anfrage, deiner Base beizutreten, ab.
oarc-your-request-rejected=Deine Anfrage zum Beitritt wurde abgelehnt.
oarc-player-joining-base=__1__ trat der Base von __2__ bei!
oarc-player-left-while-joining=__1__ verließ das Spiel. Was für ein Arsch.
oarc-buddy-spawn-options=Buddy Spawn Optionen
oarc-buddy-spawn-instructions=Um dies zu nutzen, vergewissere dich, dass du und dein Buddy zur gleichen Zeit in diesem Menü sind. Nur einer von euch muss die Anfrage senden. Wähle deinen Buddy aus der Liste aus (aktualisiere, wenn der Name deines Buddys nicht sichtbar ist) und wähle deine Spawn-Optionen. Klicke auf eine der Schaltflächen für die Anforderung, um die Anforderung zu senden. Der andere Buddy kann dann die Anfrage annehmen (oder ablehnen). Dies ermöglicht es euch beiden, nebeneinander zu spawnen, jeder mit seinem eigenen Spawn-Bereich. Sobald ein Buddy eine Spawn-Anfrage annimmt, ist sie endgültig!
oarc-buddy-select-info=Wähle zunächst einen Buddy aus der Warteliste aus. Wähle dann die Spawn-Optionen aus und sende deine Anfrage:
oarc-buddy-refresh=Buddy-Liste aktualisieren
oarc-create-buddy-team=Erstelle dein eigenes Team (geteilte Entwicklung)
oarc-buddy-spawn-near=Erfrage Buddy-Spawn (nah)
oarc-buddy-spawn-far=Erfrage Buddy-Spawn (fern)
oarc-invalid-buddy=Du hast keinen gültigen Buddy ausgewählt, versuche es noch mal.
oarc-buddy-not-avail=Der ausgewählte Buddy ist nicht länger vefügbar, bitte versuche es erneut.
oarc-waiting-for-buddy=Warte auf die Antwort vom Buddy...
oarc-wait-buddy-select-yes=Du wirst spawnen, sobald dein Buddy ja gewählt hat...
oarc-buddy-cancel-request=__1__ brach die Buddy-Anfrage ab!
oarc-buddy-requesting-from-you=__1__ fordert einen Buddy Spawn von dir an!
oarc-buddy-txt-main-team=Das Standardteam
oarc-buddy-txt-new-teams=in getrennten Teams
oarc-buddy-txt-buddy-team=ein Buddy Team
oarc-buddy-txt-moat= umgeben von einem Graben
oarc-buddy-txt-near=in der Nähe der Mitte der Karte!
oarc-buddy-txt-far=weit weg von der Mitte der Karte!
oarc-buddy-txt-would-like= möchte teilnehmen
oarc-buddy-txt-next-to-you= neben dir
oarc-buddy-declined=__1__ hat deine Buddy-Anfrage abgelehnt!
oarc-spawn-wait=Bitte warte!
oarc-wait-text=Dein Spawn wird gerade erstellt. Du wirst in __1__ Sekunden dorthin teleportiert!\nHalte dich bereit...

113
locale/en/locale.cfg Normal file
View File

@ -0,0 +1,113 @@
oarc-spawn-time-warning-msg=Due to the way this scenario works, it may take some time for the land around your new spawn area to generate... Please wait for 10-20 seconds when you select your first spawn.
oarc-i-understand=I Understand
oarc-spawn-options=Spawn Options
oarc-click-info-btn-help=Click the INFO button in the top left to learn more about this scenario! This is your ONLY chance to choose a spawn option. Choose carefully...
oarc-vanilla-spawn=Vanilla Spawn
oarc-default-spawn-behavior=This is the default spawn behavior of a vanilla game. You join the default team in the center of the map.
oarc-join-main-team-radio=Join Main Team (shared research)
oarc-create-own-team-radio=Create Your Own Team (own research tree)
oarc-moat-option=Surround your spawn with a moat
oarc-solo-spawn-near=Solo Spawn (Near)
oarc-solo-spawn-far=Solo Spawn (Far)
oarc-starting-area-vanilla=You are spawned in your own starting area (vanilla style).
oarc-vanilla-spawns-available=There are __1__ vanilla spawns available.
oarc-starting-area-normal=You are spawned in a new area, with pre-set starting resources.
oarc-join-someone-avail=Join Someone (__1__ available)
oarc-join-someone-info=You are spawned in someone else's base. This requires at least 1 person to have allowed access to their base. This choice is final and you will not be able to create your own spawn later.
oarc-no-shared-avail=There are currently no shared bases availble to spawn at.
oarc-join-check-again=Check Again
oarc-shared-spawn-disabled=Shared spawns are disabled in this mode.
oarc-buddy-spawn=Buddy Spawn
oarc-buddy-spawn-info=The buddy system requires 2 players in this menu at the same time, you spawn beside each other, each with your own resources.
oarc-max-players-shared-spawn=If you create your own spawn point you can allow up to __1__ other online players to join.
oarc-spawn-dist-notes=Near spawn is between __1__-__2__ chunks away from the center of the map.\nFar spawn is between __3__-__4__ chunks away from the center of the map.\nSolo spawns are dangerous! Expect a fight to reach other players.
oarc-player-is-joining-main-force=__1__ is joining the main force!
oarc-player-is-joining-near=__1__ is joining the game from a distance!
oarc-player-is-joining-far=__1__ is joining the game from a great distance!
oarc-please-wait=PLEASE WAIT WHILE YOUR SPAWN POINT IS GENERATED!
oarc-looking-for-buddy=__1__ is looking for a buddy.
oarc-avail-bases-join=Available Bases to Join:
oarc-spawn-spots-remaining=__1__ (__2__ spots remaining)
oarc-cancel-return-to-previous=Cancel (Return to Previous Options)
oarc-player-requesting-join-you=__1__ is requesting to join your base!
oarc-waiting-for-spawn-owner=Waiting for spawn owner to respond...
oarc-you-will-spawn-once-host=You will spawn once the host selects yes...
oarc-player-cancel-join-request=__1__ cancelled their request to join your spawn.
oarc-spawn-ctrl=Spawn Ctrl
oarc-spawn-controls=Spawn Controls:
oarc-spawn-allow-joiners=Allow others to join your base.
oarc-set-respawn-loc=Set New Respawn Location (has a cooldown)
oarc-set-respawn-loc-cooldown=Set Respawn Cooldown Remaining: __1__
oarc-set-respawn-note=This will set your respawn point to your current location.
oarc-select-player-join-queue=Select a player from the join queue:
oarc-accept=Accept
oarc-reject=Reject
oarc-no-player-join-reqs=You have no players requesting to join you at this time.
oarc-start-shared-base=New players can now join __1__'s base!
oarc-stop-shared-base=New players can no longer join __1__'s base!
oarc-spawn-point-updated=Re-spawn point updated!
oarc-selected-player-not-wait=Selected player is no longer waiting to join!
oarc-reject-joiner=You rejected __1__'s request to join your base.
oarc-your-request-rejected=Your request to join was rejected.
oarc-player-joining-base=__1__ is joining __2__'s base!
oarc-player-left-while-joining=__1__ left the game. What an ass.
oarc-buddy-spawn-options=Buddy Spawn Options
oarc-buddy-spawn-instructions=To use this, make sure you and your buddy are in this menu at the same time. Only one of you must send the request. Select your buddy from the list (refresh if your buddy's name is not visible) and select your spawn options. Click one of the request buttons to send the request. The other buddy can then accept (or deny) the request. This will allow you both to spawn next to each other, each with your own spawn area. Once a buddy accepts a spawn request, it is final!
oarc-buddy-select-info=First, select a buddy from the waiting list. Then choose the spawn options and send your request:
oarc-buddy-refresh=Refresh Buddy List
oarc-create-buddy-team=Create Your Own Buddy Team (buddy and you share research)
oarc-buddy-spawn-near=Request Buddy Spawn (Near)
oarc-buddy-spawn-far=Request Buddy Spawn (Far)
oarc-invalid-buddy=You have not selected a valid buddy! Please try again.
oarc-buddy-not-avail=Selected buddy is no longer available! Please try again.
oarc-waiting-for-buddy=Waiting for buddy to respond...
oarc-wait-buddy-select-yes=You will spawn once your buddy selects yes...
oarc-buddy-cancel-request=__1__ cancelled their buddy request!
oarc-buddy-requesting-from-you=__1__ is requesting a buddy spawn from you!
oarc-buddy-txt-main-team=the main team
oarc-buddy-txt-new-teams=on separate teams
oarc-buddy-txt-buddy-team=a buddy team
oarc-buddy-txt-moat= surrounded by a moat
oarc-buddy-txt-near=near to the center of the map!
oarc-buddy-txt-far=far from the center of the map!
oarc-buddy-txt-would-like= would like to join
oarc-buddy-txt-next-to-you= next to you
oarc-buddy-declined=__1__ declined your buddy request!
oarc-spawn-wait=Please wait!
oarc-wait-text=Your spawn is being created now.\nYou will be teleported there in __1__ seconds!\nPlease standby...

113
locale/fr/locale.cfg Normal file
View File

@ -0,0 +1,113 @@
oarc-spawn-time-warning-msg=En raison de la manière de fonctionnement de ce scénario, la génération de votre base peut prendre un certain temps ... Veuillez patienter 10 à 20 secondes lorsque vous apparaissez.
oarc-i-understand=Je comprends
oarc-spawn-options=Options d'apparition
oarc-click-info-btn-help=Cliquez sur le bouton INFO en haut à gauche pour en savoir plus sur ce scénario! Ceci est votre SEULE chance de choisir une option de spawn. Choisissez soigneusement...
oarc-vanilla-spawn=Spawn vanillia
oarc-default-spawn-behavior=C’est le comportement par défaut du spawn d’un jeu vanillia. Vous rejoignez l'équipe par défaut au centre de la carte.
oarc-join-main-team-radio=Rejoindre l'équipe principale (recherche partagée)
oarc-create-own-team-radio=Créez votre propre équipe (propre arbre de recherche)
oarc-moat-option=Entourez votre base d'eau (fossé)
oarc-solo-spawn-near=Spawn solo (proche)
oarc-solo-spawn-far=Spawn solo (Loin)
oarc-starting-area-vanilla=Vous êtes apparu dans votre propre base (style vanilla).
oarc-vanilla-spawns-available=Il y a __1__ une base vanilla disponible.
oarc-starting-area-normal=Vous êtes apparu dans une nouvelle base, avec des ressources de départ prédéfinies.
oarc-join-someone-avail=Rejoindre quelqu'un (__1__ disponible)
oarc-join-someone-info=Vous rejoindrez la base de quelqu'un d'autre. Cela nécessite que au moins 1 personne autorise l'accès à leur base. Ce choix est définitif et vous ne pourrez pas créer votre propre zone plus tard.
oarc-no-shared-avail=Il n’existe actuellement aucune base partagée disponible.
oarc-join-check-again=Vérifier à nouveau
oarc-shared-spawn-disabled=Les spawns partagés sont désactivés dans ce mode.
oarc-buddy-spawn=Spawn avec un ami
oarc-buddy-spawn-info=Se système d'amis nécessite 2 joueurs dans ce menu en même temps, vous apparaissez côte à côte, chacun avec vos propres ressources.
oarc-max-players-shared-spawn=Si vous créez votre propre point d'apparition, vous pouvez autoriser jusqu'à __1__ autres joueurs en ligne à rejoindre.
oarc-spawn-dist-notes=Le point d’apparition (proche) se situe entre __1__-__2__ morceaux du centre de la carte. \nLe point d’apparition (loin) se situe entre __3__-__4__ morceaux du centre de la carte. \nLes apparitions solo sont dangereuses! Attendez-vous à un combat pour atteindre d'autres joueurs.
oarc-player-is-joining-main-force=__1__ rejoint l'équipe principale'!
oarc-player-is-joining-near=__1__ rejoint le jeu à distance!
oarc-player-is-joining-far=__1__ rejoint le jeu avec une grande distance!
oarc-please-wait=VEUILLEZ ATTENDRE QUE VOTRE POINT D'APPARITION SOIT GÉNÉRÉ!
oarc-looking-for-buddy=__1__ est à la recherche d'un copain.
oarc-avail-bases-join=Bases disponibles à rejoindre:
oarc-spawn-spots-remaining=__1__ (__2__ places restantes)
oarc-cancel-return-to-previous=Annuler (retourner aux options précédentes)
oarc-player-requesting-join-you=__1__ demande à rejoindre votre base!
oarc-waiting-for-spawn-owner=Attendez que le propriétaire de la base réponde ...
oarc-you-will-spawn-once-host=Vous apparaîtrez une fois que l'hôte aura choisi oui ...
oarc-player-cancel-join-request=__1__ a annulé sa demande pour rejoindre votre base.
oarc-spawn-ctrl=Spawn Ctrl
oarc-spawn-controls=Contrôle d'apparition':
oarc-spawn-allow-joiners=Autoriser les autres à rejoindre votre base.
oarc-set-respawn-loc=Définir le nouvel emplacement de réapparition (il y a une heure d'attente pour réutiliser ce boutton)
oarc-set-respawn-loc-cooldown=Définir le temps d'attente pour réapparaître restant: __1__
oarc-set-respawn-note=Cela va définir votre point de réapparition à votre position actuelle.
oarc-select-player-join-queue=Sélectionnez un joueur dans la file d'attente:
oarc-accept=Accepter
oarc-reject=Rejeter
oarc-no-player-join-reqs=Vous n'avez aucun joueur demandant à vous rejoindre pour le moment.
oarc-start-shared-base=Les nouveaux joueurs peuvent maintenant rejoindre la base de __1__!
oarc-stop-shared-base=Les nouveaux joueurs ne peuvent plus rejoindre la base de __1__!
oarc-spawn-point-updated=Point de réapparition mis à jour!
oarc-selected-player-not-wait=Le joueur sélectionné n'attend plus de rejoindre!
oarc-reject-joiner=Vous avez rejeté la demande de __1__ pour rejoindre votre base.
oarc-your-request-rejected=Votre demande d'adhésion a été rejetée.
oarc-player-joining-base=__1__ à rejoint la base de __2__!
oarc-player-left-while-joining=__1__ a quitté le match. Quel âne.
oarc-buddy-spawn-options=Options d'apparition du menu (Spawn avec un ami)
oarc-buddy-spawn-instructions=Pour utiliser ceci, assurez-vous que votre ami et vous êtes dans ce menu en même temps. Un seul d'entre vous doit envoyer la demande. Sélectionnez votre ami dans la liste (actualisez-la si son nom n'est pas visible) et sélectionnez vos options d'apparition. Cliquez sur l'un des boutons de requête pour envoyer la requête. L'autre copain peut alors accepter (ou refuser) la demande. Cela vous permettra à tous les deux d'apparaître côte à côte, chacun avec votre propre base. Une fois que votre copain aura accepté une demande de spawn, c'est définitif!
oarc-buddy-select-info=D'abord, sélectionnez un ami dans la liste d'attente. Puis choisissez les options de spawn et envoyez votre demande:
oarc-buddy-refresh=Actualiser la liste d'amis
oarc-create-buddy-team=Créez votre propre équipe d'amis (vous et votre ami partagez la recherche)
oarc-buddy-spawn-near=Demander la création de la base (proche)
oarc-buddy-spawn-far=Demander la création de la base (loin)
oarc-invalid-buddy=Vous n'avez pas sélectionné de partenaire valide! Veuillez réessayer.
oarc-buddy-not-avail=Le copain sélectionné n'est plus disponible! Veuillez réessayer.
oarc-waiting-for-buddy=Attendez que votre ami réponde ...
oarc-wait-buddy-select-yes=Vous apparaîtrez une fois que votre ami aura choisi oui ...
oarc-buddy-cancel-request=__1__ a annulé sa demande!
oarc-buddy-requesting-from-you=__1__ vous demande a appraître avec lui!
oarc-buddy-txt-main-team=l'équipe principale
oarc-buddy-txt-new-teams=sur des équipes séparées
oarc-buddy-txt-buddy-team=une équipe de amis
oarc-buddy-txt-moat=entouré d'eau (fossé)
oarc-buddy-txt-near=proche du centre de la carte!
oarc-buddy-txt-far=loin du centre de la carte!
oarc-buddy-txt-would-like=aimerait rejoindre
oarc-buddy-txt-next-to-you=à côté de toi
oarc-buddy-declined=__1__ a refusé votre demande d'ami!
oarc-spawn-wait=Patienter s'il vous plaît!
oarc-wait-text=Votre spawn est en cours de création. \nVous serez téléporté dans __1__ secondes! \nVeuillez patienter ...

View File

@ -1,145 +0,0 @@
-- game_opts.lua
-- Jan 2018
-- Display current game options, maybe have some admin controls here
-- Main Configuration File
require("config")
require("locale/oarc_utils")
function CreateGameOptionsGui(event)
local player = game.players[event.player_index]
if player.gui.top.game_options == nil then
player.gui.top.add{name="game_options", type="button", caption="Info"}
end
end
local function ExpandGameOptionsGui(player)
local frame = player.gui.left["game_options_panel"]
if (frame) then
frame.destroy()
else
local frame = player.gui.left.add{type="frame",
name="game_options_panel",
caption="Server Info:",
direction="vertical"}
-- General Server Info:
AddLabel(frame, "info_1", global.welcome_msg, my_longer_label_style)
AddLabel(frame, "info_2", SERVER_MSG, my_longer_label_style)
AddSpacer(frame, "info_spacer1")
-- Enemy Settings:
local enemy_expansion_txt = "disabled"
if game.map_settings.enemy_expansion.enabled then enemy_expansion_txt = "enabled" end
local enemy_text="Server Run Time: " .. formattime_hours_mins(game.tick) .. "\n" ..
"Current Evolution: " .. string.format("%.4f", game.forces["enemy"].evolution_factor) .. "\n" ..
"Enemy evolution time factor: " .. game.map_settings.enemy_evolution.time_factor .. "\n" ..
"Enemy evolution pollution factor: " .. game.map_settings.enemy_evolution.pollution_factor .. "\n" ..
"Enemy evolution destroy factor: " .. game.map_settings.enemy_evolution.destroy_factor .. "\n" ..
"Enemy expansion is " .. enemy_expansion_txt
AddLabel(frame, "enemy_info", enemy_text, my_longer_label_style)
AddSpacer(frame, "enemy_info_spacer1")
-- Game Mode:
AddLabel(frame, "core_mod_en", "Core game mode (separate spawns) is enabled.", my_longer_label_style)
if (not ENABLE_SEPARATE_SPAWNS) then
frame.core_mod_en.caption="Core game mode (separate spawns) is DISABLED."
frame.core_mod_en.style.font_color=my_color_red
end
-- Soft Mods:
local soft_mods_string = "Oarc Core"
if (not ENABLE_SEPARATE_SPAWNS) then
soft_mods_string = "Oarc Core [DISABLED!]"
end
if (ENABLE_RSO) then
soft_mods_string = soft_mods_string .. ", RSO"
end
if (ENABLE_UNDECORATOR) then
soft_mods_string = soft_mods_string .. ", Undecorator"
end
if (ENABLE_TAGS) then
soft_mods_string = soft_mods_string .. ", Tags"
end
if (ENABLE_LONGREACH) then
soft_mods_string = soft_mods_string .. ", Long Reach"
end
if (ENABLE_AUTOFILL) then
soft_mods_string = soft_mods_string .. ", Auto Fill"
end
if (ENABLE_PLAYER_LIST) then
soft_mods_string = soft_mods_string .. ", Player List"
end
local game_info_str = "Soft Mods Enabled: " .. soft_mods_string
-- Spawn options:
if (ENABLE_SEPARATE_TEAMS) then
game_info_str = game_info_str.."\n".."You are allowed to spawn on your own team (have your own research tree). All teams are friendly!"
end
if (ENABLE_BUDDY_SPAWN) then
game_info_str = game_info_str.."\n".."You can chose to spawn alongside a buddy if you spawn together at the same time."
end
if (ENABLE_SHARED_SPAWNS) then
game_info_str = game_info_str.."\n".."Spawn hosts may choose to share their spawn and allow other players to join them."
end
if (ENABLE_SEPARATE_TEAMS and ENABLE_SHARED_TEAM_VISION) then
game_info_str = game_info_str.."\n".."Everyone (all teams) have shared vision."
end
if (FRONTIER_ROCKET_SILO_MODE) then
game_info_str = game_info_str.."\n".."Silos are NOT craftable. There is at least one already located on the map."
end
if (ENABLE_REGROWTH) then
game_info_str = game_info_str.."\n".."Old parts of the map will slowly be deleted over time (chunks without any player buildings)."
end
if (ENABLE_POWER_ARMOR_QUICK_START) then
game_info_str = game_info_str.."\n".."Power armor quick start enabled."
end
AddLabel(frame, "game_info_label", game_info_str, my_longer_label_style)
if (ENABLE_ABANDONED_BASE_REMOVAL) then
AddLabel(frame, "leave_warning_msg", "If you leave within " .. MIN_ONLINE_TIME_IN_MINUTES .. " minutes of joining, your base and character will be deleted.", my_longer_label_style)
frame.leave_warning_msg.style.font_color=my_color_red
end
-- Ending Spacer
AddSpacer(frame, "end_spacer")
-- ADMIN CONTROLS
if (player.admin) then
player_list = {}
for _,player in pairs(game.connected_players) do
table.insert(player_list, player.name)
end
frame.add{name = "ban_players_dropdown",
type = "drop-down",
items = player_list}
frame.add{name="ban_player", type="button", caption="Ban Player"}
end
end
end
function GameOptionsGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local name = event.element.name
if (name == "game_options") then
ExpandGameOptionsGui(player)
end
if (name == "ban_player") then
banIndex = event.element.parent.ban_players_dropdown.selected_index
if (banIndex ~= 0) then
banPlayer = event.element.parent.ban_players_dropdown.get_item(banIndex)
if (game.players[banPlayer]) then
game.ban_player(banPlayer, "Banned for griefing - Banned from admin panel.")
DebugPrint("Banning " .. banPlayer)
end
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -1,104 +0,0 @@
--[[--
Metaball implementation for LUA by Dark
For bruteforce usage, nor efficient nor fast
Force scales to from inf to 1 at R
--]]--
local _M = {}
local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
local abs = math.abs
local zero_value = 0x80000000
--Classic ball
local MetaBall = {x=0, y=0, radius=0, goo=1, type="MetaBall"}
MetaBall.__index = MetaBall
_M.MetaBall=MetaBall
function MetaBall:new(x, y, radius, goo)
goo = goo or 1
return setmetatable({x=x, y=y, radius=radius, goo=goo}, MetaBall)
end
function MetaBall:force(x, y)
--Calculate force at point x y
local force = sqrt( (x - self.x)^2 + (y - self.y)^2 )
if force == 0 then return zero_value end
return (self.radius / force)^self.goo
end
--Ellipse
local MetaEllipse = {x=0, y=0, radius=0, angle=0, x_scale=1, y_scale=1, type="MetaEllipse"}
MetaEllipse.__index = MetaEllipse
_M.MetaEllipse=MetaEllipse
function MetaEllipse:new(x, y, radius, angle, x_scale, y_scale, goo)
angle = angle or 0
x_scale = x_scale or 1
y_scale = y_scale or 1
goo = goo or 1
cosa = cos(angle)
sina = sin(angle)
return setmetatable({x=x, y=y, radius=radius, angle=angle, x_scale=x_scale, y_scale=y_scale, goo=goo, cosa=cosa, sina=sina}, MetaEllipse)
end
function MetaEllipse:force(x, y)
--Calculate force at point x y
local force = sqrt( (( (x - self.x)*self.cosa + (y - self.y)*self.sina )^2)/(self.x_scale) +
(( (y - self.y)*self.cosa - (x - self.x)*self.sina )^2)/(self.y_scale) )
if force == 0 then return zero_value end
return (self.radius / force)^self.goo
end
--SquareBalls
local MetaSquare = {x=0, y=0, radius=0, angle=0, x_scale=1, y_scale=1, type="MetaSquare"}
MetaSquare.__index = MetaSquare
_M.MetaSquare=MetaSquare
function MetaSquare:new(x, y, radius, angle, x_scale, y_scale, goo)
angle = angle or 0
x_scale = x_scale or 1
y_scale = y_scale or 1
goo = goo or 1
cosa = cos(angle)
sina = sin(angle)
return setmetatable({x=x, y=y, radius=radius, angle=angle, x_scale=x_scale, y_scale=y_scale, goo=goo, cosa=cosa, sina=sina}, MetaSquare)
end
function MetaSquare:force(x, y)
--Calculate force at point x y
local force = ( abs( (x - self.x)*self.cosa + (y - self.y)*self.sina )/self.x_scale +
abs( (y - self.y)*self.cosa - (x - self.x)*self.sina )/self.y_scale )
if force == 0 then return zero_value end
return (self.radius / force)^self.goo
end
--Donuts
local MetaDonut = {x=0, y=0, radius=0, angle=0, x_scale=1, y_scale=1, type="MetaDonut"}
MetaDonut.__index = MetaDonut
_M.MetaDonut=MetaDonut
function MetaDonut:new(x, y, out_r, int_r, angle, x_scale, y_scale, goo)
angle = angle or 0
x_scale = x_scale or 1
y_scale = y_scale or 1
goo = goo or 1
cosa = cos(angle)
sina = sin(angle)
if int_r >= out_r then error("int_r >= out_r ("..int_r.." > "..out_r); return; end
local radius = out_r--(out_r - int_r)*0.5
local radius2 = int_r--(radius2 + radius)*0.5
return setmetatable({x=x, y=y, radius=radius, radius2=radius2, x_scale=x_scale, y_scale=y_scale, goo=goo, cosa=cosa, sina=sina}, MetaDonut)
end
function MetaDonut:force(x, y)
--Calculate force at point x y
local force = abs(self.radius - sqrt( (( (x - self.x)*self.cosa + (y - self.y)*self.sina )^2)/(self.x_scale) +
(( (y - self.y)*self.cosa - (x - self.x)*self.sina )^2)/(self.y_scale) ))
if force == 0 then return zero_value end
return (self.radius2 / force)^self.goo
end
return _M

View File

@ -1,49 +0,0 @@
require("locale/rso/rso_config")
function add_peak(ent, peak)
if ent and ent.autoplace then
ent.autoplace.peaks[#ent.autoplace.peaks+1] = peak
end
end
function change_ocataves(autoplace, octaves)
for k,v in pairs(autoplace.peaks) do
if v.noise_layer then
v.noise_octaves_difference = (v.noise_octaves_difference or 0) + octaves
end
end
end
function generate_basic_peaks(noise_layer)
return {
{
influence = 0.1
},
{
influence = 0.67,
noise_layer = noise_layer,
noise_octaves_difference = -2.7,
noise_persistence = 0.3
}
}
end
function resetRichness(ent)
if ent and ent.autoplace then
ent.autoplace.richness_multiplier = 0
ent.autoplace.richness_base = 0
end
end
function removeAutoplace(ent)
if ent then
ent.autoplace = nil
end
end
function removePeaks(ent)
if ent and ent.autoplace then
ent.autoplace.peaks = {}
end
end

View File

@ -1,57 +0,0 @@
debug_enabled = false
region_size = 10 -- alternative mean to control how further away resources would be, default - 256 tiles or 8 chunks
-- each region is region_size*region_size chunks
-- each chunk is 32*32 tiles
use_donut_shapes = false -- setting this to false will remove donuts from possible resource layouts
starting_area_size = 1 -- starting area in regions, safe from random nonsense
absolute_resource_chance = 0.40 -- chance to spawn an resource in a region
starting_richness_mult = 1 -- multiply starting area richness for resources
global_richness_mult = 1 -- multiply richness for all resources except starting area
global_size_mult = 1 -- multiply size for all ores, doesn't affect starting area
absolute_enemy_chance = 3 -- chance to spawn enemies per sector (can be more then one base if spawned)
enemy_base_size_multiplier = 1 -- all base sizes will be multiplied by this - larger number means bigger bases
multi_resource_active = false -- global switch for multi resource chances
multi_resource_richness_factor = 0.60 -- any additional resource is multiplied by this value times resources-1
multi_resource_size_factor = 0.90
multi_resource_chance_diminish = 0.6 -- diminishing effect factor on multi_resource_chance
min_amount=250 -- default value for minimum amount of resource in single pile
richness_distance_factor= 0.8 -- exponent for richness distance factor calculation
fluid_richness_distance_factor = 0.8 -- exponent for richness distance factor calculation for fluids
size_distance_factor=0.3 -- exponent for size distance factor calculation
deterministic = true -- set to false to use system for all decisions math.random
-- mode is no longer used by generation process - it autodetects endless resources
-- endless_resource_mode = false -- if true, the size of each resource is modified by the following modifier. Use with the endless resources mod.
endless_resource_mode_sizeModifier = 0.80
-- This setting isn't used anywhere in the soft mod version of RSO -- OARC
-- Just set it from Oarc's config.lua (look for ENEMY_EXPANSION)
-- disableEnemyExpansion = false -- allows for disabling of in-game biter base building
use_RSO_biter_spawning = true -- enables spawning of biters controlled by RSO mod - less enemies around with more space between bases
use_vanilla_biter_spawning = false -- enables using of vanilla spawning
biter_ratio_segment=3 --the ratio components determining how many biters to spitters will be spawned
spitter_ratio_segment=1 --eg. 1 and 1 -> equal number of biters and spitters, 10 and 1 -> 10 times as many biters to spitters
useEnemiesInPeaceMod = false -- additional override for peace mod detection - when set to true it will spawn enemies normally, needs to have enemies enabled in peace mod
-- Always leave this setting to true in this soft mod scenario version! -- OARC
ignoreMapGenSettings = true -- stops the default behaviour of reading map gen settings
--
useResourceCollisionDetection = true -- enables avoidace calculations to reduce ores overlaping of each other
resourceCollisionDetectionRatio = 0.999 -- threshold to exit placement early
resourceCollisionDetectionRatioFallback = 0.75 -- at least this much of ore field needs to be placable to spawn it
resourceCollisionFieldSkip = true -- determines if ore field should be skipped completely if placement based on ratio failed
remove_trees = false
reveal_spawn_resources = false

File diff suppressed because it is too large Load Diff

View File

@ -1,171 +0,0 @@
local function fillVanillaConfig()
config["iron-ore"] = {
type="resource-ore",
-- general spawn params
allotment=90, -- how common resource is
spawns_per_region={min=1, max=1}, --number of chunks
richness=20000, -- resource_ore has only one richness value - resource-liquid has min/max
size={min=15, max=25}, -- rough radius of area, too high value can produce square shaped areas
min_amount=350,
-- resource provided at starting location
-- probability: 1 = 100% chance to be in starting area
-- 0 = resource is not in starting area
starting={richness=8000, size=25, probability=1},
multi_resource_chance=0.20, -- absolute value
multi_resource={
["iron-ore"] = 2, -- ["resource_name"] = allotment
['copper-ore'] = 4,
["coal"] = 4,
["stone"] = 4,
}
}
config["copper-ore"] = {
type="resource-ore",
allotment=80,
spawns_per_region={min=1, max=1},
richness=20000,
size={min=15, max=25},
min_amount=350,
starting={richness=6000, size=25, probability=1},
multi_resource_chance=0.20,
multi_resource={
["iron-ore"] = 4,
['copper-ore'] = 2,
["coal"] = 4,
["stone"] = 4,
}
}
config["coal"] = {
type="resource-ore",
allotment=80,
spawns_per_region={min=1, max=1},
size={min=15, max=25},
richness=16000,
min_amount=350,
starting={richness=6000, size=20, probability=1},
multi_resource_chance=0.30,
multi_resource={
["crude-oil"] = 1,
["iron-ore"] = 3,
['copper-ore'] = 3,
}
}
config["stone"] = {
type="resource-ore",
allotment=60,
spawns_per_region={min=1, max=1},
richness=12000,
size={min=15, max=20},
min_amount=250,
starting={richness=5000, size=16, probability=1},
multi_resource_chance=0.30,
multi_resource={
["coal"] = 4,
["iron-ore"] = 3,
['copper-ore'] = 3,
}
}
config["uranium-ore"] = {
type="resource-ore",
allotment=50,
spawns_per_region={min=1, max=1},
richness=10000,
size={min=15, max=20},
min_amount=500,
starting={richness=2000, size=10, probability=1},
}
config["crude-oil"] = {
type="resource-liquid",
minimum_amount=10000,
allotment=70,
spawns_per_region={min=1, max=1},
richness={min=400000, max=1000000}, -- richness per resource spawn
size={min=3, max=7},
starting={richness=400000, size=2, probability=1},
multi_resource_chance=0.20,
multi_resource={
["coal"] = 4,
}
}
end
local function fillEnemies()
config["enemy-base"] = {
type="entity",
force="enemy",
clear_range = {6, 6},
spawns_per_region={min=2,max=4},
size={min=2,max=4},
size_per_region_factor=0.3,
richness=3,
absolute_probability=absolute_enemy_chance, -- chance to spawn in region
probability_distance_factor=1.1, -- relative increase per region
max_probability_distance_factor=3, -- absolute value
along_resource_probability=0.20, -- chance to spawn in resource chunk anyway, absolute value. Can happen once per resource.
sub_spawn_probability=0.1, -- chance for this entity to spawn anything from sub_spawns table, absolute value
sub_spawn_size={min=1, max=2}, -- in same chunk
sub_spawn_distance_factor=1.01,
sub_spawn_max_distance_factor=1.5,
sub_spawns={
["small-worm-turret"]={
min_distance=0,
allotment=200,
allotment_distance_factor=0.99,
clear_range = {2, 2},
},
["medium-worm-turret"]={
min_distance=10,
allotment=100,
allotment_distance_factor=1.01,
clear_range = {2, 2},
},
["big-worm-turret"]={
min_distance=20,
allotment=100,
allotment_distance_factor=1.015,
clear_range = {2, 2},
}
}
}
end
function loadResourceConfig()
config={}
fillVanillaConfig()
fillEnemies()
return config
end

View File

@ -1,61 +0,0 @@
-- tag.lua
-- Apr 2017
-- Allows adding play tags
function CreateTagGui(event)
local player = game.players[event.player_index]
if player.gui.top.tag == nil then
player.gui.top.add{name="tag", type="button", caption="Tag"}
end
end
-- Tag list
local roles = {
{display_name = "[Solo]"},
{display_name = "[Mining]"},
{display_name = "[Power]"},
{display_name = "[Oil]"},
{display_name = "[Smelt]"},
{display_name = "[Rail]"},
{display_name = "[Defense]"},
{display_name = "[Circuits]"},
{display_name = "[Science!]"},
{display_name = "[Logistics]"},
{display_name = "[Misc]"},
{display_name = "[Aliens]"},
{display_name = "[Rocket]"},
{display_name = "[AFK]"},
{display_name = "Clear"}}
local function ExpandTagGui(player)
local frame = player.gui.left["tag-panel"]
if (frame) then
frame.destroy()
else
local frame = player.gui.left.add{type="frame", name="tag-panel", caption="What are you doing:"}
for _, role in pairs(roles) do
frame.add{type="button", caption=role.display_name, name=role.display_name}
end
end
end
function TagGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local name = event.element.name
if (name == "tag") then
ExpandTagGui(player)
end
if (name == "Clear") then
player.tag = ""
return
end
for _, role in pairs(roles) do
if (name == role.display_name) then
player.tag = role.display_name
end
end
end

View File

@ -1,349 +0,0 @@
-- regrowth_map.lua
-- July 2017
--
-- Code tracks all chunks generated and allows for deleting inactive chunks
-- Relies on some changes to RSO to provide random resource locations the next
-- time the land is regenerated. -- (THIS IS CURRENTLY NOT WORKING IN 0.16,
-- resources always how up in the same spot!)
--
-- Basic rules of regrowth:
-- 1. Area around player is safe for quite a large distance.
-- 2. Rocket silo won't be deleted. - PERMANENT
-- 3. Chunks with pollution won't be deleted.
-- 4. Chunks with railways won't be deleted.
-- 5. Anything within radar range won't be deleted, but radar MUST be active.
-- -- This works by refreshing all chunk timers within radar range using
-- the on_sector_scanned event.
-- 6. Chunks timeout after 1 hour-ish, configurable
-- 7. For now, oarc spawns are deletion safe as well, but only immediate area.
-- Generic Utility Includes
require("locale/oarc_utils")
-- Default timeout of generated chunks
REGROWTH_TIMEOUT_TICKS = TICKS_PER_HOUR
-- We can't delete chunks regularly without causing lag.
-- So we should save them up to delete them.
REGROWTH_CLEANING_INTERVAL_TICKS = REGROWTH_TIMEOUT_TICKS
-- Not used right now.
-- It takes a radar 7 hours and 20 minutes to scan it's whole area completely
-- So I will bump the refresh time of blocks up by 8 hours
-- RADAR_COMPLETE_SCAN_TICKS = TICKS_PER_HOUR*8
-- Additional bonus time for certain things:
-- REFRESH_BONUS_RADAR = RADAR_COMPLETE_SCAN_TICKS
-- Init globals and set player join area to be off limits.
function OarcRegrowthInit()
global.chunk_regrow = {}
global.chunk_regrow.map = {}
global.chunk_regrow.removal_list = {}
global.chunk_regrow.rso_region_roll_counter = 0
global.chunk_regrow.player_refresh_index = 1
global.chunk_regrow.min_x = 0
global.chunk_regrow.max_x = 0
global.chunk_regrow.x_index = 0
global.chunk_regrow.min_y = 0
global.chunk_regrow.max_y = 0
global.chunk_regrow.y_index = 0
global.chunk_regrow.force_removal_flag = -1000
OarcRegrowthOffLimits({x=0,y=0}, 10)
end
function GetChunkTopLeft(pos)
return {x=pos.x-(pos.x % 32), y=pos.y-(pos.y % 32)}
end
function GetChunkCoordsFromPos(pos)
return {x=math.floor(pos.x/32), y=math.floor(pos.y/32)}
end
-- This complicated function checks that if a chunk
function CheckChunkEmpty(pos)
chunkPos = GetChunkCoordsFromPos(pos)
search_top_left = {x=chunkPos.x*32, y=chunkPos.y*32}
search_area = {search_top_left, {x=search_top_left.x+32,y=search_top_left.y+32}}
total = 0
for f,_ in pairs(game.forces) do
if f ~= "neutral" and f ~= "enemy" then
entities = game.surfaces[GAME_SURFACE_NAME].find_entities_filtered{area = search_area, force=f}
total = total + #entities
if (#entities > 0) then
for _,e in pairs(entities) do
if ((e.type == "player") or
(e.type == "car") or
(e.type == "logistic-robot") or
(e.type == "construction-robot")) then
total = total - 1
end
end
end
end
end
-- A destroyed entity is still found during the event check.
return (total == 1)
end
-- game.surfaces[GAME_SURFACE_NAME].find_entities_filtered{area = {game.player.position, {game.player.position.x+32, game.player.position-`32}}, type= "resource"}
-- If an entity is mined or destroyed, then check if the chunk
-- is empty. If it's empty, reset the refresh timer.
function OarcRegrowthCheckChunkEmpty(event)
if ((event.entity.force ~= nil) and (event.entity.force ~= "neutral") and (event.entity.force ~= "enemy")) then
if CheckChunkEmpty(event.entity.position) then
DebugPrint("Resetting chunk timer."..event.entity.position.x.." "..event.entity.position.y)
OarcRegrowthForceRefreshChunk(event.entity.position, 0)
end
end
end
-- Adds new chunks to the global table to track them.
-- This should always be called first in the chunk generate sequence
-- (Compared to other RSO & Oarc related functions...)
function OarcRegrowthChunkGenerate(pos)
c_pos = GetChunkCoordsFromPos(pos)
-- If this is the first chunk in that row:
if (global.chunk_regrow.map[c_pos.x] == nil) then
global.chunk_regrow.map[c_pos.x] = {}
end
-- Confirm the chunk doesn't already have a value set:
if (global.chunk_regrow.map[c_pos.x][c_pos.y] == nil) then
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick
end
-- Store min/max values for x/y dimensions:
if (c_pos.x < global.chunk_regrow.min_x) then
global.chunk_regrow.min_x = c_pos.x
end
if (c_pos.x > global.chunk_regrow.max_x) then
global.chunk_regrow.max_x = c_pos.x
end
if (c_pos.y < global.chunk_regrow.min_y) then
global.chunk_regrow.min_y = c_pos.y
end
if (c_pos.y > global.chunk_regrow.max_y) then
global.chunk_regrow.max_y = c_pos.y
end
end
-- Mark an area for immediate forced removal
function OarcRegrowthMarkForRemoval(pos, chunk_radius)
local c_pos = GetChunkCoordsFromPos(pos)
for i=-chunk_radius,chunk_radius do
for k=-chunk_radius,chunk_radius do
local x = c_pos.x+i
local y = c_pos.y+k
if (global.chunk_regrow.map[x] == nil) then
global.chunk_regrow.map[x] = {}
end
global.chunk_regrow.map[x][y] = nil
table.insert(global.chunk_regrow.removal_list, {x=x,y=y})
end
end
end
-- Marks a chunk a position that won't ever be deleted.
function OarcRegrowthOffLimitsChunk(pos)
local c_pos = GetChunkCoordsFromPos(pos)
if (global.chunk_regrow.map[c_pos.x] == nil) then
global.chunk_regrow.map[c_pos.y] = {}
end
global.chunk_regrow.map[c_pos.x][c_pos.y] = -1
end
-- Marks a safe area around a position that won't ever be deleted.
function OarcRegrowthOffLimits(pos, chunk_radius)
local c_pos = GetChunkCoordsFromPos(pos)
for i=-chunk_radius,chunk_radius do
for k=-chunk_radius,chunk_radius do
local x = c_pos.x+i
local y = c_pos.y+k
if (global.chunk_regrow.map[x] == nil) then
global.chunk_regrow.map[x] = {}
end
global.chunk_regrow.map[x][y] = -1
end
end
end
-- Refreshes timers on a chunk containing position
function OarcRegrowthRefreshChunk(pos, bonus_time)
local c_pos = GetChunkCoordsFromPos(pos)
if (global.chunk_regrow.map[c_pos.x] == nil) then
global.chunk_regrow.map[c_pos.y] = {}
end
if (global.chunk_regrow.map[c_pos.x][c_pos.y] ~= -1) then
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick + bonus_time
end
end
-- Forcefully refreshes timers on a chunk containing position
-- Will overwrite -1 flag.
function OarcRegrowthForceRefreshChunk(pos, bonus_time)
local c_pos = GetChunkCoordsFromPos(pos)
if (global.chunk_regrow.map[c_pos.x] == nil) then
global.chunk_regrow.map[c_pos.y] = {}
end
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick + bonus_time
end
-- Refreshes timers on all chunks around a certain area
function OarcRegrowthRefreshArea(pos, chunk_radius, bonus_time)
local c_pos = GetChunkCoordsFromPos(pos)
for i=-chunk_radius,chunk_radius do
for k=-chunk_radius,chunk_radius do
local x = c_pos.x+i
local y = c_pos.y+k
if (global.chunk_regrow.map[x] == nil) then
global.chunk_regrow.map[x] = {}
end
if (global.chunk_regrow.map[x][y] ~= -1) then
global.chunk_regrow.map[x][y] = game.tick + bonus_time
end
end
end
end
-- Refreshes timers on all chunks near an ACTIVE radar
function OarcRegrowthSectorScan(event)
OarcRegrowthRefreshArea(event.radar.position, 14, 0)
OarcRegrowthRefreshChunk(event.chunk_position, 0)
end
-- Refresh all chunks near a single player. Cyles through all connected players.
function OarcRegrowthRefreshPlayerArea()
global.chunk_regrow.player_refresh_index = global.chunk_regrow.player_refresh_index + 1
if (global.chunk_regrow.player_refresh_index > #game.connected_players) then
global.chunk_regrow.player_refresh_index = 1
end
if (game.connected_players[global.chunk_regrow.player_refresh_index]) then
OarcRegrowthRefreshArea(game.connected_players[global.chunk_regrow.player_refresh_index].position, 4, 0)
end
end
-- Check each chunk in the 2d array for a timeout value
function OarcRegrowthCheckArray()
-- Increment X
if (global.chunk_regrow.x_index > global.chunk_regrow.max_x) then
global.chunk_regrow.x_index = global.chunk_regrow.min_x
-- Increment Y
if (global.chunk_regrow.y_index > global.chunk_regrow.max_y) then
global.chunk_regrow.y_index = global.chunk_regrow.min_y
DebugPrint("Finished checking regrowth array."..global.chunk_regrow.min_x.." "..global.chunk_regrow.max_x.." "..global.chunk_regrow.min_y.." "..global.chunk_regrow.max_y)
else
global.chunk_regrow.y_index = global.chunk_regrow.y_index + 1
end
else
global.chunk_regrow.x_index = global.chunk_regrow.x_index + 1
end
-- Check row exists, otherwise make one.
if (global.chunk_regrow.map[global.chunk_regrow.x_index] == nil) then
global.chunk_regrow.map[global.chunk_regrow.x_index] = {}
end
-- If the chunk has timed out, add it to the removal list
local c_timer = global.chunk_regrow.map[global.chunk_regrow.x_index][global.chunk_regrow.y_index]
if ((c_timer ~= nil) and (c_timer ~= -1) and ((c_timer+REGROWTH_TIMEOUT_TICKS) < game.tick)) then
-- Check chunk actually exists
if (game.surfaces[GAME_SURFACE_NAME].is_chunk_generated({x=(global.chunk_regrow.x_index),
y=(global.chunk_regrow.y_index)})) then
table.insert(global.chunk_regrow.removal_list, {x=global.chunk_regrow.x_index,
y=global.chunk_regrow.y_index})
global.chunk_regrow.map[global.chunk_regrow.x_index][global.chunk_regrow.y_index] = nil
end
end
end
-- Remove all chunks at same time to reduce impact to FPS/UPS
function OarcRegrowthRemoveAllChunks()
while (#global.chunk_regrow.removal_list > 0) do
local c_pos = table.remove(global.chunk_regrow.removal_list)
local c_timer = global.chunk_regrow.map[c_pos.x][c_pos.y]
-- Confirm chunk is still expired
if (c_timer == nil) then
-- Check for pollution
if (game.surfaces[GAME_SURFACE_NAME].get_pollution({c_pos.x*32,c_pos.y*32}) > 0) then
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick
-- Else delete the chunk
else
game.surfaces[GAME_SURFACE_NAME].delete_chunk(c_pos)
global.chunk_regrow.map[c_pos.x][c_pos.y] = nil
end
else
-- DebugPrint("Chunk no longer expired?")
end
end
end
-- This is the main work function, it checks a single chunk in the list
-- per tick. It works according to the rules listed in the header of this
-- file.
function OarcRegrowthOnTick()
-- Every half a second, refresh all chunks near a single player
-- Cyles through all players. Tick is offset by 2
if ((game.tick % (30)) == 2) then
OarcRegrowthRefreshPlayerArea()
end
-- Every tick, check a few points in the 2d array
-- According to /measured-command this shouldn't take more
-- than 0.1ms on average
for i=1,20 do
OarcRegrowthCheckArray()
end
-- Send a broadcast warning before it happens.
if ((game.tick % REGROWTH_CLEANING_INTERVAL_TICKS) == REGROWTH_CLEANING_INTERVAL_TICKS-601) then
if (#global.chunk_regrow.removal_list > 100) then
SendBroadcastMsg("Map cleanup in 10 seconds, if you don't want to lose what you found drop a powered radar on it!")
end
end
-- Delete all listed chunks
if ((game.tick % REGROWTH_CLEANING_INTERVAL_TICKS) == REGROWTH_CLEANING_INTERVAL_TICKS-1) then
if (#global.chunk_regrow.removal_list > 100) then
OarcRegrowthRemoveAllChunks()
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
end
end
end
-- This function removes any chunks flagged but on demand.
-- Controlled by the global.chunk_regrow.force_removal_flag
-- This function may be used outside of the normal regrowth modse.
function OarcRegrowthForceRemovalOnTick()
-- Catch force remove flag
if (game.tick == global.chunk_regrow.force_removal_flag+60) then
SendBroadcastMsg("Map cleanup in 10 seconds, if you don't want to lose what you found drop a powered radar on it!")
end
if (game.tick == global.chunk_regrow.force_removal_flag+660) then
OarcRegrowthRemoveAllChunks()
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
end
end

View File

@ -1,392 +0,0 @@
-- separate_spawns.lua
-- Nov 2016
--
-- Code that handles everything regarding giving each player a separate spawn
-- Includes the GUI stuff
--------------------------------------------------------------------------------
-- EVENT RELATED FUNCTIONS
--------------------------------------------------------------------------------
-- When a new player is created, present the spawn options
-- Assign them to the main force so they can communicate with the team
-- without shouting.
function SeparateSpawnsPlayerCreated(event)
local player = game.players[event.player_index]
player.force = MAIN_FORCE
DisplayWelcomeTextGui(player)
end
-- Check if the player has a different spawn point than the default one
-- Make sure to give the default starting items
function SeparateSpawnsPlayerRespawned(event)
local player = game.players[event.player_index]
SendPlayerToSpawn(player)
end
-- This is the main function that creates the spawn area
-- Provides resources, land and a safe zone
function SeparateSpawnsGenerateChunk(event)
local surface = event.surface
local chunkArea = event.area
-- This handles chunk generation near player spawns
-- If it is near a player spawn, it does a few things like make the area
-- safe and provide a guaranteed area of land and water tiles.
SetupAndClearSpawnAreas(surface, chunkArea, global.uniqueSpawns)
end
-- Call this if a player leaves the game
-- Still seems to have a bug.
function FindUnusedSpawns(event)
local player = game.players[event.player_index]
if (player.online_time < MIN_ONLINE_TIME) then
DropGravestoneChests(player)
-- Clear out global variables for that player
if (global.playerSpawns[player.name] ~= nil) then
global.playerSpawns[player.name] = nil
end
-- Remove them from the delayer spawn queue if they are in it
for i=#global.delayedSpawns,1,-1 do
delayedSpawn = global.delayedSpawns[i]
if (player.name == delayedSpawn.playerName) then
table.remove(global.delayedSpawns, i)
DebugPrint("Removing player from delayed spawn queue: " .. player.name)
end
end
-- Transfer or remove a shared spawn if player is owner
if (global.sharedSpawns[player.name] ~= nil) then
local teamMates = global.sharedSpawns[player.name].players
if (#teamMates >= 1) then
local newOwnerName = table.remove(teamMates)
TransferOwnershipOfSharedSpawn(player.name, newOwnerName)
else
global.sharedSpawns[player.name] = nil
end
end
-- If a uniqueSpawn was created for the player, mark it as unused.
if (global.uniqueSpawns[player.name] ~= nil) then
local spawnPos = global.uniqueSpawns[player.name].pos
-- Check if it was near someone else's base.
nearOtherSpawn = false
for spawnPlayerName,otherSpawnPos in pairs(global.uniqueSpawns) do
if ((spawnPlayerName ~= player.name) and (getDistance(spawnPos, otherSpawnPos.pos) < (ENFORCE_LAND_AREA_TILE_DIST*3))) then
DebugPrint("Won't remove base as it's close to another spawn: " .. spawnPlayerName)
nearOtherSpawn = true
end
end
if (ENABLE_ABANDONED_BASE_REMOVAL and not nearOtherSpawn) then
global.uniqueSpawns[player.name] = nil
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
else
table.insert(global.unusedSpawns, global.uniqueSpawns[player.name])
global.uniqueSpawns[player.name] = nil
SendBroadcastMsg(player.name .. " base was freed up because they left within "..MIN_ONLINE_TIME_IN_MINUTES.." minutes of joining.")
end
end
-- remove that player's cooldown setting
if (global.playerCooldowns[player.name] ~= nil) then
global.playerCooldowns[player.name] = nil
end
-- Remove from shared spawn player slots (need to search all)
for _,sharedSpawn in pairs(global.sharedSpawns) do
for key,playerName in pairs(sharedSpawn.players) do
if (player.name == playerName) then
sharedSpawn.players[key] = nil;
end
end
end
-- Remove a force if this player created it and they are the only one on it
if ((#player.force.players <= 1) and (player.force.name ~= MAIN_FORCE)) then
game.merge_forces(player.force, MAIN_FORCE)
end
-- Remove the character completely
game.remove_offline_players({player})
end
end
--------------------------------------------------------------------------------
-- NON-EVENT RELATED FUNCTIONS
--------------------------------------------------------------------------------
-- Add a spawn to the shared spawn global
-- Used for tracking which players are assigned to it, where it is and if
-- it is open for new players to join
function CreateNewSharedSpawn(player)
global.sharedSpawns[player.name] = {openAccess=true,
position=global.playerSpawns[player.name],
players={}}
end
function TransferOwnershipOfSharedSpawn(prevOwnerName, newOwnerName)
-- Transfer the shared spawn global
global.sharedSpawns[newOwnerName] = global.sharedSpawns[prevOwnerName]
global.sharedSpawns[newOwnerName].openAccess = false
global.sharedSpawns[prevOwnerName] = nil
-- Transfer the unique spawn global
global.uniqueSpawns[newOwnerName] = global.uniqueSpawns[prevOwnerName]
global.uniqueSpawns[prevOwnerName] = nil
game.players[newOwnerName].print("You have been given ownership of this base!")
end
-- Returns the number of players currently online at the shared spawn
function GetOnlinePlayersAtSharedSpawn(ownerName)
if (global.sharedSpawns[ownerName] ~= nil) then
-- Does not count base owner
local count = 0
-- For each player in the shared spawn, check if online and add to count.
for _,player in pairs(game.connected_players) do
if (ownerName == player.name) then
count = count + 1
end
for _,playerName in pairs(global.sharedSpawns[ownerName].players) do
if (playerName == player.name) then
count = count + 1
end
end
end
return count
else
return 0
end
end
-- Get the number of currently available shared spawns
-- This means the base owner has enabled access AND the number of online players
-- is below the threshold.
function GetNumberOfAvailableSharedSpawns()
local count = 0
for ownerName,sharedSpawn in pairs(global.sharedSpawns) do
if (sharedSpawn.openAccess and
(game.players[ownerName] ~= nil) and
game.players[ownerName].connected) then
if ((MAX_ONLINE_PLAYERS_AT_SHARED_SPAWN == 0) or
(GetOnlinePlayersAtSharedSpawn(ownerName) < MAX_ONLINE_PLAYERS_AT_SHARED_SPAWN)) then
count = count+1
end
end
end
return count
end
-- Initializes the globals used to track the special spawn and player
-- status information
function InitSpawnGlobalsAndForces()
-- Containes an array of all player spawns
-- A secondary array tracks whether the character will respawn there.
if (global.playerSpawns == nil) then
global.playerSpawns = {}
end
if (global.uniqueSpawns == nil) then
global.uniqueSpawns = {}
end
if (global.sharedSpawns == nil) then
global.sharedSpawns = {}
end
if (global.unusedSpawns == nil) then
global.unusedSpawns = {}
end
if (global.playerCooldowns == nil) then
global.playerCooldowns = {}
end
if (global.waitingBuddies == nil) then
global.waitingBuddies = {}
end
if (global.delayedSpawns == nil) then
global.delayedSpawns = {}
end
if (global.buddySpawnOptions == nil) then
global.buddySpawnOptions = {}
end
game.create_force(MAIN_FORCE)
game.forces[MAIN_FORCE].set_spawn_position(game.forces["player"].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME)
if ENABLE_SHARED_TEAM_VISION then
game.forces[MAIN_FORCE].share_chart = true
end
SetCeaseFireBetweenAllForces()
SetFriendlyBetweenAllForces()
if (ENABLE_ANTI_GRIEFING) then
AntiGriefing(game.forces[MAIN_FORCE])
end
end
function DoesPlayerHaveCustomSpawn(player)
for name,spawnPos in pairs(global.playerSpawns) do
if (player.name == name) then
return true
end
end
return false
end
function ChangePlayerSpawn(player, pos)
global.playerSpawns[player.name] = pos
global.playerCooldowns[player.name] = {setRespawn=game.tick}
end
function QueuePlayerForDelayedSpawn(playerName, spawn, moatEnabled)
-- If we get a valid spawn point, setup the area
if ((spawn.x ~= 0) and (spawn.y ~= 0)) then
global.uniqueSpawns[playerName] = {pos=spawn,moat=moatEnabled}
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].surface.request_to_generate_chunks(spawn, 4)
delayedTick = game.tick + delay_spawn_seconds*TICKS_PER_SECOND
table.insert(global.delayedSpawns, {playerName=playerName, spawn=spawn, moatEnabled=moatEnabled, delayedTick=delayedTick})
DisplayPleaseWaitForSpawnDialog(game.players[playerName], delay_spawn_seconds)
else
DebugPrint("THIS SHOULD NOT EVER HAPPEN! Spawn failed!")
SendBroadcastMsg("ERROR!! Failed to create spawn point for: " .. playerName)
end
end
-- Check a table to see if there are any players waiting to spawn
-- Check if we are past the delayed tick count
-- Spawn the players and remove them from the table.
function DelayedSpawnOnTick()
if ((game.tick % (30)) == 1) then
if ((global.delayedSpawns ~= nil) and (#global.delayedSpawns > 0)) then
for i=#global.delayedSpawns,1,-1 do
delayedSpawn = global.delayedSpawns[i]
if (delayedSpawn.delayedTick < game.tick) then
-- TODO, add check here for if chunks around spawn are generated surface.is_chunk_generated(chunkPos)
if (game.players[delayedSpawn.playerName] ~= nil) then
SendPlayerToNewSpawnAndCreateIt(delayedSpawn.playerName, delayedSpawn.spawn, delayedSpawn.moatEnabled)
end
table.remove(global.delayedSpawns, i)
end
end
end
end
end
function SendPlayerToNewSpawnAndCreateIt(playerName, spawn, moatEnabled)
-- Make sure the area is super safe.
ClearNearbyEnemies(spawn, SAFE_AREA_TILE_DIST, game.surfaces[GAME_SURFACE_NAME])
-- Create the spawn resources here
CreateWaterStrip(game.surfaces[GAME_SURFACE_NAME],
{x=spawn.x+WATER_SPAWN_OFFSET_X, y=spawn.y+WATER_SPAWN_OFFSET_Y},
WATER_SPAWN_LENGTH)
CreateWaterStrip(game.surfaces[GAME_SURFACE_NAME],
{x=spawn.x+WATER_SPAWN_OFFSET_X, y=spawn.y+WATER_SPAWN_OFFSET_Y+1},
WATER_SPAWN_LENGTH)
GenerateStartingResources(game.surfaces[GAME_SURFACE_NAME], spawn)
-- Send the player to that position
game.players[playerName].teleport(spawn, GAME_SURFACE_NAME)
GivePlayerStarterItems(game.players[playerName])
-- Chart the area.
ChartArea(game.players[playerName].force, game.players[playerName].position, math.ceil(ENFORCE_LAND_AREA_TILE_DIST/CHUNK_SIZE), game.players[playerName].surface)
if (game.players[playerName].gui.center.wait_for_spawn_dialog ~= nil) then
game.players[playerName].gui.center.wait_for_spawn_dialog.destroy()
end
end
function SendPlayerToSpawn(player)
if (DoesPlayerHaveCustomSpawn(player)) then
player.teleport(global.playerSpawns[player.name], GAME_SURFACE_NAME)
else
player.teleport(game.forces[MAIN_FORCE].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME)
end
end
function SendPlayerToRandomSpawn(player)
local numSpawns = TableLength(global.uniqueSpawns)
local rndSpawn = math.random(0,numSpawns)
local counter = 0
if (rndSpawn == 0) then
player.teleport(game.forces[MAIN_FORCE].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME)
else
counter = counter + 1
for name,spawn in pairs(global.uniqueSpawns) do
if (counter == rndSpawn) then
player.teleport(spawn.pos)
break
end
counter = counter + 1
end
end
end
function CreatePlayerCustomForce(player)
local newForce = nil
-- Check if force already exists
if (game.forces[player.name] ~= nil) then
DebugPrint("Force already exists!")
player.force = game.forces[player.name]
return game.forces[player.name]
-- Create a new force using the player's name
elseif (TableLength(game.forces) < MAX_FORCES) then
newForce = game.create_force(player.name)
if ENABLE_SHARED_TEAM_VISION then
newForce.share_chart = true
end
-- Chart silo areas if necessary
if FRONTIER_ROCKET_SILO_MODE and ENABLE_SILO_VISION then
ChartRocketSiloAreas(game.surfaces[GAME_SURFACE_NAME], newForce)
end
player.force = newForce
SetCeaseFireBetweenAllForces()
SetFriendlyBetweenAllForces()
if (ENABLE_ANTI_GRIEFING) then
AntiGriefing(newForce)
end
SendBroadcastMsg(player.name.." has started their own team!")
else
player.force = MAIN_FORCE
player.print("Sorry, no new teams can be created. You were assigned to the default team instead.")
end
return newForce
end