Round based gamemode

Okay so I’ve changed up the script a bit and am trying to get a player to spectate on death until the next round begins. Here is what it looks like.


function GM:PlayerInitialSpawn( ply )

	
	ply:SetTeam(TEAM_NEUTRAL)
	ply:SetGravity(1)
	ply:SetWalkSpeed(250)
	ply:SetRunSpeed(500)
	ply:SetCrouchedWalkSpeed(0.5)
	ply:SetDuckSpeed(0.5)
	
end

round = {}
round.Break	= 30
round.Time	= 600
round.TimeLeft = -1
round.Breaking = false

function round.Broadcast(Text)
	for k, v in pairs(player.GetAll()) do
		v:ConCommand("play buttons/button17.wav")
		v:ChatPrint(Text)
	end
	
end


function round.Begin(ply)
	
	for _, v in pairs(player.GetAll()) do
		if not v:Alive() then
			v:Spawn()
		end
	end	
	
	round.Broadcast("Round starting! Round ends in " .. round.Time .. " seconds!")
	round.TimeLeft = round.Time
end

function round.End()
	
	round.Broadcast("Round over! Next round in " .. round.Break .. " seconds!")
	round.TimeLeft = round.Break
end

function round.Handle()
	if (round.TimeLeft == -1) then
		if ( alivePlayers >= 2) then
			round.Begin()
			return
		end
	end
	
	round.TimeLeft = round.TimeLeft - 1
	
	if (round.TimeLeft == 0) then
		if (round.Breaking) then
			if ( alivePlayers >= 2) then
				ply:SetTeam(TEAM_NEUTRAL)
				round.Begin()
				round.Breaking = false
			end
		else
			round.End()
			round.Breaking = true
		end
	end
	
end
timer.Create("round.Handle", 1, 0, round.Handle)


