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]; decl String:configpath[PLATFORM_MAX_PATH];
ConfigGetConfigPath(config, configpath, sizeof(configpath)); 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) if (arrayConfig == INVALID_HANDLE)
{ {
// Create array in handle. // Create array in handle.

View File

@ -95,6 +95,9 @@ enum CvarsList
Handle:CVAR_VEFFECTS_FOG_STARTDIST, Handle:CVAR_VEFFECTS_FOG_STARTDIST,
Handle:CVAR_VEFFECTS_FOG_ENDDIST, Handle:CVAR_VEFFECTS_FOG_ENDDIST,
Handle:CVAR_VEFFECTS_FOG_FARZ, 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_MOAN,
Handle:CVAR_SEFFECTS_GROAN, Handle:CVAR_SEFFECTS_GROAN,
Handle:CVAR_SEFFECTS_DEATH, 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_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."); 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) // Sound Effects (module)

View File

@ -247,6 +247,7 @@ public Action:EventPlayerDeath(Handle:event, const String:name[], bool:dontBroad
ClassOnClientDeath(index); ClassOnClientDeath(index);
RoundEndOnClientDeath(); RoundEndOnClientDeath();
InfectOnClientDeath(index, attacker); InfectOnClientDeath(index, attacker);
VEffectsOnClientDeath(index);
SEffectsOnClientDeath(index); SEffectsOnClientDeath(index);
SpawnProtectOnClientDeath(index); SpawnProtectOnClientDeath(index);
RespawnOnClientDeath(index, attacker, weapon); RespawnOnClientDeath(index, attacker, weapon);

View File

@ -70,6 +70,12 @@ KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_hea
TR_GetEndPosition(clientloc); TR_GetEndPosition(clientloc);
} }
new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]);
if (!weapons)
{
return;
}
new weaponindex = WeaponsNameToIndex(weapon); new weaponindex = WeaponsNameToIndex(weapon);
if (weaponindex != -1) if (weaponindex != -1)
{ {

View File

@ -47,7 +47,6 @@ enum LogTypes
* *
* Update following when adding modules: * Update following when adding modules:
* - Admin log flag menu * - Admin log flag menu
* - Command_LogList
* - LogGetModuleNameString * - LogGetModuleNameString
* - LogGetModule * - LogGetModule
*/ */
@ -65,9 +64,10 @@ enum LogModules
bool:LogModule_Infect, bool:LogModule_Infect,
bool:LogModule_Models, bool:LogModule_Models,
bool:LogModule_Playerclasses, bool:LogModule_Playerclasses,
bool:LogModule_Soundeffects, bool:LogModule_VEffects,
bool:LogModule_SEffects,
bool:LogModule_Tools, bool:LogModule_Tools,
bool:LogModule_Volfetures, bool:LogModule_Volfeatures,
bool:LogModule_Weapons, bool:LogModule_Weapons,
bool:LogModule_Weaponrestrict 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"); 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: case LogModule_Tools:
{ {
return shortName ? strcopy(buffer, maxlen, "tools") : strcopy(buffer, maxlen, "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"); 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[]) LogModules:LogGetModule(const String:moduleName[])
{ {
// Check if empty. if (StrEqual(moduleName, "account", false))
if (strlen(moduleName) == 0)
{
return LogModule_Invalid;
}
if (strcmp(moduleName, "account", false))
{ {
return LogModule_Account; return LogModule_Account;
} }
else if (strcmp(moduleName, "antistick", false)) else if (StrEqual(moduleName, "antistick", false))
{ {
return LogModule_Antistick; return LogModule_Antistick;
} }
else if (strcmp(moduleName, "config", false)) else if (StrEqual(moduleName, "config", false))
{ {
return LogModule_Config; return LogModule_Config;
} }
else if (strcmp(moduleName, "cvars", false)) else if (StrEqual(moduleName, "cvars", false))
{ {
return LogModule_Cvars; return LogModule_Cvars;
} }
else if (strcmp(moduleName, "damage", false)) else if (StrEqual(moduleName, "damage", false))
{ {
return LogModule_Damage; return LogModule_Damage;
} }
else if (strcmp(moduleName, "downloads", false)) else if (StrEqual(moduleName, "downloads", false))
{ {
return LogModule_Downloads; return LogModule_Downloads;
} }
else if (strcmp(moduleName, "hitgroups", false)) else if (StrEqual(moduleName, "hitgroups", false))
{ {
return LogModule_Hitgroups; return LogModule_Hitgroups;
} }
else if (strcmp(moduleName, "infect", false)) else if (StrEqual(moduleName, "infect", false))
{ {
return LogModule_Infect; return LogModule_Infect;
} }
else if (strcmp(moduleName, "models", false)) else if (StrEqual(moduleName, "models", false))
{ {
return LogModule_Models; return LogModule_Models;
} }
else if (strcmp(moduleName, "playerclasses", false)) else if (StrEqual(moduleName, "playerclasses", false))
{ {
return LogModule_Playerclasses; 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; 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; return LogModule_Weapons;
} }
else if (strcmp(moduleName, "weaponrestrict", false)) else if (StrEqual(moduleName, "weaponrestrict", false))
{ {
return LogModule_Weaponrestrict; return LogModule_Weaponrestrict;
} }

View File

@ -66,7 +66,7 @@ bool:AmbientSoundsValidateConfig()
if (!FileExists(sound, true)) if (!FileExists(sound, true))
{ {
// Log invalid sound file error. // 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; return false;
} }
@ -75,7 +75,7 @@ bool:AmbientSoundsValidateConfig()
if (ambientvolume <= 0.0) if (ambientvolume <= 0.0)
{ {
// Log invalid ambient sound volume error. // 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; return false;
} }
@ -85,7 +85,7 @@ bool:AmbientSoundsValidateConfig()
if (ambientlength <= 0.0) if (ambientlength <= 0.0)
{ {
// Log invalid ambient sound length error. // 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; return false;
} }

View File

@ -100,6 +100,7 @@ ToolsFindOffsets()
// Forward event to modules. // Forward event to modules.
WeaponsOnOffsetsFound(); WeaponsOnOffsetsFound();
AccountOnOffsetsFound(); AccountOnOffsetsFound();
VEffectsOnOffsetsFound();
AntiStickOnOffsetsFound(); AntiStickOnOffsetsFound();
ZMarketOnOffsetsFound(); 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/visualambience"
#include "zr/visualeffects/ragdoll"
/** /**
* Visual effect loading. * Visual effect loading.
@ -30,6 +31,26 @@ VEffectsOnCvarInit()
VAmbienceCvarsHook(); 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. * Create an energy splash effect.
* *

View File

@ -34,8 +34,15 @@ new g_iWeaponsCurType[MAXPLAYERS + 1];
* Sends main weapon menu to client. * Sends main weapon menu to client.
* @param client The client index. * @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. // Create menu handle.
new Handle:menu_weapons_main = CreateMenu(WeaponsMenuMainHandle); new Handle:menu_weapons_main = CreateMenu(WeaponsMenuMainHandle);
@ -58,6 +65,8 @@ WeaponsMenuMain(client)
// Send menu. // Send menu.
DisplayMenu(menu_weapons_main, client, MENU_TIME_FOREVER); 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; 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. // If the weapon is restricted, then prevent pickup.
new index = WeaponsNameToIndex(weaponname); new index = WeaponsNameToIndex(weaponname);
@ -572,13 +586,6 @@ public ZRTools_Action:RestrictCanUse(client, weapon)
*/ */
public Action:RestrictCommand(client, argc) 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. // If weapons module is disabled, then stop.
new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]);
if (!weapons) if (!weapons)
@ -597,6 +604,13 @@ public Action:RestrictCommand(client, argc)
return Plugin_Handled; 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]; decl String:target[WEAPONS_MAX_LENGTH];
new args = GetCmdArgs(); new args = GetCmdArgs();
@ -626,13 +640,6 @@ public Action:RestrictCommand(client, argc)
*/ */
public Action:UnrestrictCommand(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. // If weapons module is disabled, then stop.
new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]);
if (!weapons) if (!weapons)
@ -651,6 +658,13 @@ public Action:UnrestrictCommand(client, argc)
return Plugin_Handled; 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 // arg1 = weapon being restricted
decl String:target[WEAPONS_MAX_LENGTH]; decl String:target[WEAPONS_MAX_LENGTH];

View File

@ -190,6 +190,16 @@ ZMarketGetPurchaseCount(client, const String:weapon[])
*/ */
bool:ZMarketMenuTypes(client) 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]); new bool:zmarket = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET]);
if (!zmarket) if (!zmarket)
{ {

View File

@ -61,16 +61,23 @@ public ZRAdminMenuHandle(Handle:menu_admin, MenuAction:action, client, slot)
{ {
if (action == MenuAction_Select) if (action == MenuAction_Select)
{ {
// Create variable to possible resend menu later.
new bool:resend = true;
switch(slot) switch(slot)
{ {
// Weapon management. // Weapon management.
case 0: 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) if (action == MenuAction_Cancel)