Fixed admin infect bug (I think), made roundend core module, handles all round end events, modified ClassApplyOverlay, removed mp_restartgame hook, recoded PlayerLeft and BalanceTeam functions. And added comments.
This commit is contained in:
		| @@ -17,15 +17,28 @@ | ||||
|  | ||||
| #define VERSION "3.0-dev" | ||||
|  | ||||
| // Core include. | ||||
| #include "zr/zombiereloaded" | ||||
| #include "zr/global" | ||||
| #include "zr/cvars" | ||||
| #include "zr/translation" | ||||
| #include "zr/offsets" | ||||
| #include "zr/models" | ||||
| #include "zr/overlays" | ||||
|  | ||||
| // Class system | ||||
| // External api (not done) | ||||
| //#include "zr/global" | ||||
|  | ||||
| // Cvars (core) | ||||
| #include "zr/cvars" | ||||
|  | ||||
| // Translations (core) | ||||
| #include "zr/translation" | ||||
|  | ||||
| // Offsets (core) | ||||
| #include "zr/offsets" | ||||
|  | ||||
| // Models (core) | ||||
| #include "zr/models" | ||||
|  | ||||
| // Round end (core) | ||||
| #include "zr/roundend" | ||||
|  | ||||
| // Class system (module) | ||||
| #include "zr/playerclasses/playerclasses" | ||||
|  | ||||
| #include "zr/anticamp" | ||||
| @@ -34,31 +47,31 @@ | ||||
| #include "zr/menu" | ||||
| #include "zr/sayhooks" | ||||
|  | ||||
| // Weapons | ||||
| // Weapons (module) | ||||
| #include "zr/weapons/weapons" | ||||
|  | ||||
| // Sound effects | ||||
| // Sound effects (module) | ||||
| #include "zr/soundeffects/soundeffects" | ||||
|  | ||||
| // Antistick | ||||
| // Antistick (module) | ||||
| #include "zr/antistick" | ||||
|  | ||||
| // Hitgroups | ||||
| // Hitgroups (module) | ||||
| #include "zr/hitgroups" | ||||
|  | ||||
| // Knockback | ||||
| // Knockback (module) | ||||
| #include "zr/knockback" | ||||
|  | ||||
| // Spawn protect | ||||
| // Spawn protect (module) | ||||
| #include "zr/spawnprotect" | ||||
|  | ||||
| // Respawn | ||||
| // Respawn (module) | ||||
| #include "zr/respawn" | ||||
|  | ||||
| // Napalm | ||||
| // Napalm (module) | ||||
| #include "zr/napalm" | ||||
|  | ||||
| // ZHP | ||||
| // ZHP (module) | ||||
| #include "zr/zhp" | ||||
|  | ||||
| #include "zr/zadmin" | ||||
| @@ -77,7 +90,8 @@ public Plugin:myinfo = | ||||
|  | ||||
| public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) | ||||
| { | ||||
|     CreateGlobals(); | ||||
|     // Todo: External API | ||||
|     //CreateGlobals(); | ||||
|      | ||||
|     return true; | ||||
| } | ||||
| @@ -146,6 +160,7 @@ public OnMapStart() | ||||
|     LoadDownloadData(); | ||||
|      | ||||
|     // Forward event to modules. | ||||
|     RoundEndOnMapStart(); | ||||
|     ClassLoad(); | ||||
|     WeaponsLoad(); | ||||
|     SEffectsOnMapStart(); | ||||
| @@ -190,6 +205,7 @@ public OnClientPutInServer(client) | ||||
|     bMotherInfectImmune[client] = false; | ||||
|      | ||||
|     // Forward event to modules. | ||||
|     RoundEndGetClientDXLevel(client); | ||||
|     ClassClientInit(client); | ||||
|     SEffectsClientInit(client); | ||||
|     WeaponsClientInit(client); | ||||
| @@ -198,7 +214,6 @@ public OnClientPutInServer(client) | ||||
|     ZHPClientInit(client); | ||||
|      | ||||
|     ClientHookAttack(client); | ||||
|     ZRFindClientDXLevel(client); | ||||
|      | ||||
|     for (new x = 0; x < MAXTIMERS; x++) | ||||
|     { | ||||
| @@ -229,7 +244,6 @@ public OnClientDisconnect(client) | ||||
|  | ||||
| MapChangeCleanup() | ||||
| { | ||||
|     tRound = INVALID_HANDLE; | ||||
|     tInfect = INVALID_HANDLE; | ||||
|     AntiStickReset(); | ||||
|      | ||||
| @@ -246,7 +260,7 @@ MapChangeCleanup() | ||||
|     } | ||||
| } | ||||
|  | ||||
| ZREnd() | ||||
| /*ZREnd() | ||||
| { | ||||
|     TerminateRound(3.0, Game_Commencing); | ||||
|          | ||||
| @@ -272,4 +286,4 @@ ZREnd() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| }*/ | ||||
| @@ -64,9 +64,9 @@ enum ZRSettings | ||||
|     Handle:CVAR_ANTISTICK_INTERVAL, | ||||
|     Handle:CVAR_PROTECT, | ||||
|     Handle:CVAR_CONSECUTIVE_INFECT, | ||||
|     Handle:CVAR_OVERLAYS, | ||||
|     Handle:CVAR_OVERLAYS_HUMAN, | ||||
|     Handle:CVAR_OVERLAYS_ZOMBIE, | ||||
|     Handle:CVAR_ROUNDEND_OVERLAY, | ||||
|     Handle:CVAR_ROUNDEND_OVERLAY_ZOMBIE, | ||||
|     Handle:CVAR_ROUNDEND_OVERLAY_HUMAN, | ||||
|     Handle:CVAR_ZMARKET_BUYZONE, | ||||
|     Handle:CVAR_ZSPAWN, | ||||
|     Handle:CVAR_ZTELE, | ||||
| @@ -154,9 +154,9 @@ CreateCvars() | ||||
|     gCvars[CVAR_ANTISTICK_INTERVAL]        =    CreateConVar("zr_antistick_interval", "1.0", "How often, in seconds, the anti-stick module checks each player for being stuck. (1.0: Default)"); | ||||
|     gCvars[CVAR_PROTECT]                   =    CreateConVar("zr_protect", "10", "Players that join late will be protected for this long, in seconds (0: Disable)"); | ||||
|     gCvars[CVAR_CONSECUTIVE_INFECT]        =    CreateConVar("zr_consecutive_infect", "0", "Allow player to be randomly chosen twice in a row to be a mother zombie (0: Disable)"); | ||||
|     gCvars[CVAR_OVERLAYS]                  =    CreateConVar("zr_overlays", "1", "Will show overlays that tell who the winner of the round was (0: Disable)"); | ||||
|     gCvars[CVAR_OVERLAYS_HUMAN]            =    CreateConVar("zr_overlays_human", "overlays/zr/humans_win", "The overlay shown to tell everyone that humans won when zr_overlays is 1"); | ||||
|     gCvars[CVAR_OVERLAYS_ZOMBIE]           =    CreateConVar("zr_overlays_zombie", "overlays/zr/zombies_win", "The overlay shown to tell everyone that zombies won when zr_overlays is 1"); | ||||
|     gCvars[CVAR_ROUNDEND_OVERLAY]          =    CreateConVar("zr_roundend_overlay", "1", "Shows an overlay to all clients when a team wins. (0: Disable)"); | ||||
|     gCvars[CVAR_ROUNDEND_OVERLAY_HUMAN]    =    CreateConVar("zr_roundend_overlays_human", "overlays/zr/humans_win", "Path to \"humans win\" overlay"); | ||||
|     gCvars[CVAR_ROUNDEND_OVERLAY_ZOMBIE]   =    CreateConVar("zr_roundend_overlays_zombie", "overlays/zr/zombies_win", "Path to \"zombies win\" overlay"); | ||||
|     gCvars[CVAR_ZMARKET_BUYZONE]           =    CreateConVar("zr_zmarket_buyzone", "1", "Must be in buyzone to access !zmarket, if Market is installed (0: Can be used anywhere)"); | ||||
|     gCvars[CVAR_ZSPAWN]                    =    CreateConVar("zr_zspawn", "1", "Allow players to spawn if they just joined the game (0: Disable)"); | ||||
|     gCvars[CVAR_ZTELE]                     =    CreateConVar("zr_tele", "1", "Allow players to use the teleporter to get to spawn. (0: Disable)"); | ||||
| @@ -184,7 +184,9 @@ CreateCvars() | ||||
|     gCvars[CVAR_ANTICAMP_UPDATE_INTERVAL]  =    CreateConVar("zr_anticamp_update_interval", "1", "How often to update player locations (in seconds)."); | ||||
|     gCvars[CVAR_ANTICAMP_ECHO]             =    CreateConVar("zr_anticamp_echo", "1", "Log kills done by anticamp to admin chat."); | ||||
|      | ||||
|     HookConVarChange(gCvars[CVAR_ENABLE], EnableHook); | ||||
|     // TODO: Recode. | ||||
|     //HookConVarChange(gCvars[CVAR_ENABLE], EnableHook); | ||||
|      | ||||
|     HookConVarChange(gCvars[CVAR_ANTICAMP], AnticampHook); | ||||
|     HookConVarChange(gCvars[CVAR_ANTICAMP_UPDATE_INTERVAL], UpdateIntervalHook); | ||||
|      | ||||
| @@ -198,19 +200,15 @@ HookCvars() | ||||
|      | ||||
|     HookConVarChange(FindConVar("mp_autoteambalance"), AutoTeamBalanceHook); | ||||
|     HookConVarChange(FindConVar("mp_limitteams"), LimitTeamsHook); | ||||
|      | ||||
|     HookConVarChange(FindConVar("mp_restartgame"), RestartGameHook); | ||||
| } | ||||
|  | ||||
| UnhookCvars() | ||||
| { | ||||
|     UnhookConVarChange(FindConVar("mp_autoteambalance"), AutoTeamBalanceHook); | ||||
|     UnhookConVarChange(FindConVar("mp_limitteams"), LimitTeamsHook); | ||||
|      | ||||
|     UnhookConVarChange(FindConVar("mp_restartgame"), RestartGameHook); | ||||
| } | ||||
|  | ||||
| public EnableHook(Handle:convar, const String:oldValue[], const String:newValue[]) | ||||
| /*public EnableHook(Handle:convar, const String:oldValue[], const String:newValue[]) | ||||
| { | ||||
|     new bool:enable = bool:StringToInt(newValue); | ||||
|      | ||||
| @@ -225,7 +223,7 @@ public EnableHook(Handle:convar, const String:oldValue[], const String:newValue[ | ||||
|     { | ||||
|         ZREnd(); | ||||
|     } | ||||
| } | ||||
| }*/ | ||||
|  | ||||
| public AutoTeamBalanceHook(Handle:convar, const String:oldValue[], const String:newValue[]) | ||||
| { | ||||
|   | ||||
| @@ -36,37 +36,39 @@ public Action:RoundStart(Handle:event, const String:name[], bool:dontBroadcast) | ||||
| {    | ||||
|     ChangeLightStyle(); | ||||
|      | ||||
|     // Forward event to sub-modules. | ||||
|     SEffectsOnRoundStart(); | ||||
|     AntiStickOnRoundStart(); | ||||
|      | ||||
|     if (tRound != INVALID_HANDLE) | ||||
|     { | ||||
|         KillTimer(tRound); | ||||
|         tRound = INVALID_HANDLE; | ||||
|     } | ||||
|      | ||||
|     if (tInfect != INVALID_HANDLE) | ||||
|     { | ||||
|         KillTimer(tInfect); | ||||
|         tInfect = INVALID_HANDLE; | ||||
|     } | ||||
|  | ||||
|     g_bZombieSpawned = false; | ||||
|      | ||||
|     for (new x = 1; x<= MaxClients; x++) | ||||
|     { | ||||
|         if (!IsClientInGame(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         bZombie[x] = false; | ||||
|     } | ||||
|      | ||||
|     // Balance teams, and respawn all players. | ||||
|     BalanceTeams(true); | ||||
|      | ||||
|     ZR_PrintToChat(0, "Round objective"); | ||||
|      | ||||
|     // Forward event to sub-modules. | ||||
|     RoundEndOnRoundStart(); | ||||
|     SEffectsOnRoundStart(); | ||||
|     AntiStickOnRoundStart(); | ||||
| } | ||||
|  | ||||
| public Action:RoundFreezeEnd(Handle:event, const String:name[], bool:dontBroadcast) | ||||
| { | ||||
|     RemoveObjectives(); | ||||
|      | ||||
|     if (tRound != INVALID_HANDLE) | ||||
|     { | ||||
|         KillTimer(tRound); | ||||
|     } | ||||
|      | ||||
|     new Float:roundlen = GetConVarFloat(FindConVar("mp_roundtime")) * 60.0; | ||||
|     tRound = CreateTimer(roundlen, RoundOver, _, TIMER_FLAG_NO_MAPCHANGE); | ||||
|      | ||||
|     if (tInfect != INVALID_HANDLE) | ||||
|     { | ||||
|         KillTimer(tInfect); | ||||
| @@ -78,17 +80,14 @@ public Action:RoundFreezeEnd(Handle:event, const String:name[], bool:dontBroadca | ||||
|     tInfect = CreateTimer(randlen, MotherZombie, _, TIMER_FLAG_NO_MAPCHANGE); | ||||
|      | ||||
|     // Forward events to modules. | ||||
|     RoundEndOnRoundFreezeEnd(); | ||||
|     ZTeleEnable(); | ||||
|  | ||||
| } | ||||
|  | ||||
| public Action:RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) | ||||
| { | ||||
|     if (tRound != INVALID_HANDLE) | ||||
|     { | ||||
|         KillTimer(tRound); | ||||
|         tRound = INVALID_HANDLE; | ||||
|     } | ||||
|     new reason = GetEventInt(event, "reason"); | ||||
|      | ||||
|     if (tInfect != INVALID_HANDLE) | ||||
|     { | ||||
| @@ -108,19 +107,11 @@ public Action:RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) | ||||
|         bZombie[x] = false; | ||||
|     } | ||||
|      | ||||
|     // Balance teams.     | ||||
|     BalanceTeams(); | ||||
|      | ||||
|     new reason = GetEventInt(event, "reason"); | ||||
|      | ||||
|     if (reason == CTs_PreventEscape) | ||||
|     { | ||||
|         ShowOverlays(5.0, Human); | ||||
|     } | ||||
|     else if (reason == Terrorists_Escaped) | ||||
|     { | ||||
|         ShowOverlays(5.0, Zombie); | ||||
|     } | ||||
|  | ||||
|     // Forward event to modules. | ||||
|     RoundEndOnRoundEnd(reason); | ||||
|     ZTeleReset(); | ||||
| } | ||||
|  | ||||
| @@ -296,8 +287,11 @@ public Action:PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) | ||||
|     RespawnOnClientDeath(index, attacker, weapon); | ||||
|     ZHPOnClientDeath(index); | ||||
|      | ||||
|     new ZTeam:team = IsRoundOver();     | ||||
|     RoundWin(team); | ||||
|     new RoundEndOutcome:outcome; | ||||
|     if (RoundEndGetRoundStatus(outcome)) | ||||
|     { | ||||
|         RoundEndTerminateRound(outcome); | ||||
|     } | ||||
| } | ||||
|  | ||||
| public Action:PlayerJump(Handle:event, const String:name[], bool:dontBroadcast) | ||||
|   | ||||
| @@ -1,45 +0,0 @@ | ||||
| /** | ||||
|  * ==================== | ||||
|  *   Zombie:Reloaded | ||||
|  *   File: overlays.inc | ||||
|  *   Author: Greyscale | ||||
|  * ====================  | ||||
|  */ | ||||
|  | ||||
| ShowOverlays(Float:time, ZTeam:winner) | ||||
| { | ||||
|     new bool:overlays = GetConVarBool(gCvars[CVAR_OVERLAYS]); | ||||
|     if (overlays) | ||||
|     { | ||||
|         decl String:overlay[64]; | ||||
|         if (winner == Human) | ||||
|         { | ||||
|             GetConVarString(gCvars[CVAR_OVERLAYS_HUMAN], overlay, sizeof(overlay)); | ||||
|         } | ||||
|         else if (winner == Zombie) | ||||
|         { | ||||
|             GetConVarString(gCvars[CVAR_OVERLAYS_ZOMBIE], overlay, sizeof(overlay)); | ||||
|         } | ||||
|              | ||||
|         for (new x = 1; x <= MaxClients; x++) | ||||
|         { | ||||
|             if (IsClientInGame(x)) | ||||
|             { | ||||
|                 ZRDisplayClientOverlay(x, overlay); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         CreateTimer(time, KillOverlays); | ||||
|     } | ||||
| } | ||||
|  | ||||
| public Action:KillOverlays(Handle:timer) | ||||
| { | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         if (IsClientInGame(x)) | ||||
|         { | ||||
|             ClientCommand(x, "r_screenoverlay \"\""); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -54,7 +54,7 @@ bool:ClassApplyAttributes(client, bool:improved = false) | ||||
|  */ | ||||
| bool:ClassApplyModel(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER) | ||||
| { | ||||
|     decl String:modelpath[256]; | ||||
|     decl String:modelpath[PLATFORM_MAX_PATH]; | ||||
|      | ||||
|     // Get the model path from the specified cache. | ||||
|     if (cachetype == ZR_CLASS_CACHE_PLAYER) | ||||
| @@ -130,27 +130,34 @@ bool:ClassApplyAlpha(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER) | ||||
|  */ | ||||
| bool:ClassApplyOverlay(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER) | ||||
| { | ||||
|     decl String:overlay[256]; | ||||
|      | ||||
|     // Validate DirectX requirements. | ||||
|     if (dxLevel[client] < DXLEVEL_MIN) | ||||
|     // If dxLevel is 0, then query on client failed, so try again, then stop. | ||||
|     if (!dxLevel[client]) | ||||
|     { | ||||
|         // DirectX version is too old. | ||||
|         // TODO: Log warning? | ||||
|         // Query dxlevel cvar. | ||||
|         RoundEndGetClientDXLevel(client); | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     // If client doesn't meet minimum requirement, then print unsupported text. | ||||
|     if (dxLevel[client] < ROUNDEND_MIN_DXLEVEL) | ||||
|     { | ||||
|         ZR_PrintCenterText(client, "DX90 not supported", dxLevel[client], ROUNDEND_MIN_DXLEVEL); | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     decl String:overlaypath[PLATFORM_MAX_PATH]; | ||||
|      | ||||
|     // Get the overlay path from the specified cache. | ||||
|     if (cachetype == ZR_CLASS_CACHE_PLAYER) | ||||
|     { | ||||
|         ClassGetOverlayPath(client, overlay, sizeof(overlay), cachetype); | ||||
|         ClassGetOverlayPath(client, overlaypath, sizeof(overlaypath), cachetype); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ClassGetOverlayPath(classindex, overlay, sizeof(overlay), cachetype); | ||||
|         ClassGetOverlayPath(classindex, overlaypath, sizeof(overlaypath), cachetype); | ||||
|     } | ||||
|      | ||||
|     ClassOverlayInitialize(client, overlay); | ||||
|     ClassOverlayInitialize(client, overlaypath); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -27,7 +27,7 @@ new bClientOverlayOn[MAXPLAYERS + 1]; | ||||
| /** | ||||
|  * Path to the currently active overlay. | ||||
|  */ | ||||
| new String:ActiveOverlay[MAXPLAYERS + 1][256]; | ||||
| new String:ActiveOverlay[MAXPLAYERS + 1][PLATFORM_MAX_PATH]; | ||||
|  | ||||
| bool:ClientHasOverlay(client) | ||||
| { | ||||
|   | ||||
							
								
								
									
										405
									
								
								src/zr/roundend.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								src/zr/roundend.inc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,405 @@ | ||||
| /* | ||||
|  * ============================================================================ | ||||
|  * | ||||
|  *   Zombie:Reloaded | ||||
|  * | ||||
|  *   File:        roundend.inc | ||||
|  *   Description: (Core) Handles round end actions. | ||||
|  * | ||||
|  * ============================================================================ | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @section All round end reasons. | ||||
|  */ | ||||
| #define ROUNDEND_TARGET_BOMBED							1		// Target Successfully Bombed! | ||||
| #define ROUNDEND_VIP_ESCAPED							2		// The VIP has escaped! | ||||
| #define ROUNDEND_VIP_ASSASSINATED						3		// VIP has been assassinated! | ||||
| #define ROUNDEND_TERRORISTS_ESCAPED						4		// The terrorists have escaped! | ||||
| #define ROUNDEND_CTS_PREVENTESCAPE						5		// The CT's have prevented most of the terrorists from escaping! | ||||
| #define ROUNDEND_ESCAPING_TERRORISTS_NEUTRALIZED		6		// Escaping terrorists have all been neutralized! | ||||
| #define ROUNDEND_BOMB_DEFUSED							7		// The bomb has been defused! | ||||
| #define ROUNDEND_CTS_WIN								8		// Counter-Terrorists Win! | ||||
| #define ROUNDEND_TERRORISTS_WIN							9		// Terrorists Win! | ||||
| #define ROUNDEND_ROUND_DRAW								10		// Round Draw! | ||||
| #define ROUNDEND_ALL_HOSTAGES_RESCUED					11		// All Hostages have been rescued! | ||||
| #define ROUNDEND_TARGET_SAVED							12		// Target has been saved! | ||||
| #define ROUNDEND_HOSTAGES_NOT_RESCUED					13		// Hostages have not been rescued! | ||||
| #define ROUNDEND_TERRORISTS_NOT_ESCAPED					14		// Terrorists have not escaped! | ||||
| #define ROUNDEND_VIP_NOT_ESCAPED						15		// VIP has not escaped! | ||||
| #define ROUNDEND_GAME_COMMENCING						16		// Game Commencing! | ||||
| /** | ||||
|  * @endsection | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Delay between round ending and new round starting. (Normal) | ||||
|  */ | ||||
| #define ROUNDEND_DELAY_NORMAL 5.0 | ||||
|  | ||||
| /** | ||||
|  * Delay between round ending and new round starting. (Short, for ROUNDEND_GAME_COMMENCING) | ||||
|  */ | ||||
| #define ROUNDEND_DELAY_SHORT 3.0 | ||||
|  | ||||
| /** | ||||
|  * Minimum dx level required to see overlays. | ||||
|  */ | ||||
| #define ROUNDEND_MIN_DXLEVEL 90 | ||||
|   | ||||
| /** | ||||
|  * Possible round end outcomes. | ||||
|  */ | ||||
| enum RoundEndOutcome | ||||
| { | ||||
|     HumansWin, /** Humans have killed all zombies. */ | ||||
|     ZombiesWin, /** Zombies have infected all humans. */ | ||||
|     Draw, /** Round has ended in unexpected way. */ | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Global variable to store round win timer handle. | ||||
|  */ | ||||
| new Handle:tRoundEnd = INVALID_HANDLE; | ||||
|  | ||||
| /** | ||||
|  * Global variable to store a convar query cookie | ||||
|  */  | ||||
| new QueryCookie:mat_dxlevel; | ||||
|  | ||||
| /** | ||||
|  * Map is starting. | ||||
|  */  | ||||
| RoundEndOnMapStart() | ||||
| { | ||||
|     // Reset timer handle. | ||||
|     tRoundEnd = INVALID_HANDLE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * The round is starting. | ||||
|  */ | ||||
| RoundEndOnRoundStart() | ||||
| { | ||||
|     // If round end timer is running, then kill it. | ||||
|     if (tRoundEnd != INVALID_HANDLE) | ||||
|     { | ||||
|         // Kill timer. | ||||
|         KillTimer(tRoundEnd); | ||||
|          | ||||
|         // Reset timer handle. | ||||
|         tRoundEnd = INVALID_HANDLE; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * The freeze time is ending. | ||||
|  */ | ||||
| RoundEndOnRoundFreezeEnd() | ||||
| { | ||||
|     // Calculate round length, in seconds. | ||||
|     // Get mp_roundtime. (in minutes) | ||||
|     new Float:roundtime = GetConVarFloat(FindConVar("mp_roundtime")); | ||||
|      | ||||
|     // Convert to seconds. | ||||
|     roundtime *= 60.0; | ||||
|      | ||||
|     // Start timer. | ||||
|     tRoundEnd = CreateTimer(roundtime, RoundEndTimer, _, TIMER_FLAG_NO_MAPCHANGE); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * The round is ending. | ||||
|  *  | ||||
|  * @param reason    Reason the round has ended. | ||||
|  */ | ||||
| RoundEndOnRoundEnd(reason) | ||||
| { | ||||
|     // If round end timer is running, then kill it. | ||||
|     if (tRoundEnd != INVALID_HANDLE) | ||||
|     { | ||||
|         // Kill timer. | ||||
|         KillTimer(tRoundEnd); | ||||
|          | ||||
|         // Reset timer handle. | ||||
|         tRoundEnd = INVALID_HANDLE; | ||||
|     } | ||||
|      | ||||
|     // Get outcome of the round. | ||||
|     new RoundEndOutcome:outcome = RoundEndReasonToOutcome(reason); | ||||
|      | ||||
|     // Display the overlay to all clients. | ||||
|     RoundEndOverlayStart(ROUNDEND_DELAY_NORMAL, outcome); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Finds DX level of a client. | ||||
|  *  | ||||
|  * @param client    The client index.   | ||||
|  */ | ||||
| RoundEndGetClientDXLevel(client) | ||||
| { | ||||
|     // If client is fake (or bot), then stop. | ||||
|     if (IsFakeClient(client)) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Query mat_dxlevel on client. | ||||
|     mat_dxlevel = QueryClientConVar(client, "mat_dxlevel", RoundEndQueryClientDXLevel); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Query callback function. | ||||
|  * | ||||
|  * @param cookie    Unique cookie of the query. | ||||
|  * @param client    The client index. | ||||
|  * @param result    The result of the query (see console.inc enum ConVarQueryResult) | ||||
|  * @param cvarName  Name of the cvar. | ||||
|  * @param cvarValue Value of the cvar. | ||||
|  */        | ||||
| public RoundEndQueryClientDXLevel(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[]) | ||||
| { | ||||
|     // If query cookie does not match cookie given by mat_dxlevel query, then stop, this isn't our query. | ||||
|     if (cookie != mat_dxlevel) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Reset dxLevel. | ||||
|     dxLevel[client] = 0; | ||||
|      | ||||
|     // If result is any other than ConVarQuery_Okay, then stop. | ||||
|     if (result != ConVarQuery_Okay) | ||||
|     {    | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Copy cvar value to dxLevel array. | ||||
|     dxLevel[client] = StringToInt(cvarValue); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Convert a round_end reason, to a round winner, or draw. | ||||
|  *  | ||||
|  * @param reason    The round_end reason. | ||||
|  * @return          The winner of the round. (see enum RoundEndOutcome) | ||||
|  */  | ||||
| RoundEndOutcome:RoundEndReasonToOutcome(reason) | ||||
| { | ||||
|     switch(reason) | ||||
|     { | ||||
|         // CTs won the round. | ||||
|         case ROUNDEND_CTS_WIN: | ||||
|         { | ||||
|             return HumansWin; | ||||
|         } | ||||
|         // Ts won the round. | ||||
|         case ROUNDEND_TERRORISTS_WIN: | ||||
|         { | ||||
|             return ZombiesWin; | ||||
|         } | ||||
|         // Unexpected case. | ||||
|         default: | ||||
|         { | ||||
|             return Draw; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // Return draw to satisfy compiler. (code will never reach this point.) | ||||
|     return Draw; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Timer callback, called when round time reaches 0. | ||||
|  * | ||||
|  * @param timer     The timer handle. | ||||
|  */ | ||||
| public Action:RoundEndTimer(Handle:timer) | ||||
| { | ||||
|     // Terminate the round with a normal delay, and CTs as the winner. | ||||
|     TerminateRound(ROUNDEND_DELAY_NORMAL, ROUNDEND_CTS_WIN); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Checks if the round is over. | ||||
|  *  | ||||
|  * @param outcome   Set to the outcome of the round, if round is over. | ||||
|  * @return          True if the round is over, false otherwise. | ||||
|  */ | ||||
| bool:RoundEndGetRoundStatus(&RoundEndOutcome:outcome) | ||||
| { | ||||
|     // If zombie hasn't spawned, then stop. | ||||
|     if (!g_bZombieSpawned) | ||||
|     { | ||||
|         // Round isn't over. | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     // Initialize count variables | ||||
|     new zombiecount; | ||||
|     new humancount; | ||||
|      | ||||
|     // Count valid clients. (true to only allow living clients) | ||||
|     ZRCountValidClients(zombiecount, humancount); | ||||
|      | ||||
|     // If there are no clients on either teams, then stop. | ||||
|     if (!zombiecount && !humancount) | ||||
|     { | ||||
|         // Round isn't active. | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     // If there are clients on both teams, then stop. | ||||
|     if (zombiecount && humancount) | ||||
|     { | ||||
|         // Round isn't over. | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     // We know here, that either zombiecount or humancount is 0. (not both) | ||||
|      | ||||
|     // If there are zombies, then zombies won the round. | ||||
|     if (zombiecount) | ||||
|     { | ||||
|         outcome = ZombiesWin; | ||||
|     } | ||||
|     // If there are no zombies, that means there must be humans, they win the round. | ||||
|     else | ||||
|     { | ||||
|         outcome = HumansWin; | ||||
|     } | ||||
|      | ||||
|     // Round is over. | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Ends the round with the given outcome. | ||||
|  *  | ||||
|  * @param outcome   The outcome of the round. | ||||
|  */ | ||||
| RoundEndTerminateRound(RoundEndOutcome:outcome) | ||||
| { | ||||
|     switch(outcome) | ||||
|     { | ||||
|         // Zombies won. | ||||
|         case ZombiesWin: | ||||
|         { | ||||
|             // Terminate the round with a normal delay, and Ts as the winner. | ||||
|             TerminateRound(ROUNDEND_DELAY_NORMAL, ROUNDEND_TERRORISTS_WIN); | ||||
|         } | ||||
|         // Humans won. | ||||
|         case HumansWin: | ||||
|         { | ||||
|             // Terminate the round with a normal delay, and CTs as the winner. | ||||
|             TerminateRound(ROUNDEND_DELAY_NORMAL, ROUNDEND_CTS_WIN); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Displays overlay to client, or prints unsupported message on client's screen. | ||||
|  *  | ||||
|  * @param client    The client index. | ||||
|  * @param overlay   The overlay path. | ||||
|  */     | ||||
| RoundEndDisplayClientOverlay(client, const String:overlay[]) | ||||
| { | ||||
|     // If dxLevel is 0, then query on client failed, so try again, then stop. | ||||
|     if (!dxLevel[client]) | ||||
|     { | ||||
|         // Query dxlevel cvar. | ||||
|         RoundEndGetClientDXLevel(client); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // If dxLevel is above or equal to minimum requirement, then display overlay. | ||||
|     if (dxLevel[client] >= ROUNDEND_MIN_DXLEVEL) | ||||
|     { | ||||
|         ClientCommand(client, "r_screenoverlay \"%s\"", overlay); | ||||
|     } | ||||
|     // If client doesn't meet minimum requirement, then print unsupported text. | ||||
|     else | ||||
|     { | ||||
|         ZR_PrintCenterText(client, "DX90 not supported", dxLevel[client], ROUNDEND_MIN_DXLEVEL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Displays overlays to clients, depending on the outcome. | ||||
|  *  | ||||
|  * @param time      Time to display overlays. | ||||
|  * @param outcome   The outcome of the round. | ||||
|  */ | ||||
| RoundEndOverlayStart(Float:time, RoundEndOutcome:outcome) | ||||
| { | ||||
|     // If round end overlays are disabled, then stop. | ||||
|     new bool:overlay = GetConVarBool(gCvars[CVAR_ROUNDEND_OVERLAY]); | ||||
|     if (!overlay) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     decl String:overlaypath[PLATFORM_MAX_PATH]; | ||||
|      | ||||
|     switch(outcome) | ||||
|     { | ||||
|         // Show "zombies win" overlay. | ||||
|         case ZombiesWin: | ||||
|         { | ||||
|             GetConVarString(gCvars[CVAR_ROUNDEND_OVERLAY_ZOMBIE], overlaypath, sizeof(overlaypath)); | ||||
|         } | ||||
|         // Show "humans win" overlay. | ||||
|         case HumansWin: | ||||
|         { | ||||
|             GetConVarString(gCvars[CVAR_ROUNDEND_OVERLAY_HUMAN], overlaypath, sizeof(overlaypath)); | ||||
|         } | ||||
|         // Show no overlay. | ||||
|         default: | ||||
|         { | ||||
|             strcopy(overlaypath, sizeof(overlaypath), ""); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // x = client index. | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         // If client isn't in-game, then stop. | ||||
|         if (!IsClientInGame(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         RoundEndDisplayClientOverlay(x, overlaypath); | ||||
|     } | ||||
|      | ||||
|     CreateTimer(time, RoundEndOverlayTimer, _, TIMER_FLAG_NO_MAPCHANGE); | ||||
| } | ||||
|  | ||||
| RoundEndOverlayStop() | ||||
| { | ||||
|     // x = client index. | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         // If client isn't in-game, then stop. | ||||
|         if (!IsClientInGame(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // Removes overlay from client's screen. | ||||
|         ClientCommand(x, "r_screenoverlay \"\""); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Timer callback, stops overlays on all clients. | ||||
|  *  | ||||
|  * @param timer     The timer handle. | ||||
|  */ | ||||
| public Action:RoundEndOverlayTimer(Handle:timer) | ||||
| { | ||||
|     // Stop all overlays. | ||||
|     RoundEndOverlayStop(); | ||||
| } | ||||
| @@ -90,10 +90,60 @@ ChangeLightStyle() | ||||
|     } | ||||
| } | ||||
|  | ||||
| public RestartGameHook(Handle:convar, const String:oldValue[], const String:newValue[]) | ||||
| /** | ||||
|  * Create an array populated with eligible clients to be zombie. | ||||
|  *  | ||||
|  * @param arrayEligibleClients  The handle of the array, don't forget to call CloseHandle | ||||
|  *                              on it when finished! | ||||
|  * @param immunity              True to ignore clients immune from mother infect, false to count them. | ||||
|  */   | ||||
| CreateEligibleClientList(&Handle:arrayEligibleClients, bool:team = false, bool:alive = false, bool:human = false, bool:immunity = false) | ||||
| { | ||||
|     SetConVarInt(FindConVar("mp_restartgame"), 0); | ||||
|     TerminateRound(StringToFloat(newValue), Round_Draw); | ||||
|     // Create array. | ||||
|     arrayEligibleClients = CreateArray(); | ||||
|      | ||||
|     // Populate list with eligible clients. | ||||
|     // x = client index. | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         // If client isn't in-game, then stop. | ||||
|         if (!IsClientInGame(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If client isn't on a team, then stop. | ||||
|         if (team && !ZRIsClientOnTeam(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If client is dead, then stop. | ||||
|         if (alive && !IsPlayerAlive(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If client is already zombie (via admin), then stop. | ||||
|         if (human && !IsPlayerHuman(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If client is immune from being a mother zombie, then stop. | ||||
|         if (immunity && bMotherInfectImmune[x]) | ||||
|         { | ||||
|             // Take away immunity. | ||||
|             bMotherInfectImmune[x] = false; | ||||
|              | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // Add eligible client to array. | ||||
|         PushArrayCell(arrayEligibleClients, x); | ||||
|     } | ||||
|      | ||||
|     return GetArraySize(arrayEligibleClients); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -106,40 +156,11 @@ public Action:MotherZombie(Handle:timer) | ||||
|     // Reset timer handle. | ||||
|     tInfect = INVALID_HANDLE; | ||||
|      | ||||
|     // Create array. | ||||
|     new Handle:arrayEligibleClients = CreateArray(); | ||||
|      | ||||
|     // Populate list with eligible clients. | ||||
|     // x = client index. | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         // If client isn't in-game, then stop. | ||||
|         if (!IsClientInGame(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If client is dead, then stop. | ||||
|         if (!IsPlayerAlive(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If client is immune from being a mother zombie, then stop. | ||||
|         if (bMotherInfectImmune[x]) | ||||
|         { | ||||
|             // Take away immunity. | ||||
|             bMotherInfectImmune[x] = false; | ||||
|              | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // Add eligible client to array. | ||||
|         PushArrayCell(arrayEligibleClients, x); | ||||
|     } | ||||
|     // Create eligible player list. | ||||
|     new Handle:arrayEligibleClients = INVALID_HANDLE; | ||||
|     new eligibleclients = CreateEligibleClientList(arrayEligibleClients, true, true, true, true); | ||||
|      | ||||
|     // If there are no eligible client's then stop. | ||||
|     new eligibleclients = GetArraySize(arrayEligibleClients); | ||||
|     if (!eligibleclients) | ||||
|     { | ||||
|         return; | ||||
| @@ -217,6 +238,9 @@ public Action:MotherZombie(Handle:timer) | ||||
|      | ||||
|     // Mother zombies have been infected. | ||||
|     g_bZombieSpawned = true; | ||||
|      | ||||
|     // Destroy handle. | ||||
|     CloseHandle(arrayEligibleClients); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -230,7 +254,7 @@ public Action:MotherZombie(Handle:timer) | ||||
| InfectPlayer(client, attacker = -1, bool:motherinfect = false) | ||||
| { | ||||
|     // Check if the attacker was specified. | ||||
|     if (attacker > 0) | ||||
|     if (ZRIsValidClient(attacker)) | ||||
|     { | ||||
|         // Fire death event and set weapon info. | ||||
|         new Handle:event = CreateEvent("player_death"); | ||||
| @@ -253,14 +277,21 @@ InfectPlayer(client, attacker = -1, bool:motherinfect = false) | ||||
|     ztele_count[client] = 0;    // In use? | ||||
|      | ||||
|     // Terminate the round if the last player was infected. | ||||
|     new ZTeam:team = IsRoundOver(); | ||||
|     RoundWin(team); | ||||
|     new RoundEndOutcome:outcome; | ||||
|     if (RoundEndGetRoundStatus(outcome)) | ||||
|     { | ||||
|         RoundEndTerminateRound(outcome); | ||||
|     } | ||||
|      | ||||
|     // Switch the player to terrorists. | ||||
|     CS_SwitchTeam(client, CS_TEAM_T); | ||||
|      | ||||
|     // Flag player to be immune from being mother zombie twice. | ||||
|     bMotherInfectImmune[client] = motherinfect; | ||||
|      | ||||
|     // Check if consecutive infection protection is enabled. | ||||
|     new bool:consecutive_infect = GetConVarBool(gCvars[CVAR_CONSECUTIVE_INFECT]); | ||||
|      | ||||
|     // Flag player to be immune from being mother zombie twice, if consecutive infect protection is enabled. | ||||
|     bMotherInfectImmune[client] = consecutive_infect ? motherinfect : false; | ||||
|      | ||||
|     // Forward event to modules. | ||||
|     ClassOnClientInfected(client, motherinfect); | ||||
| @@ -360,159 +391,131 @@ JumpBoost(client, Float:distance, Float:height) | ||||
|     SetPlayerVelocity(client, vel, false); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Finds a new zombie if the last one disconnects. | ||||
|  *  | ||||
|  * @param client    The client index.   | ||||
|  */  | ||||
| PlayerLeft(client) | ||||
| { | ||||
|     if (!IsClientConnected(client) || !IsClientInGame(client)) | ||||
|     // If client is dead, then stop. | ||||
|     if (!IsPlayerAlive(client)) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     new ZTeam:team = IsRoundOver(); | ||||
|     if (team == Zombie) | ||||
|     { | ||||
|         RoundWin(team); | ||||
|         return; | ||||
|     } | ||||
|          | ||||
|     if (!IsPlayerAlive(client) || !IsPlayerZombie(client)) | ||||
|     // If client isn't a zombie, then stop. | ||||
|     if (!IsPlayerZombie(client)) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     new zombiecount = GetZTeamCount(Zombie); | ||||
|     if (zombiecount > 1) | ||||
|     // Initialize count variables | ||||
|     new zombiecount; | ||||
|     new humancount; | ||||
|      | ||||
|     // Count valid clients. (true to only allow living clients) | ||||
|     ZRCountValidClients(zombiecount, humancount); | ||||
|      | ||||
|     // If there are other zombies besides the disconnecting player, then stop. | ||||
|     if (zombiecount - 1) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     new count = GetTeamClientCount(CS_TEAM_CT); | ||||
|     if (count <= 1) | ||||
|     // If there is 1 or no humans left, then stop. | ||||
|     if (humancount <= 1) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     new Handle:aClients = CreateArray(); | ||||
|     // Create eligible player list. | ||||
|     new Handle:arrayEligibleClients = INVALID_HANDLE; | ||||
|      | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         if (!IsClientInGame(x) || !IsPlayerAlive(x) || client == x || GetClientTeam(x) != CS_TEAM_CT || bMotherInfectImmune[x]) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|     // Create eligible client list, with no mother infect immunities | ||||
|     new eligibleclients = CreateEligibleClientList(arrayEligibleClients, true, true, true); | ||||
|      | ||||
|         PushArrayCell(aClients, x); | ||||
|     } | ||||
|      | ||||
|     new size = GetArraySize(aClients); | ||||
|     if (!size) | ||||
|     // If there are no eligible client's then stop. | ||||
|     if (!eligibleclients) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     new randclient = GetArrayCell(aClients, GetRandomInt(0, size-1)); | ||||
|     InfectPlayer(randclient, _, true); | ||||
|     // Get a random valid array index. | ||||
|     new randindex = GetRandomInt(0, eligibleclients - 1); | ||||
|      | ||||
|     // Get the client stored in the random array index. | ||||
|     new randclient = GetArrayCell(arrayEligibleClients, randindex); | ||||
|      | ||||
|     // Infect player. | ||||
|     InfectPlayer(randclient); | ||||
|      | ||||
|     // Tell client they have been randomly been chosen to replace disconnecting zombie. | ||||
|     ZR_PrintToChat(randclient, "Zombie replacement"); | ||||
|      | ||||
|     CloseHandle(aClients); | ||||
|     // Destroy handle. | ||||
|     CloseHandle(arrayEligibleClients); | ||||
| } | ||||
|  | ||||
| GetZTeamCount(ZTeam:team) | ||||
| /** | ||||
|  * Balances teams | ||||
|  *  | ||||
|  * @param spawn     If true, it will respawn player after switching their team. | ||||
|  */ | ||||
| BalanceTeams(bool:spawn = false) | ||||
| { | ||||
|     new count = 0; | ||||
|     // Create eligible player list. | ||||
|     new Handle:arrayEligibleClients = INVALID_HANDLE; | ||||
|     new eligibleclients = CreateEligibleClientList(arrayEligibleClients, true); | ||||
|      | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     // If there are no eligible client's then stop. | ||||
|     if (!eligibleclients) | ||||
|     { | ||||
|         if (!IsClientInGame(x) || !IsPlayerAlive(x)) | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     new client; | ||||
|      | ||||
|     // Move all clients to T | ||||
|      | ||||
|     // x = array index. | ||||
|     // client = client index. | ||||
|     for (new x = 0; x < eligibleclients; x++) | ||||
|     { | ||||
|         // Get client stored in array index. | ||||
|         client = GetArrayCell(arrayEligibleClients, x); | ||||
|          | ||||
|         // Switch client to T | ||||
|         CS_SwitchTeam(client, CS_TEAM_T); | ||||
|          | ||||
|         // If spawn is false, then stop. | ||||
|         if (!spawn) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         new ZTeam:pTeam = GetPlayerZTeam(x); | ||||
|         if (pTeam == team) | ||||
|         { | ||||
|             count++; | ||||
|         } | ||||
|         CS_RespawnPlayer(client); | ||||
|     } | ||||
|      | ||||
|     return count; | ||||
| } | ||||
|     // Move every other client back to CT | ||||
|      | ||||
| ZTeam:IsRoundOver() | ||||
| { | ||||
|     new bool:zombies = false; | ||||
|     new bool:humans = false; | ||||
|      | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     // x = array index | ||||
|     // client = client index. | ||||
|     for (new x = 0; x < eligibleclients; x += 2) | ||||
|     { | ||||
|         if (!IsClientInGame(x) || !IsPlayerAlive(x)) | ||||
|         // Get client stored in array index. | ||||
|         client = GetArrayCell(arrayEligibleClients, x); | ||||
|          | ||||
|         // Switch client to CT | ||||
|         CS_SwitchTeam(client, CS_TEAM_CT); | ||||
|          | ||||
|         // If spawn is false, then stop. | ||||
|         if (!spawn) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         if (IsPlayerZombie(x)) | ||||
|         { | ||||
|             zombies = true; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             humans = true; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     if (zombies && !humans) | ||||
|     { | ||||
|         return Zombie; | ||||
|     } | ||||
|      | ||||
|     if (humans && !zombies) | ||||
|     { | ||||
|         if (g_bZombieSpawned) | ||||
|         { | ||||
|             return Human; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return Neither; | ||||
| } | ||||
|  | ||||
| RoundWin(ZTeam:team) | ||||
| { | ||||
|     if (team == Human) | ||||
|     { | ||||
|         TerminateRound(5.0, CTs_PreventEscape); | ||||
|     } | ||||
|     else if (team == Zombie) | ||||
|     { | ||||
|         TerminateRound(5.0, Terrorists_Escaped); | ||||
|     } | ||||
| } | ||||
|  | ||||
| BalanceTeams() | ||||
| { | ||||
|     new count = 0; | ||||
|     new cPlayers[MAXPLAYERS]; | ||||
|      | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         if (!IsClientInGame(x) || GetClientTeam(x) <= 1) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         CS_SwitchTeam(x, CS_TEAM_T); | ||||
|         cPlayers[count++] = x; | ||||
|     } | ||||
|      | ||||
|     for (new x = 0; x < count; x++) | ||||
|     { | ||||
|         if (!IsClientInGame(cPlayers[x]) || GetClientTeam(cPlayers[x]) <= 1) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         CS_SwitchTeam(cPlayers[x], CS_TEAM_CT); | ||||
|         x++; | ||||
|         CS_RespawnPlayer(client); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -539,13 +542,6 @@ RemoveObjectives() | ||||
|     } | ||||
| } | ||||
|  | ||||
| public Action:RoundOver(Handle:timer) | ||||
| { | ||||
|     tRound = INVALID_HANDLE; | ||||
|      | ||||
|     RoundWin(Human); | ||||
| } | ||||
|  | ||||
| bool:IsPlayerZombie(client) | ||||
| { | ||||
|     return bZombie[client]; | ||||
| @@ -555,13 +551,3 @@ bool:IsPlayerHuman(client) | ||||
| { | ||||
|     return !bZombie[client]; | ||||
| } | ||||
|  | ||||
| ZTeam:GetPlayerZTeam(client) | ||||
| { | ||||
|     if (IsPlayerZombie(client)) | ||||
|     { | ||||
|         return Zombie; | ||||
|     } | ||||
|      | ||||
|     return Human; | ||||
| } | ||||
|   | ||||
| @@ -6,24 +6,6 @@ | ||||
|  * ====================  | ||||
|  */ | ||||
|   | ||||
| #define Target_Bombed							1		// Target Successfully Bombed! | ||||
| #define VIP_Escaped								2		// The VIP has escaped! | ||||
| #define VIP_Assassinated						3		// VIP has been assassinated! | ||||
| #define Terrorists_Escaped						4		// The terrorists have escaped! | ||||
| #define CTs_PreventEscape						5		// The CT's have prevented most of the terrorists from escaping! | ||||
| #define Escaping_Terrorists_Neutralized			6		// Escaping terrorists have all been neutralized! | ||||
| #define Bomb_Defused							7		// The bomb has been defused! | ||||
| #define CTs_Win									8		// Counter-Terrorists Win! | ||||
| #define Terrorists_Win							9		// Terrorists Win! | ||||
| #define Round_Draw								10		// Round Draw! | ||||
| #define All_Hostages_Rescued					11		// All Hostages have been rescued! | ||||
| #define Target_Saved							12		// Target has been saved! | ||||
| #define Hostages_Not_Rescued					13		// Hostages have not been rescued! | ||||
| #define Terrorists_Not_Escaped					14		// Terrorists have not escaped! | ||||
| #define VIP_Not_Escaped							15		// VIP has not escaped! | ||||
| #define Game_Commencing							16		// Game Commencing! | ||||
|  | ||||
| #define DXLEVEL_MIN 90 | ||||
| #define DEFAULT_FOV 90 | ||||
|  | ||||
| /** | ||||
| @@ -56,16 +38,6 @@ | ||||
|  * @endsection | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Lists possible returns of the game at any time. | ||||
|  */  | ||||
| enum ZTeam | ||||
| { | ||||
|     Neither, /** Round is not over */ | ||||
|     Zombie, /** Round is over because zombies win */ | ||||
|     Human, /** Round is over because humans wins */ | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Global variable set to true if market plugin is installed | ||||
|  */  | ||||
| @@ -91,11 +63,6 @@ new bool:bZombie[MAXPLAYERS + 1]; | ||||
|  */ | ||||
| new bool:bMotherInfectImmune[MAXPLAYERS + 1]; | ||||
|  | ||||
| /** | ||||
|  * Global variable to store round win timer handle. | ||||
|  */ | ||||
| new Handle:tRound = INVALID_HANDLE; | ||||
|  | ||||
| /** | ||||
|  * Global variable to store the infect timer handle. | ||||
|  */ | ||||
| @@ -161,86 +128,6 @@ ZRBoolToConfigSetting(bool:bOption, String:option[], maxlen) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Global variable to store a convar query cookie | ||||
|  */  | ||||
| new QueryCookie:mat_dxlevel; | ||||
|  | ||||
| /** | ||||
|  * Finds DX level of a client. | ||||
|  *  | ||||
|  * @param client    The client index.   | ||||
|  */ | ||||
| ZRFindClientDXLevel(client) | ||||
| { | ||||
|     // If client is fake (or bot), then stop. | ||||
|     if (IsFakeClient(client)) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Query mat_dxlevel on client. | ||||
|     mat_dxlevel = QueryClientConVar(client, "mat_dxlevel", ZRDXLevelClientQuery); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Query callback function. | ||||
|  * | ||||
|  * @param cookie    Unique cookie of the query. | ||||
|  * @param client    The client index. | ||||
|  * @param result    The result of the query (see console.inc enum ConVarQueryResult) | ||||
|  * @param cvarName  Name of the cvar. | ||||
|  * @param cvarValue Value of the cvar. | ||||
|  */        | ||||
| public ZRDXLevelClientQuery(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[]) | ||||
| { | ||||
|     // If query cookie does not match cookie given by mat_dxlevel query, then stop, this isn't our query. | ||||
|     if (cookie != mat_dxlevel) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Reset dxLevel. | ||||
|     dxLevel[client] = 0; | ||||
|      | ||||
|     // If result is any other than ConVarQuery_Okay, then stop. | ||||
|     if (result != ConVarQuery_Okay) | ||||
|     {    | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Copy cvar value to dxLevel array. | ||||
|     dxLevel[client] = StringToInt(cvarValue); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Displays overlay to client, or prints unsupported message on client's screen. | ||||
|  *  | ||||
|  * @param client    The client index. | ||||
|  * @param overlay   The overlay path. | ||||
|  */     | ||||
| ZRDisplayClientOverlay(client, const String:overlay[]) | ||||
| { | ||||
|     // If dxLevel is 0, then query on client failed, so try again, then stop. | ||||
|     if (!dxLevel[client]) | ||||
|     { | ||||
|         // Query dxlevel cvar. | ||||
|         ZRFindClientDXLevel(client); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // If dxLevel is above or equal to minimum requirement, then display overlay. | ||||
|     if (dxLevel[client] >= DXLEVEL_MIN) | ||||
|     { | ||||
|         ClientCommand(client, "r_screenoverlay \"%s\"", overlay); | ||||
|     } | ||||
|     // If client doesn't meet minimum requirement, then print unsupported text. | ||||
|     else | ||||
|     { | ||||
|         ZR_PrintCenterText(client, "DX90 not supported", dxLevel[client], DXLEVEL_MIN); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Check if a client index is a valid player. | ||||
|  *  | ||||
| @@ -260,6 +147,58 @@ bool:ZRIsValidClient(client, bool:console = false) | ||||
|     return console ? (client >= 0) : (client > 0); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Count clients on each team. | ||||
|  *  | ||||
|  * @param zombies   This is set to the number of clients that are zombies. | ||||
|  * @param humans    This is set to the number of clients that are humans. | ||||
|  * @param alive     If true it will only count live players, false will count alive and dead. | ||||
|  * @return          True if successful (zombie has spawned), false otherwise. | ||||
|  */ | ||||
| bool:ZRCountValidClients(&zombiecount = 0, &humancount = 0, bool:alive = true) | ||||
| { | ||||
|     // If zombie hasn't spawned, then stop. | ||||
|     if (!g_bZombieSpawned) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     // x = client index. | ||||
|     for (new x = 1; x <= MaxClients; x++) | ||||
|     { | ||||
|         // If client isn't in-game, then stop. | ||||
|         if (!IsClientInGame(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If client isn't on a team, then stop. | ||||
|         if (!ZRIsClientOnTeam(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If player must be alive, and player is dead, then stop. | ||||
|         if (alive && !IsPlayerAlive(x)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // If player is a zombie, then increment zombie variable. | ||||
|         if (IsPlayerZombie(x)) | ||||
|         { | ||||
|             zombiecount++; | ||||
|         } | ||||
|         // If player is a human, then increment human variable. | ||||
|         else if (IsPlayerHuman(x)) | ||||
|         { | ||||
|             humancount++; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Check if a client index is on a team. | ||||
|  *  | ||||
| @@ -291,7 +230,7 @@ bool:ZRIsClientOnTeam(client, team = -1) | ||||
|  *  | ||||
|  * @param team      (Optional) Team to check if there are clients on. | ||||
|  */ | ||||
| ZRTeamHasClients(team = -1) | ||||
| bool:ZRTeamHasClients(team = -1, bool:alive = false) | ||||
| { | ||||
|     // If team is | ||||
|     if (team == -1) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user