2016-12-01 04:41:04 +02:00
-- separate_spawns.lua
-- Nov 2016
--
2016-11-26 02:20:41 +02:00
-- Code that handles everything regarding giving each player a separate spawn
-- Includes the GUI stuff
2016-12-01 04:41:04 +02:00
--------------------------------------------------------------------------------
-- EVENT RELATED FUNCTIONS
--------------------------------------------------------------------------------
2016-11-26 02:20:41 +02:00
-- 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.
2016-12-01 04:41:04 +02:00
function SeparateSpawnsPlayerCreated ( event )
2016-11-26 02:20:41 +02:00
local player = game.players [ event.player_index ]
player.force = MAIN_FORCE
2016-12-01 04:41:04 +02:00
DisplayWelcomeTextGui ( player )
2016-11-26 02:20:41 +02:00
end
-- Check if the player has a different spawn point than the default one
-- Make sure to give the default starting items
2016-12-01 04:41:04 +02:00
function SeparateSpawnsPlayerRespawned ( event )
2016-11-26 02:20:41 +02:00
local player = game.players [ event.player_index ]
2016-12-02 23:26:49 +02:00
SendPlayerToSpawn ( player )
2016-11-26 02:20:41 +02:00
end
-- This is the main function that creates the spawn area
-- Provides resources, land and a safe zone
2016-12-01 04:41:04 +02:00
function SeparateSpawnsGenerateChunk ( event )
2016-11-26 02:20:41 +02:00
local surface = event.surface
local chunkArea = event.area
-- This handles chunk generation near player spawns
-- If it is near a player spawn, it does a few things like make the area
-- safe and provide a guaranteed area of land and water tiles.
2018-01-25 07:04:07 +02:00
SetupAndClearSpawnAreas ( surface , chunkArea , global.uniqueSpawns )
2016-11-26 02:20:41 +02:00
end
2016-12-01 04:41:04 +02:00
2016-12-02 23:26:49 +02:00
-- Call this if a player leaves the game
2017-07-26 02:20:35 +02:00
-- Still seems to have a bug.
2016-12-02 23:26:49 +02:00
function FindUnusedSpawns ( event )
local player = game.players [ event.player_index ]
if ( player.online_time < MIN_ONLINE_TIME ) then
2017-04-28 03:48:28 +02:00
DropGravestoneChests ( player )
2016-12-14 23:00:00 +02:00
2017-05-13 04:33:57 +02:00
-- Clear out global variables for that player
2016-12-02 23:26:49 +02:00
if ( global.playerSpawns [ player.name ] ~= nil ) then
global.playerSpawns [ player.name ] = nil
end
2017-05-12 01:42:23 +02:00
2017-05-13 04:33:57 +02:00
-- Transfer or remove a shared spawn if player is owner
2017-05-12 01:42:23 +02:00
if ( global.sharedSpawns [ player.name ] ~= nil ) then
2017-05-13 04:33:57 +02:00
local teamMates = global.sharedSpawns [ player.name ] . players
if ( # teamMates >= 1 ) then
local newOwnerName = table.remove ( teamMates )
TransferOwnershipOfSharedSpawn ( player.name , newOwnerName )
else
2017-05-12 01:42:23 +02:00
global.sharedSpawns [ player.name ] = nil
2017-05-13 04:33:57 +02:00
end
2017-05-12 01:42:23 +02:00
end
2016-12-02 23:26:49 +02:00
-- If a uniqueSpawn was created for the player, mark it as unused.
if ( global.uniqueSpawns [ player.name ] ~= nil ) then
2018-01-25 07:04:07 +02:00
2018-01-27 03:41:02 +02:00
local spawnPos = global.uniqueSpawns [ player.name ] . pos
2018-01-25 07:04:07 +02:00
-- Check if it was near someone else's base.
nearOtherSpawn = false
for _ , otherSpawnPos in pairs ( global.uniqueSpawns ) do
if ( getDistance ( spawnPos , otherSpawnPos ) < ( CHUNK_SIZE * 10 ) ) then
nearOtherSpawn = true
end
end
if ( ENABLE_ABANDONED_BASE_REMOVAL and not nearOtherSpawn ) then
2017-08-24 08:42:51 +02:00
global.uniqueSpawns [ player.name ] = nil
2018-01-25 07:04:07 +02:00
2017-11-08 16:13:34 +02:00
SendBroadcastMsg ( player.name .. " 's base was marked for immediate clean up because they left within " .. MIN_ONLINE_TIME_IN_MINUTES .. " minutes of joining. " )
2017-08-24 08:42:51 +02:00
OarcRegrowthMarkForRemoval ( spawnPos , 10 )
global.chunk_regrow . force_removal_flag = game.tick
else
table.insert ( global.unusedSpawns , global.uniqueSpawns [ player.name ] )
2017-11-08 16:13:34 +02:00
global.uniqueSpawns [ player.name ] = nil
SendBroadcastMsg ( player.name .. " base was freed up because they left within " .. MIN_ONLINE_TIME_IN_MINUTES .. " minutes of joining. " )
2017-08-24 08:42:51 +02:00
end
2016-12-02 23:26:49 +02:00
end
2016-12-14 01:46:48 +02:00
-- remove that player's cooldown setting
2016-12-02 23:26:49 +02:00
if ( global.playerCooldowns [ player.name ] ~= nil ) then
global.playerCooldowns [ player.name ] = nil
end
2016-12-01 04:41:04 +02:00
2016-12-14 23:00:00 +02:00
-- Remove from shared spawn player slots (need to search all)
for _ , sharedSpawn in pairs ( global.sharedSpawns ) do
for key , playerName in pairs ( sharedSpawn.players ) do
if ( player.name == playerName ) then
sharedSpawn.players [ key ] = nil ;
end
end
end
2017-04-30 15:22:45 +02:00
-- Remove a force if this player created it and they are the only one on it
2017-05-11 15:47:06 +02:00
if ( ( # player.force . players <= 1 ) and ( player.force . name ~= MAIN_FORCE ) ) then
2017-04-30 15:22:45 +02:00
game.merge_forces ( player.force , MAIN_FORCE )
end
2016-12-14 01:46:48 +02:00
-- Remove the character completely
2016-12-02 23:26:49 +02:00
game.remove_offline_players ( { player } )
end
end
2016-12-01 04:41:04 +02:00
2016-12-30 19:41:46 +02:00
--------------------------------------------------------------------------------
-- NON-EVENT RELATED FUNCTIONS
--------------------------------------------------------------------------------
-- Add a spawn to the shared spawn global
-- Used for tracking which players are assigned to it, where it is and if
-- it is open for new players to join
2016-12-14 01:46:48 +02:00
function CreateNewSharedSpawn ( player )
global.sharedSpawns [ player.name ] = { openAccess = true ,
position = global.playerSpawns [ player.name ] ,
players = { } }
end
2017-05-13 04:33:57 +02:00
function TransferOwnershipOfSharedSpawn ( prevOwnerName , newOwnerName )
2017-05-12 01:42:23 +02:00
-- Transfer the shared spawn global
2017-05-13 04:33:57 +02:00
global.sharedSpawns [ newOwnerName ] = global.sharedSpawns [ prevOwnerName ]
global.sharedSpawns [ newOwnerName ] . openAccess = false
global.sharedSpawns [ prevOwnerName ] = nil
2017-05-12 01:42:23 +02:00
-- Transfer the unique spawn global
2017-05-13 04:33:57 +02:00
global.uniqueSpawns [ newOwnerName ] = global.uniqueSpawns [ prevOwnerName ]
global.uniqueSpawns [ prevOwnerName ] = nil
game.players [ newOwnerName ] . print ( " You have been given ownership of this base! " )
2017-05-12 01:42:23 +02:00
end
2016-12-30 19:41:46 +02:00
-- Returns the number of players currently online at the shared spawn
2016-12-14 01:46:48 +02:00
function GetOnlinePlayersAtSharedSpawn ( ownerName )
if ( global.sharedSpawns [ ownerName ] ~= nil ) then
-- Does not count base owner
local count = 0
-- For each player in the shared spawn, check if online and add to count.
for _ , player in pairs ( game.connected_players ) do
if ( ownerName == player.name ) then
count = count + 1
end
for _ , playerName in pairs ( global.sharedSpawns [ ownerName ] . players ) do
if ( playerName == player.name ) then
count = count + 1
end
end
end
return count
else
return 0
end
end
-- Get the number of currently available shared spawns
-- This means the base owner has enabled access AND the number of online players
-- is below the threshold.
function GetNumberOfAvailableSharedSpawns ( )
local count = 0
for ownerName , sharedSpawn in pairs ( global.sharedSpawns ) do
if ( sharedSpawn.openAccess ) then
if ( GetOnlinePlayersAtSharedSpawn ( ownerName ) < MAX_ONLINE_PLAYERS_AT_SHARED_SPAWN ) then
count = count + 1
end
end
end
return count
end
2016-12-01 04:41:04 +02:00
2016-12-30 19:41:46 +02:00
-- Initializes the globals used to track the special spawn and player
-- status information
2016-11-26 02:20:41 +02:00
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 = { }
2016-12-02 23:26:49 +02:00
end
if ( global.uniqueSpawns == nil ) then
global.uniqueSpawns = { }
end
if ( global.sharedSpawns == nil ) then
global.sharedSpawns = { }
end
if ( global.unusedSpawns == nil ) then
global.unusedSpawns = { }
end
if ( global.playerCooldowns == nil ) then
global.playerCooldowns = { }
2016-11-26 02:20:41 +02:00
end
2017-12-15 22:43:03 +02:00
if ( global.waitingBuddies == nil ) then
global.waitingBuddies = { }
end
2018-01-25 07:04:07 +02:00
if ( global.delayedSpawns == nil ) then
global.delayedSpawns = { }
end
if ( global.buddySpawnOptions == nil ) then
global.buddySpawnOptions = { }
end
2016-11-26 02:20:41 +02:00
game.create_force ( MAIN_FORCE )
2017-04-27 02:59:48 +02:00
game.forces [ MAIN_FORCE ] . set_spawn_position ( game.forces [ " player " ] . get_spawn_position ( GAME_SURFACE_NAME ) , GAME_SURFACE_NAME )
2017-12-17 05:00:51 +02:00
if ENABLE_SHARED_TEAM_VISION then
game.forces [ MAIN_FORCE ] . share_chart = true
end
2016-11-26 02:20:41 +02:00
SetCeaseFireBetweenAllForces ( )
2017-04-27 02:59:48 +02:00
SetFriendlyBetweenAllForces ( )
2017-05-12 01:42:23 +02:00
-- AntiGriefing(game.forces[MAIN_FORCE])
2016-11-26 02:20:41 +02:00
end
function DoesPlayerHaveCustomSpawn ( player )
for name , spawnPos in pairs ( global.playerSpawns ) do
if ( player.name == name ) then
return true
end
end
return false
end
2016-12-02 23:26:49 +02:00
function ChangePlayerSpawn ( player , pos )
global.playerSpawns [ player.name ] = pos
2017-04-28 03:48:28 +02:00
global.playerCooldowns [ player.name ] = { setRespawn = game.tick }
2016-11-26 02:20:41 +02:00
end
2018-01-25 07:04:07 +02:00
function QueuePlayerForDelayedSpawn ( player , spawn , moatEnabled )
2016-11-26 02:20:41 +02:00
-- If we get a valid spawn point, setup the area
2016-12-02 23:26:49 +02:00
if ( ( spawn.x ~= 0 ) and ( spawn.y ~= 0 ) ) then
2017-07-26 02:20:35 +02:00
global.uniqueSpawns [ player.name ] = { pos = spawn , moat = moatEnabled }
2018-01-25 07:04:07 +02:00
player.print ( " Generating your spawn now, please wait 10 seconds... " )
player.surface . request_to_generate_chunks ( spawn , 4 )
delayedTick = game.tick + 10 * TICKS_PER_SECOND
table.insert ( global.delayedSpawns , { player = player , spawn = spawn , moatEnabled = moatEnabled , delayedTick = delayedTick } )
2016-12-02 23:26:49 +02:00
else
DebugPrint ( " THIS SHOULD NOT EVER HAPPEN! Spawn failed! " )
2018-01-25 07:04:07 +02:00
SendBroadcastMsg ( " ERROR!! Failed to create spawn point for: " .. player.name )
2016-11-26 02:20:41 +02:00
end
end
2018-01-25 07:04:07 +02:00
-- Check a table to see if there are any players waiting to spawn
-- Check if we are past the delayed tick count
-- Spawn the players and remove them from the table.
function DelayedSpawnOnTick ( )
if ( ( game.tick % ( 30 ) ) == 1 ) then
if ( ( global.delayedSpawns ~= nil ) and ( # global.delayedSpawns > 0 ) ) then
for i =# global.delayedSpawns , 1 , - 1 do
delayedSpawn = global.delayedSpawns [ i ]
if ( delayedSpawn.delayedTick < game.tick ) then
SendPlayerToNewSpawnAndCreateIt ( delayedSpawn.player , delayedSpawn.spawn , delayedSpawn.moatEnabled )
table.remove ( global.delayedSpawns , i )
end
end
end
end
end
function SendPlayerToNewSpawnAndCreateIt ( player , spawn , moatEnabled )
-- Make sure the area is super safe.
ClearNearbyEnemies ( spawn , SAFE_AREA_TILE_DIST , game.surfaces [ GAME_SURFACE_NAME ] )
-- Create the spawn resources here
CreateWaterStrip ( game.surfaces [ GAME_SURFACE_NAME ] ,
{ x = spawn.x + WATER_SPAWN_OFFSET_X , y = spawn.y + WATER_SPAWN_OFFSET_Y } ,
WATER_SPAWN_LENGTH )
CreateWaterStrip ( game.surfaces [ GAME_SURFACE_NAME ] ,
{ x = spawn.x + WATER_SPAWN_OFFSET_X , y = spawn.y + WATER_SPAWN_OFFSET_Y + 1 } ,
WATER_SPAWN_LENGTH )
GenerateStartingResources ( surface , spawn )
-- Send the player to that position
player.teleport ( spawn , GAME_SURFACE_NAME )
GivePlayerStarterItems ( player )
end
2016-12-02 23:26:49 +02:00
function SendPlayerToSpawn ( player )
if ( DoesPlayerHaveCustomSpawn ( player ) ) then
2017-04-27 02:59:48 +02:00
player.teleport ( global.playerSpawns [ player.name ] , GAME_SURFACE_NAME )
2016-11-26 02:20:41 +02:00
else
2017-04-27 02:59:48 +02:00
player.teleport ( game.forces [ MAIN_FORCE ] . get_spawn_position ( GAME_SURFACE_NAME ) , GAME_SURFACE_NAME )
2016-11-26 02:20:41 +02:00
end
end
function SendPlayerToRandomSpawn ( player )
2016-12-02 23:26:49 +02:00
local numSpawns = TableLength ( global.uniqueSpawns )
2016-11-26 02:20:41 +02:00
local rndSpawn = math.random ( 0 , numSpawns )
local counter = 0
if ( rndSpawn == 0 ) then
2017-04-27 02:59:48 +02:00
player.teleport ( game.forces [ MAIN_FORCE ] . get_spawn_position ( GAME_SURFACE_NAME ) , GAME_SURFACE_NAME )
2016-11-26 02:20:41 +02:00
else
counter = counter + 1
2017-07-26 02:20:35 +02:00
for name , spawn in pairs ( global.uniqueSpawns ) do
2016-11-26 02:20:41 +02:00
if ( counter == rndSpawn ) then
2017-07-26 02:20:35 +02:00
player.teleport ( spawn.pos )
2016-11-26 02:20:41 +02:00
break
end
counter = counter + 1
end
end
end
2017-04-30 15:22:45 +02:00
function CreatePlayerCustomForce ( player )
local newForce = nil
-- Check if force already exists
if ( game.forces [ player.name ] ~= nil ) then
DebugPrint ( " Force already exists! " )
player.force = game.forces [ player.name ]
return game.forces [ player.name ]
-- Create a new force using the player's name
elseif ( TableLength ( game.forces ) < MAX_FORCES ) then
newForce = game.create_force ( player.name )
2017-12-17 05:00:51 +02:00
if ENABLE_SHARED_TEAM_VISION then
newForce.share_chart = true
end
2017-04-30 15:22:45 +02:00
player.force = newForce
SetCeaseFireBetweenAllForces ( )
SetFriendlyBetweenAllForces ( )
SendBroadcastMsg ( player.name .. " has started their own team! " )
else
player.force = MAIN_FORCE
player.print ( " Sorry, no new teams can be created. You were assigned to the default team instead. " )
end
2016-11-26 02:20:41 +02:00
2017-04-30 15:22:45 +02:00
return newForce
end
2016-12-01 04:41:04 +02:00
2017-04-30 15:22:45 +02:00
-- For each force, if it's a valid force, chart the chunk that all active players
-- are in.
-- I have no idea how compute intensive this function is. If it starts to lag the game
-- we'll have to figure out how to change it.
2017-12-17 05:00:51 +02:00
-- function ShareVisionBetweenPlayers()
2016-12-01 04:41:04 +02:00
2017-12-17 05:00:51 +02:00
-- if ((game.tick % 10) == 0) then
2017-05-21 21:33:52 +02:00
2017-12-17 05:00:51 +02:00
-- for _,force in pairs(game.forces) do
-- if (force ~= nil) then
-- if ((force.name ~= enemy) and
-- (force.name ~= neutral) and
-- (force.name ~= player)) then
-- for _,player in pairs(game.connected_players) do
-- force.chart(GAME_SURFACE_NAME,
-- {{player.position.x-(2*CHUNK_SIZE),
-- player.position.y-(2*CHUNK_SIZE)},
-- {player.position.x+(2*CHUNK_SIZE),
-- player.position.y+(2*CHUNK_SIZE)}})
-- end
-- end
-- end
-- end
-- end
-- end
2017-11-29 21:39:09 +02:00
-- For each force, if it's a valid force, chart the chunk that was just scanned
-- for all forces.
-- I have no idea how compute intensive this function is. If it starts to lag the game
-- we'll have to figure out how to change it.
2017-12-17 05:00:51 +02:00
-- function ShareRadarBetweenForces(event)
-- for _,force in pairs(game.forces) do
-- if (force ~= nil) then
-- if ((force.name ~= enemy) and
-- (force.name ~= neutral) and
-- (force.name ~= player)) then
-- for _,player in pairs(game.connected_players) do
-- force.chart(GAME_SURFACE_NAME,
-- {{event.chunk_position.x*CHUNK_SIZE,
-- event.chunk_position.y*CHUNK_SIZE},
-- {event.chunk_position.x*CHUNK_SIZE,
-- event.chunk_position.y*CHUNK_SIZE}})
-- end
-- end
-- end
-- end
-- end