ph-enhanced/gamemodes/fretta/gamemode/round_controller.lua

409 lines
10 KiB
Lua

function GM:SetRoundWinner( ply, resulttext ) SetGlobalEntity( "RoundWinner", ply ) SetGlobalString( "RRText", tostring(resulttext) ) end
function GM:SetRoundResult( i, resulttext ) SetGlobalInt( "RoundResult", i ) SetGlobalString( "RRText", tostring(resulttext) ) end
function GM:ClearRoundResult() SetGlobalEntity( "RoundWinner", NULL ) SetGlobalInt( "RoundResult", 0 ) SetGlobalString( "RRText", "" ) end
function GM:SetInRound( b ) SetGlobalBool( "InRound", b ) end
function GM:InRound() return GetGlobalBool( "InRound", false ) end
--//moved to prop hunt's init.lua
-- fretta_waitforplayers = CreateConVar( "fretta_waitforplayers", "1", { FCVAR_ARCHIVE } )
function GM:OnRoundStart( num )
UTIL_UnFreezeAllPlayers()
hook.Call("PH_OnRoundStart", nil, num)
end
--local bAlreadyStarted = false
--[[moved to prop hunt's init.lua
function GM:OnRoundEnd( num )
// Check if fretta_waitforplayers is true
// This is a fast implementation for a waiting system
// Make optimisations if needed
if ( fretta_waitforplayers:GetBool() ) then
// Take away a round number quickly before it adds another when there are not enough players
// Set to false
if ( ( team.NumPlayers( TEAM_HUNTERS ) < 1 ) || ( team.NumPlayers( TEAM_PROPS ) < 1 ) ) then
bAlreadyStarted = false
end
// Check if the round was already started before so we count it as a fully played round
if ( !bAlreadyStarted ) then
SetGlobalInt( "RoundNumber", GetGlobalInt( "RoundNumber" )-1 )
end
// Set to true
if ( ( team.NumPlayers( TEAM_HUNTERS ) >= 1 ) && ( team.NumPlayers( TEAM_PROPS ) >= 1 ) ) then
bAlreadyStarted = true
end
end
end
]]--
function GM:OnRoundEnd(num)
end
function GM:OnRoundResult( result, resulttext )
// The fact that result might not be a team
// shouldn't matter when calling this..
team.AddScore( result, 1 )
end
function GM:OnRoundWinner( ply, resulttext )
// Do whatever you want to do with the winner here (this is only called in Free For All gamemodes)...
ply:AddFrags( 1 )
end
function GM:OnPreRoundStart( num )
game.CleanUpMap()
UTIL_StripAllPlayers()
UTIL_SpawnAllPlayers()
UTIL_FreezeAllPlayers()
end
function GM:CanStartRound( iNum )
return true
end
function GM:StartRoundBasedGame()
GAMEMODE:PreRoundStart( 1 )
end
// Number of rounds
function GM:GetRoundLimit()
return GAMEMODE.RoundLimit;
end
// Has the round limit been reached?
function GM:HasReachedRoundLimit( iNum )
local iRoundLimit = GAMEMODE:GetRoundLimit();
if( iRoundLimit > 0 && iNum > iRoundLimit ) then
--MapVote.Start()
return true
end
return false
end
// This is for the timer-based game end. set this to return true if you want it to end mid-round
function GM:CanEndRoundBasedGame()
return false
end
// You can add round time by calling this (takes time in seconds)
function GM:AddRoundTime( iAddedTime )
if( !GAMEMODE:InRound() ) then // don't add time if round is not in progress
return
end
SetGlobalFloat( "RoundEndTime", GetGlobalFloat( "RoundEndTime", CurTime() ) + iAddedTime );
timer.Adjust( "RoundEndTimer", GetGlobalFloat( "RoundEndTime" ) - GetGlobalFloat( "RoundStartTime" ), 0, function() GAMEMODE:RoundTimerEnd() end );
local rf = RecipientFilter()
rf:AddAllPlayers()
umsg.Start( "RoundAddedTime", rf ); // send a umsg so you can do something with the HUD
umsg.Float( iAddedTime ); // time added
umsg.End();
end
// This gets the timer for a round (you can make round number dependant round lengths, or make it cvar controlled)
function GM:GetRoundTime( iRoundNumber )
return GAMEMODE.RoundLength;
end
//
// Internal, override OnPreRoundStart if you want to do stuff here
//
function GM:PreRoundStart( iNum )
// Should the game end?
if( CurTime() >= GAMEMODE.GetTimeLimit() || GAMEMODE:HasReachedRoundLimit( iNum ) ) then
GAMEMODE:EndOfGame( true );
return;
end
if ( !GAMEMODE:CanStartRound( iNum ) ) then
timer.Simple( 1, function() GAMEMODE:PreRoundStart( iNum ) end ) // In a second, check to see if we can start
return;
end
timer.Create( "RoundStartTimer", GAMEMODE.RoundPreStartTime, 1, function() GAMEMODE:RoundStart() end )
SetGlobalInt( "RoundNumber", iNum )
SetGlobalFloat( "RoundStartTime", CurTime() + GAMEMODE.RoundPreStartTime )
GAMEMODE:ClearRoundResult()
GAMEMODE:OnPreRoundStart( GetGlobalInt( "RoundNumber" ) )
GAMEMODE:SetInRound( true )
end
//
// Internal, override OnRoundStart if you want to do stuff here
//
--[[ moved to prop hunt's init.lua
function GM:RoundStart()
local roundNum = GetGlobalInt( "RoundNumber" );
local roundDuration = GAMEMODE:GetRoundTime( roundNum )
GAMEMODE:OnRoundStart( roundNum )
timer.Create( "RoundEndTimer", roundDuration, 0, function() GAMEMODE:RoundTimerEnd() end )
timer.Create( "CheckRoundEnd", 1, 0, function() GAMEMODE:CheckRoundEnd() end )
SetGlobalFloat( "RoundEndTime", CurTime() + roundDuration );
// Check if fretta_waitforplayers is true
// This is a fast implementation for a waiting system
// Make optimisations if needed
if ( fretta_waitforplayers:GetBool() ) then
// Pause these timers if there are not enough players on the teams in the server
if ( ( team.NumPlayers( TEAM_HUNTERS ) < 1 ) || ( team.NumPlayers( TEAM_PROPS ) < 1 ) ) then
if ( timer.Exists( "RoundEndTimer" ) && timer.Exists( "CheckRoundEnd" ) ) then
timer.Pause( "RoundEndTimer" )
timer.Pause( "CheckRoundEnd" )
SetGlobalFloat( "RoundEndTime", -1 );
PrintMessage( HUD_PRINTTALK, "There's not enough players to start the game." )
end
end
end
// Send this as a global boolean
SetGlobalBool( "RoundWaitForPlayers", fretta_waitforplayers:GetBool() )
end
]]--
-- default fretta on round start.
function GM:RoundStart()
local roundNum = GetGlobalInt( "RoundNumber" );
local roundDuration = GAMEMODE:GetRoundTime( roundNum )
GAMEMODE:OnRoundStart( roundNum )
timer.Create( "RoundEndTimer", roundDuration, 0, function() GAMEMODE:RoundTimerEnd() end )
timer.Create( "CheckRoundEnd", 1, 0, function() GAMEMODE:CheckRoundEnd() end )
SetGlobalFloat( "RoundEndTime", CurTime() + roundDuration );
end
//
// Decide what text should show when a team/player wins
//
function GM:ProcessResultText( result, resulttext )
if ( resulttext == nil ) then resulttext = "" end
//the result could either be a number or a player!
// for a free for all you could do... if type(result) == "Player" and IsValid( result ) then return result:Name().." is the winner" or whatever
return resulttext
end
//
// Round Ended with Result
//
function GM:RoundEndWithResult( result, resulttext )
resulttext = GAMEMODE:ProcessResultText( result, resulttext )
if type( result ) == "number" then // the result is a team ID
GAMEMODE:SetRoundResult( result, resulttext )
GAMEMODE:RoundEnd()
GAMEMODE:OnRoundResult( result, resulttext )
else // the result is a player
GAMEMODE:SetRoundWinner( result, resulttext )
GAMEMODE:RoundEnd()
GAMEMODE:OnRoundWinner( result, resulttext )
end
end
//
// Internal, override OnRoundEnd if you want to do stuff here
//
function GM:RoundEnd()
if ( !GAMEMODE:InRound() ) then
// if someone uses RoundEnd incorrectly then do a trace.
MsgN("WARNING: RoundEnd being called while gamemode not in round...")
debug.Trace()
return
end
GAMEMODE:OnRoundEnd( GetGlobalInt( "RoundNumber" ) )
self:SetInRound( false )
timer.Destroy( "RoundEndTimer" )
timer.Destroy( "CheckRoundEnd" )
SetGlobalFloat( "RoundEndTime", -1 )
timer.Simple( GAMEMODE.RoundPostLength, function() GAMEMODE:PreRoundStart( GetGlobalInt( "RoundNumber" )+1 ) end )
hook.Call("PH_RoundEnd", nil)
end
function GM:GetTeamAliveCounts()
local TeamCounter = {}
for k,v in pairs( player.GetAll() ) do
if ( v:Alive() && v:Team() > 0 && v:Team() < 1000 ) then
TeamCounter[ v:Team() ] = TeamCounter[ v:Team() ] or 0
TeamCounter[ v:Team() ] = TeamCounter[ v:Team() ] + 1
end
end
return TeamCounter
end
//
// For round based games that end when a team is dead
//
function GM:CheckPlayerDeathRoundEnd()
if ( !GAMEMODE.RoundBased ) then return end
if ( !GAMEMODE:InRound() ) then return end
if ( GAMEMODE.RoundEndsWhenOneTeamAlive ) then
local Teams = GAMEMODE:GetTeamAliveCounts()
if ( table.Count( Teams ) == 0 ) then
GAMEMODE:RoundEndWithResult( 1001, "Draw, everyone loses!" )
return
end
if ( table.Count( Teams ) == 1 ) then
local TeamID = table.GetFirstKey( Teams )
GAMEMODE:RoundEndWithResult( TeamID )
return
end
end
end
hook.Add( "PlayerDisconnected", "RoundCheck_PlayerDisconnect", function() timer.Simple( 0.2, function() GAMEMODE:CheckPlayerDeathRoundEnd() end ) end )
hook.Add( "PostPlayerDeath", "RoundCheck_PostPlayerDeath", function() timer.Simple( 0.2, function() GAMEMODE:CheckPlayerDeathRoundEnd() end ) end )
//
// You should use this to check any round end conditions
//
function GM:CheckRoundEnd()
// Do checks..
// if something then call GAMEMODE:RoundEndWithResult( TEAM_BLUE, "Team Blue Ate All The Mushrooms!" )
// OR for a free for all you could do something like... GAMEMODE:RoundEndWithResult( SomePlayer )
end
function GM:CheckRoundEndInternal()
if ( !GAMEMODE:InRound() ) then return end
GAMEMODE:CheckRoundEnd()
timer.Create( "CheckRoundEnd", 1, 0, function() GAMEMODE:CheckRoundEndInternal() end )
end
//
// This is called when the round time ends.
//
function GM:RoundTimerEnd()
if ( !GAMEMODE:InRound() ) then return end
if ( !GAMEMODE.TeamBased ) then
local ply = GAMEMODE:SelectCurrentlyWinningPlayer()
if ply then
GAMEMODE:RoundEndWithResult( ply, "Time Up" )
else
GAMEMODE:RoundEndWithResult( -1, "Time Up" )
end
else
GAMEMODE:RoundEndWithResult( -1, "Time Up" )
end
end
//
// This is called when time runs out and there is no winner chosen yet (free for all gamemodes only)
// By default it chooses the player with the most frags but you can edit this to do what you need..
//
function GM:SelectCurrentlyWinningPlayer()
local winner
local topscore = 0
for k,v in pairs( player.GetAll() ) do
if v:Frags() > topscore and v:Team() != TEAM_CONNECTING and v:Team() != TEAM_UNASSIGNED and v:Team() != TEAM_SPECTATOR then
winner = v
topscore = v:Frags()
end
end
return winner
end