diff --git a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt index 263285e..1dac21e 100644 --- a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt +++ b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt @@ -234,12 +234,58 @@ "en" "You have been infected! Go pass it on to as many other players as you can." } + "Infect human" + { + "en" "The merciful gods (known as admins) have resurrected your soul, find some cover!" + } + "Infect disconnect" { "en" "The last zombie has left the game, and has passed the infection on to you." "ru" "Последний зомби покинул игру и передал свою инфекцию вам." } + // Commands + + "Infect command infect syntax" + { + "en" "Infect a client. Usage: zr_infect [respawn - 1/0]" + } + + "Infect command human syntax" + { + "en" "Turn a client into a human. Usage: zr_human [respawn - 1/0] [protect - 1/0]" + } + + "Infect command infect successful" + { + "#format" "{1:s}" + "en" "Player @green{1} @defaulthas been successfully infected." + } + + "Infect command infect unsuccessful" + { + "#format" "{1:s}" + "en" "Player @green{1} @defaultis already a zombie." + } + + "Infect command human successful" + { + "#format" "{1:s}" + "en" "Player @green{1} @defaulthas been successfully brought back as a human." + } + + "Infect command human unsuccessful" + { + "#format" "{1:s}" + "en" "Player @green{1} @defaultis already a human." + } + + "Infect command zombie has not spawned" + { + "en" "The mother zombie must spawn before player infection states can be changed." + } + // =========================== // Damage (core) // =========================== diff --git a/src/zr/commands.inc b/src/zr/commands.inc index 617adac..f4465d2 100644 --- a/src/zr/commands.inc +++ b/src/zr/commands.inc @@ -35,6 +35,7 @@ CommandsInit() LogOnCommandsCreate(); ClassOnCommandsCreate(); WeaponsOnCommandsCreate(); + InfectOnCommandsCreate(); VolOnCommandsCreate(); // Forward event to modules. (hook commands) @@ -97,7 +98,7 @@ CommandsInit() for (new x = 0; x < tcount; x++) { - InfectClient(targets[x]); + InfectHumanToZombie(targets[x]); if (LogCheckFlag(LOG_GAME_EVENTS, LOG_MODULE_COMMANDS)) { GetClientName(targets[x], target_name, sizeof(target_name)); diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index ee26f70..2fe20aa 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -143,6 +143,7 @@ enum CvarsList Handle:CVAR_ZSPAWN_TEAM_ZOMBIE, Handle:CVAR_ZSPAWN_TIMELIMIT, Handle:CVAR_ZSPAWN_TIMELIMIT_TIME, + Handle:CVAR_ZSPAWN_TIMELIMIT_ZOMBIE, Handle:CVAR_ZTELE_ZOMBIE, Handle:CVAR_ZTELE_HUMAN_BEFORE, Handle:CVAR_ZTELE_HUMAN_AFTER, @@ -430,13 +431,14 @@ CvarsCreate() // =========================== // ZSpawn (module) // =========================== - g_hCvarsList[CVAR_ZSPAWN] = CreateConVar("zr_zspawn", "1", "Allow players to spawn into the game late."); + g_hCvarsList[CVAR_ZSPAWN] = CreateConVar("zr_zspawn", "1", "Allow players to spawn into the game late."); - g_hCvarsList[CVAR_ZSPAWN_TEAM_OVERRIDE] = CreateConVar("zr_zspawn_team_override", "1", "Override spawn team when spawning by means of ZSpawn."); - g_hCvarsList[CVAR_ZSPAWN_TEAM_ZOMBIE] = CreateConVar("zr_zspawn_team_zombie", "0", "Spawn player on zombie team when spawning by means of ZSpawn. [Dependency: zr_zspawn_team_override | Override: zr_respawn_zombie]"); + g_hCvarsList[CVAR_ZSPAWN_TEAM_OVERRIDE] = CreateConVar("zr_zspawn_team_override", "1", "Override spawn team when spawning by means of ZSpawn."); + g_hCvarsList[CVAR_ZSPAWN_TEAM_ZOMBIE] = CreateConVar("zr_zspawn_team_zombie", "0", "Spawn player on zombie team when spawning by means of ZSpawn. [Dependency: zr_zspawn_team_override | Override: zr_respawn_zombie]"); - g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT] = CreateConVar("zr_zspawn_timelimit", "1", "Put a time limit on the use of ZSpawn."); - g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_TIME] = CreateConVar("zr_zspawn_timelimit_time", "120.0", "Time from the start of the round to allow ZSpawn. [Dependency: zr_zspawn_timelimit]"); + g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT] = CreateConVar("zr_zspawn_timelimit", "1", "Put a time limit on the use of ZSpawn."); + g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_TIME] = CreateConVar("zr_zspawn_timelimit_time", "120.0", "Time from the start of the round to allow ZSpawn. [Dependency: zr_zspawn_timelimit]"); + g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_ZOMBIE] = CreateConVar("zr_zspawn_timelimit_zombie", "1", "Spawn player on the zombie team AFTER the timelimit is up. ['-1' = Block ZSpawn | '0' = Spawn as human | '1' = Spawn as zombie | Dependency: zr_zspawn_timelimit]"); // =========================== diff --git a/src/zr/infect.inc b/src/zr/infect.inc index cbdb4a4..f201110 100644 --- a/src/zr/infect.inc +++ b/src/zr/infect.inc @@ -100,6 +100,15 @@ InfectLoad() AddFileToDownloadsTable(sound); } +/** + * Create commands specific to infect here. + */ +InfectOnCommandsCreate() +{ + RegAdminCmd("zr_infect", InfectInfectCommand, ADMFLAG_GENERIC, "Infect a client. Usage: zr_infect [respawn - 1/0]"); + RegAdminCmd("zr_human", InfectHumanCommand, ADMFLAG_GENERIC, "Turn a client into a human. Usage: zr_human [respawn - 1/0]"); +} + /** * Client is joining the server. * @@ -192,7 +201,7 @@ InfectOnClientDisconnect(client) new randclient = GetArrayCell(arrayEligibleClients, randindex); // Infect player. - InfectClient(randclient); + InfectHumanToZombie(randclient); // Tell client they have been randomly been chosen to replace disconnecting zombie. TranslationPrintToChat(randclient, "Infect disconnect"); @@ -311,7 +320,7 @@ InfectOnClientHurt(client, attacker, const String:weapon[]) } // Infect client. - InfectClient(client, attacker); + InfectHumanToZombie(client, attacker); } /** @@ -470,7 +479,7 @@ public Action:InfectMotherZombie(Handle:timer) client = GetArrayCell(arrayEligibleClients, randindex); // Infect player. - InfectClient(client, _, true); + InfectHumanToZombie(client, _, true); } else { @@ -509,7 +518,7 @@ public Action:InfectMotherZombie(Handle:timer) client = GetArrayCell(arrayEligibleClients, randindex); // Infect player. - InfectClient(client, _, true); + InfectHumanToZombie(client, _, true); // Remove player from eligible zombie list. RemoveFromArray(arrayEligibleClients, randindex); @@ -524,14 +533,16 @@ public Action:InfectMotherZombie(Handle:timer) } /** - * Infects a player. Execute events, sets attributes and flags that indicate - * that the player is a zombie. + * Infects a client. Execute events, sets attributes and flags that indicate + * that the client is a zombie. * - * @param client The player to infect. - * @param attacker (Optional) The attacker who did the infect. - * @param motherinfect (Optional) Indicates a mother zombie infect. + * @param client The client to infect. + * @param attacker (Optional) The attacker who did the infect. + * @param motherinfect (Optional) Indicates a mother zombie infect. + * @param respawnoverride (Optional) Set to true to override respawn cvar. + * @param respawn (Optional) Value to override with. */ -InfectClient(client, attacker = -1, bool:motherinfect = false) +InfectHumanToZombie(client, attacker = -1, bool:motherinfect = false, bool:respawnoverride = false, bool:respawn = false) { // Mark player as zombie. bZombie[client] = true; @@ -631,8 +642,16 @@ InfectClient(client, attacker = -1, bool:motherinfect = false) ZTeleTeleportClient(client); } } + // Check override. + else + { + if (respawnoverride && respawn) + { + ZTeleTeleportClient(client); + } + } - // Format infection message. + // Set client as translation target. SetGlobalTransTarget(client); // Print message to client. @@ -646,6 +665,46 @@ InfectClient(client, attacker = -1, bool:motherinfect = false) ZHPOnClientInfected(client); } +/** + * Turns a zombie back into a human. Execute events, sets attributes and flags that indicate + * that the client is a human. + * + * @param client The client to make human. + * @param respawn Teleport client back to spawn if true. + * @param protect Start spawn protection on new human. + */ +InfectZombieToHuman(client, bool:respawn = false, bool:protect = false) +{ + // Mark player as human. + bZombie[client] = false; + + // Switch the player to counter-terrorists. + CS_SwitchTeam(client, CS_TEAM_CT); + + // Set client as translation target. + SetGlobalTransTarget(client); + + // Print message to client. + TranslationPrintToChat(client, "Infect human"); + + // Forward event to modules. + ClassOnClientInfected(client, false); + RoundEndOnClientInfected(); + ZTeleOnClientInfected(client); + + // Check if we should respawn the client. + if (respawn) + { + ZTeleTeleportClient(client); + } + + // Check if we should spawn protect the client. + if (protect) + { + SpawnProtectStart(client); + } +} + /** * Creates effects on a newly infected client. * @@ -754,3 +813,139 @@ bool:InfectIsClientHuman(client) // Return opposite of client's zombie flag. return !bZombie[client]; } + +/** + * Command callback (zr_infect) + * Infects a client. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:InfectInfectCommand(client, argc) +{ + // If not enough arguments given, then stop. + if (argc < 1) + { + TranslationReplyToCommand(client, "Infect command infect syntax"); + return Plugin_Handled; + } + + if (!g_bZombieSpawned) + { + TranslationReplyToCommand(client, "Infect command zombie has not spawned"); + return Plugin_Handled; + } + + decl String:target[MAX_NAME_LENGTH], String:targetname[MAX_NAME_LENGTH]; + new targets[MAXPLAYERS], bool:tn_is_ml, result; + + // Get targetname. + GetCmdArg(1, target, sizeof(target)); + + // Find a target. + result = ProcessTargetString(target, client, targets, sizeof(targets), COMMAND_FILTER_ALIVE | COMMAND_FILTER_NO_MULTI, targetname, sizeof(targetname), tn_is_ml); + + // Check if there was a problem finding a client. + if (result <= 0) + { + ZRReplyToTargetError(client, result); + return Plugin_Handled; + } + + // Check if client is a human before turning into zombie. + if (InfectIsClientHuman(targets[0])) + { + new bool:respawnoverride, bool:respawn; + decl String:strRespawn[8]; + + // Get respawn parameter. + GetCmdArg(2, strRespawn, sizeof(strRespawn)); + + // If parameter exists then cast it into a bool and feed it to infect function. + if (strRespawn[0]) + { + respawnoverride = true; + respawn = bool:StringToInt(strRespawn); + } + + // Turn client into a zombie. + InfectHumanToZombie(targets[0], _, _, respawnoverride, respawn); + + // Tell admin command was successful. + TranslationReplyToCommand(client, "Infect command infect successful", targetname); + } + else + { + // Tell admin command was unsuccessful. + TranslationReplyToCommand(client, "Infect command infect unsuccessful", targetname); + } + + return Plugin_Handled; +} + +/** + * Command callback (zr_human) + * Turns a client into a human. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:InfectHumanCommand(client, argc) +{ + // If not enough arguments given, then stop. + if (argc < 1) + { + TranslationReplyToCommand(client, "Infect command human syntax"); + return Plugin_Handled; + } + + if (!g_bZombieSpawned) + { + TranslationReplyToCommand(client, "Infect command zombie has not spawned"); + return Plugin_Handled; + } + + decl String:target[MAX_NAME_LENGTH], String:targetname[MAX_NAME_LENGTH]; + new targets[MAXPLAYERS], bool:tn_is_ml, result; + + // Get targetname. + GetCmdArg(1, target, sizeof(target)); + + // Find a target. + result = ProcessTargetString(target, client, targets, sizeof(targets), COMMAND_FILTER_ALIVE | COMMAND_FILTER_NO_MULTI, targetname, sizeof(targetname), tn_is_ml); + + // Check if there was a problem finding a client. + if (result <= 0) + { + ZRReplyToTargetError(client, result); + return Plugin_Handled; + } + + // Check if client is a human before turning into zombie. + if (InfectIsClientInfected(targets[0])) + { + new bool:respawn, bool:protect; + decl String:strRespawn[8], String:strProtect[8]; + + // Get respawn&protect parameters + GetCmdArg(2, strRespawn, sizeof(strRespawn)); + GetCmdArg(3, strProtect, sizeof(strProtect)); + + // If parameter exists then cast it into a bool and feed it to "humanize" function. + respawn = (strRespawn[0]) ? (bool:StringToInt(strRespawn)) : false; + protect = (strProtect[0]) ? (bool:StringToInt(strProtect)) : false; + + // Turn client into a zombie. + InfectZombieToHuman(targets[0], respawn, protect); + + // Tell admin command was successful. + TranslationReplyToCommand(client, "Infect command human successful", targetname); + } + else + { + // Tell admin command was unsuccessful. + TranslationReplyToCommand(client, "Infect command human unsuccessful", targetname); + } + + return Plugin_Handled; +} \ No newline at end of file diff --git a/src/zr/respawn.inc b/src/zr/respawn.inc index 3e22c53..c36f3ce 100644 --- a/src/zr/respawn.inc +++ b/src/zr/respawn.inc @@ -155,13 +155,13 @@ RespawnSpawnClient(client, bool:zombie = false) // Infect if zombie is true. if (zombie) { - InfectClient(client); + InfectHumanToZombie(client); return; } if (GetConVarBool(g_hCvarsList[CVAR_RESPAWN_TEAM_ZOMBIE_WORLD]) && bKilledByWorld[client]) { - InfectClient(client); + InfectHumanToZombie(client); bKilledByWorld[client] = false; } } diff --git a/src/zr/spawnprotect.inc b/src/zr/spawnprotect.inc index 98c5e1a..05ec86e 100644 --- a/src/zr/spawnprotect.inc +++ b/src/zr/spawnprotect.inc @@ -73,8 +73,43 @@ SpawnProtectOnClientSpawn(client) */ SpawnProtectOnClientSpawnPost(client) { - // If client isn't on a team, then stop. - if (!ZRIsClientOnTeam(client)) + // If protect cvar is disabled, then stop. + new bool:protect = GetConVarBool(g_hCvarsList[CVAR_SPAWNPROTECT]); + if (!protect) + { + return; + } + + // Start spawn protection. + SpawnProtectStart(client); +} + +/** + * Client has been killed. + * + * @param client The client index. + */ +SpawnProtectOnClientDeath(client) +{ + // If timer is running, kill it. + if (tSpawnProtect[client] != INVALID_HANDLE) + { + KillTimer(tSpawnProtect[client]); + } + + // Reset timer handle. + tSpawnProtect[client] = INVALID_HANDLE; +} + +/** + * Start spawn protection on a client. + * + * @param client The client index. + */ +SpawnProtectStart(client) +{ + // If client is dead, then stop. + if (!IsPlayerAlive(client)) { return; } @@ -85,13 +120,6 @@ SpawnProtectOnClientSpawnPost(client) return; } - // If protect cvar is disabled, then stop. - new bool:protect = GetConVarBool(g_hCvarsList[CVAR_SPAWNPROTECT]); - if (!protect) - { - return; - } - // If client is a zombie, then stop. if (InfectIsClientInfected(client)) { @@ -123,23 +151,6 @@ SpawnProtectOnClientSpawnPost(client) tSpawnProtect[client] = CreateTimer(1.0, SpawnProtectTimer, client, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); } -/** - * Client has been killed. - * - * @param client The client index. - */ -SpawnProtectOnClientDeath(client) -{ - // If timer is running, kill it. - if (tSpawnProtect[client] != INVALID_HANDLE) - { - KillTimer(tSpawnProtect[client]); - } - - // Reset timer handle. - tSpawnProtect[client] = INVALID_HANDLE; -} - /** * Timer callback function, countdown for spawn protection. * diff --git a/src/zr/zadmin.inc b/src/zr/zadmin.inc index 051f716..16e4172 100644 --- a/src/zr/zadmin.inc +++ b/src/zr/zadmin.inc @@ -333,7 +333,7 @@ public ZRAdminMenuHandle(Handle:menu_admin, MenuAction:action, client, slot) { decl String:name[64]; GetClientName(target, name, sizeof(name)); - InfectClient(target); + InfectHumanToZombie(target); ShowActivity2(client, "[ZR] ", "Infected %s", name); ZRInfectMenu(client); } diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index ce5688b..5fd08e7 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -254,6 +254,54 @@ stock bool:ZRIsClientAdmin(client) return true; } +/** + * Replies to a client with a given message describing a targetting + * failure reason. (formatted for ZR) + * + * Note: The translation phrases are found in common.phrases.txt. + * + * @param client Client index, or 0 for server. + * @param reason COMMAND_TARGET reason. + */ +stock ZRReplyToTargetError(client, reason) +{ + switch (reason) + { + case COMMAND_TARGET_NONE: + { + TranslationReplyToCommand(client, "No matching client"); + } + case COMMAND_TARGET_NOT_ALIVE: + { + TranslationReplyToCommand(client, "Target must be alive"); + } + case COMMAND_TARGET_NOT_DEAD: + { + TranslationReplyToCommand(client, "Target must be dead"); + } + case COMMAND_TARGET_NOT_IN_GAME: + { + TranslationReplyToCommand(client, "Target is not in game"); + } + case COMMAND_TARGET_IMMUNE: + { + TranslationReplyToCommand(client, "Unable to target"); + } + case COMMAND_TARGET_EMPTY_FILTER: + { + TranslationReplyToCommand(client, "No matching clients"); + } + case COMMAND_TARGET_NOT_HUMAN: + { + TranslationReplyToCommand(client, "Cannot target bot"); + } + case COMMAND_TARGET_AMBIGUOUS: + { + TranslationReplyToCommand(client, "More than one client matched"); + } + } +} + /** * Adds support for printing strings longer than 1 KB to console. Max 4 KB. * diff --git a/src/zr/zspawn.inc b/src/zr/zspawn.inc index ce1e209..5e6fd5c 100644 --- a/src/zr/zspawn.inc +++ b/src/zr/zspawn.inc @@ -175,25 +175,40 @@ bool:ZSpawnClient(client) return false; } + // Check if zspawn override is enabled, and if so get overidden value. + new bool:teamoverride = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_OVERRIDE]); + new bool:teamzombie = teamoverride ? GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_ZOMBIE]) : GetConVarBool(g_hCvarsList[CVAR_RESPAWN_TEAM_ZOMBIE]); + // Block is the time limit is up. new bool:zspawntimelimit = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT]); if (zspawntimelimit) { if (tZSpawn == INVALID_HANDLE) { - // Get timelimit - new Float:zspawntime = GetConVarFloat(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_TIME]); - - // Tell client the timelimit for this command has expired. - TranslationPrintToChat(client, "ZSpawn timelimit", RoundToNearest(zspawntime)); - return false; + new zspawntimelimitzombie = GetConVarInt(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_ZOMBIE]); + switch(zspawntimelimitzombie) + { + case -1: + { + // Get timelimit + new Float:zspawntime = GetConVarFloat(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_TIME]); + + // Tell client the timelimit for this command has expired. + TranslationPrintToChat(client, "ZSpawn timelimit", RoundToNearest(zspawntime)); + return false; + } + case 0: + { + teamzombie = false; + } + case 1: + { + teamzombie = true; + } + } } } - // Check if zspawn override is enabled, and if so get overidden value. - new bool:teamoverride = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_OVERRIDE]); - new bool:teamzombie = teamoverride ? GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_ZOMBIE]) : GetConVarBool(g_hCvarsList[CVAR_RESPAWN_TEAM_ZOMBIE]); - // Tell respawn module to respawn client. RespawnSpawnClient(client, teamzombie);