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:
Greyscale 2009-04-18 01:44:41 +02:00
parent 879446ac7c
commit c34e32097d
9 changed files with 708 additions and 410 deletions

View File

@ -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()
}
}
}
}
}*/

View File

@ -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[])
{

View File

@ -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)

View File

@ -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 \"\"");
}
}
}

View File

@ -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;
}

View File

@ -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
View 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();
}

View File

@ -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()
// x = array index
// client = client index.
for (new x = 0; x < eligibleclients; x += 2)
{
new bool:zombies = false;
new bool:humans = false;
// Get client stored in array index.
client = GetArrayCell(arrayEligibleClients, x);
for (new x = 1; x <= MaxClients; x++)
{
if (!IsClientInGame(x) || !IsPlayerAlive(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;
}

View File

@ -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)