diff options
| author | aura <nw@moneybot.cc> | 2026-02-17 23:42:09 +0100 |
|---|---|---|
| committer | aura <nw@moneybot.cc> | 2026-02-17 23:42:09 +0100 |
| commit | 5e2eb7d67ae933b7566f1944d0bb7744da03d586 (patch) | |
| tree | 054acff1113270a9cd07933df760f3768c1b6853 /source/sourcemod/scripting/game_manager.sp | |
| parent | 341db13a008dc12bb22ceb50452d93d01476308c (diff) | |
move source stuff to its own folder
Diffstat (limited to 'source/sourcemod/scripting/game_manager.sp')
| -rw-r--r-- | source/sourcemod/scripting/game_manager.sp | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/source/sourcemod/scripting/game_manager.sp b/source/sourcemod/scripting/game_manager.sp new file mode 100644 index 0000000..f182205 --- /dev/null +++ b/source/sourcemod/scripting/game_manager.sp @@ -0,0 +1,718 @@ +#pragma semicolon 1 +#include <sourcemod> +#include <sdktools> +#include <cstrike> +#include <sdkhooks> +#include <smlib> +#include <morecolors> + +#define PLUGIN_VERSION "1.0.0" +#define MAX_FILE_LEN 80 + +public Plugin:myinfo = +{ + name = "networkheaven game manager", + author = "networkheaven.net", + description = "", + version = PLUGIN_VERSION, + url = "networkheaven.net" +}; + +new g_oneChanceDone = false; +new g_maxrounds; +new g_roundCount; +new bool:halftime; +new Handle:g_h_mp_startmoney = INVALID_HANDLE; +new Handle:g_h_mp_maxrounds = INVALID_HANDLE; +new Handle:g_h_mp_buytime = INVALID_HANDLE; +new Handle:g_h_nh_warmup = INVALID_HANDLE; +new Handle:g_h_nh_buytime = INVALID_HANDLE; +new Handle:g_h_nh_teamlimit = INVALID_HANDLE; +new Handle:g_h_mp_ignoreconditions = INVALID_HANDLE; +new g_mp_startmoney; +new bool:g_doReset = false; +new g_CtScore, g_TScore; +new Handle:g_h_roundExtentTimer = INVALID_HANDLE; +new Handle:g_h_execServerCfgTimer = INVALID_HANDLE; +new g_lastDmMode = 0; +new Float:g_botVoteEnd = -1.0; +new Float:g_voteTime = 20.0; +new bool:g_hasVoted[MAXPLAYERS + 1] = {false, ...}; +new g_voteCount[9] = {0, ...}; +new bool:g_botVoteDone = false; +new bool:g_isKZ = false; + +/* forwards */ +new Handle:g_f_on_ht = INVALID_HANDLE; + +// Offsets +new g_iAccount = -1; + + +public OnMapStart(){ + halftime = false; + g_roundCount = 0; + + new String:mapName[256]; + GetCurrentMap( mapName, sizeof(mapName) ); + + if( !strncmp( mapName, "kz_", 3, false ) + || !strncmp( mapName, "xc_", 3, false ) + || !strncmp( mapName, "bhop_", 5, false ) + || !strncmp( mapName, "bkz_", 4, false ) ) { + g_isKZ = true; + } else { + g_isKZ = false; + } + + g_mp_startmoney = GetConVarInt( g_h_mp_startmoney ); + g_maxrounds = GetConVarInt( g_h_mp_maxrounds ); + + g_lastDmMode = 0; + + g_botVoteEnd = -1.0; + LogMessage( "map name: %s kz: %d", mapName, g_isKZ ); + + if( g_isKZ == false ) { + OnDmModeChanged( g_h_nh_warmup, "", "" ); + SetConVarInt( g_h_nh_warmup, 60 ); + CreateTimer( 20.0, BotVoteCreateTimer, _ ); + } +} + +public OnConfigsExecuted() { + halftime = false; +} + +public OnPluginStart() { + HookEvent("round_start", Event_RoundStart); + HookEvent("round_end", Event_RoundEnd); + HookEvent("player_death", Event_PlayerDeath); + HookEvent("player_spawn", Event_PlayerSpawn); + HookEvent("player_team", Event_PlayerTeam); + AddCommandListener( Listener_JoinTeam, "jointeam" ); + + g_h_mp_startmoney = FindConVar( "mp_startmoney" ); + g_h_mp_maxrounds = FindConVar( "mp_maxrounds" ); + g_h_mp_buytime = FindConVar( "mp_buytime"); + g_h_mp_ignoreconditions = FindConVar( "mp_ignore_round_win_conditions" ); + g_h_nh_warmup = CreateConVar( "nh_warmup", "0", "set warmup time. -1 for infinite.", 0 ); + g_h_nh_buytime = CreateConVar( "nh_buytime", "0.5", "buytime outside of warmup.", 0 ); + g_h_nh_teamlimit = CreateConVar( "nh_teamlimit", "5", "player limit per team", 0 ); + if( g_h_nh_warmup != INVALID_HANDLE ) { + HookConVarChange( g_h_nh_warmup, OnDmModeChanged ); + } + + g_f_on_ht = CreateGlobalForward( "nthvnHalftime", ET_Ignore ); + + RegAdminCmd("sm_admbotvote", CreateBotVote, ADMFLAG_RCON); + RegConsoleCmd("sm_botvote", CreateBotVotePlayer); + + // Finding offset for CS cash + g_iAccount = FindSendPropOffs("CCSPlayer", "m_iAccount"); + if (g_iAccount == -1) + SetFailState("m_iAccount offset not found"); +} + +public OnDmModeChanged( Handle:cvar, const String:oldVal[], const String:newVal[]) { + new dm = GetConVarInt( cvar ); + + if( !!dm != !!g_lastDmMode ) { + SetConVarInt( g_h_mp_ignoreconditions, dm ); + for( new i = 1; i < MaxClients; ++i ) { + if( IsClientConnected( i ) && IsClientInGame( i ) ) + ForcePlayerSuicide( i ); + } + + ServerCommand( "mp_restartgame 1" ); + + g_CtScore = g_TScore = g_roundCount = 0; + SetTeamScore( CS_TEAM_CT, g_CtScore ); + SetTeamScore( CS_TEAM_T, g_TScore ); + } + + if( !dm ) { + SetConVarFloat( g_h_mp_buytime, GetConVarFloat( g_h_nh_buytime ) ); + if( g_h_roundExtentTimer ) { + KillTimer( g_h_roundExtentTimer ); + g_h_roundExtentTimer = INVALID_HANDLE; + } + + PrintToChatAll( "\x04===========[ game live ]===========" ); + } + else { + if( g_h_roundExtentTimer == INVALID_HANDLE ) { + g_h_roundExtentTimer = CreateTimer( 1.0, WarmupTimer, 0, TIMER_REPEAT ); + } + } + + g_lastDmMode = dm; +} + +public Action:WarmupTimer( Handle:timer, any:userid ) { + new dm = GetConVarInt( g_h_nh_warmup ); + if( dm > 0 ) { + if( dm <= 5 ) { + PrintToChatAll( "\x04========[ warmup ending in %d ]========", dm ); + } + + SetConVarInt( g_h_nh_warmup, dm - 1 ); + } + + SetConVarFloat( g_h_mp_buytime, 420.0 ); + new time = GameRules_GetProp( "m_iRoundTime" ); + if( time < 420 * 60 ) + time = 420 * 60 + 1; + GameRules_SetProp( "m_iRoundTime", time + 1, 4, 0, true ); + + new String:name[65]; + for( new i = 1; i < GetMaxEntities(); ++i ) { + if( !IsValidEdict(i) || !IsValidEntity(i) ) + continue; + + if( GetGameTime() > g_botVoteEnd ) { + if( i < MaxClients && IsClientConnected( i ) && IsClientInGame( i ) ) { + if( dm > 0 ) { + new secs = dm % 60; + new mins = (dm - secs) / 60; + PrintHintText( i, "---[ WARMUP %d:%02d ]---", mins, secs ); + } + else { + PrintHintText( i, "---[ WARMUP ]---" ); + } + + continue; + } + } + + GetEdictClassname( i, name, sizeof(name) ); + if( StrContains( name, "weapon_c4" ) != -1 ) { + RemoveEdict( i ); + } + } +} + +public OnClientPutInServer( client ) { + if( g_h_execServerCfgTimer != INVALID_HANDLE ) { + KillTimer( g_h_execServerCfgTimer ); + g_h_execServerCfgTimer = INVALID_HANDLE; + } + + SDKHook( client, SDKHook_PostThinkPost, Hook_PostThinkPost ); + + for( new i = 1; i < MaxClients; ++i ) { + if( i != client && IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) ) + return; + } + + if( !g_isKZ ) { + SetConVarInt( g_h_nh_warmup, 60 ); + CreateTimer( 20.0, BotVoteCreateTimer, _ ); + } +} + +public Hook_PostThinkPost( entity ) { + new dm = GetConVarInt( g_h_nh_warmup ); + + if( dm ) + SetEntProp( entity, Prop_Send, "m_bInBuyZone", 1 ); +} + +public ShowBotVoteMenu( client ) { + new Handle:hPanel = CreateMenu(BotVoteHandler); + + AddMenuItem( hPanel, "0", "vote for the amount of bots!" ); + AddMenuItem( hPanel, "1", "" ); + AddMenuItem( hPanel, "2", "" ); + AddMenuItem( hPanel, "3", "no bots" ); + AddMenuItem( hPanel, "4", "3v3 bots" ); + AddMenuItem( hPanel, "5", "5v5 bots" ); + AddMenuItem( hPanel, "6", "no choice" ); + + DisplayMenu(hPanel, client, MENU_TIME_FOREVER); +} + +public BotVoteHandler( Handle:hMenu, MenuAction:ma, client, nItem ) { + switch( ma ) { + case MenuAction_Select: + { + if( nItem == 6 ) { + g_hasVoted[client] = true; + } + else if( nItem < 3 && GetGameTime() < g_botVoteEnd ) { + ShowBotVoteMenu( client ); + } + else { + g_voteCount[nItem - 3]++; + g_hasVoted[client] = true; + } + } + + case MenuAction_End: + { + CloseHandle( hMenu ); + } + } +} + +public FinishBotVote() { + new winner = -1; + new maxvotes = 0; + for( new i = 0; i < 9; ++i ) { + if( g_voteCount[i] > maxvotes ) + winner = i; + } + + switch( winner ) { + case 0: + { + ServerCommand( "bot_kick; bot_quota 0" ); + PrintToChatAll( "Vote for no bots won, kicking all bots." ); + } + case 1: + { + ServerCommand( "bot_quota 6" ); + PrintToChatAll( "Vote for 3v3 bots won, setting quota to 6 bots." ); + } + case 2: { + ServerCommand( "bot_quota 10" ); + PrintToChatAll( "Vote for 3v3 bots won, setting quota to 10 bots." ); + } + } + + for( new i = 0; i < 9; ++i ) { + g_voteCount[i] = 0; + } + + for( new i = 0; i < MAXPLAYERS; ++i ) { + g_hasVoted[i] = false; + } +} + +public Action:BotVoteTimer( Handle:timer, any:unused ) { + new dm = GetConVarInt( g_h_nh_warmup ); + new String:hintStr[256]; + new Float:diff = g_botVoteEnd - GetGameTime(); + + if( diff <= 0 ) { + FinishBotVote(); + KillTimer( timer ); + return; + } + + for( new i = 1; i < MaxClients; ++i ) { + if( !IsClientConnected(i) || !IsClientInGame(i) || IsFakeClient(i) ) + continue; + + Format( + hintStr, + sizeof(hintStr), + "bot vote [%.0f sec left]:\nno bots: %d\n3v3 bots: %d\n5v5 bots: %d", + diff, + g_voteCount[0], + g_voteCount[1], + g_voteCount[2] + ); + + if( dm > 0 ) { + new secs = dm % 60; + new mins = (dm - secs) / 60; + Format( hintStr, sizeof(hintStr), "%s\n---[ WARMUP %d:%02d ]---", hintStr, mins, secs ); + } + else if( dm < 0 ) { + Format( hintStr, sizeof(hintStr), "%s\n---[ WARMUP ]---", hintStr ); + } + + PrintHintText( i, hintStr ); + if( !g_hasVoted[i] ) + ShowBotVoteMenu( i ); + } +} + +public Action:CreateBotVote( client, args ) { + if( GetGameTime() < g_botVoteEnd ) + return Plugin_Handled; + + if( g_isKZ ) + return Plugin_Handled; + + g_botVoteDone = true; + g_botVoteEnd = GetGameTime() + g_voteTime; + + for( new i = 0; i < 9; ++i ) { + g_voteCount[i] = 0; + } + + for( new i = 0; i < MAXPLAYERS; ++i ) { + g_hasVoted[i] = false; + } + + BotVoteTimer( INVALID_HANDLE, 0 ); + CreateTimer( 1.0, BotVoteTimer, 0, TIMER_REPEAT ); + return Plugin_Handled; +} + +public Action:CreateBotVotePlayer( client, args ) { + if( GetGameTime() < g_botVoteEnd ) { + g_hasVoted[client] = false; + ShowBotVoteMenu( client ); + } + + if( g_botVoteDone ) { + CPrintToChat( client, "{fuchsia}A bot vote has already concluded this round." ); + return Plugin_Handled; + } + + CreateBotVote( client, args ); + return Plugin_Handled; +} + +public Action:BotVoteCreateTimer( Handle: timer, any:unused ) { + CreateBotVote( 0, 0 ); +} + +public OnClientDisconnect( client ) { + if( IsFakeClient( client ) ) + return; + + for( new i = 1; i < MaxClients; ++i ) { + if( i == client ) + continue; + if( IsClientConnected( i ) && IsClientInGame( i ) && !IsFakeClient( i ) ) + return; + } + + SetConVarInt( g_h_nh_warmup, 0 ); + if( g_h_execServerCfgTimer != INVALID_HANDLE ) + KillTimer( g_h_execServerCfgTimer ); + + g_h_execServerCfgTimer = CreateTimer( 30.0, ExecServerCfg, _ ); +} + +public Action:ExecServerCfg( Handle:timer, any:unused ) { + if( g_isKZ ) + return; + + g_botVoteDone = false; + ServerCommand( "exec server.cfg" ); + g_h_execServerCfgTimer = INVALID_HANDLE; +} + +public Event_PlayerSpawn( Handle:event, const String:name[], bool dontBroadcast ) { + new dmmode = GetConVarInt( g_h_nh_warmup ); + new uid = GetEventInt( event, "userid" ); + new id = GetClientOfUserId( uid ); + + if( dmmode ) + SetEntData( id, g_iAccount, 16000, 4, true ); +} + +public Event_PlayerDeath( Handle:event, const String:name[], bool dontBroadcast ) { + CreateTimer( 0.15, OneChance, 0 ); + CreateTimer( 1.5, RespawnPlayerDeathmatch, GetEventInt( event, "userid" ) ); +} + +public Action:RespawnPlayerDeathmatch( Handle:timer, any:userid ) { + new dmmode = GetConVarInt( g_h_nh_warmup ); + if( !dmmode && !g_isKZ ) + return; + + new id = GetClientOfUserId( userid ); + if( !id ) + return; + CS_RespawnPlayer( id ); +} + +public Action:VerifyTeamCounts( Handle:timer, any:unused ) { + new entToKickT = 0; + new entToKickCT = 0; + new countCT = 0; + new countT = 0; + new maxTeam = GetConVarInt( g_h_nh_teamlimit ); + + for( new i = 1; i < MaxClients; ++i ) { + if( !IsClientConnected( i ) || !IsClientInGame( i ) ) + continue; + + + new playerTeam = GetClientTeam(i); + if( playerTeam == CS_TEAM_T ) { + ++countT; + if( IsFakeClient( i ) && (!entToKickCT || !IsPlayerAlive( i )) ) { + entToKickT = i; + } + } + if( playerTeam == CS_TEAM_CT ) { + ++countCT; + if( IsFakeClient( i ) && (!entToKickCT || !IsPlayerAlive( i )) ) { + entToKickCT = i; + } + } + } + + if( countCT > maxTeam && entToKickCT ) { + KickClient( entToKickCT, "kicked for game balance" ); + } + if( countT > maxTeam && entToKickT ) { + KickClient( entToKickT, "kicked for game balance" ); + } +} + +public bool:CanJoinTeam( id, oldTeam, newTeam ) { + new countT = 0; + new countCT = 0; + new maxTeam = GetConVarInt( g_h_nh_teamlimit ); + + for( new i = 1; i < MaxClients; ++i ) { + if( i == id ) + continue; + if( !IsClientConnected( i ) || !IsClientInGame( i ) || IsFakeClient( i ) ) + continue; + + new playerTeam = GetClientTeam(i); + if( playerTeam == CS_TEAM_T ) + ++countT; + if( playerTeam == CS_TEAM_CT ) + ++countCT; + } + + if( (newTeam == CS_TEAM_T && countT >= maxTeam) + || (newTeam == CS_TEAM_CT && countCT >= maxTeam) + ) { + return false; + } + + return true; +} + +public Action:Listener_JoinTeam( id, const String: command[], args ) { + new String:sArg1[3]; + GetCmdArg(1, sArg1, sizeof(sArg1)); + new newTeam = StringToInt(sArg1); + new oldTeam = GetClientTeam( id ); + + if( !CanJoinTeam( id, oldTeam, newTeam ) ) { + ChangeClientTeam( id, oldTeam ); + PrintHintText( id, "team is full" ); + return Plugin_Handled; + } + + return Plugin_Continue; +} + +public Action:RespawnPlayerDelay( Handle: timer, any: userid ) { + new id = GetClientOfUserId( userid ); + + if( id <= 0 ) + return Plugin_Handled; + + if( !IsClientConnected( id ) || !IsClientInGame( id ) ) + return Plugin_Handled; + + if( IsPlayerAlive( id ) ) + return Plugin_Handled; + + new team = GetClientTeam( id ); + if( team < 2 ) + return Plugin_Handled; + + CS_RespawnPlayer( id ); +} + +public Action:Event_PlayerTeam( Handle:event, const String:name[], bool dontBroadcast ) { + CreateTimer( 0.2, VerifyTeamCounts, 0, 0 ); + new uid = GetEventInt( event, "userid" ); + + if( GetConVarInt( g_h_nh_warmup ) != 0 || g_isKZ ) { + CreateTimer( 0.5, RespawnPlayerDelay, uid ); + } + + return Plugin_Continue; +} + +public Action:OneChance(Handle:timer, any:unused) { + if( g_roundCount != g_maxrounds ) + return; + + if( g_oneChanceDone ) + return; + + new dm = GetConVarInt( g_h_nh_warmup ); + if( dm ) + return; + + new ctAlive = 0; + new tAlive = 0; + + new clutcherT = 0; + new clutcherCT = 0; + + for( new i = 1; i <= MaxClients; ++i ) { + if( !IsClientInGame(i) || !IsPlayerAlive(i) ) + continue; + + new playerTeam = GetClientTeam(i); + if( playerTeam == CS_TEAM_CT ) { + ++ctAlive; + if( ctAlive > 1 ) + clutcherCT = 0; + else + clutcherCT = i; + } + else if( playerTeam == CS_TEAM_T ) { + ++tAlive; + if( tAlive > 1 ) + clutcherT = 0; + else + clutcherT = i; + } + } + + if( !(tAlive == 1 && ctAlive > 2) && !(ctAlive == 1 && tAlive > 2) ) + return; + + new clutcher = clutcherT ? clutcherT : clutcherCT; + decl String:clutcherName[64]; + GetClientName( clutcher, clutcherName, sizeof(clutcherName) ); + + PrintToChatAll( "\x01%s \x04has one chance, one opportunity. will they seize it, or will they let it slip?", clutcherName ); + Client_RemoveAllWeapons( clutcher ); + Client_GiveWeapon( clutcher, "weapon_awp", false ); + Client_GiveWeapon( clutcher, "weapon_deagle", false ); + Client_GiveWeapon( clutcher, "weapon_knife", true ); + GivePlayerItem( clutcher, "weapon_flashbang" ); + GivePlayerItem( clutcher, "weapon_flashbang" ); + GivePlayerItem( clutcher, "weapon_hegrenade" ); + + SetEntityHealth( clutcher, 100 ); + Client_SetArmor( clutcher, 100 ); + SetEntProp( clutcher, Prop_Send, "m_bHasHelmet", 1, 1); + + g_oneChanceDone = true; +} + +public Event_RoundStart( Handle:event, const String:name[], bool:dontBroadcast ) +{ + new wepIdx; + new playerTeam; + + g_oneChanceDone = false; + + g_CtScore = GetTeamScore( CS_TEAM_CT ); + g_TScore = GetTeamScore( CS_TEAM_T ); + + new newRoundCount = g_CtScore + g_TScore + 1; + if( newRoundCount < g_roundCount ) { + halftime = false; + g_CtScore = 0; + g_TScore = 0; + g_roundCount = 0; + g_doReset = true; + } + else { + g_roundCount = newRoundCount; + } + + for( new client = 1; client <= MaxClients; client++ ) { + if( !IsClientConnected( client ) || !IsClientInGame( client ) ) + continue; + + else if( g_doReset ) { + for( new w = 0; w < 6; w++ ) { + if( w != 2 && w != 4 ) + while( ( wepIdx = GetPlayerWeaponSlot(client, w) ) != -1 ) + RemovePlayerItem(client, wepIdx); + } + + playerTeam = GetClientTeam( client ); + if( playerTeam == CS_TEAM_T ) { + GivePlayerItem( client, "weapon_glock" ); + } + else if( playerTeam == CS_TEAM_CT ) { + GivePlayerItem( client, "weapon_usp" ); + if ((wepIdx = GetPlayerWeaponSlot( client, 6 ) ) != -1) + RemovePlayerItem(client, wepIdx); + } + SetEntProp(client, Prop_Send, "m_ArmorValue", 0, 1); + SetEntProp(client, Prop_Send, "m_bHasHelmet", 0, 1); + + SetEntData(client, g_iAccount, g_mp_startmoney, 4, true); + } + } + + g_doReset = false; +} + +public OnGameFrame() { +} + +public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) +{ + new reason = GetEventInt(event, "reason"); + new winner = GetEventInt(event, "winner"); + + g_botVoteDone = false; + g_mp_startmoney = GetConVarInt(g_h_mp_startmoney); + g_maxrounds = GetConVarInt(g_h_mp_maxrounds); + + // game commencing + if( reason == 15 ) { + g_CtScore = 0; + g_TScore = 0; + g_roundCount = 0; + return; + } + + if( winner==CS_TEAM_T ) + g_TScore++; + else if( winner==CS_TEAM_CT ) + g_CtScore++; + + if( g_TScore > g_maxrounds/2 || g_CtScore > g_maxrounds/2 ) { + SetConVarInt( g_h_mp_maxrounds, 1, true, false ); + PrintToChatAll("\x04============[ game end ]============"); + + if( g_TScore > g_CtScore ) { + PrintToChatAll("\x04Winner: T"); + } + else { + PrintToChatAll("\x04Winner: CT"); + } + } + + if( halftime || g_roundCount < g_maxrounds/2 ) { + SetTeamScore( CS_TEAM_CT, g_CtScore ); + SetTeamScore( CS_TEAM_T, g_TScore ); + return; + } + + new playerTeam; + + Call_StartForward(g_f_on_ht); + Call_Finish(); + + halftime = true; + for( new i = 1; i <= MaxClients; i++ ) { + if( IsClientInGame( i ) && IsClientConnected( i ) ) { + g_doReset = true; + + playerTeam = GetClientTeam(i); + if( playerTeam == CS_TEAM_T ) { + CS_SwitchTeam( i, CS_TEAM_CT ); + } + else if( playerTeam == CS_TEAM_CT ) { + CS_SwitchTeam( i, CS_TEAM_T ); + } + } + } + + new tmp; + tmp = g_CtScore; + g_CtScore = g_TScore; + g_TScore = tmp; + + PrintToChatAll("\x04==========[ halftime switch ]=========="); + + SetTeamScore( CS_TEAM_CT, g_CtScore ); + SetTeamScore( CS_TEAM_T, g_TScore ); +} |
