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
This commit is contained in:
Greyscale 2009-06-07 21:05:50 -07:00
parent 208fe7fe28
commit d0c25862d8
14 changed files with 267 additions and 50 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -100,6 +100,7 @@ ToolsFindOffsets()
// Forward event to modules.
WeaponsOnOffsetsFound();
AccountOnOffsetsFound();
VEffectsOnOffsetsFound();
AntiStickOnOffsetsFound();
ZMarketOnOffsetsFound();
}

View File

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

View File

@ -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.
*

View File

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

View File

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

View File

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

View File

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