function GM:PlayerSelectSpawn(ply)
	local spawnpoints
	local i
	
	if ply:Team() == TEAM_NEUTRAL then
		spawnpoints = ents.FindByClass("spawns")
		i = math.random(#spawnpoints)
		return spawnpoints*
	end
end

function AddSpawnpoints()

	local spawn_points = {
		Vector(-11431.851563, 11290.193359, 353.031250),
		Vector(-9055.885742, 13388.874023, 217.037521),
		Vector(-11781.977539, 11343.624023, 353.031250)
	}
	local map = {
		"rp_headattackcity_v1"
	}
	timer.Simple(3, function()
		if game.GetMap() == table.Random(map) then
			local crate = ents.Create("spawns")
			if not crate:IsValid() then return end
			crate:SetPos(table.Random(spawn_points))
			crate:Spawn()
			crate:DropToFloor()
		end
	end)
end
hook.Add("InitPostEntity", "AddSpawnpoints", AddSpawnpoints)

local function AlivePlayers()
	
	for k,v in pairs(player.GetAll()) do
		if v:Alive() then
			alivePlayers = alivePlayers + 1
		end
	end

	return alivePlayers
end


hook.Add("PlayerDeath", "checkAlivePlayers", function()
	if AlivePlayers() <= 1 then
		round.End()
	end
end)

function GM:PlayerDeath( victim, infl, attacker)

   victim:SetTeam(TEAM_SPEC)
   victim:Freeze(false)
   victim:Spectate(OBS_MODE_IN_EYE)
   victim:Extinguish()
end

function GM:CanPlayerSuicide(ply)
   return false
end

The player doesn’t spectate on death, not sure why though. Any help is appreciated and welcomed. Thank you for your time :slight_smile:

Ca

Call round.End() in a PlayerDeath hook which first checks if the amount of players alive is only 1?

This should work (untested)
[LUA]local function AlivePlayers()
local alivePlayers = 0
for k,v in pairs(player.GetAll()) do
if v:Alive() then
alivePlayers = alivePlayers + 1
end
end

return alivePlayers

end

hook.Add(“PlayerDeath”, “checkAlivePlayers”, function()
if AlivePlayers() <= 1 then
round.End()
end
end)
[/LUA]

what if player disconnects?

I got that working, thank you. I editted my OP because I can’t seem to get a player to spectate on death.

Call round.End() when a on PlayerDeath and PlayerDisconnect (or better EntityRemoved with a IsPlayer check)?

As to the updated op, I think it’s because spectator/observer mode doesn’t transition past spawning. Players get set to spectator mode when dying but upon spawning right after that gets reset. You’d wanna set observer mode in PlayerSpawn if they are TEAM_SPEC. You also wanna set the team back in round.Begin.

So it isn’t possible to set them to TEAM_SPEC on death and have them actually spectate until the round is over, then spawn again?

use hook.call to create an gameevent, so you could hook in it and upon round restart it sets them to the desired team.

No it is totally possible. You can do it in one of two ways;

  • Prevent players from respawning after dying altogether (return false in PlayerDeathThink)
  • In your GM:PlayerSpawn function, check if the player is TEAM_SPEC, then set their observer mode to OBS_MODE_IN_EYE again. Then in round.Begin set every players team back to the normal one before calling ply:Spawn() (so they spawn normally again).

I would probably so number two, but without calling ply:Spectate in PlayerDeath and instead only setting TEAM_SPEC, then call Spectate in PlayerSpawn. This way you have the normal deathcam at your ragdoll, and when you click to ‘respawn’, you enter spectator mode.

So i’ve changed this up a bit and now it spawns me in the sky with no ground only a skybox.


function GM:PlayerInitialSpawn( ply )
	
	if !round.Breaking then
		ply:SetTeam(TEAM_SPEC)
	else
		ply:SetTeam(TEAM_NEUTRAL)
	end
	
	if ply:Team() == TEAM_NEUTRAL then
		ply:SetGravity(1)
		ply:SetWalkSpeed(250)
		ply:SetRunSpeed(500)
		ply:SetCrouchedWalkSpeed(0.5)
		ply:SetDuckSpeed(0.5)
	end
	
	if ply:Team() == TEAM_SPEC then
		ply:Spectate( OBS_MODE_IN_EYE )
	end
	
end

function GM:PlayerDeath( ply, wep, attacker)
	ply:SetTeam(TEAM_SPEC)
end

function round.Broadcast(Text)
	for k, v in pairs(player.GetAll()) do
		v:ConCommand("play buttons/button17.wav")
		v:ChatPrint(Text)
	end
	
end


function round.Begin(ply)
	
	for _, v in pairs(player.GetAll()) do
		if not v:Alive() then
			ply:SetTeam(TEAM_NEUTRAL)
			v:Spawn()
		end
	end	
	
	round.Broadcast("Round starting! Round ends in " .. round.Time .. " seconds!")
	round.TimeLeft = round.Time
end

function round.End()
	
	round.Broadcast("Round over! Next round in " .. round.Break .. " seconds!")
	round.TimeLeft = round.Break
end

function round.Handle()
	if (round.TimeLeft == -1) then
		if ( alivePlayers >= 2) then
			round.Begin()
			return
		end
	end
	
	round.TimeLeft = round.TimeLeft - 1
	
	if (round.TimeLeft == 0) then
		if (round.Breaking) then
			if ( alivePlayers >= 2) then
				round.Begin()
				round.Breaking = false
			end
		else
			round.End()
			round.Breaking = true
		end
	end
	
end
timer.Create("round.Handle", 1, 0, round.Handle)

Do I have the right concept going on?

It would seem that any way I flip this code around it still doesn’t work properly. I don’t think i’m calling anything too early. Not sure why the above is happening.

Can anyone help me to spot what i’m doing wrong? I’ll correct it myself of course, just need help spotting what I’m doing wrong.


function GM:PlayerSpawn( ply )
	
	if !round.Breaking then
		ply:SetTeam(TEAM_SPEC)
	else
		ply:SetTeam(TEAM_NEUTRAL)
	end

	if ply:Team() == TEAM_NEUTRAL then
		ply:SetGravity(1)
		ply:SetWalkSpeed(250)
		ply:SetRunSpeed(500)
		ply:SetCrouchedWalkSpeed(0.5)
		ply:SetDuckSpeed(0.5)
	end
end

function GM:PlayerDeath( ply, wep, killer )
	if ply:Team() != 1 then ply:SetTeam(1) end
	ply:Spectate( OBS_MODE_CHASE )
	ply:SpectateEntity( killer )
end
function round.Broadcast(Text)
	for k, v in pairs(player.GetAll()) do
		v:ConCommand("play buttons/button17.wav")
		v:ChatPrint(Text)
	end
	
end


function round.Begin(ply)
	
	for _, v in pairs(player.GetAll()) do
		if not v:Alive() then
			ply:SetTeam(TEAM_NEUTRAL)
			v:Spawn()
		end
	end	
	
	round.Broadcast("Round starting! Round ends in " .. round.Time .. " seconds!")
	round.TimeLeft = round.Time
end

That is my current cycle.


v:ConCommand("play buttons/button17.wav")

Whaattt???
Why not networking to the client something like surface.PlaySound(File Here)?

I’ll fix this all up just as soon as I can get this spectating issue resolved. Not sure what the deal is, but I’ll keep messing with it to get it correct haha =)