-- separate_spawns.lua -- Nov 2016 -- -- Code that handles everything regarding giving each player a separate spawn -- Includes the GUI stuff -------------------------------------------------------------------------------- -- EVENT RELATED FUNCTIONS -------------------------------------------------------------------------------- -- When a new player is created, present the spawn options -- Assign them to the main force so they can communicate with the team -- without shouting. function SeparateSpawnsPlayerCreated(event) local player = game.players[event.player_index] player.force = MAIN_FORCE DisplayWelcomeTextGui(player) end -- Check if the player has a different spawn point than the default one -- Make sure to give the default starting items function SeparateSpawnsPlayerRespawned(event) local player = game.players[event.player_index] SendPlayerToSpawn(player) end -- This is the main function that creates the spawn area -- Provides resources, land and a safe zone function SeparateSpawnsGenerateChunk(event) local surface = event.surface local chunkArea = event.area -- This handles chunk generation near player spawns -- If it is near a player spawn, it does a few things like make the area -- safe and provide a guaranteed area of land and water tiles. CreateSpawnAreas(surface, chunkArea, global.uniqueSpawns) end -- Call this if a player leaves the game -- Seems to be susceptiable to causing desyncs... function FindUnusedSpawns(event) local player = game.players[event.player_index] if (player.online_time < MIN_ONLINE_TIME) then DropGravestoneChests(player) -- Clear out global variables for that player??? if (global.playerSpawns[player.name] ~= nil) then global.playerSpawns[player.name] = nil end -- If a uniqueSpawn was created for the player, mark it as unused. if (global.uniqueSpawns[player.name] ~= nil) then table.insert(global.unusedSpawns, global.uniqueSpawns[player.name]) -- TODO: Test player joining and leaving quickly to ensure -- spawn points are not messed up... -- global.uniqueSpawns[player.name] = nil SendBroadcastMsg(player.name .. " base was freed up because they left within 5 minutes of joining.") end -- Remove from shared spawns if (global.sharedSpawns[player.name] ~= nil) then global.sharedSpawns[player.name] = nil end -- remove that player's cooldown setting if (global.playerCooldowns[player.name] ~= nil) then global.playerCooldowns[player.name] = nil end -- Remove from shared spawn player slots (need to search all) for _,sharedSpawn in pairs(global.sharedSpawns) do for key,playerName in pairs(sharedSpawn.players) do if (player.name == playerName) then sharedSpawn.players[key] = nil; end end end -- Remove a force if this player created it and they are the only one on it if (#player.force.players <= 1) then game.merge_forces(player.force, MAIN_FORCE) end -- Remove the character completely game.remove_offline_players({player}) end end -------------------------------------------------------------------------------- -- NON-EVENT RELATED FUNCTIONS -- These should be local functions where possible! -------------------------------------------------------------------------------- -- Add a spawn to the shared spawn global -- Used for tracking which players are assigned to it, where it is and if -- it is open for new players to join function CreateNewSharedSpawn(player) global.sharedSpawns[player.name] = {openAccess=true, position=global.playerSpawns[player.name], players={}} end -- Returns the number of players currently online at the shared spawn function GetOnlinePlayersAtSharedSpawn(ownerName) if (global.sharedSpawns[ownerName] ~= nil) then -- Does not count base owner local count = 0 -- For each player in the shared spawn, check if online and add to count. for _,player in pairs(game.connected_players) do if (ownerName == player.name) then count = count + 1 end for _,playerName in pairs(global.sharedSpawns[ownerName].players) do if (playerName == player.name) then count = count + 1 end end end return count else return 0 end end -- Get the number of currently available shared spawns -- This means the base owner has enabled access AND the number of online players -- is below the threshold. function GetNumberOfAvailableSharedSpawns() local count = 0 for ownerName,sharedSpawn in pairs(global.sharedSpawns) do if (sharedSpawn.openAccess) then if (GetOnlinePlayersAtSharedSpawn(ownerName) < MAX_ONLINE_PLAYERS_AT_SHARED_SPAWN) then count = count+1 end end end return count end -- Initializes the globals used to track the special spawn and player -- status information function InitSpawnGlobalsAndForces() -- Containes an array of all player spawns -- A secondary array tracks whether the character will respawn there. if (global.playerSpawns == nil) then global.playerSpawns = {} end if (global.uniqueSpawns == nil) then global.uniqueSpawns = {} end if (global.sharedSpawns == nil) then global.sharedSpawns = {} end if (global.unusedSpawns == nil) then global.unusedSpawns = {} end if (global.playerCooldowns == nil) then global.playerCooldowns = {} end game.create_force(MAIN_FORCE) game.forces[MAIN_FORCE].set_spawn_position(game.forces["player"].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME) SetCeaseFireBetweenAllForces() SetFriendlyBetweenAllForces() AntiGriefing(game.forces[MAIN_FORCE]) end function DoesPlayerHaveCustomSpawn(player) for name,spawnPos in pairs(global.playerSpawns) do if (player.name == name) then return true end end return false end function ChangePlayerSpawn(player, pos) global.playerSpawns[player.name] = pos global.playerCooldowns[player.name] = {setRespawn=game.tick} end function SendPlayerToNewSpawnAndCreateIt(player, spawn) -- Send the player to that position player.teleport(spawn, GAME_SURFACE_NAME) GivePlayerStarterItems(player) ChartArea(player.force, player.position, 4, player.surface) -- If we get a valid spawn point, setup the area if ((spawn.x ~= 0) and (spawn.y ~= 0)) then global.uniqueSpawns[player.name] = spawn ClearNearbyEnemies(player, SAFE_AREA_TILE_DIST) else DebugPrint("THIS SHOULD NOT EVER HAPPEN! Spawn failed!") SendBroadcastMsg("Failed to create spawn point for: " .. player.name) end end function SendPlayerToSpawn(player) if (DoesPlayerHaveCustomSpawn(player)) then player.teleport(global.playerSpawns[player.name], GAME_SURFACE_NAME) else player.teleport(game.forces[MAIN_FORCE].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME) end end function SendPlayerToRandomSpawn(player) local numSpawns = TableLength(global.uniqueSpawns) local rndSpawn = math.random(0,numSpawns) local counter = 0 if (rndSpawn == 0) then player.teleport(game.forces[MAIN_FORCE].get_spawn_position(GAME_SURFACE_NAME), GAME_SURFACE_NAME) else counter = counter + 1 for name,spawnPos in pairs(global.uniqueSpawns) do if (counter == rndSpawn) then player.teleport(spawnPos) break end counter = counter + 1 end end end function CreatePlayerCustomForce(player) local newForce = nil -- Check if force already exists if (game.forces[player.name] ~= nil) then DebugPrint("Force already exists!") player.force = game.forces[player.name] return game.forces[player.name] -- Create a new force using the player's name elseif (TableLength(game.forces) < MAX_FORCES) then newForce = game.create_force(player.name) 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 return newForce end -- 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. function ShareVisionBetweenPlayers() 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-CHUNK_SIZE, player.position.y-CHUNK_SIZE}, {player.position.x+CHUNK_SIZE, player.position.y+CHUNK_SIZE}}) end end end end end