#pragma semicolon 1 #include #include #include #include #include #include #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 ) 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 ) { 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 ); }