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:
commit
bc5e566e24
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
config.lua
|
73
README.md
73
README.md
@ -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
|
||||
|
405
config.lua
405
config.lua
@ -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!"
|
403
control.lua
403
control.lua
@ -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
423
example-config.lua
Normal 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
|
72
example/example-map-gen-settings.json
Normal file
72
example/example-map-gen-settings.json
Normal 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
|
||||
}
|
113
example/example-map-settings.json
Normal file
113
example/example-map-settings.json
Normal 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
28
lib/admin_commands.lua
Normal 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)
|
@ -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
144
lib/game_opts.lua
Normal 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
|
@ -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
211
lib/oarc_global_cfg.lua
Normal 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
246
lib/oarc_gui_tabs.lua
Normal 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
137
lib/oarc_gui_utils.lua
Normal 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
1064
lib/oarc_utils.lua
Normal file
File diff suppressed because it is too large
Load Diff
46
lib/player_list.lua
Normal file
46
lib/player_list.lua
Normal 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
382
lib/regrowth_map.lua
Normal 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
80
lib/rocket_launch.lua
Normal 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
800
lib/separate_spawns.lua
Normal 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
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
52
lib/tag.lua
Normal 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
1
lib/test_lib_file.lua
Normal file
@ -0,0 +1 @@
|
||||
-- test_lib_file.lua
|
@ -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
113
locale/de/locale.cfg
Normal 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
113
locale/en/locale.cfg
Normal 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
113
locale/fr/locale.cfg
Normal 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 ...
|
@ -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
@ -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
|
@ -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
|
@ -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
@ -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
|
@ -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
|
349
regrowth_map.lua
349
regrowth_map.lua
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user