From d0c25862d8537e654faf3601dee30bcbb3c3c8df Mon Sep 17 00:00:00 2001 From: Greyscale Date: Sun, 7 Jun 2009 21:05:50 -0700 Subject: [PATCH] Added ragdoll module that removes ragdolls normally or with effects. *Added log entries, fixed typo. *Fixed some errors caused by disabling the weapons module. *Replaced strcmp with StrEqual --- src/zr/config.inc | 2 +- src/zr/cvars.inc | 8 ++ src/zr/event.inc | 1 + src/zr/knockback.inc | 6 ++ src/zr/log.h.inc | 6 +- src/zr/log.inc | 54 +++++----- src/zr/soundeffects/ambientsounds.inc | 6 +- src/zr/tools.inc | 1 + src/zr/visualeffects/ragdoll.inc | 138 +++++++++++++++++++++++++ src/zr/visualeffects/visualeffects.inc | 21 ++++ src/zr/weapons/menu_weapons.inc | 11 +- src/zr/weapons/restrict.inc | 42 +++++--- src/zr/weapons/zmarket.inc | 10 ++ src/zr/zadmin.inc | 11 +- 14 files changed, 267 insertions(+), 50 deletions(-) create mode 100644 src/zr/visualeffects/ragdoll.inc diff --git a/src/zr/config.inc b/src/zr/config.inc index 38c1472..12fc7d4 100644 --- a/src/zr/config.inc +++ b/src/zr/config.inc @@ -422,7 +422,7 @@ stock bool:ConfigLoadConfig(ConfigFile:config, &Handle:arrayConfig) decl String:configpath[PLATFORM_MAX_PATH]; ConfigGetConfigPath(config, configpath, sizeof(configpath)); - // If handle is still open, then close it before creating a new one. + // If array hasn't been created, then create. if (arrayConfig == INVALID_HANDLE) { // Create array in handle. diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index c6cfa6d..c5ea460 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -95,6 +95,9 @@ enum CvarsList Handle:CVAR_VEFFECTS_FOG_STARTDIST, Handle:CVAR_VEFFECTS_FOG_ENDDIST, Handle:CVAR_VEFFECTS_FOG_FARZ, + Handle:CVAR_VEFFECTS_RAGDOLL_REMOVE, + Handle:CVAR_VEFFECTS_RAGDOLL_DISSOLVE, + Handle:CVAR_VEFFECTS_RAGDOLL_DELAY, Handle:CVAR_SEFFECTS_MOAN, Handle:CVAR_SEFFECTS_GROAN, Handle:CVAR_SEFFECTS_DEATH, @@ -366,6 +369,11 @@ CvarsCreate() g_hCvarsList[CVAR_VEFFECTS_FOG_ENDDIST] = CreateConVar("zr_veffects_fog_enddist", "400", "(UNSUPPORTED) Distance from player to stop rendering fog. [Dependency: zr_veffects_fog]"); g_hCvarsList[CVAR_VEFFECTS_FOG_FARZ] = CreateConVar("zr_veffects_fog_farz", "2000", "(UNSUPPORTED) Vertical clipping plane."); + // Ragdoll + + g_hCvarsList[CVAR_VEFFECTS_RAGDOLL_REMOVE] = CreateConVar("zr_veffects_ragdoll_remove", "1", "Remove players' ragdolls from the game after a delay."); + g_hCvarsList[CVAR_VEFFECTS_RAGDOLL_DISSOLVE] = CreateConVar("zr_veffects_ragdoll_dissolve", "1", "The ragdoll removal effect. [-1: Effectless removal | 0: Energy dissolve | 1: Heavy electrical dissolve | 2: Light electrical dissolve | 3: Core dissolve | Dependency: zr_veffects_ragdoll_remove]"); + g_hCvarsList[CVAR_VEFFECTS_RAGDOLL_DELAY] = CreateConVar("zr_veffects_ragdoll_delay", "0.5", "Time to wait before removing the ragdoll. [Dependency: zr_veffects_ragdoll_remove]"); // =========================== // Sound Effects (module) diff --git a/src/zr/event.inc b/src/zr/event.inc index c0221d8..2474aa9 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -247,6 +247,7 @@ public Action:EventPlayerDeath(Handle:event, const String:name[], bool:dontBroad ClassOnClientDeath(index); RoundEndOnClientDeath(); InfectOnClientDeath(index, attacker); + VEffectsOnClientDeath(index); SEffectsOnClientDeath(index); SpawnProtectOnClientDeath(index); RespawnOnClientDeath(index, attacker, weapon); diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index b714640..be3144c 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -70,6 +70,12 @@ KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_hea TR_GetEndPosition(clientloc); } + new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); + if (!weapons) + { + return; + } + new weaponindex = WeaponsNameToIndex(weapon); if (weaponindex != -1) { diff --git a/src/zr/log.h.inc b/src/zr/log.h.inc index f90d1a4..6b7b04c 100644 --- a/src/zr/log.h.inc +++ b/src/zr/log.h.inc @@ -47,7 +47,6 @@ enum LogTypes * * Update following when adding modules: * - Admin log flag menu - * - Command_LogList * - LogGetModuleNameString * - LogGetModule */ @@ -65,9 +64,10 @@ enum LogModules bool:LogModule_Infect, bool:LogModule_Models, bool:LogModule_Playerclasses, - bool:LogModule_Soundeffects, + bool:LogModule_VEffects, + bool:LogModule_SEffects, bool:LogModule_Tools, - bool:LogModule_Volfetures, + bool:LogModule_Volfeatures, bool:LogModule_Weapons, bool:LogModule_Weaponrestrict } diff --git a/src/zr/log.inc b/src/zr/log.inc index e161c35..16938f5 100644 --- a/src/zr/log.inc +++ b/src/zr/log.inc @@ -80,15 +80,19 @@ LogGetModuleNameString(String:buffer[], maxlen, LogModules:module, bool:shortNam { return shortName ? strcopy(buffer, maxlen, "playerclasses") : strcopy(buffer, maxlen, "Player Classes"); } - case LogModule_Soundeffects: + case LogModule_VEffects: { - return shortName ? strcopy(buffer, maxlen, "soundeffects") : strcopy(buffer, maxlen, "Sound Effects"); + return shortName ? strcopy(buffer, maxlen, "veffects") : strcopy(buffer, maxlen, "Visual Effects"); + } + case LogModule_SEffects: + { + return shortName ? strcopy(buffer, maxlen, "seffects") : strcopy(buffer, maxlen, "Sound Effects"); } case LogModule_Tools: { return shortName ? strcopy(buffer, maxlen, "tools") : strcopy(buffer, maxlen, "Tools"); } - case LogModule_Volfetures: + case LogModule_Volfeatures: { return shortName ? strcopy(buffer, maxlen, "volfeatures") : strcopy(buffer, maxlen, "Volumetric Features"); } @@ -115,69 +119,67 @@ LogGetModuleNameString(String:buffer[], maxlen, LogModules:module, bool:shortNam */ LogModules:LogGetModule(const String:moduleName[]) { - // Check if empty. - if (strlen(moduleName) == 0) - { - return LogModule_Invalid; - } - - if (strcmp(moduleName, "account", false)) + if (StrEqual(moduleName, "account", false)) { return LogModule_Account; } - else if (strcmp(moduleName, "antistick", false)) + else if (StrEqual(moduleName, "antistick", false)) { return LogModule_Antistick; } - else if (strcmp(moduleName, "config", false)) + else if (StrEqual(moduleName, "config", false)) { return LogModule_Config; } - else if (strcmp(moduleName, "cvars", false)) + else if (StrEqual(moduleName, "cvars", false)) { return LogModule_Cvars; } - else if (strcmp(moduleName, "damage", false)) + else if (StrEqual(moduleName, "damage", false)) { return LogModule_Damage; } - else if (strcmp(moduleName, "downloads", false)) + else if (StrEqual(moduleName, "downloads", false)) { return LogModule_Downloads; } - else if (strcmp(moduleName, "hitgroups", false)) + else if (StrEqual(moduleName, "hitgroups", false)) { return LogModule_Hitgroups; } - else if (strcmp(moduleName, "infect", false)) + else if (StrEqual(moduleName, "infect", false)) { return LogModule_Infect; } - else if (strcmp(moduleName, "models", false)) + else if (StrEqual(moduleName, "models", false)) { return LogModule_Models; } - else if (strcmp(moduleName, "playerclasses", false)) + else if (StrEqual(moduleName, "playerclasses", false)) { return LogModule_Playerclasses; } - else if (strcmp(moduleName, "soundeffects", false)) + else if (StrEqual(moduleName, "veffects", false)) { - return LogModule_Soundeffects; + return LogModule_VEffects; } - else if (strcmp(moduleName, "tools", false)) + else if (StrEqual(moduleName, "seffects", false)) + { + return LogModule_SEffects; + } + else if (StrEqual(moduleName, "tools", false)) { return LogModule_Tools; } - else if (strcmp(moduleName, "volfeatures", false)) + else if (StrEqual(moduleName, "volfeatures", false)) { - return LogModule_Volfetures; + return LogModule_Volfeatures; } - else if (strcmp(moduleName, "weapons", false)) + else if (StrEqual(moduleName, "weapons", false)) { return LogModule_Weapons; } - else if (strcmp(moduleName, "weaponrestrict", false)) + else if (StrEqual(moduleName, "weaponrestrict", false)) { return LogModule_Weaponrestrict; } diff --git a/src/zr/soundeffects/ambientsounds.inc b/src/zr/soundeffects/ambientsounds.inc index 9245816..3cd6024 100644 --- a/src/zr/soundeffects/ambientsounds.inc +++ b/src/zr/soundeffects/ambientsounds.inc @@ -66,7 +66,7 @@ bool:AmbientSoundsValidateConfig() if (!FileExists(sound, true)) { // Log invalid sound file error. - LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Soundeffects, "Config Validation", "Invalid sound file specified in \"zr_ambientsounds_file\": %s", sound); + LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_SEffects, "Config Validation", "Invalid sound file specified in \"zr_ambientsounds_file\": %s", sound); return false; } @@ -75,7 +75,7 @@ bool:AmbientSoundsValidateConfig() if (ambientvolume <= 0.0) { // Log invalid ambient sound volume error. - LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Soundeffects, "Config Validation", "Ambient sound volume specified in \"zr_ambientsounds_volume\"is either muted or invalid."); + LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_SEffects, "Config Validation", "Ambient sound volume specified in \"zr_ambientsounds_volume\"is either muted or invalid."); return false; } @@ -85,7 +85,7 @@ bool:AmbientSoundsValidateConfig() if (ambientlength <= 0.0) { // Log invalid ambient sound length error. - LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Soundeffects, "Config Validation", "Ambient sound length specified in \"zr_ambientsounds_length\" is invalid."); + LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_SEffects, "Config Validation", "Ambient sound length specified in \"zr_ambientsounds_length\" is invalid."); return false; } diff --git a/src/zr/tools.inc b/src/zr/tools.inc index d632662..ec54118 100644 --- a/src/zr/tools.inc +++ b/src/zr/tools.inc @@ -100,6 +100,7 @@ ToolsFindOffsets() // Forward event to modules. WeaponsOnOffsetsFound(); AccountOnOffsetsFound(); + VEffectsOnOffsetsFound(); AntiStickOnOffsetsFound(); ZMarketOnOffsetsFound(); } diff --git a/src/zr/visualeffects/ragdoll.inc b/src/zr/visualeffects/ragdoll.inc new file mode 100644 index 0000000..b5c732d --- /dev/null +++ b/src/zr/visualeffects/ragdoll.inc @@ -0,0 +1,138 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: ragdoll.inc + * Type: Module + * Description: Remove ragdolls with optional effects. + * + * ============================================================================ + */ + +#define VEFFECTS_RAGDOLL_DISSOLVE_EFFECTLESS -1 +#define VEFFECTS_RAGDOLL_DISSOLVE_ENERGY 0 +#define VEFFECTS_RAGDOLL_DISSOLVE_ELECTRICALH 1 +#define VEFFECTS_RAGDOLL_DISSOLVE_ELECTRICALL 2 +#define VEFFECTS_RAGDOLL_DISSOLVE_CORE 3 + +/** + * Variable to store ragdoll offset value. + */ +new g_iToolsRagdoll; + +/** + * Find VAmbience-specific offsets here. + */ +RagdollOnOffsetsFound() +{ + // If offset "m_iAccount" can't be found, then stop the plugin. + g_iToolsRagdoll = FindSendPropInfo("CCSPlayer", "m_hRagdoll"); + if (g_iToolsRagdoll == -1) + { + LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_VEffects, "Offsets", "Offset \"CCSPlayer::m_hRagdoll\" was not found."); + } +} + +/** + * Client has been killed. + * + * @param client The client index. + */ +RagdollOnClientDeath(client) +{ + new ragdoll = RagdollGetClientRagdoll(client); + + // If the ragdoll is invalid, then stop. + if (ragdoll == -1) + { + return; + } + + // Get the delay. + new Float:dissolvedelay = GetConVarFloat(g_hCvarsList[CVAR_VEFFECTS_RAGDOLL_DELAY]); + + // If the delay is 0 or less, then remove right now. + if (dissolvedelay <= 0) + { + RagdollTimer(INVALID_HANDLE, ragdoll); + return; + } + + // Create a timer to remove/dissolve ragdoll. + CreateTimer(dissolvedelay, RagdollTimer, ragdoll, TIMER_FLAG_NO_MAPCHANGE); +} + +/** + * Removed a ragdoll from the game following plugin settings. + * + * @param ragdoll The ragdoll index. + */ +RagdollRemove(ragdoll) +{ + // Get the dissolve type. + new dissolve = GetConVarInt(g_hCvarsList[CVAR_VEFFECTS_RAGDOLL_DISSOLVE]); + + if (dissolve == VEFFECTS_RAGDOLL_DISSOLVE_EFFECTLESS) + { + // Remove entity from world. + RemoveEdict(ragdoll); + return; + } + + // Prep the ragdoll for dissolving. + decl String:targetname[64]; + Format(targetname, sizeof(targetname), "zr_dissolve_%d", ragdoll); + DispatchKeyValue(ragdoll, "targetname", targetname); + + // Prep the dissolve entity. + new dissolver = CreateEntityByName("env_entity_dissolver"); + + // Set the target to the ragdoll. + DispatchKeyValue(dissolver, "target", targetname); + + // Set the dissolve type. + decl String:dissolvetype[16]; + Format(dissolvetype, sizeof(dissolvetype), "%d", dissolve); + DispatchKeyValue(dissolver, "dissolvetype", dissolvetype); + + // Tell the entity to dissolve the ragdoll. + AcceptEntityInput(dissolver, "Dissolve"); + + // Remove the dissolver. + RemoveEdict(dissolver); +} + +/** + * Timer callback. Removed a client's ragdoll. + * + * @param timer The timer handle. + * @param ragdoll The ragdoll index. + */ +public Action:RagdollTimer(Handle:timer, any:ragdoll) +{ + // If ragdoll removal is disabled, then stop. + new bool:ragdollremove = GetConVarBool(g_hCvarsList[CVAR_VEFFECTS_RAGDOLL_REMOVE]); + if (!ragdollremove) + { + return; + } + + // If the ragdoll is already gone, then stop. + if (!IsValidEdict(ragdoll)) + { + return; + } + + // Remove the ragdoll. + RagdollRemove(ragdoll); +} + +/** Finds the ragdoll entity of a client. + * @param client The client index. + * @return The entity index of the client's ragdoll, -1 if none exists. + */ +RagdollGetClientRagdoll(client) +{ + return GetEntDataEnt2(client, g_iToolsRagdoll); +} \ No newline at end of file diff --git a/src/zr/visualeffects/visualeffects.inc b/src/zr/visualeffects/visualeffects.inc index cb771af..069010f 100644 --- a/src/zr/visualeffects/visualeffects.inc +++ b/src/zr/visualeffects/visualeffects.inc @@ -11,6 +11,7 @@ */ #include "zr/visualeffects/visualambience" +#include "zr/visualeffects/ragdoll" /** * Visual effect loading. @@ -30,6 +31,26 @@ VEffectsOnCvarInit() VAmbienceCvarsHook(); } +/** + * Find VEffects-specific offsets here. + */ +VEffectsOnOffsetsFound() +{ + // Forward event to sub-modules + RagdollOnOffsetsFound(); +} + +/** + * Client has been killed. + * + * @param client The client index. + */ +VEffectsOnClientDeath(client) +{ + // Forward event to sub-modules. + RagdollOnClientDeath(client); +} + /** * Create an energy splash effect. * diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index c04212c..be1e765 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -34,8 +34,15 @@ new g_iWeaponsCurType[MAXPLAYERS + 1]; * Sends main weapon menu to client. * @param client The client index. */ -WeaponsMenuMain(client) +bool:WeaponsMenuMain(client) { + // If weapons module is disabled, then stop. + new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); + if (!weapons) + { + return false; + } + // Create menu handle. new Handle:menu_weapons_main = CreateMenu(WeaponsMenuMainHandle); @@ -58,6 +65,8 @@ WeaponsMenuMain(client) // Send menu. DisplayMenu(menu_weapons_main, client, MENU_TIME_FOREVER); + + return true; } /** diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index cbd6561..7874dd0 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -530,6 +530,20 @@ public ZRTools_Action:RestrictCanUse(client, weapon) return ZRTools_Continue; } + // If weapons module is disabled, then stop. + new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); + if (!weapons) + { + return ZRTools_Continue; + } + + // If restrict module is disabled, then stop. + new bool:restrict = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_RESTRICT]); + if (!restrict) + { + return ZRTools_Continue; + } + // If the weapon is restricted, then prevent pickup. new index = WeaponsNameToIndex(weaponname); @@ -572,13 +586,6 @@ public ZRTools_Action:RestrictCanUse(client, weapon) */ public Action:RestrictCommand(client, argc) { - // If not enough arguments given, then stop. - if (argc < 1) - { - TranslationReplyToCommand(client, "Weapons command restrict syntax"); - return Plugin_Handled; - } - // If weapons module is disabled, then stop. new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); if (!weapons) @@ -597,6 +604,13 @@ public Action:RestrictCommand(client, argc) return Plugin_Handled; } + // If not enough arguments given, then stop. + if (argc < 1) + { + TranslationReplyToCommand(client, "Weapons command restrict syntax"); + return Plugin_Handled; + } + decl String:target[WEAPONS_MAX_LENGTH]; new args = GetCmdArgs(); @@ -626,13 +640,6 @@ public Action:RestrictCommand(client, argc) */ public Action:UnrestrictCommand(client, argc) { - // If not enough arguments given, then stop. - if (argc < 1) - { - TranslationReplyToCommand(client, "Weapons command unrestrict syntax"); - return Plugin_Handled; - } - // If weapons module is disabled, then stop. new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); if (!weapons) @@ -651,6 +658,13 @@ public Action:UnrestrictCommand(client, argc) return Plugin_Handled; } + // If not enough arguments given, then stop. + if (argc < 1) + { + TranslationReplyToCommand(client, "Weapons command unrestrict syntax"); + return Plugin_Handled; + } + // arg1 = weapon being restricted decl String:target[WEAPONS_MAX_LENGTH]; diff --git a/src/zr/weapons/zmarket.inc b/src/zr/weapons/zmarket.inc index 4c82345..a10940f 100644 --- a/src/zr/weapons/zmarket.inc +++ b/src/zr/weapons/zmarket.inc @@ -190,6 +190,16 @@ ZMarketGetPurchaseCount(client, const String:weapon[]) */ bool:ZMarketMenuTypes(client) { + // If weapons module is disabled, then stop. + new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); + if (!weapons) + { + // Telle client feature is disabled. + TranslationPrintToChat(client, "Feature is disabled"); + return false; + } + + // If ZMarket module is disabled, then stop. new bool:zmarket = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET]); if (!zmarket) { diff --git a/src/zr/zadmin.inc b/src/zr/zadmin.inc index c857b30..29521d6 100644 --- a/src/zr/zadmin.inc +++ b/src/zr/zadmin.inc @@ -61,16 +61,23 @@ public ZRAdminMenuHandle(Handle:menu_admin, MenuAction:action, client, slot) { if (action == MenuAction_Select) { + // Create variable to possible resend menu later. + new bool:resend = true; + switch(slot) { // Weapon management. case 0: { - WeaponsMenuMain(client); + resend = !WeaponsMenuMain(client); } } - // TODO: Resend menu if feature is disabled or unopenable. + // Re-send menu if selection failed. + if (resend) + { + ZRAdminMenu(client); + } } if (action == MenuAction_Cancel)