mirror of
https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git
synced 2024-12-12 10:13:58 +02:00
Added RSO, tags, frontier silo, multiple improvements
This commit is contained in:
parent
46f0905059
commit
9339ce2964
119
config.lua
Normal file
119
config.lua
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
-- config.lua
|
||||||
|
-- Configuration Options
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Useful constants
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
CHUNK_SIZE = 32
|
||||||
|
MAX_FORCES = 64
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
WELCOME_MSG = "Welcome to Oarc's server! This is a BETA test of my custom scenario."
|
||||||
|
GAME_MODE_MSG = "In the current game mode, a satellite must be launched from the rocket silo to the far east to win!"
|
||||||
|
-- GAME_MODE_MSG = "The current game mode is just basic vanilla!"
|
||||||
|
MODULES_ENABLED = "Mods Enabled: Separate Spawns, RSO, Gravestone Chests"
|
||||||
|
-- MODULES_ENABLED = "Mods Enabled: Gravestone-Chests"
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Module Enables
|
||||||
|
-- These enables are not fully tested! For example, disable separate spawns
|
||||||
|
-- will probably break the frontier rocket silo mode
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Separate spawns
|
||||||
|
FRONTIER_ROCKET_SILO_MODE = true
|
||||||
|
|
||||||
|
-- Frontier style rocket silo mode
|
||||||
|
ENABLE_SEPARATE_SPAWNS = true
|
||||||
|
|
||||||
|
-- Enable Scenario version of RSO
|
||||||
|
ENABLE_RSO = true
|
||||||
|
|
||||||
|
-- Enable Gravestone Chests
|
||||||
|
ENABLE_GRAVESTONE_CHESTS = true
|
||||||
|
|
||||||
|
-- Enable Undecorator
|
||||||
|
ENABLE_UNDECORATOR = true
|
||||||
|
|
||||||
|
-- DEBUG prints for me
|
||||||
|
global.oarcDebugEnabled = false
|
||||||
|
global.spawnDebugEnabled = false
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Spawn Options
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
-- Distance Options
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
-- Distance in chunks
|
||||||
|
FAR_MIN_DIST = 50
|
||||||
|
FAR_MAX_DIST = 125
|
||||||
|
---------------------------------------
|
||||||
|
-- Resource Options
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
-- Start resource amounts
|
||||||
|
START_IRON_AMOUNT = 1500
|
||||||
|
START_COPPER_AMOUNT = 1500
|
||||||
|
START_STONE_AMOUNT = 1500
|
||||||
|
START_COAL_AMOUNT = 1500
|
||||||
|
START_OIL_AMOUNT = 30000
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
-- Safe Spawn Area Options
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
-- Safe area has no aliens
|
||||||
|
-- +/- this in x and y direction
|
||||||
|
SAFE_AREA_TILE_DIST = 300
|
||||||
|
|
||||||
|
-- Warning area has reduced aliens
|
||||||
|
-- +/- this in x and y direction
|
||||||
|
WARNING_AREA_TILE_DIST = 500
|
||||||
|
|
||||||
|
-- 1 : X (spawners alive : spawners destroyed) in this area
|
||||||
|
WARN_AREA_REDUCTION_RATIO = 15
|
||||||
|
|
||||||
|
-- Create a circle of land area for the spawn
|
||||||
|
ENFORCE_LAND_AREA_TILE_DIST = 40
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
-- Other Forces/Teams Options
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
-- Enable if people can join their own teams
|
||||||
|
ENABLE_OTHER_TEAMS = false
|
||||||
|
|
||||||
|
-- Main force is what default players join
|
||||||
|
MAIN_FORCE = "main_force"
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
-- Alien Options
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
-- Disable enemy expansion
|
||||||
|
ENEMY_EXPANSION = false
|
||||||
|
|
||||||
|
|
||||||
|
-- Divide the alien factors by this number to reduce it (or multiply if < 1)
|
||||||
|
ENEMY_POLLUTION_FACTOR_DIVISOR = 10
|
||||||
|
ENEMY_DESTROY_FACTOR_DIVISOR = 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Frontier Options
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SILO_CHUNK_DISTANCE_X = 250
|
||||||
|
SILO_DISTANCE_X = SILO_CHUNK_DISTANCE_X*CHUNK_SIZE + CHUNK_SIZE/2
|
||||||
|
SILO_DISTANCE_Y = 16
|
||||||
|
|
||||||
|
-- Should be in the middle of a chunk
|
||||||
|
SILO_POSITION = {x = SILO_DISTANCE_X, y = SILO_DISTANCE_Y}
|
973
control.lua
973
control.lua
@ -13,903 +13,39 @@
|
|||||||
-- if they were not already.
|
-- if they were not already.
|
||||||
|
|
||||||
|
|
||||||
-- TODO
|
-- To do:
|
||||||
-- Anti griefer? Drop all items on leaving?
|
-- Clean up text around spawn choices.
|
||||||
-- Better long term goal like frontier
|
-- Make rocket silo more obvious, try to spawn a train station
|
||||||
-- Better interaction with other forces?
|
-- Add longreach
|
||||||
|
|
||||||
-- config options
|
|
||||||
|
|
||||||
-- Near spawn option is on the edge of generated chunks
|
require("event")
|
||||||
-- On a large map, this may be quite far from spawn.
|
require("config")
|
||||||
local MIN_CHUNK_SPAWN_DIST = 2
|
require("rso_control") -- MUST LOAD THIS before other modifications to chunk generation
|
||||||
|
require("oarc_utils")
|
||||||
-- Far spawn options is this number of chunks past generated area
|
require("separate_spawns")
|
||||||
local FAR_CHUNK_SPAWN_DIST = 10
|
require("tag")
|
||||||
|
|
||||||
local FAR_MIN_DIST = 1000^2
|
|
||||||
local FAR_MAX_DIST = 6000^2
|
|
||||||
|
|
||||||
-- Start resource amountsmm
|
|
||||||
local START_IRON_AMOUNT = 1500
|
|
||||||
local START_COPPER_AMOUNT = 1000
|
|
||||||
local START_STONE_AMOUNT = 1500
|
|
||||||
local START_COAL_AMOUNT = 1500
|
|
||||||
local START_OIL_AMOUNT = 20000
|
|
||||||
|
|
||||||
-- Safe area has no aliens
|
|
||||||
-- +/- this in x and y direction
|
|
||||||
local SAFE_AREA_TILE_DIST = 250
|
|
||||||
|
|
||||||
-- Warning area has reduced aliens
|
|
||||||
-- +/- this in x and y direction
|
|
||||||
local WARNING_AREA_TILE_DIST = 500
|
|
||||||
|
|
||||||
-- 1 : X (spawners alive : spawners destroyed) in this area
|
|
||||||
local WARN_AREA_REDUCTION_RATIO = 15
|
|
||||||
|
|
||||||
-- Create a circle of land area for the spawn
|
|
||||||
local ENFORCE_LAND_AREA_TILE_DIST = 40
|
|
||||||
local ENFORCE_LAND_AREA_TILE_DIST_SQUARED = ENFORCE_LAND_AREA_TILE_DIST^2
|
|
||||||
|
|
||||||
-- Main force is what default players join
|
|
||||||
local MAIN_FORCE = "main_force"
|
|
||||||
local ENABLE_OTHER_TEAMS = false
|
|
||||||
|
|
||||||
-- Disable enemy expansion
|
|
||||||
local ENEMY_EXPANSION = false
|
|
||||||
|
|
||||||
-- Divide the alien factors by this number to reduce it (or multiply if < 1)
|
|
||||||
local ENEMY_POLLUTION_FACTOR_DIVISOR = 10
|
|
||||||
local ENEMY_DESTROY_FACTOR_DIVISOR = 1
|
|
||||||
|
|
||||||
-- Useful constants
|
|
||||||
local CHUNK_SIZE = 32
|
|
||||||
local MAX_FORCES = 64
|
|
||||||
|
|
||||||
|
|
||||||
-- Print debug only to me while testing.
|
|
||||||
-- Should remove this if you are hosting it yourself.
|
|
||||||
local function DebugPrint(msg)
|
|
||||||
if ((game.players["Oarc"] ~= nil) and (global.oarcDebugEnabled)) then
|
|
||||||
game.players["Oarc"].print("DEBUG: " .. msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Simple function to get total number of items in table
|
|
||||||
function TableLength(T)
|
|
||||||
local count = 0
|
|
||||||
for _ in pairs(T) do count = count + 1 end
|
|
||||||
return count
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Give player these default items.
|
|
||||||
local function GivePlayerItems(player)
|
|
||||||
player.insert{name="pistol", count=1}
|
|
||||||
player.insert{name="firearm-magazine", count=10}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Additional starter only items
|
|
||||||
local function GivePlayerStarterItems(player)
|
|
||||||
GivePlayerItems(player)
|
|
||||||
player.insert{name="iron-plate", count=8}
|
|
||||||
player.insert{name="burner-mining-drill", count = 1}
|
|
||||||
player.insert{name="stone-furnace", count = 1}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if given position is in area bounding box
|
|
||||||
local function CheckIfInArea(point, area)
|
|
||||||
if ((point.x > area.left_top.x) and (point.x < area.right_bottom.x)) then
|
|
||||||
if ((point.y > area.left_top.y) and (point.y < area.right_bottom.y)) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Ceasefire
|
|
||||||
-- All forces are always neutral
|
|
||||||
local function SetCeaseFireBetweenAllForces()
|
|
||||||
for name,team in pairs(game.forces) do
|
|
||||||
if name ~= "neutral" and name ~= "enemy" then
|
|
||||||
for x,y in pairs(game.forces) do
|
|
||||||
if x ~= "neutral" and x ~= "enemy" then
|
|
||||||
team.set_cease_fire(x,true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Broadcast messages
|
|
||||||
local function SendBroadcastMsg(msg)
|
|
||||||
for name,player in pairs(game.players) do
|
|
||||||
player.print(msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function CreateNewSpawnCoordinates(spawn_distance, recursion_max)
|
|
||||||
local position = {x=0,y=0}
|
|
||||||
local chunkPos = {x=0,y=0}
|
|
||||||
local randVec = {x=0,y=0}
|
|
||||||
|
|
||||||
-- Create a random direction vector to look in
|
|
||||||
while ((randVec.x == 0) and (randVec.y == 0))
|
|
||||||
do
|
|
||||||
randVec.x = math.random(-3,3)
|
|
||||||
randVec.y = math.random(-3,3)
|
|
||||||
end
|
|
||||||
DebugPrint("direction: x=" .. randVec.x .. ", y=" .. randVec.y)
|
|
||||||
|
|
||||||
while(true)
|
|
||||||
do
|
|
||||||
|
|
||||||
-- Set some absolute limits.
|
|
||||||
if ((math.abs(chunkPos.x) > 1000) or (math.abs(chunkPos.y) > 1000)) then
|
|
||||||
break
|
|
||||||
|
|
||||||
-- If chunk is already generated, keep looking
|
|
||||||
elseif (game.surfaces["nauvis"].is_chunk_generated(chunkPos)) then
|
|
||||||
chunkPos.x = chunkPos.x + randVec.x*spawn_distance
|
|
||||||
chunkPos.y = chunkPos.y + randVec.y*spawn_distance
|
|
||||||
|
|
||||||
-- Found a possible ungenerated area
|
|
||||||
else
|
|
||||||
|
|
||||||
chunkPos.x = chunkPos.x + (randVec.x*spawn_distance)
|
|
||||||
chunkPos.y = chunkPos.y + (randVec.y*spawn_distance)
|
|
||||||
|
|
||||||
-- If it's still ungenerated even further out, use that position.
|
|
||||||
if (not game.surfaces["nauvis"].is_chunk_generated(chunkPos)) then
|
|
||||||
position.x = (chunkPos.x*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
|
||||||
position.y = (chunkPos.y*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Very dangerous and stupid recursive call.
|
|
||||||
if (spawn_distance == FAR_CHUNK_SPAWN_DIST) then
|
|
||||||
local distSqrd = position.x^2 + position.y^2
|
|
||||||
if ((distSqrd < FAR_MIN_DIST) or (distSqrd > FAR_MAX_DIST)) then
|
|
||||||
if (recursion_max == 0) then
|
|
||||||
return {x=0,y=0}
|
|
||||||
else
|
|
||||||
DebugPrint("spawn: x=" .. position.x .. ", y=" .. position.y)
|
|
||||||
return CreateNewSpawnCoordinates(spawn_distance, recursion_max-1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
DebugPrint("spawn: x=" .. position.x .. ", y=" .. position.y)
|
|
||||||
return position
|
|
||||||
end
|
|
||||||
|
|
||||||
local my_label_style = {
|
|
||||||
minimal_width = 450,
|
|
||||||
maximal_width = 450,
|
|
||||||
font_color = {r=1,g=1,b=1}
|
|
||||||
}
|
|
||||||
|
|
||||||
local my_note_style = {
|
|
||||||
minimal_width = 450,
|
|
||||||
maximal_height = 10,
|
|
||||||
font = "default-small-semibold",
|
|
||||||
font_color = {r=1,g=0.5,b=0.5}
|
|
||||||
}
|
|
||||||
|
|
||||||
local my_warning_style = {
|
|
||||||
minimal_width = 450,
|
|
||||||
maximal_width = 450,
|
|
||||||
font_color = {r=1,g=0.1,b=0.1}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ApplyStyle (guiIn, styleIn)
|
|
||||||
for k,v in pairs(styleIn) do
|
|
||||||
guiIn.style[k]=v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DisplaySpawnOptions(player)
|
|
||||||
player.gui.center.add{name = "spawn_opts",
|
|
||||||
type = "frame",
|
|
||||||
direction = "vertical",
|
|
||||||
caption="Spawn Options"}
|
|
||||||
local spawnGui = player.gui.center.spawn_opts
|
|
||||||
|
|
||||||
spawnGui.style.maximal_width = 450
|
|
||||||
spawnGui.style.maximal_height = 650
|
|
||||||
|
|
||||||
spawnGui.add{name = "warning_lbl1", type = "label",
|
|
||||||
caption="CHOOSE CAREFULLY - YOU ONLY GET ONE CUSTOM SPAWN POINT!"}
|
|
||||||
spawnGui.add{name = "warning_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(spawnGui.warning_lbl1, my_warning_style)
|
|
||||||
ApplyStyle(spawnGui.warning_spacer, my_label_style)
|
|
||||||
|
|
||||||
spawnGui.add{name = "normal_spawn",
|
|
||||||
type = "button",
|
|
||||||
caption="Default Spawn"}
|
|
||||||
spawnGui.add{name = "normal_spawn_lbl1", type = "label",
|
|
||||||
caption="This is the default spawn behavior of a vanilla game."}
|
|
||||||
spawnGui.add{name = "normal_spawn_lbl2", type = "label",
|
|
||||||
caption="You join the default team in the center of the map."}
|
|
||||||
spawnGui.add{name = "normal_spawn_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(spawnGui.normal_spawn_lbl1, my_label_style)
|
|
||||||
ApplyStyle(spawnGui.normal_spawn_lbl2, my_label_style)
|
|
||||||
ApplyStyle(spawnGui.normal_spawn_spacer, my_label_style)
|
|
||||||
|
|
||||||
spawnGui.add{name = "isolated_spawn",
|
|
||||||
type = "button",
|
|
||||||
caption="Isolated Spawn"}
|
|
||||||
spawnGui.add{name = "isolated_spawn_far",
|
|
||||||
type = "button",
|
|
||||||
caption="Isolated Spawn (Far Away)"}
|
|
||||||
spawnGui.add{name = "isolated_spawn_lbl1", type = "label",
|
|
||||||
caption="You are spawned in a new area, with starting resources."}
|
|
||||||
spawnGui.add{name = "isolated_spawn_lbl2", type = "label",
|
|
||||||
caption="You will still be part of the default team."}
|
|
||||||
spawnGui.add{name = "isolated_spawn_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(spawnGui.isolated_spawn_lbl1, my_label_style)
|
|
||||||
ApplyStyle(spawnGui.isolated_spawn_lbl2, my_label_style)
|
|
||||||
ApplyStyle(spawnGui.isolated_spawn_spacer, my_label_style)
|
|
||||||
|
|
||||||
|
|
||||||
if (ENABLE_OTHER_TEAMS) then
|
|
||||||
spawnGui.add{name = "new_force",
|
|
||||||
type = "button",
|
|
||||||
caption="Separate Team"}
|
|
||||||
spawnGui.add{name = "new_force_far",
|
|
||||||
type = "button",
|
|
||||||
caption="Separate Team (Far Away)"}
|
|
||||||
spawnGui.add{name = "new_force_lbl1", type = "label",
|
|
||||||
caption="You are spawned in a new area, with starting resources."}
|
|
||||||
spawnGui.add{name = "new_force_lbl2", type = "label",
|
|
||||||
caption="You will be on your own team. (No shared vision or research with others.)"}
|
|
||||||
spawnGui.add{name = "new_force_lbl3", type = "label",
|
|
||||||
caption="Do not choose this option if you are new to the game!"}
|
|
||||||
spawnGui.add{name = "new_force_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(spawnGui.new_force_lbl1, my_label_style)
|
|
||||||
ApplyStyle(spawnGui.new_force_lbl2, my_warning_style)
|
|
||||||
ApplyStyle(spawnGui.new_force_lbl3, my_warning_style)
|
|
||||||
ApplyStyle(spawnGui.new_force_spacer, my_label_style)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spawnGui.add{name = "note_lbl1", type = "label",
|
|
||||||
caption="All members of a team share map vision and research."}
|
|
||||||
spawnGui.add{name = "note_lbl2", type = "label",
|
|
||||||
caption="To talk to someone on a different team, you need to use /s to shout."}
|
|
||||||
spawnGui.add{name = "note_lbl3", type = "label",
|
|
||||||
caption="All teams are neutral. This is still a cooperative PvE game... NOT PVP!"}
|
|
||||||
ApplyStyle(spawnGui.note_lbl1, my_note_style)
|
|
||||||
ApplyStyle(spawnGui.note_lbl2, my_note_style)
|
|
||||||
ApplyStyle(spawnGui.note_lbl3, my_note_style)
|
|
||||||
end
|
|
||||||
spawnGui.add{name = "note_lbl4", type = "label",
|
|
||||||
caption="Far away spawn is between 1000-6000 distance units away from the center of the map."}
|
|
||||||
spawnGui.add{name = "note_lbl5", type = "label",
|
|
||||||
caption="Isolated spawns are dangerous! You will have to fight to reach other players."}
|
|
||||||
spawnGui.add{name = "note_lbl6", type = "label",
|
|
||||||
caption="You can change your spawn options when you die."}
|
|
||||||
|
|
||||||
ApplyStyle(spawnGui.note_lbl4, my_note_style)
|
|
||||||
ApplyStyle(spawnGui.note_lbl5, my_note_style)
|
|
||||||
end
|
|
||||||
|
|
||||||
function DisplayRespawnContinueOption(player)
|
|
||||||
|
|
||||||
player.gui.center.add{name = "respawn_continue_opts",
|
|
||||||
type = "frame",
|
|
||||||
direction = "vertical",
|
|
||||||
caption="Respawn Options"}
|
|
||||||
local respawnGui = player.gui.center.respawn_continue_opts
|
|
||||||
|
|
||||||
respawnGui.style.maximal_width = 450
|
|
||||||
respawnGui.style.maximal_height = 550
|
|
||||||
|
|
||||||
respawnGui.add{name = "respawn_continue",
|
|
||||||
type = "button",
|
|
||||||
caption="Continue"}
|
|
||||||
respawnGui.add{name = "respawn_continue_lbl1", type = "label",
|
|
||||||
caption="Continue at your current spawn location."}
|
|
||||||
respawnGui.add{name = "respawn_continue_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(respawnGui.respawn_continue_lbl1, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_continue_spacer, my_label_style)
|
|
||||||
|
|
||||||
respawnGui.add{name = "respawn_change",
|
|
||||||
type = "button",
|
|
||||||
caption="Change Spawn"}
|
|
||||||
respawnGui.add{name = "respawn_change_lbl1", type = "label",
|
|
||||||
caption="Allow you to change your spawn and team."}
|
|
||||||
respawnGui.add{name = "respawn_change_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(respawnGui.respawn_change_lbl1, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_change_spacer, my_label_style)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function DisplayRespawnOptions(player)
|
|
||||||
|
|
||||||
player.gui.center.add{name = "respawn_opts",
|
|
||||||
type = "frame",
|
|
||||||
direction = "vertical",
|
|
||||||
caption="Respawn Options"}
|
|
||||||
local respawnGui = player.gui.center.respawn_opts
|
|
||||||
|
|
||||||
respawnGui.style.maximal_width = 450
|
|
||||||
respawnGui.style.maximal_height = 750
|
|
||||||
|
|
||||||
-- Basically a cancel button to avoid choosing a different spawn.
|
|
||||||
respawnGui.add{name = "respawn_continue",
|
|
||||||
type = "button",
|
|
||||||
caption="Cancel"}
|
|
||||||
respawnGui.add{name = "respawn_continue_lbl1", type = "label",
|
|
||||||
caption="Continue with current spawn."}
|
|
||||||
respawnGui.add{name = "respawn_continue_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(respawnGui.respawn_continue_lbl1, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_continue_spacer, my_label_style)
|
|
||||||
|
|
||||||
respawnGui.add{name = "respawn_mainforce",
|
|
||||||
type = "button",
|
|
||||||
caption="Use Default Spawn"}
|
|
||||||
respawnGui.add{name = "respawn_mainforce_lbl1", type = "label",
|
|
||||||
caption="This will join the default team."}
|
|
||||||
respawnGui.add{name = "respawn_mainforce_lbl2", type = "label",
|
|
||||||
caption="If you are on another team all your research will be lost!"}
|
|
||||||
respawnGui.add{name = "respawn_mainforce_lbl3", type = "label",
|
|
||||||
caption="You will spawn at the default spawn point in the center."}
|
|
||||||
respawnGui.add{name = "respawn_mainforce_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(respawnGui.respawn_mainforce_lbl1, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_mainforce_lbl2, my_warning_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_mainforce_lbl3, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_mainforce_spacer, my_label_style)
|
|
||||||
|
|
||||||
|
|
||||||
respawnGui.add{name = "respawn_custom_spawn",
|
|
||||||
type = "button",
|
|
||||||
caption="Custom Spawn"}
|
|
||||||
respawnGui.add{name = "respawn_custom_lbl1", type = "label",
|
|
||||||
caption="This will join the default team."}
|
|
||||||
respawnGui.add{name = "respawn_custom_lbl2", type = "label",
|
|
||||||
caption="If you are on another team all your research will be lost!"}
|
|
||||||
respawnGui.add{name = "respawn_custom_lbl3", type = "label",
|
|
||||||
caption="You will spawn at your previous custom spawn point."}
|
|
||||||
respawnGui.add{name = "respawn_custom_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_lbl1, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_lbl2, my_warning_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_lbl3, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_spacer, my_label_style)
|
|
||||||
|
|
||||||
if (ENABLE_OTHER_TEAMS) then
|
|
||||||
respawnGui.add{name = "respawn_custom_team",
|
|
||||||
type = "button",
|
|
||||||
caption="Custom Team Spawn"}
|
|
||||||
respawnGui.add{name = "respawn_custom_team_lbl1", type = "label",
|
|
||||||
caption="This will join your own custom team."}
|
|
||||||
respawnGui.add{name = "respawn_custom_team_lbl2", type = "label",
|
|
||||||
caption="You will have your own map vision and research tree. Use /s to talk to others."}
|
|
||||||
respawnGui.add{name = "respawn_custom_team_lbl3", type = "label",
|
|
||||||
caption="You will spawn at your previous custom spawn point."}
|
|
||||||
respawnGui.add{name = "respawn_custom_team_spacer", type = "label",
|
|
||||||
caption=" "}
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_team_lbl1, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_team_lbl2, my_warning_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_team_lbl3, my_label_style)
|
|
||||||
ApplyStyle(respawnGui.respawn_custom_team_spacer, my_label_style)
|
|
||||||
end
|
|
||||||
|
|
||||||
if (global.enableRespawnSurprise == true) then
|
|
||||||
respawnGui.add{name = "respawn_surpise",
|
|
||||||
type = "button",
|
|
||||||
caption="Surprise me!"}
|
|
||||||
end
|
|
||||||
|
|
||||||
respawnGui.add{name = "respawn_note1", type = "label",
|
|
||||||
caption="You cannot generate new custom spawn points."}
|
|
||||||
ApplyStyle(respawnGui.respawn_note1, my_note_style)
|
|
||||||
end
|
|
||||||
|
|
||||||
function GenerateStartingResources(player)
|
|
||||||
local surface = player.surface
|
|
||||||
|
|
||||||
-- Generate stone
|
|
||||||
local stonePos = {x=player.position.x-25,
|
|
||||||
y=player.position.y-31}
|
|
||||||
|
|
||||||
-- Generate coal
|
|
||||||
local coalPos = {x=player.position.x-25,
|
|
||||||
y=player.position.y-16}
|
|
||||||
|
|
||||||
-- Generate copper ore
|
|
||||||
local copperOrePos = {x=player.position.x-25,
|
|
||||||
y=player.position.y+0}
|
|
||||||
|
|
||||||
-- Generate iron ore
|
|
||||||
local ironOrePos = {x=player.position.x-25,
|
|
||||||
y=player.position.y+15}
|
|
||||||
|
|
||||||
-- Tree generation is taken care of in chunk generation
|
|
||||||
|
|
||||||
-- Generate oil patches
|
|
||||||
surface.create_entity({name="crude-oil", amount=START_OIL_AMOUNT,
|
|
||||||
position={player.position.x-30, player.position.y-2}})
|
|
||||||
surface.create_entity({name="crude-oil", amount=START_OIL_AMOUNT,
|
|
||||||
position={player.position.x-30, player.position.y+2}})
|
|
||||||
|
|
||||||
for y=0, 15 do
|
|
||||||
for x=0, 15 do
|
|
||||||
if ((x-7)^2 + (y - 7)^2 < 7^2) then
|
|
||||||
surface.create_entity({name="iron-ore", amount=START_IRON_AMOUNT,
|
|
||||||
position={ironOrePos.x+x, ironOrePos.y+y}})
|
|
||||||
surface.create_entity({name="copper-ore", amount=START_COPPER_AMOUNT,
|
|
||||||
position={copperOrePos.x+x, copperOrePos.y+y}})
|
|
||||||
surface.create_entity({name="stone", amount=START_STONE_AMOUNT,
|
|
||||||
position={stonePos.x+x, stonePos.y+y}})
|
|
||||||
surface.create_entity({name="coal", amount=START_COAL_AMOUNT,
|
|
||||||
position={coalPos.x+x, coalPos.y+y}})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function RemoveDecorationsArea(surface, area )
|
|
||||||
for _, entity in pairs(surface.find_entities_filtered{area = area, type="decorative"}) do
|
|
||||||
entity.destroy()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function ClearNearbyEnemies(player)
|
|
||||||
local safeArea = {left_top=
|
|
||||||
{x=player.position.x-SAFE_AREA_TILE_DIST,
|
|
||||||
y=player.position.y-SAFE_AREA_TILE_DIST},
|
|
||||||
right_bottom=
|
|
||||||
{x=player.position.x+SAFE_AREA_TILE_DIST,
|
|
||||||
y=player.position.y+SAFE_AREA_TILE_DIST}}
|
|
||||||
|
|
||||||
for _, entity in pairs(player.surface.find_entities_filtered{area = safeArea, force = "enemy"}) do
|
|
||||||
entity.destroy()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function DoesPlayerHaveCustomSpawn(player)
|
|
||||||
for name,spawnPos in pairs(global.playerSpawns) do
|
|
||||||
if (player.name == name) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local function DoesPlayerHaveActiveCustomSpawn(player)
|
|
||||||
if (DoesPlayerHaveCustomSpawn(player)) then
|
|
||||||
return global.activePlayerSpawns[player.name]
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function ActivatePlayerCustomSpawn(player, value)
|
|
||||||
for name,_ in pairs(global.playerSpawns) do
|
|
||||||
if (player.name == name) then
|
|
||||||
global.activePlayerSpawns[player.name] = value
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function CreatePlayerCustomForce(player)
|
|
||||||
local newForce = nil
|
|
||||||
|
|
||||||
-- Check if force already exists
|
|
||||||
if (game.forces[player.name] ~= nil) then
|
|
||||||
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)
|
|
||||||
player.force = newForce
|
|
||||||
SetCeaseFireBetweenAllForces()
|
|
||||||
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
|
|
||||||
|
|
||||||
local function SendPlayerToNewSpawnAndCreateIt(player, spawn)
|
|
||||||
-- Send the player to that position
|
|
||||||
player.teleport(spawn)
|
|
||||||
GivePlayerStarterItems(player)
|
|
||||||
|
|
||||||
-- If we get a valid spawn point, setup the area
|
|
||||||
if (spawn ~= {x=0,y=0}) then
|
|
||||||
GenerateStartingResources(player)
|
|
||||||
ClearNearbyEnemies(player)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function SendPlayerToActiveSpawn(player)
|
|
||||||
if (DoesPlayerHaveActiveCustomSpawn(player)) then
|
|
||||||
player.teleport(global.playerSpawns[player.name])
|
|
||||||
else
|
|
||||||
player.teleport(game.forces[MAIN_FORCE].get_spawn_position("nauvis"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function SendPlayerToRandomSpawn(player)
|
|
||||||
local numSpawns = TableLength(global.playerSpawns)
|
|
||||||
local rndSpawn = math.random(0,numSpawns)
|
|
||||||
local counter = 0
|
|
||||||
|
|
||||||
if (rndSpawn == 0) then
|
|
||||||
player.teleport(game.forces[MAIN_FORCE].get_spawn_position("nauvis"))
|
|
||||||
else
|
|
||||||
counter = counter + 1
|
|
||||||
for name,spawnPos in pairs(global.playerSpawns) do
|
|
||||||
if (counter == rndSpawn) then
|
|
||||||
player.teleport(spawnPos)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
counter = counter + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- 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.
|
|
||||||
script.on_event(defines.events.on_player_created, function(event)
|
|
||||||
local player = game.players[event.player_index]
|
|
||||||
player.force = MAIN_FORCE
|
|
||||||
DisplaySpawnOptions(player)
|
|
||||||
player.print("Welcome to Oarc's server! Now with oil spots, better respawn menus and gravestone chests!")
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- Create the appropriate force & spawn when player selects their choice
|
|
||||||
script.on_event(defines.events.on_gui_click, function (event)
|
|
||||||
|
|
||||||
local player = game.players[event.player_index]
|
|
||||||
local buttonClicked = event.element.name
|
|
||||||
|
|
||||||
-- Only clear gui if a valid button was clicked!!
|
|
||||||
if ((buttonClicked == "normal_spawn") or
|
|
||||||
(buttonClicked == "isolated_spawn") or
|
|
||||||
(buttonClicked == "isolated_spawn_far") or
|
|
||||||
(buttonClicked == "new_force") or
|
|
||||||
(buttonClicked == "new_force_far") or
|
|
||||||
(buttonClicked == "respawn_continue") or
|
|
||||||
(buttonClicked == "respawn_change") or
|
|
||||||
(buttonClicked == "respawn_custom_team") or
|
|
||||||
(buttonClicked == "respawn_custom_spawn") or
|
|
||||||
(buttonClicked == "respawn_surpise") or
|
|
||||||
(buttonClicked == "respawn_mainforce")) then
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (player.gui.center.spawn_opts ~= nil) then
|
|
||||||
player.gui.center.spawn_opts.destroy()
|
|
||||||
end
|
|
||||||
if (player.gui.center.respawn_opts ~= nil) then
|
|
||||||
player.gui.center.respawn_opts.destroy()
|
|
||||||
end
|
|
||||||
if (player.gui.center.respawn_continue_opts ~= nil) then
|
|
||||||
player.gui.center.respawn_continue_opts.destroy()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- In this option, the vanilla spawn is used and the player is
|
|
||||||
-- part of the main force.
|
|
||||||
if (buttonClicked == "normal_spawn") then
|
|
||||||
player.force = MAIN_FORCE
|
|
||||||
GivePlayerStarterItems(player)
|
|
||||||
SendBroadcastMsg(player.name .. " joined the main force!")
|
|
||||||
|
|
||||||
-- In this option, the player gets a separate spawn point
|
|
||||||
-- but is still part of the main force.
|
|
||||||
elseif ((buttonClicked == "isolated_spawn") or (buttonClicked == "isolated_spawn_far")) then
|
|
||||||
player.force = MAIN_FORCE
|
|
||||||
|
|
||||||
-- Create a new spawn point
|
|
||||||
local newSpawn = {}
|
|
||||||
if (buttonClicked == "isolated_spawn_far") then
|
|
||||||
newSpawn = CreateNewSpawnCoordinates(FAR_CHUNK_SPAWN_DIST, 20)
|
|
||||||
else
|
|
||||||
newSpawn = CreateNewSpawnCoordinates(MIN_CHUNK_SPAWN_DIST, 20)
|
|
||||||
end
|
|
||||||
global.playerSpawns[player.name] = newSpawn
|
|
||||||
global.activePlayerSpawns[player.name] = true
|
|
||||||
|
|
||||||
SendPlayerToNewSpawnAndCreateIt(player, newSpawn)
|
|
||||||
if (buttonClicked == "isolated_spawn") then
|
|
||||||
SendBroadcastMsg(player.name .. " joined the main force from a distance!")
|
|
||||||
elseif (buttonClicked == "isolated_spawn_far") then
|
|
||||||
SendBroadcastMsg(player.name .. " joined the main force from a great distance!")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- In this option, the player is given a new force and a
|
|
||||||
-- separate spawn point
|
|
||||||
elseif ((buttonClicked == "new_force") or (buttonClicked == "new_force_far")) then
|
|
||||||
|
|
||||||
-- Create a new force using the player's name
|
|
||||||
local newForce = CreatePlayerCustomForce(player)
|
|
||||||
|
|
||||||
-- Create a new spawn point
|
|
||||||
local newSpawn = {}
|
|
||||||
if (buttonClicked == "new_force_far") then
|
|
||||||
newSpawn = CreateNewSpawnCoordinates(FAR_CHUNK_SPAWN_DIST, 20)
|
|
||||||
else
|
|
||||||
newSpawn = CreateNewSpawnCoordinates(MIN_CHUNK_SPAWN_DIST, 20)
|
|
||||||
end
|
|
||||||
global.playerSpawns[player.name] = newSpawn
|
|
||||||
global.activePlayerSpawns[player.name] = true
|
|
||||||
|
|
||||||
-- Set the new spawn point
|
|
||||||
if (newForce ~= nil) then
|
|
||||||
newForce.set_spawn_position(newSpawn, "nauvis")
|
|
||||||
end
|
|
||||||
|
|
||||||
SendPlayerToNewSpawnAndCreateIt(player, newSpawn)
|
|
||||||
SendBroadcastMsg(player.name .. " is going it alone!")
|
|
||||||
|
|
||||||
-- Continue to respawn on your own team at that location
|
|
||||||
elseif (buttonClicked == "respawn_continue") then
|
|
||||||
GivePlayerItems(player)
|
|
||||||
|
|
||||||
|
|
||||||
-- If changing your spawn behavior
|
|
||||||
elseif (buttonClicked == "respawn_change") then
|
|
||||||
if (DoesPlayerHaveCustomSpawn(player)) then
|
|
||||||
DisplayRespawnOptions(player)
|
|
||||||
else
|
|
||||||
DisplaySpawnOptions(player)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Respawn with the main force in the default location
|
|
||||||
elseif (buttonClicked == "respawn_mainforce") then
|
|
||||||
|
|
||||||
-- Remove custom force if it exists
|
|
||||||
if (player.force.name ~= MAIN_FORCE) then
|
|
||||||
game.merge_forces(player.name, MAIN_FORCE)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Deactivate the stored spawn point
|
|
||||||
ActivatePlayerCustomSpawn(player, false)
|
|
||||||
player.teleport(player.force.get_spawn_position("nauvis"))
|
|
||||||
GivePlayerStarterItems(player)
|
|
||||||
SendBroadcastMsg(player.name .. " is returning to base!")
|
|
||||||
|
|
||||||
-- Respawn in your already generated custom spawn area on the main team
|
|
||||||
elseif (buttonClicked == "respawn_custom_spawn") then
|
|
||||||
|
|
||||||
-- Remove custom force if it exists
|
|
||||||
if (player.force.name ~= MAIN_FORCE) then
|
|
||||||
game.merge_forces(player.name, MAIN_FORCE)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Activate the stored spawn point
|
|
||||||
ActivatePlayerCustomSpawn(player, true)
|
|
||||||
SendPlayerToActiveSpawn(player)
|
|
||||||
GivePlayerStarterItems(player)
|
|
||||||
SendBroadcastMsg(player.name .. " is returning to their outpost!")
|
|
||||||
|
|
||||||
-- Respawn in your already generated custom spawn area but on your own
|
|
||||||
-- force. This force is created new if it doesn't exist.
|
|
||||||
elseif (buttonClicked == "respawn_custom_team") then
|
|
||||||
|
|
||||||
-- Create a new force using the player's name
|
|
||||||
local newForce = CreatePlayerCustomForce(player)
|
|
||||||
|
|
||||||
-- Set the new spawn point
|
|
||||||
if (newForce ~= nil) then
|
|
||||||
newForce.set_spawn_position(global.playerSpawns[player.name], "nauvis")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Activate the stored spawn point
|
|
||||||
ActivatePlayerCustomSpawn(player, true)
|
|
||||||
SendPlayerToActiveSpawn(player)
|
|
||||||
GivePlayerStarterItems(player)
|
|
||||||
SendBroadcastMsg(player.name .. " is returning to their outpost alone!")
|
|
||||||
|
|
||||||
-- lol wut
|
|
||||||
elseif (buttonClicked == "respawn_surpise") then
|
|
||||||
|
|
||||||
-- Remove custom force if it exists
|
|
||||||
if (player.force.name ~= MAIN_FORCE) then
|
|
||||||
game.merge_forces(player.name, MAIN_FORCE)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Activate the stored spawn point
|
|
||||||
SendPlayerToRandomSpawn(player)
|
|
||||||
GivePlayerStarterItems(player)
|
|
||||||
SendBroadcastMsg(player.name .. " is surprised!")
|
|
||||||
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- local testFlag = false
|
|
||||||
|
|
||||||
-- Check if the player has a different spawn point than the default one
|
|
||||||
-- Make sure to give the default starting items
|
|
||||||
script.on_event(defines.events.on_player_respawned, function(event)
|
|
||||||
local player = game.players[event.player_index]
|
|
||||||
|
|
||||||
-- local testSpawn
|
|
||||||
-- if testFlag then
|
|
||||||
-- testSpawn = CreateNewSpawnCoordinates(FAR_CHUNK_SPAWN_DIST, 20)
|
|
||||||
-- else
|
|
||||||
-- testSpawn = CreateNewSpawnCoordinates(MIN_CHUNK_SPAWN_DIST, 20)
|
|
||||||
-- end
|
|
||||||
-- testFlag = not testFlag
|
|
||||||
-- player.teleport(testSpawn)
|
|
||||||
-- DebugPrint("Test Spawn: " .. testSpawn.x .. "," .. testSpawn.y)
|
|
||||||
|
|
||||||
|
|
||||||
-- If a player has an active spawn, use it.
|
|
||||||
if (DoesPlayerHaveActiveCustomSpawn(player)) then
|
|
||||||
player.teleport(global.playerSpawns[player.name])
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Display the respawn continue option
|
|
||||||
DisplayRespawnContinueOption(player)
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- New spawn area tile generation and enemy clearing must go here
|
|
||||||
script.on_event(defines.events.on_chunk_generated, function(event)
|
|
||||||
local surface = event.surface
|
|
||||||
if surface.name ~= "nauvis" then return end
|
|
||||||
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.
|
|
||||||
for name,spawnPos in pairs(global.playerSpawns) do
|
|
||||||
|
|
||||||
local landArea = {left_top=
|
|
||||||
{x=spawnPos.x-ENFORCE_LAND_AREA_TILE_DIST,
|
|
||||||
y=spawnPos.y-ENFORCE_LAND_AREA_TILE_DIST},
|
|
||||||
right_bottom=
|
|
||||||
{x=spawnPos.x+ENFORCE_LAND_AREA_TILE_DIST,
|
|
||||||
y=spawnPos.y+ENFORCE_LAND_AREA_TILE_DIST}}
|
|
||||||
|
|
||||||
local safeArea = {left_top=
|
|
||||||
{x=spawnPos.x-SAFE_AREA_TILE_DIST,
|
|
||||||
y=spawnPos.y-SAFE_AREA_TILE_DIST},
|
|
||||||
right_bottom=
|
|
||||||
{x=spawnPos.x+SAFE_AREA_TILE_DIST,
|
|
||||||
y=spawnPos.y+SAFE_AREA_TILE_DIST}}
|
|
||||||
|
|
||||||
local warningArea = {left_top=
|
|
||||||
{x=spawnPos.x-WARNING_AREA_TILE_DIST,
|
|
||||||
y=spawnPos.y-WARNING_AREA_TILE_DIST},
|
|
||||||
right_bottom=
|
|
||||||
{x=spawnPos.x+WARNING_AREA_TILE_DIST,
|
|
||||||
y=spawnPos.y+WARNING_AREA_TILE_DIST}}
|
|
||||||
|
|
||||||
local chunkAreaCenter = {x=chunkArea.left_top.x+(CHUNK_SIZE/2),
|
|
||||||
y=chunkArea.left_top.y+(CHUNK_SIZE/2)}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Make chunks near a spawn safe by removing enemies
|
|
||||||
if CheckIfInArea(chunkAreaCenter,safeArea) then
|
|
||||||
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, force = "enemy"}) do
|
|
||||||
entity.destroy()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Create a warning area with reduced enemies
|
|
||||||
elseif CheckIfInArea(chunkAreaCenter,warningArea) then
|
|
||||||
local counter = 0
|
|
||||||
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, force = "enemy"}) do
|
|
||||||
if ((counter % WARN_AREA_REDUCTION_RATIO) ~= 0) then
|
|
||||||
entity.destroy()
|
|
||||||
end
|
|
||||||
counter = counter + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Remove all big and huge worms
|
|
||||||
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, name = "medium-worm-turret"}) do
|
|
||||||
entity.destroy()
|
|
||||||
end
|
|
||||||
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, name = "big-worm-turret"}) do
|
|
||||||
entity.destroy()
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Fill in any water to make sure we have guaranteed land mass at the spawn point.
|
|
||||||
if CheckIfInArea(chunkAreaCenter,landArea) then
|
|
||||||
|
|
||||||
-- remove trees in the immediate areas?
|
|
||||||
for key, entity in pairs(surface.find_entities_filtered({area=chunkArea, type= "tree"})) do
|
|
||||||
if ((spawnPos.x - entity.position.x)^2 + (spawnPos.y - entity.position.y)^2 < ENFORCE_LAND_AREA_TILE_DIST^2) then
|
|
||||||
entity.destroy()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local dirtTiles = {}
|
|
||||||
for i=chunkArea.left_top.x,chunkArea.right_bottom.x,1 do
|
|
||||||
for j=chunkArea.left_top.y,chunkArea.right_bottom.y,1 do
|
|
||||||
|
|
||||||
-- This ( X^2 + Y^2 ) is used to calculate if something
|
|
||||||
-- is inside a circle area.
|
|
||||||
local distVar = math.floor((spawnPos.x - i)^2 + (spawnPos.y - j)^2)
|
|
||||||
|
|
||||||
-- Fill in all unexpected water in a circle
|
|
||||||
if (distVar < ENFORCE_LAND_AREA_TILE_DIST_SQUARED) then
|
|
||||||
if (surface.get_tile(i,j).collides_with("water-tile")) then
|
|
||||||
table.insert(dirtTiles, {name = "grass", position ={i,j}})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Create a circle of trees around the spawn point.
|
|
||||||
if ((distVar < ENFORCE_LAND_AREA_TILE_DIST_SQUARED-200) and
|
|
||||||
(distVar > ENFORCE_LAND_AREA_TILE_DIST_SQUARED-260)) then
|
|
||||||
surface.create_entity({name="tree-01", amount=1, position={i, j}})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
surface.set_tiles(dirtTiles)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Provide a guaranteed spot of water to use for power generation
|
|
||||||
if CheckIfInArea(spawnPos,chunkArea) then
|
|
||||||
local waterTiles = {{name = "water", position ={spawnPos.x+0,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+1,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+2,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+3,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+4,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+5,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+6,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+7,spawnPos.y-30}},
|
|
||||||
{name = "water", position ={spawnPos.x+8,spawnPos.y-30}}}
|
|
||||||
-- DebugPrint("Setting water tiles in this chunk! " .. chunkArea.left_top.x .. "," .. chunkArea.left_top.y)
|
|
||||||
surface.set_tiles(waterTiles)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Remove decor to save on file size
|
|
||||||
RemoveDecorationsArea(surface, chunkArea)
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
-- On init stuff
|
||||||
script.on_init(function(event)
|
script.on_init(function(event)
|
||||||
|
if ENABLE_SEPARATE_SPAWNS then
|
||||||
|
-- For separate spawns stuff required on init
|
||||||
|
InitSpawnGlobalsAndForces()
|
||||||
|
|
||||||
-- Containes an array of all player spawns
|
-- Adjust alien params
|
||||||
-- A secondary array tracks whether the character will respawn there.
|
game.map_settings.enemy_evolution.time_factor=0
|
||||||
if (global.playerSpawns == nil) then
|
game.map_settings.enemy_evolution.destroy_factor = game.map_settings.enemy_evolution.destroy_factor / ENEMY_DESTROY_FACTOR_DIVISOR
|
||||||
global.playerSpawns = {}
|
game.map_settings.enemy_evolution.pollution_factor = game.map_settings.enemy_evolution.pollution_factor / ENEMY_POLLUTION_FACTOR_DIVISOR
|
||||||
global.activePlayerSpawns = {}
|
game.map_settings.enemy_expansion.enabled = ENEMY_EXPANSION
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Adjust alien params
|
if FRONTIER_ROCKET_SILO_MODE then
|
||||||
game.map_settings.enemy_evolution.time_factor=0
|
game.forces[MAIN_FORCE].chart(game.surfaces["nauvis"], {{SILO_POSITION.x-CHUNK_SIZE, SILO_POSITION.y-CHUNK_SIZE}, {SILO_POSITION.x+CHUNK_SIZE, SILO_POSITION.y+CHUNK_SIZE}})
|
||||||
game.map_settings.enemy_evolution.destroy_factor = game.map_settings.enemy_evolution.destroy_factor / ENEMY_DESTROY_FACTOR_DIVISOR
|
end
|
||||||
game.map_settings.enemy_evolution.pollution_factor = game.map_settings.enemy_evolution.pollution_factor / ENEMY_POLLUTION_FACTOR_DIVISOR
|
|
||||||
game.map_settings.enemy_expansion.enabled = ENEMY_EXPANSION
|
|
||||||
|
|
||||||
game.create_force(MAIN_FORCE)
|
|
||||||
game.forces[MAIN_FORCE].set_spawn_position(game.forces["player"].get_spawn_position("nauvis"), "nauvis")
|
|
||||||
SetCeaseFireBetweenAllForces()
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
-- Freeplay rocket launch info
|
-- Freeplay rocket launch info
|
||||||
|
-- Slightly modified for my purposes
|
||||||
script.on_event(defines.events.on_rocket_launched, function(event)
|
script.on_event(defines.events.on_rocket_launched, function(event)
|
||||||
local force = event.rocket.force
|
local force = event.rocket.force
|
||||||
if event.rocket.get_item_count("satellite") == 0 then
|
if event.rocket.get_item_count("satellite") == 0 then
|
||||||
@ -940,66 +76,3 @@ script.on_event(defines.events.on_rocket_launched, function(event)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Return steel chest entity (or nil)
|
|
||||||
local function DropEmptySteelChest(player)
|
|
||||||
local pos = player.surface.find_non_colliding_position("steel-chest", player.position, 15, 1)
|
|
||||||
if not pos then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
local grave = player.surface.create_entity{name="steel-chest", position=pos, force="neutral"}
|
|
||||||
return grave
|
|
||||||
end
|
|
||||||
|
|
||||||
-- My modified version of gravestone. Makes sure you get all items even if
|
|
||||||
-- it requires multiple steel chests.
|
|
||||||
script.on_event(defines.events.on_player_died, function(event)
|
|
||||||
|
|
||||||
local player = game.players[event.player_index]
|
|
||||||
|
|
||||||
-- Create the 1st chest to fill
|
|
||||||
local grave = DropEmptySteelChest(player)
|
|
||||||
if (grave == nil) then
|
|
||||||
player.print("Not able to place a chest nearby! All items lost!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Init the inventroy space counter
|
|
||||||
local grave_inv = grave.get_inventory(defines.inventory.chest)
|
|
||||||
local count = 0
|
|
||||||
|
|
||||||
-- Loop through a players different inventories
|
|
||||||
-- Put it all into the chest
|
|
||||||
-- If the chest is full, create a new chest.
|
|
||||||
for i, id in ipairs{
|
|
||||||
defines.inventory.player_armor,
|
|
||||||
defines.inventory.player_main,
|
|
||||||
defines.inventory.player_quickbar,
|
|
||||||
defines.inventory.player_guns,
|
|
||||||
defines.inventory.player_ammo,
|
|
||||||
defines.inventory.player_tools,
|
|
||||||
defines.inventory.player_trash} do
|
|
||||||
local inv = player.get_inventory(id)
|
|
||||||
for j = 1, #inv do
|
|
||||||
if inv[j].valid_for_read then
|
|
||||||
count = count + 1
|
|
||||||
|
|
||||||
grave_inv[count].set_stack(inv[j])
|
|
||||||
|
|
||||||
if (count == #grave_inv) then
|
|
||||||
count = 0
|
|
||||||
grave = DropEmptySteelChest(player)
|
|
||||||
if (grave == nil) then
|
|
||||||
player.print("Not able to place a chest nearby! Some items lost!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
grave_inv = grave.get_inventory(defines.inventory.chest)
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
player.print("Successfully dropped your items into a chest! Go get them quick!")
|
|
||||||
|
|
||||||
end)
|
|
||||||
|
269
drand.lua
Normal file
269
drand.lua
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
--[[------------------------------------
|
||||||
|
RandomLua v0.3.1
|
||||||
|
Pure Lua Pseudo-Random Numbers Generator
|
||||||
|
Under the MIT license.
|
||||||
|
copyright(c) 2011 linux-man
|
||||||
|
--]]------------------------------------
|
||||||
|
|
||||||
|
local _M = {}
|
||||||
|
local mod = math.fmod
|
||||||
|
local floor = math.floor
|
||||||
|
local abs = math.abs
|
||||||
|
|
||||||
|
local function normalize(n) --keep numbers at (positive) 32 bits
|
||||||
|
return n % 0x80000000
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_and(a, b)
|
||||||
|
local r = 0
|
||||||
|
local m = 0
|
||||||
|
for m = 0, 31 do
|
||||||
|
if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end
|
||||||
|
if a % 2 ~= 0 then a = a - 1 end
|
||||||
|
if b % 2 ~= 0 then b = b - 1 end
|
||||||
|
a = a / 2 b = b / 2
|
||||||
|
end
|
||||||
|
return normalize(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_or(a, b)
|
||||||
|
local r = 0
|
||||||
|
local m = 0
|
||||||
|
for m = 0, 31 do
|
||||||
|
if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end
|
||||||
|
if a % 2 ~= 0 then a = a - 1 end
|
||||||
|
if b % 2 ~= 0 then b = b - 1 end
|
||||||
|
a = a / 2 b = b / 2
|
||||||
|
end
|
||||||
|
return normalize(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_xor(a, b)
|
||||||
|
local r = 0
|
||||||
|
local m = 0
|
||||||
|
for m = 0, 31 do
|
||||||
|
if a % 2 ~= b % 2 then r = r + 2^m end
|
||||||
|
if a % 2 ~= 0 then a = a - 1 end
|
||||||
|
if b % 2 ~= 0 then b = b - 1 end
|
||||||
|
a = a / 2 b = b / 2
|
||||||
|
end
|
||||||
|
return normalize(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function seed()
|
||||||
|
--return normalize(tonumber(tostring(os.time()):reverse()))
|
||||||
|
return normalize(os.time())
|
||||||
|
end
|
||||||
|
|
||||||
|
--Mersenne twister
|
||||||
|
mersenne_twister = {}
|
||||||
|
mersenne_twister.__index = mersenne_twister
|
||||||
|
|
||||||
|
function mersenne_twister:randomseed(s)
|
||||||
|
if not s then s = seed() end
|
||||||
|
self.mt[0] = normalize(s)
|
||||||
|
for i = 1, 623 do
|
||||||
|
self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], floor(self.mt[i-1] / 0x40000000)) + i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mersenne_twister:random(a, b)
|
||||||
|
local y
|
||||||
|
if self.index == 0 then
|
||||||
|
for i = 0, 623 do
|
||||||
|
--y = bit_or(floor(self.mt[i] / 0x80000000) * 0x80000000, self.mt[(i + 1) % 624] % 0x80000000)
|
||||||
|
y = self.mt[(i + 1) % 624] % 0x80000000
|
||||||
|
self.mt[i] = bit_xor(self.mt[(i + 397) % 624], floor(y / 2))
|
||||||
|
if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
y = self.mt[self.index]
|
||||||
|
y = bit_xor(y, floor(y / 0x800))
|
||||||
|
y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680))
|
||||||
|
y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000))
|
||||||
|
y = bit_xor(y, floor(y / 0x40000))
|
||||||
|
self.index = (self.index + 1) % 624
|
||||||
|
if not a then return y / 0x80000000
|
||||||
|
elseif not b then
|
||||||
|
if a == 0 then return y
|
||||||
|
else return 1 + (y % a)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return a + (y % (b - a + 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _M.twister(s)
|
||||||
|
local temp = {}
|
||||||
|
setmetatable(temp, mersenne_twister)
|
||||||
|
temp.mt = {}
|
||||||
|
temp.index = 0
|
||||||
|
temp:randomseed(s)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
--Linear Congruential Generator
|
||||||
|
linear_congruential_generator = {}
|
||||||
|
linear_congruential_generator.__index = linear_congruential_generator
|
||||||
|
|
||||||
|
function linear_congruential_generator:random(a, b)
|
||||||
|
local y = (self.a * self.x + self.c) % self.m
|
||||||
|
self.x = y
|
||||||
|
if not a then return y / 0x10000
|
||||||
|
elseif not b then
|
||||||
|
if a == 0 then return y
|
||||||
|
else return 1 + (y % a) end
|
||||||
|
else
|
||||||
|
return a + (y % (b - a + 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function linear_congruential_generator:randomseed(s)
|
||||||
|
if not s then s = seed() end
|
||||||
|
self.x = normalize(s)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _M.lcg(s, r)
|
||||||
|
local temp = {}
|
||||||
|
setmetatable(temp, linear_congruential_generator)
|
||||||
|
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
|
||||||
|
if r then
|
||||||
|
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
|
||||||
|
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
|
||||||
|
end
|
||||||
|
temp:randomseed(s)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Multiply-with-carry
|
||||||
|
multiply_with_carry = {}
|
||||||
|
multiply_with_carry.__index = multiply_with_carry
|
||||||
|
|
||||||
|
function multiply_with_carry:random(a, b)
|
||||||
|
local m = self.m
|
||||||
|
local t = self.a * self.x + self.c
|
||||||
|
local y = t % m
|
||||||
|
self.x = y
|
||||||
|
self.c = floor(t / m)
|
||||||
|
if not a then return y / 0x10000
|
||||||
|
elseif not b then
|
||||||
|
if a == 0 then return y
|
||||||
|
else return 1 + (y % a) end
|
||||||
|
else
|
||||||
|
local diff = 0
|
||||||
|
if a == b then return a end
|
||||||
|
if a < 0 then
|
||||||
|
diff = abs(a)
|
||||||
|
a = a + diff
|
||||||
|
b = b + diff
|
||||||
|
end
|
||||||
|
return a + (y % (b - a + 1)) - diff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function multiply_with_carry:randomseed(s)
|
||||||
|
if not s then s = seed() end
|
||||||
|
self.c = self.ic
|
||||||
|
self.x = normalize(s)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _M.mwc(s, r)
|
||||||
|
local temp = {}
|
||||||
|
setmetatable(temp, multiply_with_carry)
|
||||||
|
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
|
||||||
|
if r then
|
||||||
|
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
|
||||||
|
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
|
||||||
|
end
|
||||||
|
temp.ic = temp.c
|
||||||
|
temp:randomseed(s)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
function _M.mwvc(s)
|
||||||
|
return _M.mwc(s, 'mvc')
|
||||||
|
end
|
||||||
|
|
||||||
|
local B = 0x10000
|
||||||
|
|
||||||
|
-- rough adaptation of Knuth float generator
|
||||||
|
function _M.krandom( seedobj, fVal1, fVal2 )
|
||||||
|
local ma = seedobj.ma
|
||||||
|
local seed = seedobj.seed
|
||||||
|
local mj, mk
|
||||||
|
if seed < 0 or not ma then
|
||||||
|
ma = {}
|
||||||
|
seedobj.ma = ma
|
||||||
|
mj = normalize( seed )
|
||||||
|
mj = mod( mj, B )
|
||||||
|
ma[55] = mj
|
||||||
|
mk = 1
|
||||||
|
for i = 1, 54 do
|
||||||
|
local ii = mod( 21 * i, 55 )
|
||||||
|
ma[ii] = mk
|
||||||
|
mk = mj - mk
|
||||||
|
if mk < 0 then mk = mk + B end
|
||||||
|
mj = ma[ii]
|
||||||
|
end
|
||||||
|
for k = 1, 4 do
|
||||||
|
for i = 1, 55 do
|
||||||
|
ma[i] = ma[i] - ma[ 1 + mod( i + 30, 55) ]
|
||||||
|
if ma[i] < 0 then ma[i] = ma[i] + B end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
seedobj.inext = 0
|
||||||
|
seedobj.inextp = 31
|
||||||
|
seedobj.seed = 1
|
||||||
|
end -- if
|
||||||
|
local inext = seedobj.inext
|
||||||
|
local inextp = seedobj.inextp
|
||||||
|
inext = inext + 1
|
||||||
|
if inext == 56 then inext = 1 end
|
||||||
|
seedobj.inext = inext
|
||||||
|
inextp = inextp + 1
|
||||||
|
if inextp == 56 then inextp = 1 end
|
||||||
|
seedobj.inextp = inextp
|
||||||
|
mj = ma[ inext ] - ma[ inextp ]
|
||||||
|
if mj < 0 then mj = mj + B end
|
||||||
|
ma[ inext ] = mj
|
||||||
|
local temp_rand = mj / B
|
||||||
|
if fVal2 then
|
||||||
|
return floor( fVal1 + 0.5 + temp_rand * ( fVal2 - fVal1 ) )
|
||||||
|
elseif fVal1 then
|
||||||
|
return floor( temp_rand * fVal1 ) + 1
|
||||||
|
else
|
||||||
|
return temp_rand
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sys rand
|
||||||
|
sys_rand = {}
|
||||||
|
sys_rand.__index = sys_rand
|
||||||
|
function sys_rand:random(a, b)
|
||||||
|
local diff = 0
|
||||||
|
if a and b and a == b then math.random(); return a end
|
||||||
|
if a and b then
|
||||||
|
if a < 0 then
|
||||||
|
diff = abs(a)
|
||||||
|
a = a + diff
|
||||||
|
b = b + diff
|
||||||
|
end
|
||||||
|
return math.random(a, b) - diff
|
||||||
|
end
|
||||||
|
if a and a == 0 then return floor(math.random() * 0x10000) end
|
||||||
|
if a then return math.random(a) end
|
||||||
|
return math.random()
|
||||||
|
end
|
||||||
|
|
||||||
|
function sys_rand:randomseed(s)
|
||||||
|
-- ignore
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
function _M.sys_rand(s)
|
||||||
|
local temp = {}
|
||||||
|
setmetatable(temp, sys_rand)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
return _M
|
123
event.lua
Normal file
123
event.lua
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
--Event Capture
|
||||||
|
--A 3Ra Gaming revision, original from Factorio-Stdlib by Afforess
|
||||||
|
-- @module Event
|
||||||
|
|
||||||
|
function fail_if_missing(var, msg)
|
||||||
|
if not var then
|
||||||
|
if msg then
|
||||||
|
error(msg, 3)
|
||||||
|
else
|
||||||
|
error("Missing value", 3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Event = {
|
||||||
|
_registry = {},
|
||||||
|
core_events = {
|
||||||
|
init = -1,
|
||||||
|
load = -2,
|
||||||
|
configuration_changed = -3,
|
||||||
|
_register = function(id)
|
||||||
|
if id == Event.core_events.init then
|
||||||
|
script.on_init(function()
|
||||||
|
Event.dispatch({name = Event.core_events.init, tick = game.tick})
|
||||||
|
end)
|
||||||
|
elseif id == Event.core_events.load then
|
||||||
|
script.on_load(function()
|
||||||
|
Event.dispatch({name = Event.core_events.load, tick = -1})
|
||||||
|
end)
|
||||||
|
elseif id == Event.core_events.configuration_changed then
|
||||||
|
script.on_configuration_changed(function(data)
|
||||||
|
Event.dispatch({name = Event.core_events.configuration_changed, tick = game.tick, data = data})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Registers a function for a given event
|
||||||
|
-- @param event or array containing events to register
|
||||||
|
-- @param handler Function to call when event is triggered
|
||||||
|
-- @return #Event
|
||||||
|
function Event.register(event, handler)
|
||||||
|
fail_if_missing(event, "missing event argument")
|
||||||
|
|
||||||
|
if type(event) == "number" then
|
||||||
|
event = {event}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, event_id in pairs(event) do
|
||||||
|
fail_if_missing(event_id, "missing event id")
|
||||||
|
if handler == nil then
|
||||||
|
Event._registry[event_id] = nil
|
||||||
|
script.on_event(event_id, nil)
|
||||||
|
else
|
||||||
|
if not Event._registry[event_id] then
|
||||||
|
Event._registry[event_id] = {}
|
||||||
|
|
||||||
|
if event_id >= 0 then
|
||||||
|
script.on_event(event_id, Event.dispatch)
|
||||||
|
else
|
||||||
|
Event.core_events._register(event_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(Event._registry[event_id], handler)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return Event
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calls the registerd handlers
|
||||||
|
-- @param event LuaEvent as created by game.raise_event
|
||||||
|
function Event.dispatch(event)
|
||||||
|
fail_if_missing(event, "missing event argument")
|
||||||
|
if Event._registry[event.name] then
|
||||||
|
for _, handler in pairs(Event._registry[event.name]) do
|
||||||
|
local metatbl = { __index = function(tbl, key) if key == '_handler' then return handler else return rawget(tbl, key) end end }
|
||||||
|
setmetatable(event, metatbl)
|
||||||
|
local success, err = pcall(handler, event)
|
||||||
|
if not success then
|
||||||
|
-- may be nil in on_load
|
||||||
|
game.print(err)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if err then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes the handler from the event
|
||||||
|
-- @param event event or array containing events to remove the handler
|
||||||
|
-- @param handler to remove
|
||||||
|
-- @return #Event
|
||||||
|
function Event.remove(event, handler)
|
||||||
|
fail_if_missing(event, "missing event argument")
|
||||||
|
fail_if_missing(handler, "missing handler argument")
|
||||||
|
|
||||||
|
if type(event) == "number" then
|
||||||
|
event = {event}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, event_id in pairs(event) do
|
||||||
|
fail_if_missing(event_id, "missing event id")
|
||||||
|
if Event._registry[event_id] then
|
||||||
|
for i=#Event._registry[event_id], 1, -1 do
|
||||||
|
if Event._registry[event_id][i] == handler then
|
||||||
|
table.remove(Event._registry[event_id], i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #Event._registry[event_id] == 0 then
|
||||||
|
Event._registry[event_id] = nil
|
||||||
|
script.on_event(event_id, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return Event
|
||||||
|
end
|
||||||
|
|
||||||
|
return Event
|
104
metaball.lua
Normal file
104
metaball.lua
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
--[[--
|
||||||
|
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
|
472
oarc_utils.lua
Normal file
472
oarc_utils.lua
Normal file
@ -0,0 +1,472 @@
|
|||||||
|
-- oarc_utils.lua
|
||||||
|
--
|
||||||
|
-- My general purpose utility functions for factorio
|
||||||
|
-- Also contains some constants and gui styles
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Useful constants
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
CHUNK_SIZE = 32
|
||||||
|
MAX_FORCES = 64
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- GUI Label Styles
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
my_label_style = {
|
||||||
|
minimal_width = 450,
|
||||||
|
maximal_width = 450,
|
||||||
|
font_color = {r=1,g=1,b=1}
|
||||||
|
}
|
||||||
|
my_note_style = {
|
||||||
|
minimal_width = 450,
|
||||||
|
maximal_height = 10,
|
||||||
|
font = "default-small-semibold",
|
||||||
|
font_color = {r=1,g=0.5,b=0.5}
|
||||||
|
}
|
||||||
|
my_warning_style = {
|
||||||
|
minimal_width = 450,
|
||||||
|
maximal_width = 450,
|
||||||
|
font_color = {r=1,g=0.1,b=0.1}
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Print debug only to me while testing.
|
||||||
|
-- Should remove this if you are hosting it yourself.
|
||||||
|
function DebugPrint(msg)
|
||||||
|
if ((game.players["Oarc"] ~= nil) and (global.oarcDebugEnabled)) then
|
||||||
|
game.players["Oarc"].print("DEBUG: " .. msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Broadcast messages
|
||||||
|
function SendBroadcastMsg(msg)
|
||||||
|
for name,player in pairs(game.connected_players) do
|
||||||
|
player.print(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Simple function to get total number of items in table
|
||||||
|
function TableLength(T)
|
||||||
|
local count = 0
|
||||||
|
for _ in pairs(T) do count = count + 1 end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Give player these default items.
|
||||||
|
function GivePlayerItems(player)
|
||||||
|
player.insert{name="pistol", count=1}
|
||||||
|
player.insert{name="firearm-magazine", count=10}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Additional starter only items
|
||||||
|
function GivePlayerStarterItems(player)
|
||||||
|
GivePlayerItems(player)
|
||||||
|
player.insert{name="iron-plate", count=8}
|
||||||
|
player.insert{name="burner-mining-drill", count = 1}
|
||||||
|
player.insert{name="stone-furnace", count = 1}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if given position is in area bounding box
|
||||||
|
function CheckIfInArea(point, area)
|
||||||
|
if ((point.x > area.left_top.x) and (point.x < area.right_bottom.x)) then
|
||||||
|
if ((point.y > area.left_top.y) and (point.y < area.right_bottom.y)) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ceasefire
|
||||||
|
-- All forces are always neutral
|
||||||
|
function SetCeaseFireBetweenAllForces()
|
||||||
|
for name,team in pairs(game.forces) do
|
||||||
|
if name ~= "neutral" and name ~= "enemy" then
|
||||||
|
for x,y in pairs(game.forces) do
|
||||||
|
if x ~= "neutral" and x ~= "enemy" then
|
||||||
|
team.set_cease_fire(x,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Undecorator
|
||||||
|
function RemoveDecorationsArea(surface, area )
|
||||||
|
for _, entity in pairs(surface.find_entities_filtered{area = area, type="decorative"}) do
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply a style option to a GUI
|
||||||
|
function ApplyStyle (guiIn, styleIn)
|
||||||
|
for k,v in pairs(styleIn) do
|
||||||
|
guiIn.style[k]=v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get a random 1 or -1
|
||||||
|
function RandomNegPos()
|
||||||
|
if (math.random(0,1) == 1) then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create a random direction vector to look in
|
||||||
|
function GetRandomVector()
|
||||||
|
local randVec = {x=0,y=0}
|
||||||
|
while ((randVec.x == 0) and (randVec.y == 0)) do
|
||||||
|
randVec.x = math.random(-3,3)
|
||||||
|
randVec.y = math.random(-3,3)
|
||||||
|
end
|
||||||
|
DebugPrint("direction: x=" .. randVec.x .. ", y=" .. randVec.y)
|
||||||
|
return randVec
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check for ungenerated chunks around a specific chunk
|
||||||
|
-- +/- chunkDist in x and y directions
|
||||||
|
function IsChunkAreaUngenerated(chunkPos, chunkDist)
|
||||||
|
for x=-chunkDist, chunkDist do
|
||||||
|
for y=-chunkDist, chunkDist do
|
||||||
|
local checkPos = {x=chunkPos.x+x,
|
||||||
|
y=chunkPos.y+y}
|
||||||
|
if (game.surfaces["nauvis"].is_chunk_generated(checkPos)) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clear out enemies around an area with a certain distance
|
||||||
|
function ClearNearbyEnemies(player, safeDist)
|
||||||
|
local safeArea = {left_top=
|
||||||
|
{x=player.position.x-safeDist,
|
||||||
|
y=player.position.y-safeDist},
|
||||||
|
right_bottom=
|
||||||
|
{x=player.position.x+safeDist,
|
||||||
|
y=player.position.y+safeDist}}
|
||||||
|
|
||||||
|
for _, entity in pairs(player.surface.find_entities_filtered{area = safeArea, force = "enemy"}) do
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Function to find coordinates of ungenerated map area in a given direction
|
||||||
|
-- starting from the center of the map
|
||||||
|
function FindMapEdge(directionVec)
|
||||||
|
local position = {x=0,y=0}
|
||||||
|
local chunkPos = {x=0,y=0}
|
||||||
|
|
||||||
|
-- Keep checking chunks in the direction of the vector
|
||||||
|
while(true) do
|
||||||
|
|
||||||
|
-- Set some absolute limits.
|
||||||
|
if ((math.abs(chunkPos.x) > 1000) or (math.abs(chunkPos.y) > 1000)) then
|
||||||
|
break
|
||||||
|
|
||||||
|
-- If chunk is already generated, keep looking
|
||||||
|
elseif (game.surfaces["nauvis"].is_chunk_generated(chunkPos)) then
|
||||||
|
chunkPos.x = chunkPos.x + directionVec.x
|
||||||
|
chunkPos.y = chunkPos.y + directionVec.y
|
||||||
|
|
||||||
|
-- Found a possible ungenerated area
|
||||||
|
else
|
||||||
|
|
||||||
|
chunkPos.x = chunkPos.x + directionVec.x
|
||||||
|
chunkPos.y = chunkPos.y + directionVec.y
|
||||||
|
|
||||||
|
-- Check there are no generated chunks in a 10x10 area.
|
||||||
|
if IsChunkAreaUngenerated(chunkPos, 5) then
|
||||||
|
position.x = (chunkPos.x*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||||
|
position.y = (chunkPos.y*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DebugPrint("spawn: x=" .. position.x .. ", y=" .. position.y)
|
||||||
|
return position
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Find random coordinates within a given distance away
|
||||||
|
-- maxTries is the recursion limit basically.
|
||||||
|
function FindUngeneratedCoordinates(minDistChunks, maxDistChunks)
|
||||||
|
local position = {x=0,y=0}
|
||||||
|
local chunkPos = {x=0,y=0}
|
||||||
|
|
||||||
|
local maxTries = 100
|
||||||
|
local tryCounter = 0
|
||||||
|
|
||||||
|
local minDistSqr = minDistChunks^2
|
||||||
|
local maxDistSqr = maxDistChunks^2
|
||||||
|
|
||||||
|
while(true) do
|
||||||
|
chunkPos.x = math.random(0,maxDistChunks) * RandomNegPos()
|
||||||
|
chunkPos.y = math.random(0,maxDistChunks) * RandomNegPos()
|
||||||
|
|
||||||
|
local distSqrd = chunkPos.x^2 + chunkPos.y^2
|
||||||
|
|
||||||
|
-- Enforce a max number of tries
|
||||||
|
tryCounter = tryCounter + 1
|
||||||
|
if (tryCounter > maxTries) then
|
||||||
|
break
|
||||||
|
|
||||||
|
-- Check that the distance is within the min,max specified
|
||||||
|
elseif ((distSqrd < minDistSqr) or (distSqrd > maxDistSqr)) then
|
||||||
|
-- Keep searching!
|
||||||
|
|
||||||
|
-- Check there are no generated chunks in a 10x10 area.
|
||||||
|
elseif IsChunkAreaUngenerated(chunkPos, 5) then
|
||||||
|
position.x = (chunkPos.x*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||||
|
position.y = (chunkPos.y*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||||
|
break -- SUCCESS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DebugPrint("spawn: x=" .. position.x .. ", y=" .. position.y)
|
||||||
|
return position
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return steel chest entity (or nil)
|
||||||
|
function DropEmptySteelChest(player)
|
||||||
|
local pos = player.surface.find_non_colliding_position("steel-chest", player.position, 15, 1)
|
||||||
|
if not pos then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local grave = player.surface.create_entity{name="steel-chest", position=pos, force="neutral"}
|
||||||
|
return grave
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Gravestone soft mod. With my own modifications/improvements.
|
||||||
|
function DropGravestoneChests(player)
|
||||||
|
|
||||||
|
local grave
|
||||||
|
local count = 0
|
||||||
|
|
||||||
|
-- Use "game.player.cursorstack" to get items in player's hand.
|
||||||
|
|
||||||
|
-- Loop through a players different inventories
|
||||||
|
-- Put it all into the chest
|
||||||
|
-- If the chest is full, create a new chest.
|
||||||
|
for i, id in ipairs{
|
||||||
|
defines.inventory.player_armor,
|
||||||
|
defines.inventory.player_main,
|
||||||
|
defines.inventory.player_quickbar,
|
||||||
|
defines.inventory.player_guns,
|
||||||
|
defines.inventory.player_ammo,
|
||||||
|
defines.inventory.player_tools,
|
||||||
|
defines.inventory.player_trash} do
|
||||||
|
local inv = player.get_inventory(id)
|
||||||
|
if (not inv.is_empty()) then
|
||||||
|
for j = 1, #inv do
|
||||||
|
if inv[j].valid_for_read then
|
||||||
|
|
||||||
|
-- Create a chest when counter is reset
|
||||||
|
if (count == 0) then
|
||||||
|
grave = DropEmptySteelChest(player)
|
||||||
|
if (grave == nil) then
|
||||||
|
player.print("Not able to place a chest nearby! Some items lost!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
grave_inv = grave.get_inventory(defines.inventory.chest)
|
||||||
|
end
|
||||||
|
count = count + 1
|
||||||
|
|
||||||
|
grave_inv[count].set_stack(inv[j])
|
||||||
|
|
||||||
|
-- Reset counter when chest is full
|
||||||
|
if (count == #grave_inv) then
|
||||||
|
count = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (grave ~= nil) then
|
||||||
|
player.print("Successfully dropped your items into a chest! Go get them quick!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Enforce a circle of land, also adds trees in a ring around the area.
|
||||||
|
function CreateCropCircle(surface, centerPos, chunkArea, tileRadius)
|
||||||
|
|
||||||
|
local tileRadSqr = tileRadius^2
|
||||||
|
|
||||||
|
local dirtTiles = {}
|
||||||
|
for i=chunkArea.left_top.x,chunkArea.right_bottom.x,1 do
|
||||||
|
for j=chunkArea.left_top.y,chunkArea.right_bottom.y,1 do
|
||||||
|
|
||||||
|
-- This ( X^2 + Y^2 ) is used to calculate if something
|
||||||
|
-- is inside a circle area.
|
||||||
|
local distVar = math.floor((centerPos.x - i)^2 + (centerPos.y - j)^2)
|
||||||
|
|
||||||
|
-- Fill in all unexpected water in a circle
|
||||||
|
if (distVar < tileRadSqr) then
|
||||||
|
if (surface.get_tile(i,j).collides_with("water-tile")) then
|
||||||
|
table.insert(dirtTiles, {name = "grass", position ={i,j}})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create a circle of trees around the spawn point.
|
||||||
|
if ((distVar < tileRadSqr-200) and
|
||||||
|
(distVar > tileRadSqr-260)) then
|
||||||
|
surface.create_entity({name="tree-01", amount=1, position={i, j}})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
surface.set_tiles(dirtTiles)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- THIS DOES NOT WORK IN SCENARIOS!
|
||||||
|
-- function DisableVanillaResouresAndEnemies()
|
||||||
|
|
||||||
|
-- local map_gen_ctrls = game.surfaces["nauvis"].map_gen_settings.autoplace_controls
|
||||||
|
|
||||||
|
-- map_gen_ctrls["coal"].size = "none"
|
||||||
|
-- map_gen_ctrls["stone"].size = "none"
|
||||||
|
-- map_gen_ctrls["iron-ore"].size = "none"
|
||||||
|
-- map_gen_ctrls["copper-ore"].size = "none"
|
||||||
|
-- map_gen_ctrls["crude-oil"].size = "none"
|
||||||
|
-- map_gen_ctrls["enemy-base"].size = "none"
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- Create a rocket silo
|
||||||
|
function CreateRocketSilo(surface, chunkArea)
|
||||||
|
if CheckIfInArea(SILO_POSITION, chunkArea) then
|
||||||
|
|
||||||
|
-- Delete any entities beneat the silo?
|
||||||
|
for _, entity in pairs(surface.find_entities_filtered{area = {{SILO_POSITION.x-5, SILO_POSITION.y-6},{SILO_POSITION.x+6, SILO_POSITION.y+6}}}) do
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set tiles below the silo
|
||||||
|
local tiles = {}
|
||||||
|
local i = 1
|
||||||
|
for dx = -6,6 do
|
||||||
|
for dy = -7,6 do
|
||||||
|
tiles[i] = {name = "grass", position = {SILO_POSITION.x+dx, SILO_POSITION.y+dy}}
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
surface.set_tiles(tiles, false)
|
||||||
|
tiles = {}
|
||||||
|
i = 1
|
||||||
|
for dx = -5,5 do
|
||||||
|
for dy = -6,5 do
|
||||||
|
tiles[i] = {name = "concrete", position = {SILO_POSITION.x+dx, SILO_POSITION.y+dy}}
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
surface.set_tiles(tiles, true)
|
||||||
|
|
||||||
|
-- Create silo and assign to main force
|
||||||
|
local silo = surface.create_entity{name = "rocket-silo", position = {SILO_POSITION.x+0.5, SILO_POSITION.y}, force = MAIN_FORCE}
|
||||||
|
silo.destructible = false
|
||||||
|
silo.minable = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove rocket silo from recipes
|
||||||
|
function RemoveRocketSiloRecipe(event)
|
||||||
|
local recipes = event.research.force.recipes
|
||||||
|
if recipes["rocket-silo"] then
|
||||||
|
recipes["rocket-silo"].enabled = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Generates the rocket silo during chunk generation event
|
||||||
|
-- Includes a crop circle
|
||||||
|
function GenerateRocketSiloChunk(event)
|
||||||
|
local surface = event.surface
|
||||||
|
if surface.name ~= "nauvis" then return end
|
||||||
|
local chunkArea = event.area
|
||||||
|
|
||||||
|
local chunkAreaCenter = {x=chunkArea.left_top.x+(CHUNK_SIZE/2),
|
||||||
|
y=chunkArea.left_top.y+(CHUNK_SIZE/2)}
|
||||||
|
local safeArea = {left_top=
|
||||||
|
{x=SILO_POSITION.x-150,
|
||||||
|
y=SILO_POSITION.y-150},
|
||||||
|
right_bottom=
|
||||||
|
{x=SILO_POSITION.x+150,
|
||||||
|
y=SILO_POSITION.y+150}}
|
||||||
|
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create rocket silo
|
||||||
|
CreateRocketSilo(surface, chunkArea)
|
||||||
|
CreateCropCircle(surface, SILO_POSITION, chunkArea, ENFORCE_LAND_AREA_TILE_DIST)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Display messages to a user everytime they join
|
||||||
|
function PlayerJoinedMessages(event)
|
||||||
|
local player = game.players[event.player_index]
|
||||||
|
player.print(WELCOME_MSG)
|
||||||
|
player.print(GAME_MODE_MSG)
|
||||||
|
player.print(MODULES_ENABLED)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create the gravestone chests for a player when they die
|
||||||
|
function CreateGravestoneChestsOnDeath(event)
|
||||||
|
DropGravestoneChests(game.players[event.player_index])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove decor to save on file size
|
||||||
|
function UndecorateOnChunkGenerate(event)
|
||||||
|
local surface = event.surface
|
||||||
|
local chunkArea = event.area
|
||||||
|
RemoveDecorationsArea(surface, chunkArea)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Give player items on respawn
|
||||||
|
-- Intended to be the default behavior when not using separate spawns
|
||||||
|
function PlayerRespawnItems(event)
|
||||||
|
GivePlayerItems(game.players[event.player_index])
|
||||||
|
end
|
||||||
|
|
||||||
|
function PlayerSpawnItems(event)
|
||||||
|
GivePlayerStarterItems(game.players[event.player_index])
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Register events
|
||||||
|
-- These must be placed after the functions that are referenced!
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Event.register(defines.events.on_player_joined_game, PlayerJoinedMessages)
|
||||||
|
|
||||||
|
-- Rocket SIlo "frontier" mode
|
||||||
|
if FRONTIER_ROCKET_SILO_MODE then
|
||||||
|
Event.register(defines.events.on_chunk_generated, GenerateRocketSiloChunk)
|
||||||
|
Event.register(defines.events.on_research_finished, RemoveRocketSiloRecipe)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ENABLE_GRAVESTONE_CHESTS then
|
||||||
|
Event.register(defines.events.on_player_died, CreateGravestoneChestsOnDeath)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ENABLE_UNDECORATOR then
|
||||||
|
Event.register(defines.events.on_chunk_generated, UndecorateOnChunkGenerate)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Separate teams mod does the starting items itself
|
||||||
|
if not ENABLE_SEPARATE_SPAWNS then
|
||||||
|
Event.register(defines.events.on_player_created, PlayerSpawnItems)
|
||||||
|
Event.register(defines.events.on_player_respawned, PlayerRespawnItems)
|
||||||
|
end
|
52
rso_config.lua
Normal file
52
rso_config.lua
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
debug_enabled = false
|
||||||
|
debug_items_enabled = false
|
||||||
|
|
||||||
|
region_size = 7 -- 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.60 -- 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 = 0.25 -- 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 = true -- 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.7 -- exponent for richness distance factor calculation
|
||||||
|
size_distance_factor=0.1 -- 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
|
||||||
|
|
||||||
|
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=1 --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
|
||||||
|
|
||||||
|
ignoreMapGenSettings = true -- stops the default behaviour of reading map gen settings
|
||||||
|
|
||||||
|
fluidResourcesFactor = 20 -- temporary factor for calculation of resource %-ages for fluids
|
||||||
|
|
||||||
|
useResourceCollisionDetection = true -- enables avoidace calculations to reduce ores overlaping of each other
|
||||||
|
resourceCollisionDetectionRatio = 0.8 -- 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
|
1364
rso_control.lua
Normal file
1364
rso_control.lua
Normal file
File diff suppressed because it is too large
Load Diff
159
rso_resource_config.lua
Normal file
159
rso_resource_config.lua
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
|
||||||
|
local function fillVanillaConfig()
|
||||||
|
|
||||||
|
config["iron-ore"] = {
|
||||||
|
type="resource-ore",
|
||||||
|
|
||||||
|
-- general spawn params
|
||||||
|
allotment=100, -- how common resource is
|
||||||
|
spawns_per_region={min=1, max=1}, --number of chunks
|
||||||
|
richness=18000, -- resource_ore has only one richness value - resource-liquid has min/max
|
||||||
|
|
||||||
|
size={min=20, max=30}, -- 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=100,
|
||||||
|
spawns_per_region={min=1, max=1},
|
||||||
|
richness=16000,
|
||||||
|
size={min=20, max=30},
|
||||||
|
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=13000,
|
||||||
|
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=11000,
|
||||||
|
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["crude-oil"] = {
|
||||||
|
type="resource-liquid",
|
||||||
|
minimum_amount=10000,
|
||||||
|
allotment=70,
|
||||||
|
spawns_per_region={min=1, max=2},
|
||||||
|
richness={min=10000, max=30000}, -- richness per resource spawn
|
||||||
|
size={min=2, max=5},
|
||||||
|
|
||||||
|
starting={richness=20000, 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.4,
|
||||||
|
richness=1,
|
||||||
|
|
||||||
|
absolute_probability=absolute_enemy_chance, -- chance to spawn in region
|
||||||
|
probability_distance_factor=1.15, -- relative increase per region
|
||||||
|
max_probability_distance_factor=3.0, -- 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.3, -- 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.04,
|
||||||
|
sub_spawn_max_distance_factor=3,
|
||||||
|
sub_spawns={
|
||||||
|
["small-worm-turret"]={
|
||||||
|
min_distance=2,
|
||||||
|
allotment=200,
|
||||||
|
allotment_distance_factor=0.9,
|
||||||
|
clear_range = {2, 2},
|
||||||
|
},
|
||||||
|
["medium-worm-turret"]={
|
||||||
|
min_distance=4,
|
||||||
|
allotment=100,
|
||||||
|
allotment_distance_factor=1.05,
|
||||||
|
clear_range = {2, 2},
|
||||||
|
},
|
||||||
|
["big-worm-turret"]={
|
||||||
|
min_distance=6,
|
||||||
|
allotment=100,
|
||||||
|
allotment_distance_factor=1.15,
|
||||||
|
clear_range = {2, 2},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function loadResourceConfig()
|
||||||
|
|
||||||
|
config={}
|
||||||
|
|
||||||
|
fillVanillaConfig()
|
||||||
|
fillEnemies()
|
||||||
|
|
||||||
|
return config
|
||||||
|
end
|
644
separate_spawns.lua
Normal file
644
separate_spawns.lua
Normal file
@ -0,0 +1,644 @@
|
|||||||
|
-- Separate spawns
|
||||||
|
-- Code that handles everything regarding giving each player a separate spawn
|
||||||
|
-- Includes the GUI stuff
|
||||||
|
|
||||||
|
require("event")
|
||||||
|
|
||||||
|
-- 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 PlayerCreated(event)
|
||||||
|
local player = game.players[event.player_index]
|
||||||
|
player.force = MAIN_FORCE
|
||||||
|
DisplaySpawnOptions(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Check if the player has a different spawn point than the default one
|
||||||
|
-- Make sure to give the default starting items
|
||||||
|
function PlayerRespawned(event)
|
||||||
|
local player = game.players[event.player_index]
|
||||||
|
|
||||||
|
-- If a player has an active spawn, use it.
|
||||||
|
if (DoesPlayerHaveActiveCustomSpawn(player)) then
|
||||||
|
player.teleport(global.playerSpawns[player.name])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Display the respawn continue option
|
||||||
|
DisplayRespawnContinueOption(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create the appropriate force & spawn when player selects their choice
|
||||||
|
function SpawnGuiClick(event)
|
||||||
|
local player = game.players[event.player_index]
|
||||||
|
local buttonClicked = event.element.name
|
||||||
|
|
||||||
|
-- Only clear gui if a valid button was clicked!!
|
||||||
|
if ((buttonClicked == "normal_spawn") or
|
||||||
|
(buttonClicked == "isolated_spawn") or
|
||||||
|
(buttonClicked == "isolated_spawn_far") or
|
||||||
|
(buttonClicked == "new_force") or
|
||||||
|
(buttonClicked == "new_force_far") or
|
||||||
|
(buttonClicked == "respawn_continue") or
|
||||||
|
(buttonClicked == "respawn_change") or
|
||||||
|
(buttonClicked == "respawn_custom_team") or
|
||||||
|
(buttonClicked == "respawn_custom_spawn") or
|
||||||
|
(buttonClicked == "respawn_surpise") or
|
||||||
|
(buttonClicked == "respawn_mainforce")) then
|
||||||
|
|
||||||
|
if not global.spawnDebugEnabled then
|
||||||
|
if (player.gui.center.spawn_opts ~= nil) then
|
||||||
|
player.gui.center.spawn_opts.destroy()
|
||||||
|
end
|
||||||
|
if (player.gui.center.respawn_opts ~= nil) then
|
||||||
|
player.gui.center.respawn_opts.destroy()
|
||||||
|
end
|
||||||
|
if (player.gui.center.respawn_continue_opts ~= nil) then
|
||||||
|
player.gui.center.respawn_continue_opts.destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- In this option, the vanilla spawn is used and the player is
|
||||||
|
-- part of the main force.
|
||||||
|
if (buttonClicked == "normal_spawn") then
|
||||||
|
player.force = MAIN_FORCE
|
||||||
|
GivePlayerStarterItems(player)
|
||||||
|
SendBroadcastMsg(player.name .. " joined the main force!")
|
||||||
|
|
||||||
|
-- In this option, the player gets a separate spawn point
|
||||||
|
-- but is still part of the main force.
|
||||||
|
elseif ((buttonClicked == "isolated_spawn") or (buttonClicked == "isolated_spawn_far")) then
|
||||||
|
player.force = MAIN_FORCE
|
||||||
|
|
||||||
|
-- Create a new spawn point
|
||||||
|
local newSpawn = {}
|
||||||
|
if (buttonClicked == "isolated_spawn_far") then
|
||||||
|
newSpawn = FindUngeneratedCoordinates(FAR_MIN_DIST,FAR_MAX_DIST)
|
||||||
|
else
|
||||||
|
newSpawn = FindMapEdge(GetRandomVector())
|
||||||
|
end
|
||||||
|
global.playerSpawns[player.name] = newSpawn
|
||||||
|
global.activePlayerSpawns[player.name] = true
|
||||||
|
|
||||||
|
SendPlayerToNewSpawnAndCreateIt(player, newSpawn)
|
||||||
|
if (buttonClicked == "isolated_spawn") then
|
||||||
|
SendBroadcastMsg(player.name .. " joined the main force from a distance!")
|
||||||
|
elseif (buttonClicked == "isolated_spawn_far") then
|
||||||
|
SendBroadcastMsg(player.name .. " joined the main force from a great distance!")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- In this option, the player is given a new force and a
|
||||||
|
-- separate spawn point
|
||||||
|
elseif ((buttonClicked == "new_force") or (buttonClicked == "new_force_far")) then
|
||||||
|
|
||||||
|
-- Create a new force using the player's name
|
||||||
|
local newForce = CreatePlayerCustomForce(player)
|
||||||
|
|
||||||
|
-- Create a new spawn point
|
||||||
|
local newSpawn = {}
|
||||||
|
if (buttonClicked == "new_force_far") then
|
||||||
|
newSpawn = FindUngeneratedCoordinates(FAR_MIN_DIST,FAR_MAX_DIST)
|
||||||
|
else
|
||||||
|
newSpawn = FindMapEdge(GetRandomVector())
|
||||||
|
end
|
||||||
|
global.playerSpawns[player.name] = newSpawn
|
||||||
|
global.activePlayerSpawns[player.name] = true
|
||||||
|
|
||||||
|
-- Set the new spawn point
|
||||||
|
if (newForce ~= nil) then
|
||||||
|
newForce.set_spawn_position(newSpawn, "nauvis")
|
||||||
|
end
|
||||||
|
|
||||||
|
SendPlayerToNewSpawnAndCreateIt(player, newSpawn)
|
||||||
|
SendBroadcastMsg(player.name .. " is going it alone!")
|
||||||
|
|
||||||
|
-- Continue to respawn on your own team at that location
|
||||||
|
elseif (buttonClicked == "respawn_continue") then
|
||||||
|
GivePlayerItems(player)
|
||||||
|
|
||||||
|
|
||||||
|
-- If changing your spawn behavior
|
||||||
|
elseif (buttonClicked == "respawn_change") then
|
||||||
|
if (DoesPlayerHaveCustomSpawn(player)) then
|
||||||
|
DisplayRespawnOptions(player)
|
||||||
|
else
|
||||||
|
DisplaySpawnOptions(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Respawn with the main force in the default location
|
||||||
|
elseif (buttonClicked == "respawn_mainforce") then
|
||||||
|
|
||||||
|
-- Remove custom force if it exists
|
||||||
|
if (player.force.name ~= MAIN_FORCE) then
|
||||||
|
game.merge_forces(player.name, MAIN_FORCE)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Deactivate the stored spawn point
|
||||||
|
ActivatePlayerCustomSpawn(player, false)
|
||||||
|
player.teleport(player.force.get_spawn_position("nauvis"))
|
||||||
|
GivePlayerStarterItems(player)
|
||||||
|
SendBroadcastMsg(player.name .. " is returning to base!")
|
||||||
|
|
||||||
|
-- Respawn in your already generated custom spawn area on the main team
|
||||||
|
elseif (buttonClicked == "respawn_custom_spawn") then
|
||||||
|
|
||||||
|
-- Remove custom force if it exists
|
||||||
|
if (player.force.name ~= MAIN_FORCE) then
|
||||||
|
game.merge_forces(player.name, MAIN_FORCE)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Activate the stored spawn point
|
||||||
|
ActivatePlayerCustomSpawn(player, true)
|
||||||
|
SendPlayerToActiveSpawn(player)
|
||||||
|
GivePlayerStarterItems(player)
|
||||||
|
SendBroadcastMsg(player.name .. " is returning to their outpost!")
|
||||||
|
|
||||||
|
-- Respawn in your already generated custom spawn area but on your own
|
||||||
|
-- force. This force is created new if it doesn't exist.
|
||||||
|
elseif (buttonClicked == "respawn_custom_team") then
|
||||||
|
|
||||||
|
-- Create a new force using the player's name
|
||||||
|
local newForce = CreatePlayerCustomForce(player)
|
||||||
|
|
||||||
|
-- Set the new spawn point
|
||||||
|
if (newForce ~= nil) then
|
||||||
|
newForce.set_spawn_position(global.playerSpawns[player.name], "nauvis")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Activate the stored spawn point
|
||||||
|
ActivatePlayerCustomSpawn(player, true)
|
||||||
|
SendPlayerToActiveSpawn(player)
|
||||||
|
GivePlayerStarterItems(player)
|
||||||
|
SendBroadcastMsg(player.name .. " is returning to their outpost alone!")
|
||||||
|
|
||||||
|
-- lol wut
|
||||||
|
elseif (buttonClicked == "respawn_surpise") then
|
||||||
|
|
||||||
|
-- Remove custom force if it exists
|
||||||
|
if (player.force.name ~= MAIN_FORCE) then
|
||||||
|
game.merge_forces(player.name, MAIN_FORCE)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Activate the stored spawn point
|
||||||
|
SendPlayerToRandomSpawn(player)
|
||||||
|
GivePlayerStarterItems(player)
|
||||||
|
SendBroadcastMsg(player.name .. " is surprised!")
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This is the main function that creates the spawn area
|
||||||
|
-- Provides resources, land and a safe zone
|
||||||
|
function GenerateChunk(event)
|
||||||
|
local surface = event.surface
|
||||||
|
if surface.name ~= "nauvis" then return end
|
||||||
|
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.
|
||||||
|
for name,spawnPos in pairs(global.playerSpawns) do
|
||||||
|
|
||||||
|
local landArea = {left_top=
|
||||||
|
{x=spawnPos.x-ENFORCE_LAND_AREA_TILE_DIST,
|
||||||
|
y=spawnPos.y-ENFORCE_LAND_AREA_TILE_DIST},
|
||||||
|
right_bottom=
|
||||||
|
{x=spawnPos.x+ENFORCE_LAND_AREA_TILE_DIST,
|
||||||
|
y=spawnPos.y+ENFORCE_LAND_AREA_TILE_DIST}}
|
||||||
|
|
||||||
|
local safeArea = {left_top=
|
||||||
|
{x=spawnPos.x-SAFE_AREA_TILE_DIST,
|
||||||
|
y=spawnPos.y-SAFE_AREA_TILE_DIST},
|
||||||
|
right_bottom=
|
||||||
|
{x=spawnPos.x+SAFE_AREA_TILE_DIST,
|
||||||
|
y=spawnPos.y+SAFE_AREA_TILE_DIST}}
|
||||||
|
|
||||||
|
local warningArea = {left_top=
|
||||||
|
{x=spawnPos.x-WARNING_AREA_TILE_DIST,
|
||||||
|
y=spawnPos.y-WARNING_AREA_TILE_DIST},
|
||||||
|
right_bottom=
|
||||||
|
{x=spawnPos.x+WARNING_AREA_TILE_DIST,
|
||||||
|
y=spawnPos.y+WARNING_AREA_TILE_DIST}}
|
||||||
|
|
||||||
|
local chunkAreaCenter = {x=chunkArea.left_top.x+(CHUNK_SIZE/2),
|
||||||
|
y=chunkArea.left_top.y+(CHUNK_SIZE/2)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Make chunks near a spawn safe by removing enemies
|
||||||
|
if CheckIfInArea(chunkAreaCenter,safeArea) then
|
||||||
|
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, force = "enemy"}) do
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create a warning area with reduced enemies
|
||||||
|
elseif CheckIfInArea(chunkAreaCenter,warningArea) then
|
||||||
|
local counter = 0
|
||||||
|
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, force = "enemy"}) do
|
||||||
|
if ((counter % WARN_AREA_REDUCTION_RATIO) ~= 0) then
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
counter = counter + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove all big and huge worms
|
||||||
|
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, name = "medium-worm-turret"}) do
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, name = "big-worm-turret"}) do
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fill in any water to make sure we have guaranteed land mass at the spawn point.
|
||||||
|
if CheckIfInArea(chunkAreaCenter,landArea) then
|
||||||
|
|
||||||
|
-- remove trees in the immediate areas?
|
||||||
|
for key, entity in pairs(surface.find_entities_filtered({area=chunkArea, type= "tree"})) do
|
||||||
|
if ((spawnPos.x - entity.position.x)^2 + (spawnPos.y - entity.position.y)^2 < ENFORCE_LAND_AREA_TILE_DIST^2) then
|
||||||
|
entity.destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CreateCropCircle(surface, spawnPos, chunkArea, ENFORCE_LAND_AREA_TILE_DIST)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Provide a guaranteed spot of water to use for power generation
|
||||||
|
if CheckIfInArea(spawnPos,chunkArea) then
|
||||||
|
local waterTiles = {{name = "water", position ={spawnPos.x+0,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+1,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+2,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+3,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+4,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+5,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+6,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+7,spawnPos.y-30}},
|
||||||
|
{name = "water", position ={spawnPos.x+8,spawnPos.y-30}}}
|
||||||
|
-- DebugPrint("Setting water tiles in this chunk! " .. chunkArea.left_top.x .. "," .. chunkArea.left_top.y)
|
||||||
|
surface.set_tiles(waterTiles)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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 = {}
|
||||||
|
global.activePlayerSpawns = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
game.create_force(MAIN_FORCE)
|
||||||
|
game.forces[MAIN_FORCE].set_spawn_position(game.forces["player"].get_spawn_position("nauvis"), "nauvis")
|
||||||
|
SetCeaseFireBetweenAllForces()
|
||||||
|
end
|
||||||
|
|
||||||
|
function DisplaySpawnOptions(player)
|
||||||
|
player.gui.center.add{name = "spawn_opts",
|
||||||
|
type = "frame",
|
||||||
|
direction = "vertical",
|
||||||
|
caption="Spawn Options"}
|
||||||
|
local spawnGui = player.gui.center.spawn_opts
|
||||||
|
|
||||||
|
spawnGui.style.maximal_width = 450
|
||||||
|
spawnGui.style.maximal_height = 650
|
||||||
|
|
||||||
|
spawnGui.add{name = "warning_lbl1", type = "label",
|
||||||
|
caption="You can only generate one custom spawn point!"}
|
||||||
|
spawnGui.add{name = "warning_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(spawnGui.warning_lbl1, my_warning_style)
|
||||||
|
ApplyStyle(spawnGui.warning_spacer, my_label_style)
|
||||||
|
|
||||||
|
spawnGui.add{name = "normal_spawn",
|
||||||
|
type = "button",
|
||||||
|
caption="Default Spawn"}
|
||||||
|
spawnGui.add{name = "normal_spawn_lbl1", type = "label",
|
||||||
|
caption="This is the default spawn behavior of a vanilla game."}
|
||||||
|
spawnGui.add{name = "normal_spawn_lbl2", type = "label",
|
||||||
|
caption="You join the default team in the center of the map."}
|
||||||
|
spawnGui.add{name = "normal_spawn_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(spawnGui.normal_spawn_lbl1, my_label_style)
|
||||||
|
ApplyStyle(spawnGui.normal_spawn_lbl2, my_label_style)
|
||||||
|
ApplyStyle(spawnGui.normal_spawn_spacer, my_label_style)
|
||||||
|
|
||||||
|
spawnGui.add{name = "isolated_spawn",
|
||||||
|
type = "button",
|
||||||
|
caption="Isolated Spawn"}
|
||||||
|
spawnGui.add{name = "isolated_spawn_far",
|
||||||
|
type = "button",
|
||||||
|
caption="Isolated Spawn (Far Away)"}
|
||||||
|
spawnGui.add{name = "isolated_spawn_lbl1", type = "label",
|
||||||
|
caption="You are spawned in a new area, with starting resources."}
|
||||||
|
spawnGui.add{name = "isolated_spawn_lbl2", type = "label",
|
||||||
|
caption="You will still be part of the default team."}
|
||||||
|
spawnGui.add{name = "isolated_spawn_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(spawnGui.isolated_spawn_lbl1, my_label_style)
|
||||||
|
ApplyStyle(spawnGui.isolated_spawn_lbl2, my_label_style)
|
||||||
|
ApplyStyle(spawnGui.isolated_spawn_spacer, my_label_style)
|
||||||
|
|
||||||
|
|
||||||
|
if (ENABLE_OTHER_TEAMS) then
|
||||||
|
spawnGui.add{name = "new_force",
|
||||||
|
type = "button",
|
||||||
|
caption="Separate Team"}
|
||||||
|
spawnGui.add{name = "new_force_far",
|
||||||
|
type = "button",
|
||||||
|
caption="Separate Team (Far Away)"}
|
||||||
|
spawnGui.add{name = "new_force_lbl1", type = "label",
|
||||||
|
caption="You are spawned in a new area, with starting resources."}
|
||||||
|
spawnGui.add{name = "new_force_lbl2", type = "label",
|
||||||
|
caption="You will be on your own team. (No shared vision or research with others.)"}
|
||||||
|
spawnGui.add{name = "new_force_lbl3", type = "label",
|
||||||
|
caption="Do not choose this option if you are new to the game!"}
|
||||||
|
spawnGui.add{name = "new_force_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(spawnGui.new_force_lbl1, my_label_style)
|
||||||
|
ApplyStyle(spawnGui.new_force_lbl2, my_warning_style)
|
||||||
|
ApplyStyle(spawnGui.new_force_lbl3, my_warning_style)
|
||||||
|
ApplyStyle(spawnGui.new_force_spacer, my_label_style)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
spawnGui.add{name = "note_lbl1", type = "label",
|
||||||
|
caption="All members of a team share map vision and research."}
|
||||||
|
spawnGui.add{name = "note_lbl2", type = "label",
|
||||||
|
caption="To talk to someone on a different team, you need to use /s to shout."}
|
||||||
|
spawnGui.add{name = "note_lbl3", type = "label",
|
||||||
|
caption="All teams are neutral. This is still a cooperative PvE game... NOT PVP!"}
|
||||||
|
ApplyStyle(spawnGui.note_lbl1, my_note_style)
|
||||||
|
ApplyStyle(spawnGui.note_lbl2, my_note_style)
|
||||||
|
ApplyStyle(spawnGui.note_lbl3, my_note_style)
|
||||||
|
end
|
||||||
|
|
||||||
|
spawnGui.add{name = "note_lbl4", type = "label",
|
||||||
|
caption="Far away spawn is between " .. FAR_MIN_DIST*CHUNK_SIZE .. "-" .. FAR_MAX_DIST*CHUNK_SIZE .. " tiles away from the center of the map."}
|
||||||
|
spawnGui.add{name = "note_lbl5", type = "label",
|
||||||
|
caption="Isolated spawns are dangerous! You will have to fight to reach other players."}
|
||||||
|
spawnGui.add{name = "note_lbl6", type = "label",
|
||||||
|
caption="You can change your spawn options when you die."}
|
||||||
|
|
||||||
|
ApplyStyle(spawnGui.note_lbl4, my_note_style)
|
||||||
|
ApplyStyle(spawnGui.note_lbl5, my_note_style)
|
||||||
|
end
|
||||||
|
|
||||||
|
function DisplayRespawnContinueOption(player)
|
||||||
|
|
||||||
|
player.gui.center.add{name = "respawn_continue_opts",
|
||||||
|
type = "frame",
|
||||||
|
direction = "vertical",
|
||||||
|
caption="Respawn Options"}
|
||||||
|
local respawnGui = player.gui.center.respawn_continue_opts
|
||||||
|
|
||||||
|
respawnGui.style.maximal_width = 450
|
||||||
|
respawnGui.style.maximal_height = 550
|
||||||
|
|
||||||
|
respawnGui.add{name = "respawn_continue",
|
||||||
|
type = "button",
|
||||||
|
caption="Continue"}
|
||||||
|
respawnGui.add{name = "respawn_continue_lbl1", type = "label",
|
||||||
|
caption="Continue at your current spawn location."}
|
||||||
|
respawnGui.add{name = "respawn_continue_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(respawnGui.respawn_continue_lbl1, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_continue_spacer, my_label_style)
|
||||||
|
|
||||||
|
respawnGui.add{name = "respawn_change",
|
||||||
|
type = "button",
|
||||||
|
caption="Change Spawn"}
|
||||||
|
respawnGui.add{name = "respawn_change_lbl1", type = "label",
|
||||||
|
caption="Allow you to change your spawn and team."}
|
||||||
|
respawnGui.add{name = "respawn_change_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(respawnGui.respawn_change_lbl1, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_change_spacer, my_label_style)
|
||||||
|
end
|
||||||
|
|
||||||
|
function DisplayRespawnOptions(player)
|
||||||
|
|
||||||
|
player.gui.center.add{name = "respawn_opts",
|
||||||
|
type = "frame",
|
||||||
|
direction = "vertical",
|
||||||
|
caption="Respawn Options"}
|
||||||
|
local respawnGui = player.gui.center.respawn_opts
|
||||||
|
|
||||||
|
respawnGui.style.maximal_width = 450
|
||||||
|
respawnGui.style.maximal_height = 750
|
||||||
|
|
||||||
|
-- Basically a cancel button to avoid choosing a different spawn.
|
||||||
|
respawnGui.add{name = "respawn_continue",
|
||||||
|
type = "button",
|
||||||
|
caption="Cancel"}
|
||||||
|
respawnGui.add{name = "respawn_continue_lbl1", type = "label",
|
||||||
|
caption="Continue with current spawn."}
|
||||||
|
respawnGui.add{name = "respawn_continue_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(respawnGui.respawn_continue_lbl1, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_continue_spacer, my_label_style)
|
||||||
|
|
||||||
|
respawnGui.add{name = "respawn_mainforce",
|
||||||
|
type = "button",
|
||||||
|
caption="Use Default Spawn"}
|
||||||
|
respawnGui.add{name = "respawn_mainforce_lbl1", type = "label",
|
||||||
|
caption="This will join the default team."}
|
||||||
|
respawnGui.add{name = "respawn_mainforce_lbl2", type = "label",
|
||||||
|
caption="If you are on another team all your research will be lost!"}
|
||||||
|
respawnGui.add{name = "respawn_mainforce_lbl3", type = "label",
|
||||||
|
caption="You will spawn at the default spawn point in the center."}
|
||||||
|
respawnGui.add{name = "respawn_mainforce_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(respawnGui.respawn_mainforce_lbl1, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_mainforce_lbl2, my_warning_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_mainforce_lbl3, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_mainforce_spacer, my_label_style)
|
||||||
|
|
||||||
|
|
||||||
|
respawnGui.add{name = "respawn_custom_spawn",
|
||||||
|
type = "button",
|
||||||
|
caption="Custom Spawn"}
|
||||||
|
respawnGui.add{name = "respawn_custom_lbl1", type = "label",
|
||||||
|
caption="This will join the default team."}
|
||||||
|
respawnGui.add{name = "respawn_custom_lbl2", type = "label",
|
||||||
|
caption="If you are on another team all your research will be lost!"}
|
||||||
|
respawnGui.add{name = "respawn_custom_lbl3", type = "label",
|
||||||
|
caption="You will spawn at your previous custom spawn point."}
|
||||||
|
respawnGui.add{name = "respawn_custom_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_lbl1, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_lbl2, my_warning_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_lbl3, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_spacer, my_label_style)
|
||||||
|
|
||||||
|
if (ENABLE_OTHER_TEAMS) then
|
||||||
|
respawnGui.add{name = "respawn_custom_team",
|
||||||
|
type = "button",
|
||||||
|
caption="Custom Team Spawn"}
|
||||||
|
respawnGui.add{name = "respawn_custom_team_lbl1", type = "label",
|
||||||
|
caption="This will join your own custom team."}
|
||||||
|
respawnGui.add{name = "respawn_custom_team_lbl2", type = "label",
|
||||||
|
caption="You will have your own map vision and research tree. Use /s to talk to others."}
|
||||||
|
respawnGui.add{name = "respawn_custom_team_lbl3", type = "label",
|
||||||
|
caption="You will spawn at your previous custom spawn point."}
|
||||||
|
respawnGui.add{name = "respawn_custom_team_spacer", type = "label",
|
||||||
|
caption=" "}
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_team_lbl1, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_team_lbl2, my_warning_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_team_lbl3, my_label_style)
|
||||||
|
ApplyStyle(respawnGui.respawn_custom_team_spacer, my_label_style)
|
||||||
|
end
|
||||||
|
|
||||||
|
if (global.enableRespawnSurprise == true) then
|
||||||
|
respawnGui.add{name = "respawn_surpise",
|
||||||
|
type = "button",
|
||||||
|
caption="Surprise me!"}
|
||||||
|
end
|
||||||
|
|
||||||
|
respawnGui.add{name = "respawn_note1", type = "label",
|
||||||
|
caption="You cannot generate new custom spawn points."}
|
||||||
|
ApplyStyle(respawnGui.respawn_note1, my_note_style)
|
||||||
|
end
|
||||||
|
|
||||||
|
function GenerateStartingResources(player)
|
||||||
|
local surface = player.surface
|
||||||
|
|
||||||
|
-- Generate stone
|
||||||
|
local stonePos = {x=player.position.x-25,
|
||||||
|
y=player.position.y-31}
|
||||||
|
|
||||||
|
-- Generate coal
|
||||||
|
local coalPos = {x=player.position.x-25,
|
||||||
|
y=player.position.y-16}
|
||||||
|
|
||||||
|
-- Generate copper ore
|
||||||
|
local copperOrePos = {x=player.position.x-25,
|
||||||
|
y=player.position.y+0}
|
||||||
|
|
||||||
|
-- Generate iron ore
|
||||||
|
local ironOrePos = {x=player.position.x-25,
|
||||||
|
y=player.position.y+15}
|
||||||
|
|
||||||
|
-- Tree generation is taken care of in chunk generation
|
||||||
|
|
||||||
|
-- Generate oil patches
|
||||||
|
surface.create_entity({name="crude-oil", amount=START_OIL_AMOUNT,
|
||||||
|
position={player.position.x-30, player.position.y-2}})
|
||||||
|
surface.create_entity({name="crude-oil", amount=START_OIL_AMOUNT,
|
||||||
|
position={player.position.x-30, player.position.y+2}})
|
||||||
|
|
||||||
|
for y=0, 15 do
|
||||||
|
for x=0, 15 do
|
||||||
|
if ((x-7)^2 + (y - 7)^2 < 7^2) then
|
||||||
|
surface.create_entity({name="iron-ore", amount=START_IRON_AMOUNT,
|
||||||
|
position={ironOrePos.x+x, ironOrePos.y+y}})
|
||||||
|
surface.create_entity({name="copper-ore", amount=START_COPPER_AMOUNT,
|
||||||
|
position={copperOrePos.x+x, copperOrePos.y+y}})
|
||||||
|
surface.create_entity({name="stone", amount=START_STONE_AMOUNT,
|
||||||
|
position={stonePos.x+x, stonePos.y+y}})
|
||||||
|
surface.create_entity({name="coal", amount=START_COAL_AMOUNT,
|
||||||
|
position={coalPos.x+x, coalPos.y+y}})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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 DoesPlayerHaveActiveCustomSpawn(player)
|
||||||
|
if (DoesPlayerHaveCustomSpawn(player)) then
|
||||||
|
return global.activePlayerSpawns[player.name]
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ActivatePlayerCustomSpawn(player, value)
|
||||||
|
for name,_ in pairs(global.playerSpawns) do
|
||||||
|
if (player.name == name) then
|
||||||
|
global.activePlayerSpawns[player.name] = value
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreatePlayerCustomForce(player)
|
||||||
|
local newForce = nil
|
||||||
|
|
||||||
|
-- Check if force already exists
|
||||||
|
if (game.forces[player.name] ~= nil) then
|
||||||
|
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)
|
||||||
|
player.force = newForce
|
||||||
|
SetCeaseFireBetweenAllForces()
|
||||||
|
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
|
||||||
|
|
||||||
|
function SendPlayerToNewSpawnAndCreateIt(player, spawn)
|
||||||
|
-- Send the player to that position
|
||||||
|
player.teleport(spawn)
|
||||||
|
GivePlayerStarterItems(player)
|
||||||
|
|
||||||
|
-- If we get a valid spawn point, setup the area
|
||||||
|
if (spawn ~= {x=0,y=0}) then
|
||||||
|
GenerateStartingResources(player)
|
||||||
|
ClearNearbyEnemies(player, SAFE_AREA_TILE_DIST)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SendPlayerToActiveSpawn(player)
|
||||||
|
if (DoesPlayerHaveActiveCustomSpawn(player)) then
|
||||||
|
player.teleport(global.playerSpawns[player.name])
|
||||||
|
else
|
||||||
|
player.teleport(game.forces[MAIN_FORCE].get_spawn_position("nauvis"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SendPlayerToRandomSpawn(player)
|
||||||
|
local numSpawns = TableLength(global.playerSpawns)
|
||||||
|
local rndSpawn = math.random(0,numSpawns)
|
||||||
|
local counter = 0
|
||||||
|
|
||||||
|
if (rndSpawn == 0) then
|
||||||
|
player.teleport(game.forces[MAIN_FORCE].get_spawn_position("nauvis"))
|
||||||
|
else
|
||||||
|
counter = counter + 1
|
||||||
|
for name,spawnPos in pairs(global.playerSpawns) do
|
||||||
|
if (counter == rndSpawn) then
|
||||||
|
player.teleport(spawnPos)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
counter = counter + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Register event functions
|
||||||
|
-- These must be placed after the functions that are referenced!
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if ENABLE_SEPARATE_SPAWNS then
|
||||||
|
Event.register(defines.events.on_player_created, PlayerCreated)
|
||||||
|
Event.register(defines.events.on_player_respawned, PlayerRespawned)
|
||||||
|
Event.register(defines.events.on_gui_click, SpawnGuiClick)
|
||||||
|
Event.register(defines.events.on_chunk_generated, GenerateChunk)
|
||||||
|
end
|
59
tag.lua
Normal file
59
tag.lua
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
function create_tag_gui(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 = "[Labs]"},
|
||||||
|
{display_name = "[Logistics]"},
|
||||||
|
{display_name = "[Misc]"},
|
||||||
|
{display_name = "[Aliens]"},
|
||||||
|
{display_name = "[Rocket]"},
|
||||||
|
{display_name = "[AFK]"},
|
||||||
|
{display_name = "Clear"}}
|
||||||
|
|
||||||
|
function expand_tag_gui(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
|
||||||
|
|
||||||
|
local function on_gui_click(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
|
||||||
|
expand_tag_gui(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
|
||||||
|
|
||||||
|
|
||||||
|
Event.register(defines.events.on_gui_click, on_gui_click)
|
||||||
|
Event.register(defines.events.on_player_joined_game, create_tag_gui)
|
Loading…
Reference in New Issue
Block a user