Merged heads.
This commit is contained in:
commit
162bd1e107
BIN
bin/spcomp
BIN
bin/spcomp
Binary file not shown.
@ -1092,16 +1092,18 @@
|
||||
"ru" "Здоровье: {1}"
|
||||
}
|
||||
|
||||
// ===========================
|
||||
// Volumetric features (module)
|
||||
// ===========================
|
||||
|
||||
|
||||
"Unfair camping"
|
||||
"Vol Anticamp Message"
|
||||
{
|
||||
"en" "An admin has marked this area as unfair, please move along, or die."
|
||||
"en" "This area is restricted, please move along."
|
||||
}
|
||||
|
||||
"Unfair camper slayed"
|
||||
"Vol Slay"
|
||||
{
|
||||
"#format" "{1:s},{2:d}"
|
||||
"en" "Player {1} has been slayed for camping in a restricted area. (ID: {2})"
|
||||
"en" "Player \"{1}\" has been slayed for camping in a restricted area (ID: {2})."
|
||||
}
|
||||
}
|
@ -80,7 +80,7 @@ warning is logged in the SourceMod error logs.
|
||||
|
||||
The validation prevents unexpected or invalid behaviour in the plugin. Dealing
|
||||
with errors or warnings in error logs helps a lot troubleshooting eventual
|
||||
eventual issues in the plugin caused by incorrect configurations.
|
||||
issues in the plugin caused by incorrect configurations.
|
||||
|
||||
It's also possible to specify the path of configuration files. This can be used
|
||||
in combination with map configs, so it's possible to have different
|
||||
|
@ -63,6 +63,10 @@ public const MaxClients; /**< Maximum number of players the server supports (dyn
|
||||
* If you return false (or return nothing), the client will be rejected. If the client is
|
||||
* rejected by this forward or any other, OnClientDisconnect will not be called.
|
||||
*
|
||||
* Note: Do not write to rejectmsg if you plan on returning true. If multiple plugins write
|
||||
* to the string buffer, it is not defined which plugin's string will be shown to the client,
|
||||
* but it is guaranteed one of them will.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param rejectmsg Buffer to store the rejection message when the connection is refused.
|
||||
* @param maxlen Maximum number of characters for rejection buffer.
|
||||
|
@ -817,9 +817,11 @@ native bool:FindNextConCommand(Handle:search, String:buffer[], max_size, &bool:i
|
||||
native bool:SendConVarValue(client, Handle:convar, const String:value[]);
|
||||
|
||||
/**
|
||||
* Appends a string to Valve's sv_tags convar and makes sure it remains after mapchanges.
|
||||
* Adds an informational string to the server's public "tags".
|
||||
* This string should be a short, unique identifier.
|
||||
*
|
||||
* Note: Tags are automatically removed on plugin unload
|
||||
* Note: Tags are automatically removed when a plugin unloads.
|
||||
* Note: Currently, this function does nothing because of bugs in the Valve master.
|
||||
*
|
||||
* @param tag Tag string to append.
|
||||
* @noreturn
|
||||
@ -827,9 +829,7 @@ native bool:SendConVarValue(client, Handle:convar, const String:value[]);
|
||||
native AddServerTag(const String:tag[]);
|
||||
|
||||
/**
|
||||
* Removes a string from valve's sv_tags convar.
|
||||
*
|
||||
* Note: You can only remove tags created by you.
|
||||
* Removes a tag previously added by the calling plugin.
|
||||
*
|
||||
* @param tag Tag string to remove.
|
||||
* @noreturn
|
||||
|
@ -94,6 +94,8 @@ enum MenuAction
|
||||
#define VOTEINFO_ITEM_INDEX 0 /**< Item index */
|
||||
#define VOTEINFO_ITEM_VOTES 1 /**< Number of votes for the item */
|
||||
|
||||
#define VOTEFLAG_NO_REVOTES (1<<0) /**< Players cannot change their votes */
|
||||
|
||||
/**
|
||||
* Reasons a menu can be cancelled (MenuAction_Cancel).
|
||||
*/
|
||||
@ -469,22 +471,24 @@ native CancelVote();
|
||||
* @param clients Array of clients to broadcast to.
|
||||
* @param numClients Number of clients in the array.
|
||||
* @param time Maximum time to leave menu on the screen.
|
||||
* @param flags Optional voting flags.
|
||||
* @return True on success, false if this menu already has a vote session
|
||||
* in progress.
|
||||
* @error Invalid Handle, or a vote is already in progress.
|
||||
*/
|
||||
native bool:VoteMenu(Handle:menu, clients[], numClients, time);
|
||||
native bool:VoteMenu(Handle:menu, clients[], numClients, time, flags=0);
|
||||
|
||||
/**
|
||||
* Sends a vote menu to all clients. See VoteMenu() for more information.
|
||||
*
|
||||
* @param menu Menu Handle.
|
||||
* @param time Maximum time to leave menu on the screen.
|
||||
* @param flags Optional voting flags.
|
||||
* @return True on success, false if this menu already has a vote session
|
||||
* in progress.
|
||||
* @error Invalid Handle.
|
||||
*/
|
||||
stock VoteMenuToAll(Handle:menu, time)
|
||||
stock VoteMenuToAll(Handle:menu, time, flags=0)
|
||||
{
|
||||
new num = GetMaxClients();
|
||||
new total;
|
||||
@ -499,7 +503,7 @@ stock VoteMenuToAll(Handle:menu, time)
|
||||
players[total++] = i;
|
||||
}
|
||||
|
||||
return VoteMenu(menu, players, total, time);
|
||||
return VoteMenu(menu, players, total, time, flags);
|
||||
}
|
||||
/**
|
||||
* Callback for when a vote has ended and results are available.
|
||||
@ -543,7 +547,7 @@ native CheckVoteDelay();
|
||||
/**
|
||||
* Returns whether a client is in the pool of clients allowed
|
||||
* to participate in the current vote. This is determined by
|
||||
* the client list passed to StartVote().
|
||||
* the client list passed to VoteMenu().
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return True if client is allowed to vote, false otherwise.
|
||||
@ -555,12 +559,13 @@ native bool:IsClientInVotePool(client);
|
||||
* Redraws the current vote menu to a client in the voting pool.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param revotes True to allow revotes, false otherwise.
|
||||
* @return True on success, false if the client is in the vote pool
|
||||
* but cannot vote again.
|
||||
* @error No vote in progress, client is not in the voting pool,
|
||||
* or client index is invalid.
|
||||
*/
|
||||
native bool:RedrawClientVoteMenu(client);
|
||||
native bool:RedrawClientVoteMenu(client, bool:revotes=true);
|
||||
|
||||
/**
|
||||
* Returns a style's global Handle.
|
||||
@ -807,3 +812,4 @@ stock bool:IsNewVoteAllowed()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,14 @@ enum TFTeam
|
||||
TFTeam_Blue = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a client on fire for 10 seconds.
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @noreturn
|
||||
* @error Invalid client index, client not in game, or no mod support.
|
||||
*/
|
||||
native TF2_IgnitePlayer(client, target);
|
||||
|
||||
/**
|
||||
* Respawns a client
|
||||
|
@ -37,6 +37,6 @@
|
||||
|
||||
#define SOURCEMOD_V_MAJOR 1 /**< SourceMod Major version */
|
||||
#define SOURCEMOD_V_MINOR 2 /**< SourceMod Minor version */
|
||||
#define SOURCEMOD_V_RELEASE 0 /**< SourceMod Release version */
|
||||
#define SOURCEMOD_V_RELEASE 1 /**< SourceMod Release version */
|
||||
|
||||
#define SOURCEMOD_VERSION "1.2.0" /**< SourceMod version string (major.minor.release.build) */
|
||||
#define SOURCEMOD_VERSION "1.2.1" /**< SourceMod version string (major.minor.release.build) */
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "zr/zcookies"
|
||||
#include "zr/jumpboost"
|
||||
#include "zr/volfeatures/volfeatures"
|
||||
#include "zr/debugtools"
|
||||
|
||||
/**
|
||||
* Record plugin info.
|
||||
@ -136,6 +137,7 @@ public OnMapStart()
|
||||
InfectOnMapStart();
|
||||
SEffectsOnMapStart();
|
||||
ZSpawnOnMapStart();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,6 +46,8 @@ CommandsInit()
|
||||
ZHPOnCommandsCreate();
|
||||
VolOnCommandsCreate();
|
||||
|
||||
DebugOnCommandsCreate();
|
||||
|
||||
// Forward event to modules. (hook commands)
|
||||
ClassOnCommandsHook();
|
||||
DamageOnCommandsHook();
|
||||
|
@ -429,8 +429,8 @@ CvarsCreate()
|
||||
// Volumetric Features (module)
|
||||
// ===========================
|
||||
g_hCvarsList[CVAR_VOL] = CreateConVar("zr_vol", "1", "Enables volumetric features.");
|
||||
g_hCvarsList[CVAR_VOL_UPDATE_INTERVAL] = CreateConVar("zr_vol_update_interval", "1.0", "How often to update player positions and trigger events, in seconds.");
|
||||
g_hCvarsList[CVAR_VOL_TRIGGER_INTERVAL] = CreateConVar("zr_vol_trigger_interval", "1.0", "How often to check for delayed events, in seconds. Use lower values for more precise delays.");
|
||||
g_hCvarsList[CVAR_VOL_UPDATE_INTERVAL] = CreateConVar("zr_vol_update_interval", "0.5", "How often to update player positions and trigger events, in seconds.");
|
||||
g_hCvarsList[CVAR_VOL_TRIGGER_INTERVAL] = CreateConVar("zr_vol_trigger_interval", "0.5", "How often to check for delayed events, in seconds. Use lower values for more precise delays.");
|
||||
|
||||
|
||||
// ===========================
|
||||
|
105
src/zr/debugtools.inc
Normal file
105
src/zr/debugtools.inc
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* ============================================================================
|
||||
*
|
||||
* Zombie:Reloaded
|
||||
*
|
||||
* File: debugtools.inc
|
||||
* Type: Core
|
||||
* Description: Place to put custom functions and test stuff.
|
||||
*
|
||||
* Copyright (C) 2009 Greyscale, Richard Helgeby
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
DebugOnCommandsCreate()
|
||||
{
|
||||
// Custom test commands:
|
||||
RegConsoleCmd("zr_getparametercount", Command_GetParameterCount, "Test GetParameterCount function in paramtools.inc. Usage: zr_getparametercount <paramstring>");
|
||||
RegConsoleCmd("zr_getparametervalue", Command_GetParameterValue, "Test GetParameterValue function in paramtools.inc. Usage: zr_getparametervalue <paramname> <paramstring>");
|
||||
}
|
||||
|
||||
public Action:Command_GetParameterCount(client, argc)
|
||||
{
|
||||
if (argc < 1)
|
||||
{
|
||||
ReplyToCommand(client, "No parameter string passed. Usage: zr_getparametercount <paramstring>");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
decl String:argbuffer[256];
|
||||
decl String:paramstring[256];
|
||||
|
||||
paramstring[0] = 0;
|
||||
|
||||
// Join the last parameters in a string.
|
||||
for (new arg = 1; arg <= argc; arg++)
|
||||
{
|
||||
GetCmdArg(arg, argbuffer, sizeof(argbuffer));
|
||||
StrCat(paramstring, sizeof(paramstring), argbuffer);
|
||||
|
||||
// Add space, except on the last parameter.
|
||||
if (arg < argc)
|
||||
{
|
||||
StrCat(paramstring, sizeof(paramstring), " ");
|
||||
}
|
||||
}
|
||||
|
||||
ReplyToCommand(client, "Parameter string: \"%s\"", paramstring);
|
||||
new paramcount = GetParameterCount(paramstring);
|
||||
ReplyToCommand(client, "Parameter count: %d", paramcount);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:Command_GetParameterValue(client, argc)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
ReplyToCommand(client, "Missing parameters. Usage: zr_getparametervalue <paramname> <paramstring>");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
decl String:paramname[256];
|
||||
decl String:paramstring[256];
|
||||
|
||||
decl String:valuebuffer[64];
|
||||
decl String:argbuffer[256];
|
||||
|
||||
paramstring[0] = 0;
|
||||
valuebuffer[0] = 0;
|
||||
|
||||
GetCmdArg(1, paramname, sizeof(paramname));
|
||||
|
||||
// Join the last parameters in a string.
|
||||
for (new arg = 2; arg <= argc; arg++)
|
||||
{
|
||||
GetCmdArg(arg, argbuffer, sizeof(argbuffer));
|
||||
StrCat(paramstring, sizeof(paramstring), argbuffer);
|
||||
|
||||
// Add space, except on the last parameter.
|
||||
if (arg < argc)
|
||||
{
|
||||
StrCat(paramstring, sizeof(paramstring), " ");
|
||||
}
|
||||
}
|
||||
|
||||
new retval = GetParameterValue(valuebuffer, sizeof(valuebuffer), paramstring, paramname);
|
||||
|
||||
ReplyToCommand(client, "Return value: %d\nParameter string: \"%s\"\nParameter value: \"%s\"", retval, paramstring, valuebuffer);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
@ -8,6 +8,8 @@
|
||||
* Description: Provides functions for parsing strings with parameters in
|
||||
* key=value format.
|
||||
*
|
||||
* Note: Does not support spaces or quoted strings.
|
||||
*
|
||||
* Copyright (C) 2009 Greyscale, Richard Helgeby
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -34,6 +36,8 @@ stock GetParameterCount(const String:rawString[])
|
||||
{
|
||||
new lenRawString = strlen(rawString);
|
||||
new paramCount;
|
||||
new searchPos;
|
||||
new splitPos;
|
||||
|
||||
// Check if the raw string is empty.
|
||||
if (lenRawString == 0)
|
||||
@ -42,20 +46,26 @@ stock GetParameterCount(const String:rawString[])
|
||||
}
|
||||
|
||||
// Count number of "=".
|
||||
for (new searchPos = 0; searchPos < lenRawString; searchPos++)
|
||||
for (splitPos = 0; splitPos < lenRawString; splitPos++)
|
||||
{
|
||||
// Set searchPos and check if "=" was found.
|
||||
searchPos = StrContains(rawString[searchPos], "=");
|
||||
if (searchPos)
|
||||
// Find next "=".
|
||||
searchPos = StrContains(rawString[splitPos], "=", false);
|
||||
|
||||
// Note: searchPos is an offset from rawString[splitPos]. If searchPos
|
||||
// is 0, then the real position is splitPos.
|
||||
|
||||
// Check if "=" was found.
|
||||
if (searchPos >= 0)
|
||||
{
|
||||
// Parameter found.
|
||||
paramCount++;
|
||||
|
||||
// Increment one position so we dont find the same "=" again.
|
||||
searchPos++;
|
||||
// Update split position.
|
||||
splitPos += searchPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Exit loop.
|
||||
// No need to continue. "=" not found.
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -86,9 +96,11 @@ stock GetParameterValue(String:buffer[], maxlen, const String:rawString[], const
|
||||
new valuePos;
|
||||
new valueLen;
|
||||
new nextPos;
|
||||
new splitPos;
|
||||
|
||||
// Get the position of parameter.
|
||||
paramPos = StrContains(rawString, parameter, false);
|
||||
splitPos = paramPos;
|
||||
|
||||
// Check if found.
|
||||
if (paramPos >= 0)
|
||||
@ -96,8 +108,8 @@ stock GetParameterValue(String:buffer[], maxlen, const String:rawString[], const
|
||||
// Get parameter length.
|
||||
paramLen = strlen(parameter);
|
||||
|
||||
// Get the position of the next parameter.
|
||||
nextPos = StrContains(rawString[paramPos + 1], " ");
|
||||
// Get the position of the next parameter by finding the next space.
|
||||
nextPos = StrContains(rawString[splitPos], " ");
|
||||
|
||||
// Check if the next parameter was found.
|
||||
if (nextPos >= 0)
|
||||
@ -105,8 +117,9 @@ stock GetParameterValue(String:buffer[], maxlen, const String:rawString[], const
|
||||
// Calculate value starting position.
|
||||
valuePos = paramPos + paramLen + 1;
|
||||
|
||||
// Calculate value length.
|
||||
valueLen = nextPos - valuePos;
|
||||
// Calculate value length. Note: Adding 1 for space to the null
|
||||
// terminator.
|
||||
valueLen = nextPos + splitPos - valuePos + 1;
|
||||
|
||||
// Check if value length is longer than buffer size.
|
||||
if (valueLen > maxlen)
|
||||
@ -145,6 +158,7 @@ stock GetParameterName(String:buffer[], maxlen, const String:rawString[], parame
|
||||
new paramPos;
|
||||
new valuePos;
|
||||
new nextValuePos;
|
||||
new splitPos;
|
||||
|
||||
// Check if the raw string is empty.
|
||||
if (strlen(rawString) == 0)
|
||||
@ -157,22 +171,26 @@ stock GetParameterName(String:buffer[], maxlen, const String:rawString[], parame
|
||||
// Get the value starting position for the previous index.
|
||||
for (new index = 0; index < parameterIndex - 1; index++)
|
||||
{
|
||||
valuePos = StrContains(rawString[valuePos], "=");
|
||||
valuePos = StrContains(rawString[splitPos], "=");
|
||||
splitPos += valuePos;
|
||||
}
|
||||
|
||||
// Find the next space from valuePos where the specified parameter
|
||||
// Find the next space from splitPos where the specified parameter
|
||||
// starts.
|
||||
paramPos = StrContains(rawString[valuePos], " ") + 1;
|
||||
paramPos = StrContains(rawString[splitPos], " ") + splitPos + 1;
|
||||
|
||||
// Find the next value position from paramPos to get the end position
|
||||
// Update split position.
|
||||
splitPos += paramPos;
|
||||
|
||||
// Find the next value position from splitPos to get the end position
|
||||
// of the parameter name.
|
||||
nextValuePos = StrContains(rawString[paramPos], "=");
|
||||
nextValuePos = StrContains(rawString[splitPos], "=") + splitPos;
|
||||
|
||||
// Check if a value is specified.
|
||||
if (nextValuePos > 0)
|
||||
{
|
||||
// Return the parameter name between paramPos and nextValuePos.
|
||||
return strcopy(buffer, nextValuePos - paramPos, rawString[paramPos]);
|
||||
return strcopy(buffer, nextValuePos - paramPos + 1, rawString[paramPos]); // + 1 to include null terminator.
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -189,7 +207,7 @@ stock GetParameterName(String:buffer[], maxlen, const String:rawString[], parame
|
||||
if (valuePos > 0)
|
||||
{
|
||||
// Return the parameter name.
|
||||
return strcopy(buffer, valuePos, rawString);
|
||||
return strcopy(buffer, valuePos + 1, rawString); // + 1 to include null terminator.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -384,7 +384,7 @@ stock ClassGetIndex(const String:name[], cachetype = ZR_CLASS_CACHE_MODIFIED)
|
||||
*/
|
||||
stock ClassGetActiveIndex(client)
|
||||
{
|
||||
new teamid = GetClientTeam(client);
|
||||
new teamid;
|
||||
|
||||
if (!ZRIsClientOnTeam(client))
|
||||
{
|
||||
|
@ -56,6 +56,7 @@ TranslationInit()
|
||||
{
|
||||
// Load translations phrases used by plugin.
|
||||
LoadTranslations("common.phrases.txt");
|
||||
LoadTranslations("core.phrases.txt");
|
||||
LoadTranslations("zombiereloaded.phrases.txt");
|
||||
}
|
||||
|
||||
|
@ -25,31 +25,16 @@
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data structure for a anti-camp volume.
|
||||
*/
|
||||
enum VolTypeAnticamp
|
||||
{
|
||||
Float:anticamp_interval, /** How often to trigger an action. */
|
||||
Handle:anticamp_timer, /** Action timer handle. */
|
||||
|
||||
VolAnticampAction:anticamp_action, /** What to do with players in anti-camp volumes */
|
||||
Float:anticamp_amount, /** Amount depending on action type. Usually time in seconds or damage amount. */
|
||||
|
||||
VolAnticampeWarningType:anticamp_warning, /** How to warn the player. */
|
||||
String:anticamp_message[256] /** Override warning message. Max 256 characters. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions to do with players in anti-camp volumes.
|
||||
*/
|
||||
enum VolAnticampAction
|
||||
{
|
||||
anticamp_no_action, /** Do nothing but give a warning. */
|
||||
anticamp_damage, /** Give damage to player. */
|
||||
anticamp_slay, /** Slay player. */
|
||||
anticamp_drug, /** Drug player. */
|
||||
anticamp_fire /** Ignite player. */
|
||||
Anticamp_NoAction, /** Do nothing but give a warning. */
|
||||
Anticamp_Damage, /** Give damage to player. */
|
||||
Anticamp_Slay, /** Slay player. */
|
||||
Anticamp_Drug, /** Drug player. */
|
||||
Anticamp_Ignite /** Ignite player. */
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,13 +42,797 @@ enum VolAnticampAction
|
||||
*/
|
||||
enum VolAnticampeWarningType
|
||||
{
|
||||
anticamp_no_warning, /** No warning messages. */
|
||||
anticamp_chat, /** Print warning in chat area. */
|
||||
anticamp_center, /** Print centered warning message. */
|
||||
anticamp_menu /** Print a menu-like warning message with close option. */
|
||||
Anticamp_NoWarning, /** No warning messages. */
|
||||
Anticamp_Chat, /** Print warning in chat area. */
|
||||
Anticamp_Center, /** Print centered warning message. */
|
||||
Anticamp_Menu /** Print a menu-like warning message with close option. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Data structure for a anti-camp volume.
|
||||
*/
|
||||
enum VolTypeAnticamp
|
||||
{
|
||||
bool:Anticamp_InUse, /** Specifies if the data index is used or not. */
|
||||
Float:Anticamp_Interval, /** How often to trigger an action. */
|
||||
Handle:Anticamp_Timer, /** Action timer handle. */
|
||||
|
||||
VolAnticampAction:Anticamp_Action, /** What to do with players in anti-camp volumes */
|
||||
Float:Anticamp_Amount, /** Amount depending on action type. Usually time in seconds or damage amount. */
|
||||
|
||||
VolAnticampeWarningType:Anticamp_Warning, /** How to warn the player. */
|
||||
String:Anticamp_Message[256] /** Override warning message. Max 256 characters. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti-camp data.
|
||||
*/
|
||||
new AnticampData[ZR_VOLUMES_MAX][VolTypeAnticamp];
|
||||
|
||||
/**
|
||||
* Event callback. Enables a anticamp volume.
|
||||
*
|
||||
* @param volumeIndex The volume index.
|
||||
*/
|
||||
VolAnticampEnable(volumeIndex)
|
||||
{
|
||||
new Float:interval;
|
||||
|
||||
// Validate index.
|
||||
if (!VolIsValidIndex(volumeIndex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get data index.
|
||||
new dataindex = Volumes[volumeIndex][Vol_DataIndex];
|
||||
|
||||
// Validate data index.
|
||||
if (!VolAnticampValidateIndex(dataindex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if in use.
|
||||
if (AnticampData[dataindex][Anticamp_InUse])
|
||||
{
|
||||
// Start timer if not running.
|
||||
if (AnticampData[dataindex][Anticamp_Timer] == INVALID_HANDLE)
|
||||
{
|
||||
// Get interval.
|
||||
interval = AnticampData[dataindex][Anticamp_Interval];
|
||||
|
||||
// Validate interval.
|
||||
if (interval > 0.0)
|
||||
{
|
||||
AnticampData[dataindex][Anticamp_Timer] = CreateTimer(interval, Event_VolAnticampTrigger, _, TIMER_REPEAT);
|
||||
}
|
||||
}
|
||||
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Vol state", "Enabled anticamp volume %d.", volumeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts all existing anticamp timers.
|
||||
*/
|
||||
stock VolAnticampEnableAll()
|
||||
{
|
||||
new Float:interval;
|
||||
|
||||
// Loop through all volumes.
|
||||
for (new dataindex = 0; dataindex < ZR_VOLUMES_MAX; dataindex++)
|
||||
{
|
||||
// Check if in use.
|
||||
if (AnticampData[dataindex][Anticamp_InUse])
|
||||
{
|
||||
// Start timer if not running.
|
||||
if (AnticampData[dataindex][Anticamp_Timer] == INVALID_HANDLE)
|
||||
{
|
||||
// Get interval.
|
||||
interval = AnticampData[dataindex][Anticamp_Interval];
|
||||
|
||||
// Validate interval.
|
||||
if (interval > 0.0)
|
||||
{
|
||||
AnticampData[dataindex][Anticamp_Timer] = CreateTimer(interval, Event_VolAnticampTrigger, _, TIMER_REPEAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event callback. Stops existing anticamp timer on a volume.
|
||||
*/
|
||||
VolAnticampDisable(volumeIndex)
|
||||
{
|
||||
new Handle:timerbuffer;
|
||||
|
||||
// Validate index.
|
||||
if (!VolIsValidIndex(volumeIndex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get data index.
|
||||
new dataindex = Volumes[volumeIndex][Vol_DataIndex];
|
||||
|
||||
// Validate data index.
|
||||
if (!VolAnticampValidateIndex(dataindex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if in use.
|
||||
if (AnticampData[dataindex][Anticamp_InUse])
|
||||
{
|
||||
// Stop timer.
|
||||
timerbuffer = AnticampData[dataindex][Anticamp_Timer];
|
||||
if (timerbuffer != INVALID_HANDLE)
|
||||
{
|
||||
KillTimer(timerbuffer);
|
||||
AnticampData[dataindex][Anticamp_Timer] = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Vol state", "Disabled anticamp volume %d.", volumeIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all existing anticamp timers.
|
||||
*/
|
||||
stock VolAnticampDisableAll()
|
||||
{
|
||||
new Handle:timerbuffer;
|
||||
|
||||
// Loop through all volumes.
|
||||
for (new dataindex = 0; dataindex < ZR_VOLUMES_MAX; dataindex++)
|
||||
{
|
||||
// Check if in use.
|
||||
if (AnticampData[dataindex][Anticamp_InUse])
|
||||
{
|
||||
// Stop timer.
|
||||
timerbuffer = AnticampData[dataindex][Anticamp_Timer];
|
||||
if (timerbuffer != INVALID_HANDLE)
|
||||
{
|
||||
KillTimer(timerbuffer);
|
||||
AnticampData[dataindex][Anticamp_Timer] = INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables feature and resets data to defaults at the specified index.
|
||||
*
|
||||
* @param dataIndex Local data index.
|
||||
*/
|
||||
VolAnticampReset(dataIndex)
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_InUse] = false;
|
||||
|
||||
AnticampData[dataIndex][Anticamp_Interval] = 1.0;
|
||||
if (AnticampData[dataIndex][Anticamp_Timer] != INVALID_HANDLE)
|
||||
{
|
||||
KillTimer(AnticampData[dataIndex][Anticamp_Timer]);
|
||||
AnticampData[dataIndex][Anticamp_Timer] = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
AnticampData[dataIndex][Anticamp_Action] = Anticamp_Damage;
|
||||
AnticampData[dataIndex][Anticamp_Amount] = 5.0;
|
||||
|
||||
AnticampData[dataIndex][Anticamp_Warning] = Anticamp_Chat;
|
||||
Format(String:AnticampData[dataIndex][Anticamp_Message], 256, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization event for anticamp feature.
|
||||
*/
|
||||
VolAnticampInit()
|
||||
{
|
||||
// Set default attributes.
|
||||
for (new dataindex = 0; dataindex < ZR_VOLUMES_MAX; dataindex++)
|
||||
{
|
||||
VolAnticampReset(dataindex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer callback for anticamp volumes. Applies actions on players in volumes.
|
||||
*/
|
||||
public Action:Event_VolAnticampTrigger(Handle:timer)
|
||||
{
|
||||
// Loop through all players.
|
||||
for (new client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
// Loop through all volumes.
|
||||
for (new volumeindex = 0; volumeindex < ZR_VOLUMES_MAX; volumeindex++)
|
||||
{
|
||||
// Check if the volume is enabled and in use.
|
||||
if (VolIsEnabled(volumeindex) && VolInUse(volumeindex))
|
||||
{
|
||||
// Check if player is in a anticamp volume.
|
||||
if (VolPlayerInVolume[client][volumeindex] && Volumes[volumeindex][Vol_Type] == VolFeature_Anticamp)
|
||||
{
|
||||
// Apply action.
|
||||
VolAnticampApplyAction(client, Volumes[volumeindex][Vol_DataIndex], volumeindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies action on a client for the specified volume.
|
||||
*
|
||||
* @param client The client index.
|
||||
* @param dataIndex Local data index.
|
||||
* @param volumeIndex The volume index.
|
||||
*/
|
||||
VolAnticampApplyAction(client, dataIndex, volumeIndex)
|
||||
{
|
||||
new Float:amount = AnticampData[dataIndex][Anticamp_Amount];
|
||||
|
||||
// Send warning message.
|
||||
VolAnticampWarnPlayer(client, dataIndex);
|
||||
|
||||
switch (AnticampData[dataIndex][Anticamp_Action])
|
||||
{
|
||||
case Anticamp_NoAction:
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
case Anticamp_Damage:
|
||||
{
|
||||
// Give damage to player. Kill if zero HP.
|
||||
new damage = RoundToNearest(amount);
|
||||
new health = GetClientHealth(client) - damage;
|
||||
decl String:name[64];
|
||||
decl String:buffer[256];
|
||||
|
||||
if (health > 0)
|
||||
{
|
||||
SetEntityHealth(client, health);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Health is zero or below. Kill player.
|
||||
ForcePlayerSuicide(client);
|
||||
|
||||
// Log event.
|
||||
GetClientName(client, name, sizeof(name));
|
||||
SetGlobalTransTarget(client);
|
||||
Format(buffer, sizeof(buffer), "%t", "Vol Slay", name, volumeIndex);
|
||||
|
||||
/*if (LogFlagCheck(LOG_GAME_EVENTS, LOG_MODULE_ANTICAMP)) ZR_LogMessageFormatted(client, "anticamp", "kill", "%s", true, buffer);
|
||||
if (anticamp_echo)
|
||||
{
|
||||
FormatTextString(buffer, sizeof(buffer));
|
||||
ZR_PrintToAdminChat(buffer);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
case Anticamp_Slay:
|
||||
{
|
||||
|
||||
}
|
||||
case Anticamp_Drug:
|
||||
{
|
||||
|
||||
}
|
||||
case Anticamp_Ignite:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a warning to the specified player for the specified volume.
|
||||
*
|
||||
* @param client The client index.
|
||||
* @param dataIndex Local data index.
|
||||
*/
|
||||
VolAnticampWarnPlayer(client, dataIndex)
|
||||
{
|
||||
decl String:buffer[256];
|
||||
new bool:custommessage = (strlen(AnticampData[dataIndex][Anticamp_Message]) > 0) ? true : false;
|
||||
|
||||
// Set language.
|
||||
SetGlobalTransTarget(client);
|
||||
|
||||
// Format message.
|
||||
if (custommessage)
|
||||
{
|
||||
// Use custom message.
|
||||
strcopy(buffer, sizeof(buffer), AnticampData[dataIndex][Anticamp_Message]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use message in translations file.
|
||||
Format(buffer, sizeof(buffer), "%t", "Vol Anticamp Message");
|
||||
}
|
||||
|
||||
switch (AnticampData[dataIndex][Anticamp_Warning])
|
||||
{
|
||||
case Anticamp_NoWarning:
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
case Anticamp_Chat:
|
||||
{
|
||||
// Apply ZR formatting and print chat message.
|
||||
TranslationPluginFormatString(buffer, sizeof(buffer));
|
||||
PrintToChat(client, buffer);
|
||||
}
|
||||
case Anticamp_Center:
|
||||
{
|
||||
// Print centered message.
|
||||
PrintCenterText(client, buffer);
|
||||
}
|
||||
case Anticamp_Menu:
|
||||
{
|
||||
// Display the message in a menu panel.
|
||||
new Handle:panel = CreatePanel();
|
||||
|
||||
SetPanelTitle(panel, "Zombie:Reloaded");
|
||||
DrawPanelItem(panel, "", ITEMDRAW_SPACER);
|
||||
DrawPanelItem(panel, buffer);
|
||||
DrawPanelItem(panel, "", ITEMDRAW_SPACER);
|
||||
|
||||
SetPanelCurrentKey(panel, 10);
|
||||
|
||||
Format(buffer, sizeof(buffer), "%t", "Exit");
|
||||
DrawPanelItem(panel, buffer, ITEMDRAW_CONTROL);
|
||||
|
||||
SendPanelToClient(panel, client, Handler_AnitcampDummy, 10);
|
||||
CloseHandle(panel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy handler for panel messages.
|
||||
*/
|
||||
public Handler_AnitcampDummy(Handle:menu, MenuAction:action, param1, param2)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first free anticamp data index.
|
||||
*
|
||||
* @return The first free anticamp data index if successful, or -1 if
|
||||
* there are no free volumes.
|
||||
*/
|
||||
VolAnticampGetFreeIndex()
|
||||
{
|
||||
// Loop through all indexes.
|
||||
for (new dataindex = 0; dataindex < ZR_VOLUMES_MAX; dataindex++)
|
||||
{
|
||||
// Check if it's free.
|
||||
if (!AnticampData[dataindex][Anticamp_InUse])
|
||||
{
|
||||
return dataindex;
|
||||
}
|
||||
}
|
||||
|
||||
// No free index found.
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates local data index.
|
||||
*
|
||||
* @param dataIndex Index to validate.
|
||||
* @return True if valid, false otherwise.
|
||||
*/
|
||||
bool:VolAnticampValidateIndex(dataIndex)
|
||||
{
|
||||
if (dataIndex >= 0 && dataIndex < ZR_VOLUMES_MAX)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps data to be used by zr_vol_list command.
|
||||
*
|
||||
* @param dataIndex Index in anticamp data array.
|
||||
* @param buffer Destination string buffer.
|
||||
* @param maxlen Size of destination buffer.
|
||||
* @return Number of cells written.
|
||||
*/
|
||||
VolAnticampDumpData(dataIndex, String:buffer[], maxlen)
|
||||
{
|
||||
decl String:linebuffer[128];
|
||||
decl String:valuebuffer[256];
|
||||
new anticampcache[VolTypeAnticamp];
|
||||
new cellswritten;
|
||||
|
||||
// Validate index.
|
||||
if (!VolAnticampValidateIndex(dataIndex))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize and clear buffer.
|
||||
buffer[0] = 0;
|
||||
|
||||
// Cache data.
|
||||
anticampcache = AnticampData[dataIndex];
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "Interval: %.2f\n", anticampcache[Anticamp_Interval]);
|
||||
cellswritten += StrCat(buffer, maxlen, linebuffer);
|
||||
|
||||
VolAnticampActionToString(anticampcache[Anticamp_Action], valuebuffer, sizeof(valuebuffer));
|
||||
Format(linebuffer, sizeof(linebuffer), "Action: %s\n", valuebuffer);
|
||||
cellswritten += StrCat(buffer, maxlen, linebuffer);
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "Action amount: %.2f\n", anticampcache[Anticamp_Amount]);
|
||||
cellswritten += StrCat(buffer, maxlen, linebuffer);
|
||||
|
||||
VolAnticampWarningToString(anticampcache[Anticamp_Warning], valuebuffer, sizeof(valuebuffer));
|
||||
Format(linebuffer, sizeof(linebuffer), "Warning type: %s\n", valuebuffer);
|
||||
cellswritten += StrCat(buffer, maxlen, linebuffer);
|
||||
|
||||
strcopy(valuebuffer, sizeof(valuebuffer), anticampcache[Anticamp_Message]);
|
||||
Format(linebuffer, sizeof(linebuffer), "Warning message: \"%s\"\n", valuebuffer);
|
||||
cellswritten += StrCat(buffer, maxlen, linebuffer);
|
||||
|
||||
return cellswritten;
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* *
|
||||
* CONVERTING FUNCTIONS *
|
||||
* *
|
||||
**************************************/
|
||||
|
||||
/**
|
||||
* Converts a action type to a string.
|
||||
*
|
||||
* @param actionType Action type to convert.
|
||||
* @param buffer Destination string buffer.
|
||||
* @param maxlen Size of destination buffer.
|
||||
* @param shortName Optional. Write short name or human readable name.
|
||||
* Default is human readable (false).
|
||||
* @return Number of cells written.
|
||||
*/
|
||||
VolAnticampActionToString(VolAnticampAction:actionType, String:buffer[], maxlen, bool:shortName = false)
|
||||
{
|
||||
switch (actionType)
|
||||
{
|
||||
case Anticamp_NoAction:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "none") : strcopy(buffer, maxlen, "No action");
|
||||
}
|
||||
case Anticamp_Damage:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "damage") : strcopy(buffer, maxlen, "Damage player");
|
||||
}
|
||||
case Anticamp_Drug:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "drug") : strcopy(buffer, maxlen, "Drug player ");
|
||||
}
|
||||
case Anticamp_Ignite:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "ignite") : strcopy(buffer, maxlen, "Ignite player");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a action string type to a action type.
|
||||
*
|
||||
* @param action Action string type to convert.
|
||||
* @return Action type or Anticamp_NoAction if failed.
|
||||
*/
|
||||
stock VolAnticampAction:VolAnticampStringToAction(const String:action[])
|
||||
{
|
||||
// Check if empty.
|
||||
if (strlen(action) == 0)
|
||||
{
|
||||
return Anticamp_NoAction;
|
||||
}
|
||||
|
||||
if (StrEqual(action, "none", false))
|
||||
{
|
||||
return Anticamp_NoWarning;
|
||||
}
|
||||
else if (StrEqual(action, "damage", false))
|
||||
{
|
||||
return Anticamp_Damage;
|
||||
}
|
||||
else if (StrEqual(action, "drug", false))
|
||||
{
|
||||
return Anticamp_Drug;
|
||||
}
|
||||
else if (StrEqual(action, "ignite", false))
|
||||
{
|
||||
return Anticamp_Ignite;
|
||||
}
|
||||
|
||||
// No match.
|
||||
return Anticamp_NoAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a warning type to a string.
|
||||
*
|
||||
* @param warningType Warning type to convert.
|
||||
* @param buffer Destination string buffer.
|
||||
* @param maxlen Size of destination buffer.
|
||||
* @param shortName Optional. Write short name or human readable name.
|
||||
* Default is human readable (false).
|
||||
* @return Number of cells written.
|
||||
*/
|
||||
VolAnticampWarningToString(VolAnticampeWarningType:warningType, String:buffer[], maxlen, bool:shortName = false)
|
||||
{
|
||||
switch (warningType)
|
||||
{
|
||||
case Anticamp_NoWarning:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "none") : strcopy(buffer, maxlen, "No warning");
|
||||
}
|
||||
case Anticamp_Chat:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "chat") : strcopy(buffer, maxlen, "Chat area");
|
||||
}
|
||||
case Anticamp_Center:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "center") : strcopy(buffer, maxlen, "Centered message");
|
||||
}
|
||||
case Anticamp_Menu:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "meny") : strcopy(buffer, maxlen, "Message in menu panel");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a warning string type to a warning type.
|
||||
*
|
||||
* @param warning Warning string type to convert.
|
||||
* @return Warning type, or Anticamp_NoWarning if failed.
|
||||
*/
|
||||
stock VolAnticampeWarningType:VolAnticampStringToWarning(const String:warning[])
|
||||
{
|
||||
// Check if empty.
|
||||
if (strlen(warning) == 0)
|
||||
{
|
||||
return Anticamp_NoWarning;
|
||||
}
|
||||
|
||||
if (StrEqual(warning, "none", false))
|
||||
{
|
||||
return Anticamp_NoWarning;
|
||||
}
|
||||
else if (StrEqual(warning, "chat", false))
|
||||
{
|
||||
return Anticamp_Chat;
|
||||
}
|
||||
else if (StrEqual(warning, "center", false))
|
||||
{
|
||||
return Anticamp_Center;
|
||||
}
|
||||
else if (StrEqual(warning, "menu", false))
|
||||
{
|
||||
return Anticamp_Menu;
|
||||
}
|
||||
|
||||
// No match.
|
||||
return Anticamp_NoWarning;
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* *
|
||||
* ATTRIBUTE FUNCTIONS *
|
||||
* *
|
||||
**************************************/
|
||||
|
||||
/**
|
||||
* Sets anticamp spesific attributes on a anticamp volume.
|
||||
*
|
||||
* @param dataIndex Local data index.
|
||||
* @param attribName Attribute to modify.
|
||||
* @param attribVlue Attribute value to set.
|
||||
* @return True if successfully set, false otherwise.
|
||||
*/
|
||||
bool:VolAnticampSetAttribute(dataIndex, const String:attribName[], const String:attribValue[])
|
||||
{
|
||||
// Validate data index.
|
||||
if (!VolAnticampValidateIndex(dataIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check attribute names.
|
||||
if (StrEqual(attribName, "interval", false))
|
||||
{
|
||||
if (VolAnticampSetIntervalString(dataIndex, attribValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (StrEqual(attribName, "action", false))
|
||||
{
|
||||
if (VolAnticampSetActionString(dataIndex, attribValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (StrEqual(attribName, "amount", false))
|
||||
{
|
||||
if (VolAnticampSetAmountString(dataIndex, attribValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (StrEqual(attribName, "warning", false))
|
||||
{
|
||||
if (VolAnticampSetWarningString(dataIndex, attribValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (StrEqual(attribName, "message", false))
|
||||
{
|
||||
// Unsupported because of technical limits in command parser. Spaces
|
||||
// and quoted strings aren't supported yet.
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a interval string value and applies it to the specified volume.
|
||||
*
|
||||
* @param dataIndex Local data index.
|
||||
* @param interval Interval to set. A floating point number formatted as a
|
||||
* string.
|
||||
* @return True if successfully set, false otherwise.
|
||||
*/
|
||||
bool:VolAnticampSetIntervalString(dataIndex, const String:interval[])
|
||||
{
|
||||
new Float:anticampinterval;
|
||||
|
||||
// Check if string value is empty.
|
||||
if (strlen(interval) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert value.
|
||||
anticampinterval = StringToFloat(interval);
|
||||
|
||||
// Apply value.
|
||||
AnticampData[dataIndex][Anticamp_Interval] = anticampinterval;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a action type string value and applies it to the specified volume.
|
||||
*
|
||||
* @param dataIndex Local data index.
|
||||
* @param action Action type to set.
|
||||
* @return True if successfully set, false otherwise.
|
||||
*/
|
||||
bool:VolAnticampSetActionString(dataIndex, const String:action[])
|
||||
{
|
||||
// Check if string value is empty.
|
||||
if (strlen(action) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check effect string values and apply them to the volume.
|
||||
if (StrEqual(action, "none", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Action] = Anticamp_NoAction;
|
||||
return true;
|
||||
}
|
||||
else if (StrEqual(action, "damage", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Action] = Anticamp_Damage;
|
||||
return true;
|
||||
}
|
||||
else if (StrEqual(action, "slay", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Action] = Anticamp_Slay;
|
||||
return true;
|
||||
}
|
||||
else if (StrEqual(action, "drug", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Action] = Anticamp_Drug;
|
||||
return true;
|
||||
}
|
||||
else if (StrEqual(action, "ignite", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Action] = Anticamp_Ignite;
|
||||
return true;
|
||||
}
|
||||
|
||||
// The string value didn't match any valid action types.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a action amount string value and applies it to the specified volume.
|
||||
*
|
||||
* @param dataIndex Local data index.
|
||||
* @param amount Amount to set. A floating point number formatted as a
|
||||
* string.
|
||||
* @return True if successfully set, false otherwise.
|
||||
*/
|
||||
bool:VolAnticampSetAmountString(dataIndex, const String:amount[])
|
||||
{
|
||||
new Float:actionamount;
|
||||
|
||||
// Check if string value is empty.
|
||||
if (strlen(amount) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert value.
|
||||
actionamount = StringToFloat(amount);
|
||||
|
||||
// Apply value.
|
||||
AnticampData[dataIndex][Anticamp_Amount] = actionamount;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a warning type string value and applies it to the specified volume.
|
||||
*
|
||||
* @param dataIndex Local data index.
|
||||
* @param warning warning type to set.
|
||||
* @return True if successfully set, false otherwise.
|
||||
*/
|
||||
bool:VolAnticampSetWarningString(dataIndex, const String:warning[])
|
||||
{
|
||||
|
||||
// Check if string value is empty.
|
||||
if (strlen(warning) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check effect string values and apply them to the volume.
|
||||
if (StrEqual(warning, "none", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Warning] = Anticamp_NoWarning;
|
||||
return true;
|
||||
}
|
||||
else if (StrEqual(warning, "chat", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Warning] = Anticamp_Chat;
|
||||
return true;
|
||||
}
|
||||
else if (StrEqual(warning, "center", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Warning] = Anticamp_Center;
|
||||
return true;
|
||||
}
|
||||
else if (StrEqual(warning, "menu", false))
|
||||
{
|
||||
AnticampData[dataIndex][Anticamp_Warning] = Anticamp_Menu;
|
||||
return true;
|
||||
}
|
||||
|
||||
// The string value didn't match any valid action types.
|
||||
return false;
|
||||
}
|
||||
|
@ -49,9 +49,433 @@ Example:
|
||||
zr_vol_add 0 0 0 100 200 300 anticamp team=humans delay=5 effect=wireframe effect_color=255,0,0
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Creates commands for managing volumes.
|
||||
*/
|
||||
VolOnCommandsCreate()
|
||||
{
|
||||
RegAdminCmd("zr_vol_add", VolAddVolumeCommand, ADMFLAG_CONFIG, "Creates a rectangular volume in the map. Usage: zr_vol_add <x1> <y1> <z1> <x2> <y2> <z2> <type> [params]");
|
||||
RegAdminCmd("zr_vol_remove", VolRemoveVolumeCommand, ADMFLAG_CONFIG, "Removes an existing volume in the map. Usage: zr_vol_remove <volume index>");
|
||||
RegConsoleCmd("zr_vol_list", VolListCommand, "Lists existing volumes in the map, or dumps detail data to the specified volume. Usage: zr_vol_list [volume index]");
|
||||
RegConsoleCmd("zr_vol_dumpstates", VolDumpStatesCommand, "Dumps volume states for the specified player. Usage: zr_vol_dumpstates <index|targetname>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Command callback for creating a new volume.
|
||||
*/
|
||||
public Action:VolAddVolumeCommand(client, argc)
|
||||
{
|
||||
decl String:buffer[640];
|
||||
buffer[0] = 0;
|
||||
|
||||
if (argc < 7)
|
||||
{
|
||||
// Write syntax info.
|
||||
StrCat(buffer, sizeof(buffer), "Creates a rectangular volume in the map. Usage: zr_vol_add <x1> <y1> <z1> <x2> <y2> <z2> <type> [params]\n\n");
|
||||
StrCat(buffer, sizeof(buffer), "Parameters:\n");
|
||||
StrCat(buffer, sizeof(buffer), "x1, y1, z1 Coordinates to first corner (any corner)\n");
|
||||
StrCat(buffer, sizeof(buffer), "x2, y2, z2 Coordinates to oposite corner (diagonally to oposite height)\n");
|
||||
StrCat(buffer, sizeof(buffer), "type Volumetric feature type:\n");
|
||||
StrCat(buffer, sizeof(buffer), " anticamp\n");
|
||||
StrCat(buffer, sizeof(buffer), "params Parameter string with additional volume data. Generic parameters:\n");
|
||||
StrCat(buffer, sizeof(buffer), " teamfilter=all|humans|zombies\n");
|
||||
StrCat(buffer, sizeof(buffer), " delay=0\n");
|
||||
StrCat(buffer, sizeof(buffer), " effect=none|wireframe|smoke\n");
|
||||
StrCat(buffer, sizeof(buffer), " effect_color=0,0,0\n");
|
||||
StrCat(buffer, sizeof(buffer), " enabled=1");
|
||||
|
||||
ReplyToCommand(client, buffer);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
new Float:x1;
|
||||
new Float:y1;
|
||||
new Float:z1;
|
||||
new Float:x2;
|
||||
new Float:y2;
|
||||
new Float:z2;
|
||||
new Float:min[3];
|
||||
new Float:max[3];
|
||||
new VolumeFeatureTypes:voltype;
|
||||
new Float:floatbuffer;
|
||||
new volindex;
|
||||
new dataindex;
|
||||
new paramcount;
|
||||
|
||||
decl String:params[256];
|
||||
decl String:argbuffer[256];
|
||||
|
||||
params[0] = 0;
|
||||
|
||||
// Get a free volume index.
|
||||
volindex = VolGetFreeVolume();
|
||||
|
||||
// Validate index.
|
||||
if (!VolIsValidIndex(volindex))
|
||||
{
|
||||
ReplyToCommand(client, "Cannot add volume. Maximum number of volumes reached.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Get positions.
|
||||
GetCmdArg(1, argbuffer, sizeof(argbuffer));
|
||||
x1 = StringToFloat(argbuffer);
|
||||
|
||||
GetCmdArg(2, argbuffer, sizeof(argbuffer));
|
||||
y1 = StringToFloat(argbuffer);
|
||||
|
||||
GetCmdArg(3, argbuffer, sizeof(argbuffer));
|
||||
z1 = StringToFloat(argbuffer);
|
||||
|
||||
GetCmdArg(4, argbuffer, sizeof(argbuffer));
|
||||
x2 = StringToFloat(argbuffer);
|
||||
|
||||
GetCmdArg(5, argbuffer, sizeof(argbuffer));
|
||||
y2 = StringToFloat(argbuffer);
|
||||
|
||||
GetCmdArg(6, argbuffer, sizeof(argbuffer));
|
||||
z2 = StringToFloat(argbuffer);
|
||||
|
||||
// Check if both locations are equal.
|
||||
if (FloatCompare(x1, x2) == 0)
|
||||
{
|
||||
if (FloatCompare(y1, y2) == 0)
|
||||
{
|
||||
if (FloatCompare(z1, z2) == 0)
|
||||
{
|
||||
ReplyToCommand(client, "Cannot add volume. Both locations are equal.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort out max and min values so 1-values are smaller.
|
||||
if (FloatCompare(x1, x2) == 1)
|
||||
{
|
||||
// x1 is bigger than x2. Swap values.
|
||||
floatbuffer = x1;
|
||||
x1 = x2;
|
||||
x2 = floatbuffer;
|
||||
}
|
||||
if (FloatCompare(y1, y2) == 1)
|
||||
{
|
||||
// y1 is bigger than y2. Swap values.
|
||||
floatbuffer = y1;
|
||||
y1 = y2;
|
||||
y2 = floatbuffer;
|
||||
}
|
||||
if (FloatCompare(z1, z2) == 1)
|
||||
{
|
||||
// z1 is bigger than z2. Swap values.
|
||||
floatbuffer = z1;
|
||||
z1 = z2;
|
||||
z2 = floatbuffer;
|
||||
}
|
||||
|
||||
// Copy coordinates to location vectors.
|
||||
min[0] = x1;
|
||||
min[1] = y1;
|
||||
min[2] = z1;
|
||||
max[0] = x2;
|
||||
max[1] = y2;
|
||||
max[2] = z2;
|
||||
|
||||
// Get volume type.
|
||||
GetCmdArg(7, argbuffer, sizeof(argbuffer));
|
||||
voltype = VolGetTypeFromString(argbuffer);
|
||||
|
||||
// Validate volume type.
|
||||
if (voltype == VolFeature_Invalid)
|
||||
{
|
||||
ReplyToCommand(client, "Cannot add volume. Invalid volume type: %s", argbuffer);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Get free data index for the specified type.
|
||||
dataindex = VolGetFreeDataIndex(voltype);
|
||||
|
||||
// Validate data index.
|
||||
if (dataindex < 0)
|
||||
{
|
||||
ReplyToCommand(client, "Cannot add volume. Out of free data indexes for type \"%s\"", argbuffer);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Add volume.
|
||||
volindex = VolAdd(volindex, min, max, voltype, dataindex);
|
||||
|
||||
// Get additional parameters if they exist.
|
||||
if (argc >= 8)
|
||||
{
|
||||
// Join the last parameters in a string.
|
||||
for (new arg = 8; arg <= argc; arg++)
|
||||
{
|
||||
GetCmdArg(arg, argbuffer, sizeof(argbuffer));
|
||||
StrCat(params, sizeof(params), argbuffer);
|
||||
|
||||
// Add space, except on the last parameter.
|
||||
if (arg < argc)
|
||||
{
|
||||
StrCat(params, sizeof(params), " ");
|
||||
}
|
||||
}
|
||||
|
||||
// Set attributes.
|
||||
paramcount = VolSetAttributes(volindex, params);
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Add volume", "Parsing parameter string. Param count = \"%d\". String = \"%s\"", paramcount, params);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No attributes set.
|
||||
paramcount = 0;
|
||||
}
|
||||
|
||||
if (paramcount < 1)
|
||||
{
|
||||
Format(buffer, sizeof(buffer), "No additional attributes set.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Format(buffer, sizeof(buffer), "Additional attributes set: %d", paramcount);
|
||||
}
|
||||
|
||||
ReplyToCommand(client, "Added volume at index %d. %s", volindex, buffer);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command callback for removing a volume.
|
||||
*/
|
||||
public Action:VolRemoveVolumeCommand(client, argc)
|
||||
{
|
||||
decl String:arg[16];
|
||||
new volindex;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
// Write syntax info.
|
||||
ReplyToCommand(client, "Removes an existing volume in the map. Usage: zr_vol_remove <volume index>");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Get volume index.
|
||||
GetCmdArg(1, arg, sizeof(arg));
|
||||
volindex = StringToInt(arg);
|
||||
|
||||
// Validate index.
|
||||
if (!VolIsValidIndex(volindex))
|
||||
{
|
||||
ReplyToCommand(client, "Invalid volume index.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Check if volume exist.
|
||||
if (!Volumes[volindex][Vol_InUse])
|
||||
{
|
||||
ReplyToCommand(client, "Volume %d doesn't exist.", volindex);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Remove volume.
|
||||
VolRemove(volindex);
|
||||
|
||||
ReplyToCommand(client, "Successfully disabled and removed volume %d.", volindex);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command callback for listing volumes or dumping data.
|
||||
*/
|
||||
public Action:VolListCommand(client, argc)
|
||||
{
|
||||
decl String:buffer[1022]; // Two chars reserved for newline and null terminator.
|
||||
decl String:linebuffer[128];
|
||||
decl String:valuebuffer[32];
|
||||
decl String:arg[16];
|
||||
|
||||
buffer[0] = 0;
|
||||
linebuffer[0] = 0;
|
||||
|
||||
new volindex;
|
||||
new volcount;
|
||||
new volcache[VolumeAttributes];
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
// No volume specified. Display syntax and list volumes.
|
||||
StrCat(buffer, sizeof(buffer), "Lists existing volumes in the map, or dumps detail data to the specified volume. Usage: zr_vol_list [volume index]\n\n");
|
||||
StrCat(buffer, sizeof(buffer), "ID: Type: Min loc: Max loc:\n");
|
||||
StrCat(buffer, sizeof(buffer), "--------------------------------------------------------------------------------");
|
||||
ReplyToCommand(client, buffer);
|
||||
|
||||
// Loop through all indexes.
|
||||
for (volindex = 0; volindex < ZR_VOLUMES_MAX; volindex++)
|
||||
{
|
||||
// Check if in use.
|
||||
if (Volumes[volindex][Vol_InUse])
|
||||
{
|
||||
// Cache volume data.
|
||||
volcache = Volumes[volindex];
|
||||
|
||||
// Add to list.
|
||||
VolTypeToString(volcache[Vol_Type], valuebuffer, sizeof(valuebuffer), true);
|
||||
Format(linebuffer, sizeof(linebuffer), "%-4d %-15s %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f",
|
||||
volindex,
|
||||
valuebuffer,
|
||||
volcache[Vol_xMin],
|
||||
volcache[Vol_yMin],
|
||||
volcache[Vol_zMin],
|
||||
volcache[Vol_xMax],
|
||||
volcache[Vol_yMax],
|
||||
volcache[Vol_zMax]);
|
||||
|
||||
ReplyToCommand(client, linebuffer);
|
||||
volcount++;
|
||||
}
|
||||
}
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "\nTotal volumes: %d", volcount);
|
||||
ReplyToCommand(client, linebuffer);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dump data for the specified volume.
|
||||
|
||||
// Get volume index.
|
||||
GetCmdArg(1, arg, sizeof(arg));
|
||||
volindex = StringToInt(arg);
|
||||
|
||||
// Validate index.
|
||||
if (!VolIsValidIndex(volindex))
|
||||
{
|
||||
ReplyToCommand(client, "The specified volume index is invalid: %d", volindex);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Check if unused.
|
||||
if (!VolInUse(volindex))
|
||||
{
|
||||
ReplyToCommand(client, "The specified volume doesn't exist: %d.", volindex);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Cache volume data.
|
||||
volcache = Volumes[volindex];
|
||||
|
||||
// Dump generic volume data.
|
||||
Format(linebuffer, sizeof(linebuffer), "Volume data at index %d:\n", volindex);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
StrCat(buffer, sizeof(buffer), "--------------------------------------------------------------------------------");
|
||||
ReplyToCommand(client, buffer);
|
||||
|
||||
// Clear buffer.
|
||||
buffer[0] = 0;
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "ID: %d\n", volindex);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "Enabled: %d\n", volcache[Vol_Enabled]);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
VolTypeToString(volcache[Vol_Type], valuebuffer, sizeof(valuebuffer));
|
||||
Format(linebuffer, sizeof(linebuffer), "Type: %s\n", valuebuffer);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "Min loc: %-8.2f %-8.2f %-8.2f\n", volcache[Vol_xMin], volcache[Vol_yMin], volcache[Vol_zMin]);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "Max loc: %-8.2f %-8.2f %-8.2f\n", volcache[Vol_xMax], volcache[Vol_yMax], volcache[Vol_zMax]);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
VolEffectToString(volcache[Vol_Effect], valuebuffer, sizeof(valuebuffer));
|
||||
Format(linebuffer, sizeof(linebuffer), "Effect: %s\n", valuebuffer);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "Effect color: %d, %d, %d\n", volcache[Vol_EffectColor][0], volcache[Vol_EffectColor][1], volcache[Vol_EffectColor][2]);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
VolTeamToString(volcache[Vol_TeamFilter], valuebuffer, sizeof(valuebuffer));
|
||||
Format(linebuffer, sizeof(linebuffer), "Team filter: %s\n", valuebuffer);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
Format(linebuffer, sizeof(linebuffer), "Trigger delay: %.2f", volcache[Vol_TriggerDelay]);
|
||||
StrCat(buffer, sizeof(buffer), linebuffer);
|
||||
|
||||
// Print generic attributes.
|
||||
ReplyToCommand(client, buffer);
|
||||
|
||||
// Clear buffer.
|
||||
buffer[0] = 0;
|
||||
|
||||
// Get type spesific attributes.
|
||||
switch (volcache[Vol_Type])
|
||||
{
|
||||
case VolFeature_Anticamp:
|
||||
{
|
||||
VolAnticampDumpData(volcache[Vol_DataIndex], buffer, sizeof(buffer));
|
||||
}
|
||||
case VolFeature_Knockback:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Print type spesific attributes if any.
|
||||
if (strlen(buffer) > 0)
|
||||
{
|
||||
ReplyToCommand(client, buffer);
|
||||
}
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
}
|
||||
|
||||
public Action:VolDumpStatesCommand(client, argc)
|
||||
{
|
||||
decl String:target[64];
|
||||
new targetclient;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
ReplyToCommand(client, "Dumps volume states for the specified player. Usage: zr_vol_dumpstates <index|targetname>");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Get target.
|
||||
GetCmdArg(1, target, sizeof(target));
|
||||
targetclient = FindTarget(client, target);
|
||||
|
||||
// Validate target.
|
||||
if (targetclient <= 0)
|
||||
{
|
||||
// Note: FindTarget automatically print error messages.
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Print header.
|
||||
ReplyToCommand(client, "Volume ID: Player in volume:\n----------------------------------------");
|
||||
|
||||
// Get player states.
|
||||
new bool:statebuffer[ZR_VOLUMES_MAX];
|
||||
VolGetPlayerStates(targetclient, statebuffer, sizeof(statebuffer));
|
||||
|
||||
// Set language.
|
||||
SetGlobalTransTarget(client);
|
||||
|
||||
// Loop through each volume.
|
||||
for (new volumeindex = 0; volumeindex < ZR_VOLUMES_MAX; volumeindex++)
|
||||
{
|
||||
// Check if volume is in use.
|
||||
if (VolInUse(volumeindex))
|
||||
{
|
||||
// Dump state.
|
||||
ReplyToCommand(client, "%-11d %t", volumeindex, statebuffer[volumeindex] ? "Yes" : "No");
|
||||
}
|
||||
}
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,6 +483,7 @@ public Action:VolAddVolumeCommand(client, argc)
|
||||
*
|
||||
* Note: Extra volume attributes must be set using VolSetAttributes.
|
||||
*
|
||||
* @param index Optional. Add volume at the specified index.
|
||||
* @param locMin Minimum x, y and z values.
|
||||
* @param locMax Maximum x, y and z values.
|
||||
* @param volumeType Specifies the volumetric feature type.
|
||||
@ -66,39 +491,43 @@ public Action:VolAddVolumeCommand(client, argc)
|
||||
*
|
||||
* @return The new volume index, or -1 if failed.
|
||||
*/
|
||||
VolAdd(Float:locMin[3], Float:locMax[3], VolumeFeatureTypes:volumeType, dataIndex)
|
||||
VolAdd(volumeIndex = -1, Float:locMin[3], Float:locMax[3], VolumeFeatureTypes:volumeType, dataIndex)
|
||||
{
|
||||
new volumeIndex;
|
||||
|
||||
// Get a free volume index.
|
||||
volumeIndex = VolGetFreeVolume();
|
||||
if (volumeIndex < 0)
|
||||
{
|
||||
// Get a free volume index.
|
||||
volumeIndex = VolGetFreeVolume();
|
||||
}
|
||||
|
||||
// Validate index.
|
||||
if (volumeIndex >= 0)
|
||||
if (VolIsValidIndex(volumeIndex))
|
||||
{
|
||||
// Mark volume as enabled and in use.
|
||||
Volumes[volumeIndex][vol_enabled] = true;
|
||||
Volumes[volumeIndex][vol_in_use] = true;
|
||||
Volumes[volumeIndex][Vol_Enabled] = true;
|
||||
Volumes[volumeIndex][Vol_InUse] = true;
|
||||
|
||||
// Set location data.
|
||||
Volumes[volumeIndex][vol_x_min] = locMin[0];
|
||||
Volumes[volumeIndex][vol_y_min] = locMin[1];
|
||||
Volumes[volumeIndex][vol_z_min] = locMin[2];
|
||||
Volumes[volumeIndex][Vol_xMin] = locMin[0];
|
||||
Volumes[volumeIndex][Vol_yMin] = locMin[1];
|
||||
Volumes[volumeIndex][Vol_zMin] = locMin[2];
|
||||
|
||||
Volumes[volumeIndex][vol_x_max] = locMax[0];
|
||||
Volumes[volumeIndex][vol_y_max] = locMax[1];
|
||||
Volumes[volumeIndex][vol_z_max] = locMax[2];
|
||||
Volumes[volumeIndex][Vol_xMax] = locMax[0];
|
||||
Volumes[volumeIndex][Vol_yMax] = locMax[1];
|
||||
Volumes[volumeIndex][Vol_zMax] = locMax[2];
|
||||
|
||||
// Set type.
|
||||
Volumes[volumeIndex][vol_type] = volumeType;
|
||||
Volumes[volumeIndex][vol_data_index] = dataIndex;
|
||||
Volumes[volumeIndex][Vol_Type] = volumeType;
|
||||
Volumes[volumeIndex][Vol_DataIndex] = dataIndex;
|
||||
|
||||
// Update number of volumes.
|
||||
VolumeCount++;
|
||||
|
||||
// Return the new index.
|
||||
return volumeIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No free volumes.
|
||||
// No free volumes or invalid index.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -112,14 +541,22 @@ VolAdd(Float:locMin[3], Float:locMax[3], VolumeFeatureTypes:volumeType, dataInde
|
||||
bool:VolRemove(volumeIndex)
|
||||
{
|
||||
// Validate index.
|
||||
if (volumeIndex >= 0)
|
||||
if (VolIsValidIndex(volumeIndex))
|
||||
{
|
||||
// Trigger event.
|
||||
VolOnVolumeDisabled(volumeIndex);
|
||||
// Trigger event to clean up data and stop timers.
|
||||
VolOnDisabled(volumeIndex);
|
||||
|
||||
// Mark volume as disabled and unused.
|
||||
Volumes[volumeIndex][vol_enabled] = false;
|
||||
Volumes[volumeIndex][vol_in_use] = false;
|
||||
// Clear feature data.
|
||||
switch (Volumes[volumeIndex][Vol_Type])
|
||||
{
|
||||
case VolFeature_Anticamp:
|
||||
{
|
||||
VolAnticampReset(Volumes[volumeIndex][Vol_DataIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear volume data.
|
||||
VolClear(volumeIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -130,6 +567,31 @@ bool:VolRemove(volumeIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears volume data at the specified index.
|
||||
*
|
||||
* @param volumeIndex The volume index.
|
||||
*/
|
||||
VolClear(volumeIndex)
|
||||
{
|
||||
Volumes[volumeIndex][Vol_Enabled] = false;
|
||||
Volumes[volumeIndex][Vol_InUse] = false;
|
||||
|
||||
Volumes[volumeIndex][Vol_xMin] = 0.0;
|
||||
Volumes[volumeIndex][Vol_yMin] = 0.0;
|
||||
Volumes[volumeIndex][Vol_zMin] = 0.0;
|
||||
|
||||
Volumes[volumeIndex][Vol_xMax] = 0.0;
|
||||
Volumes[volumeIndex][Vol_yMax] = 0.0;
|
||||
Volumes[volumeIndex][Vol_zMax] = 0.0;
|
||||
|
||||
Volumes[volumeIndex][Vol_Type] = VolFeature_Invalid;
|
||||
Volumes[volumeIndex][Vol_DataIndex] = -1;
|
||||
|
||||
Volumes[volumeIndex][Vol_TeamFilter] = VolTeam_All;
|
||||
Volumes[volumeIndex][Vol_TriggerDelay] = 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets extra attributes on a volume.
|
||||
*
|
||||
@ -142,6 +604,8 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
{
|
||||
new attribCount;
|
||||
new successfulCount;
|
||||
new VolumeFeatureTypes:voltype;
|
||||
new dataindex;
|
||||
decl String:attribName[64];
|
||||
decl String:attribValue[256];
|
||||
|
||||
@ -160,8 +624,14 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get volumetric feature type.
|
||||
voltype = Volumes[volumeIndex][Vol_Type];
|
||||
|
||||
// Get feature data index.
|
||||
dataindex = Volumes[volumeIndex][Vol_DataIndex];
|
||||
|
||||
// Loop through all attributes.
|
||||
for (new attrib = 0; attrib > attribCount; attrib++)
|
||||
for (new attrib = 0; attrib < attribCount; attrib++)
|
||||
{
|
||||
// Get attribute name.
|
||||
GetParameterName(attribName, sizeof(attribName), attributes, attrib);
|
||||
@ -169,8 +639,10 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
// Get attribute value.
|
||||
GetParameterValue(attribValue, sizeof(attribValue), attributes, attribName);
|
||||
|
||||
// Check names and set volume attributes.
|
||||
if (strcmp(attribName, "team", false))
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Set attribute", "Got parameter: \"%s\" = \"%s\"", attribName, attribValue);
|
||||
|
||||
// Check generic attributes.
|
||||
if (StrEqual(attribName, "teamfilter", false))
|
||||
{
|
||||
// Parse team string value.
|
||||
if (VolSetTeamString(volumeIndex, attribValue))
|
||||
@ -178,7 +650,7 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
successfulCount++;
|
||||
}
|
||||
}
|
||||
else if (strcmp(attribName, "delay", false))
|
||||
else if (StrEqual(attribName, "delay", false))
|
||||
{
|
||||
// Parse delay string value.
|
||||
if (VolSetDelayString(volumeIndex, attribValue))
|
||||
@ -186,7 +658,7 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
successfulCount++;
|
||||
}
|
||||
}
|
||||
else if (strcmp(attribName, "effect", false))
|
||||
else if (StrEqual(attribName, "effect", false))
|
||||
{
|
||||
// Parse effect string value.
|
||||
if (VolSetEffectString(volumeIndex, attribValue))
|
||||
@ -194,7 +666,7 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
successfulCount++;
|
||||
}
|
||||
}
|
||||
else if (strcmp(attribName, "effect_color", false))
|
||||
else if (StrEqual(attribName, "effect_color", false))
|
||||
{
|
||||
// Parse effect color string value.
|
||||
if (VolSetEffectColorString(volumeIndex, attribValue))
|
||||
@ -202,7 +674,7 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
successfulCount++;
|
||||
}
|
||||
}
|
||||
else if (strcmp(attribName, "enabled", false))
|
||||
else if (StrEqual(attribName, "enabled", false))
|
||||
{
|
||||
// Parse enabled string value.
|
||||
if (VolSetEnabledString(volumeIndex, attribValue))
|
||||
@ -210,16 +682,23 @@ VolSetAttributes(volumeIndex, const String:attributes[])
|
||||
successfulCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass attribute onto the volumetric feature attribute handler.
|
||||
else
|
||||
{
|
||||
switch (voltype)
|
||||
{
|
||||
case VolFeature_Anticamp:
|
||||
{
|
||||
if (VolAnticampSetAttribute(dataindex, attribName, attribValue))
|
||||
{
|
||||
successfulCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return number of successfully attributes set.
|
||||
return successfulCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates commands for managing volumes.
|
||||
*/
|
||||
VolOnCommandsCreate()
|
||||
{
|
||||
RegAdminCmd("zr_vol_add", VolAddVolumeCommand, ADMFLAG_GENERIC, "Adds a new volume. Usage: zr_vol_add <x1> <y1> <z1> <x2> <y2> <z2> <type> [params]");
|
||||
}
|
||||
|
@ -39,9 +39,11 @@ VolOnPlayerEnter(client, volumeIndex)
|
||||
// Volumetric features disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Event", "Player %N entered volume %d.", client, volumeIndex);
|
||||
|
||||
// Forward event to features.
|
||||
// VolAnticampStart(client, volume);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,8 +61,10 @@ VolOnPlayerLeave(client, volumeIndex)
|
||||
return;
|
||||
}
|
||||
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Event", "Player %N left volume %d.", client, volumeIndex);
|
||||
|
||||
// Forward event to features.
|
||||
// VolAnticampStop(client, volume);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,6 +110,9 @@ VolOnRoundStart()
|
||||
|
||||
// Start main timer.
|
||||
VolStartUpdateTimer();
|
||||
|
||||
// Start volumes.
|
||||
VolEnableVolumes();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,26 +123,42 @@ VolOnRoundEnd()
|
||||
// Stop main timer.
|
||||
VolStopUpdateTimer();
|
||||
|
||||
// Forward stop event to features.
|
||||
// VolAnticampStop();
|
||||
// Stop volumes.
|
||||
VolDisableVolumes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a volume is disabled.
|
||||
* @param volumeIndex The volume index.
|
||||
*/
|
||||
VolOnVolumeDisabled(volumeIndex)
|
||||
VolOnDisabled(volumeIndex)
|
||||
{
|
||||
// Forward stop event to features.
|
||||
new VolumeFeatureTypes:voltype = Volumes[volumeIndex][Vol_Type];
|
||||
|
||||
// Forward stop event to features.
|
||||
switch (voltype)
|
||||
{
|
||||
case VolFeature_Anticamp:
|
||||
{
|
||||
VolAnticampDisable(volumeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a volume is enabled.
|
||||
* @param volumeIndex The volume index.
|
||||
*/
|
||||
VolOnVolumeEnabled(volumeIndex)
|
||||
VolOnEnabled(volumeIndex)
|
||||
{
|
||||
// Forward start event to features.
|
||||
new VolumeFeatureTypes:voltype = Volumes[volumeIndex][Vol_Type];
|
||||
|
||||
// Forward stop event to features.
|
||||
switch (voltype)
|
||||
{
|
||||
case VolFeature_Anticamp:
|
||||
{
|
||||
VolAnticampEnable(volumeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,30 +36,30 @@
|
||||
enum VolumeAttributes
|
||||
{
|
||||
/* General */
|
||||
bool:vol_enabled, /** Volume state. */
|
||||
bool:vol_in_use, /** Marks if the volume is used. */
|
||||
bool:Vol_Enabled, /** Volume state. */
|
||||
bool:Vol_InUse, /** Marks if the volume is used. */
|
||||
|
||||
/* Location */
|
||||
Float:vol_x_min, /** Minimum x position. */
|
||||
Float:vol_x_max, /** Maximum x position. */
|
||||
Float:Vol_xMin, /** Minimum x position. */
|
||||
Float:Vol_xMax, /** Maximum x position. */
|
||||
|
||||
Float:vol_y_min, /** Minimum y position. */
|
||||
Float:vol_y_max, /** Maximum y position. */
|
||||
Float:Vol_yMin, /** Minimum y position. */
|
||||
Float:Vol_yMax, /** Maximum y position. */
|
||||
|
||||
Float:vol_z_min, /** Minimum z position. */
|
||||
Float:vol_z_max, /** Maximum z position. */
|
||||
Float:Vol_zMin, /** Minimum z position. */
|
||||
Float:Vol_zMax, /** Maximum z position. */
|
||||
|
||||
/* Style */
|
||||
VolumeEffects:vol_effect, /** Visual effect to apply on the volume. */
|
||||
vol_effect_color[3], /** Render color of the effect. RGB colors. */
|
||||
VolumeEffects:Vol_Effect, /** Visual effect to apply on the volume. */
|
||||
Vol_EffectColor[3], /** Render color of the effect. RGB colors. */
|
||||
|
||||
/* Data */
|
||||
VolumeFeatureTypes:vol_type, /** The volumetric feature type. */
|
||||
vol_data_index, /** Index in remote feature array. */
|
||||
VolumeFeatureTypes:Vol_Type, /** The volumetric feature type. */
|
||||
Vol_DataIndex, /** Index in remote feature array. */
|
||||
|
||||
/* Behaviour */
|
||||
VolumeTeamFilters:vol_team_filter, /** Team filtering. Trigger by certain teams, or all. */
|
||||
Float:vol_trigger_delay /** Trigger delay. How many seconds players have to stay to trigger volume events. */
|
||||
VolumeTeamFilters:Vol_TeamFilter, /** Team filtering. Trigger by certain teams, or all. */
|
||||
Float:Vol_TriggerDelay /** Trigger delay. How many seconds players have to stay to trigger volume events. */
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,7 +67,8 @@ enum VolumeAttributes
|
||||
*/
|
||||
enum VolumeFeatureTypes
|
||||
{
|
||||
VolFeature_Anticamp = 0,
|
||||
VolFeature_Invalid = 0,
|
||||
VolFeature_Anticamp,
|
||||
VolFeature_Knockback
|
||||
}
|
||||
|
||||
@ -106,6 +107,11 @@ new VolumeCount;
|
||||
*/
|
||||
new Float:VolPlayerLoc[MAXPLAYERS + 1][3];
|
||||
|
||||
/**
|
||||
* Cache that specifies if a player is in a volume or not.
|
||||
*/
|
||||
new bool:VolPlayerInVolume[MAXPLAYERS + 1][ZR_VOLUMES_MAX];
|
||||
|
||||
/**
|
||||
* Specifies whether the volumetric features module is enabled or not. Synced
|
||||
* with zr_vol CVAR.
|
||||
@ -121,7 +127,7 @@ new Float:VolPlayerCountDown[MAXPLAYERS + 1][ZR_VOLUMES_MAX];
|
||||
* The handle for a timer that updates player locations. This is the main timer
|
||||
* and any feature events can't be updated faster than this interval.
|
||||
*
|
||||
* Note: Some features may have its own timer.
|
||||
* Note: Some features may have its own timer for actions on players.
|
||||
*/
|
||||
new Handle:hVolUpdateTimer;
|
||||
|
||||
@ -138,6 +144,8 @@ new Float:VolTriggerInterval;
|
||||
#include "zr/volfeatures/volevents"
|
||||
#include "zr/volfeatures/volgenericattributes"
|
||||
#include "zr/volfeatures/volcommands"
|
||||
|
||||
// Sub features.
|
||||
#include "zr/volfeatures/volanticamp"
|
||||
|
||||
|
||||
@ -148,6 +156,9 @@ VolLoad()
|
||||
{
|
||||
// Cache CVAR value.
|
||||
VolEnabled = GetConVarBool(g_hCvarsList[CVAR_VOL]);
|
||||
|
||||
// Initialize sub features.
|
||||
VolAnticampInit();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,8 +168,51 @@ VolDisable()
|
||||
{
|
||||
VolEnabled = false;
|
||||
VolStopUpdateTimer();
|
||||
VolDisableVolumes();
|
||||
|
||||
// TODO: Send disable/stop event to volumes with their own timers.
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Disabled", "Volfeatures disabled.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Function alias for starting volumetric features.
|
||||
*/
|
||||
VolEnable()
|
||||
{
|
||||
VolEnabled = true;
|
||||
VolStartUpdateTimer();
|
||||
VolEnableVolumes();
|
||||
|
||||
LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Enabled", "Volfeatures enabled.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables all enabled volumes.
|
||||
*/
|
||||
VolDisableVolumes()
|
||||
{
|
||||
// Trigger disable event on all enabled volumes in use.
|
||||
for (new volindex = 0; volindex < ZR_VOLUMES_MAX; volindex++)
|
||||
{
|
||||
if (Volumes[volindex][Vol_InUse] && Volumes[volindex][Vol_Enabled])
|
||||
{
|
||||
VolOnDisabled(volindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables all disabled volumes.
|
||||
*/
|
||||
VolEnableVolumes()
|
||||
{
|
||||
// Trigger enable event on all volumes in use.
|
||||
for (new volindex = 0; volindex < ZR_VOLUMES_MAX; volindex++)
|
||||
{
|
||||
if (Volumes[volindex][Vol_InUse] && !Volumes[volindex][Vol_Enabled])
|
||||
{
|
||||
VolOnEnabled(volindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,7 +249,8 @@ bool:VolStartUpdateTimer()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Volumetric features disabled.
|
||||
// Volumetric features disabled.
|
||||
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Volfeatures, "Config Validation", "Warning: Console variable \"zr_vol_update_interval\" is set to zero or negative. Must be positive.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -236,7 +291,7 @@ bool:VolStartTriggerTimer()
|
||||
if (VolTriggerInterval > 0.0)
|
||||
{
|
||||
// Start the timer.
|
||||
hVolTriggerTimer = CreateTimer(VolTriggerInterval, Event_VolUpdateTimer, _, TIMER_REPEAT);
|
||||
hVolTriggerTimer = CreateTimer(VolTriggerInterval, Event_VolTriggerTimer, _, TIMER_REPEAT);
|
||||
|
||||
// Trigger timer started.
|
||||
return true;
|
||||
@ -244,6 +299,7 @@ bool:VolStartTriggerTimer()
|
||||
else
|
||||
{
|
||||
// Trigger timer not running. Either disabled or invalid interval.
|
||||
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Volfeatures, "Config Validation", "Warning: Console variable \"zr_vol_trigger_interval\" is set to zero or negative. Must be positive.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -302,7 +358,7 @@ VolResetCountDown(client = -1)
|
||||
*/
|
||||
VolUpdatePlayerLocation(client = -1)
|
||||
{
|
||||
if (client <= 0)
|
||||
if (client > 0)
|
||||
{
|
||||
// Assume the client is valid and save location in array.
|
||||
GetClientAbsOrigin(client, VolPlayerLoc[client]);
|
||||
@ -343,10 +399,11 @@ VolUpdatePlayerChanges()
|
||||
// Check if client is in game and alive.
|
||||
if (!IsClientConnected(client) || !IsClientInGame(client) || !IsPlayerAlive(client))
|
||||
{
|
||||
return;
|
||||
// Skip client.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the current volume states.
|
||||
// Get the current volume states based on player location cache.
|
||||
VolGetPlayerStates(client, volumeStates, sizeof(volumeStates));
|
||||
|
||||
// Update player location cache.
|
||||
@ -356,23 +413,37 @@ VolUpdatePlayerChanges()
|
||||
VolGetPlayerStates(client, volumeNewStates, sizeof(volumeNewStates));
|
||||
|
||||
// Loop through each volume and compare states.
|
||||
for (new volumeIndex = 0; volumeIndex < VolumeCount; volumeIndex++)
|
||||
for (new volumeIndex = 0; volumeIndex < ZR_VOLUMES_MAX; volumeIndex++)
|
||||
{
|
||||
// Check if the volume is disabled and unused.
|
||||
if (!VolInUse(volumeIndex) || !VolIsEnabled(volumeIndex))
|
||||
{
|
||||
// Skip volume.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check team filtering on the volume.
|
||||
if (!VolTeamFilterMatch(client, volumeIndex))
|
||||
{
|
||||
// Team filter mismatch.
|
||||
continue;
|
||||
}
|
||||
|
||||
newState = volumeNewStates[volumeIndex];
|
||||
oldState = volumeStates[volumeIndex];
|
||||
|
||||
// Compare new states with old states.
|
||||
// Check for no change.
|
||||
if (newState == oldState)
|
||||
{
|
||||
// No change. Skip to next volume.
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if client entered the volume.
|
||||
else if (!newState && oldState)
|
||||
if (newState && !oldState)
|
||||
{
|
||||
// Get trigger delay value.
|
||||
trigger_delay = Volumes[volumeIndex][vol_trigger_delay];
|
||||
trigger_delay = Volumes[volumeIndex][Vol_TriggerDelay];
|
||||
|
||||
// Check if the volume has a trigger delay.
|
||||
if (trigger_delay > 0.0)
|
||||
@ -382,17 +453,23 @@ VolUpdatePlayerChanges()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update cache.
|
||||
VolPlayerInVolume[client][volumeIndex] = true;
|
||||
|
||||
// No trigger delay, trigger event instantly.
|
||||
VolOnPlayerEnter(client, volumeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if client left the volume.
|
||||
else if (newState && !oldState)
|
||||
else if (!newState && oldState)
|
||||
{
|
||||
// Make sure count down value is reset.
|
||||
VolPlayerCountDown[client][volumeIndex] = -1.0;
|
||||
|
||||
// Update cache.
|
||||
VolPlayerInVolume[client][volumeIndex] = false;
|
||||
|
||||
// Trigger event.
|
||||
VolOnPlayerLeave(client, volumeIndex);
|
||||
}
|
||||
@ -401,20 +478,20 @@ VolUpdatePlayerChanges()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns wether a position is within a certain location.
|
||||
* Returns wether a point is within a certain location.
|
||||
*
|
||||
* @param loc The position to check.
|
||||
* @param point The point to check.
|
||||
* @param min Minimum x, y and z values of the location.
|
||||
* @param max Maximum x, y and z values of the location.
|
||||
* @return True if the position is within min and max values. False
|
||||
* otherwise.
|
||||
*/
|
||||
bool:IsPositionInLocation(Float:pos[3], Float:min[3], Float:max[3])
|
||||
bool:IsPointInLocation(Float:point[3], Float:min[3], Float:max[3])
|
||||
{
|
||||
// Cache location to avoid re-indexing arrays.
|
||||
new Float:posX = pos[0];
|
||||
new Float:posY = pos[1];
|
||||
new Float:posZ = pos[2];
|
||||
// Cache to avoid re-indexing arrays.
|
||||
new Float:posX = point[0];
|
||||
new Float:posY = point[1];
|
||||
new Float:posZ = point[2];
|
||||
|
||||
// Check if within x boundaries.
|
||||
if ((posX >= min[0]) && (posX <= max[0]))
|
||||
@ -425,13 +502,13 @@ bool:IsPositionInLocation(Float:pos[3], Float:min[3], Float:max[3])
|
||||
// Check if within x boundaries.
|
||||
if ((posZ >= min[2]) && (posZ <= max[2]))
|
||||
{
|
||||
// The player is within the location boundaries.
|
||||
// The point is within the location boundaries.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The player is outside the location boundaries.
|
||||
// The point is outside the location boundaries.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -443,9 +520,22 @@ bool:IsPositionInLocation(Float:pos[3], Float:min[3], Float:max[3])
|
||||
* @param volumeIndex The volume index.
|
||||
* @return True if in use, false otherwise.
|
||||
*/
|
||||
bool:VolIsInUse(volumeIndex)
|
||||
bool:VolInUse(volumeIndex)
|
||||
{
|
||||
return Volumes[volumeIndex][vol_in_use];
|
||||
return Volumes[volumeIndex][Vol_InUse];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns wether a volume is enabled or not.
|
||||
*
|
||||
* Note: Does not validate index.
|
||||
*
|
||||
* @param volumeIndex The volume index.
|
||||
* @return True if enabled, false otherwise.
|
||||
*/
|
||||
bool:VolIsEnabled(volumeIndex)
|
||||
{
|
||||
return Volumes[volumeIndex][Vol_Enabled];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -478,7 +568,7 @@ VolGetFreeVolume()
|
||||
for (new volumeIndex = 0; volumeIndex < ZR_VOLUMES_MAX; volumeIndex++)
|
||||
{
|
||||
// Check if it's free.
|
||||
if (!VolIsInUse(volumeIndex))
|
||||
if (!VolInUse(volumeIndex))
|
||||
{
|
||||
return volumeIndex;
|
||||
}
|
||||
@ -488,6 +578,69 @@ VolGetFreeVolume()
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a free index in the data array for the specified volume type.
|
||||
*
|
||||
* @param volumeType Volumetric feature type.
|
||||
* @return Data index, or -1 on error.
|
||||
*/
|
||||
VolGetFreeDataIndex(VolumeFeatureTypes:volumeType)
|
||||
{
|
||||
switch (volumeType)
|
||||
{
|
||||
case VolFeature_Anticamp:
|
||||
{
|
||||
return VolAnticampGetFreeIndex();
|
||||
}
|
||||
case VolFeature_Knockback:
|
||||
{
|
||||
// TOTO: Finish incomplete feature.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// No match.
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified client match the team filtering for the specified
|
||||
* volume.
|
||||
*
|
||||
* @param client The client index.
|
||||
* @param volumeIndex The volume to check team filtering on.
|
||||
* @return True if client pass the team filtering, false otherwise.
|
||||
*/
|
||||
bool:VolTeamFilterMatch(client, volumeIndex)
|
||||
{
|
||||
new VolumeTeamFilters:filter;
|
||||
|
||||
// Chache filter value.
|
||||
filter = Volumes[volumeIndex][Vol_TeamFilter];
|
||||
|
||||
switch (filter)
|
||||
{
|
||||
case VolTeam_All:
|
||||
{
|
||||
// All maches everyone.
|
||||
return true;
|
||||
}
|
||||
case VolTeam_Humans:
|
||||
{
|
||||
// Check if client is a human.
|
||||
return InfectIsClientHuman(client);
|
||||
}
|
||||
case VolTeam_Zombies:
|
||||
{
|
||||
// Check if client is a zombie.
|
||||
return InfectIsClientInfected(client);
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid filter value.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets wether a client is within volumes or not. Result is stored in a boolean
|
||||
* array.
|
||||
@ -506,25 +659,25 @@ VolGetPlayerStates(client, bool:buffer[], maxlen)
|
||||
new Float:volMaxBuffer[3];
|
||||
|
||||
// Loop through all available volumes.
|
||||
for (new volumeIndex = 0; volumeIndex < VolumeCount && volumeIndex < maxlen; volumeIndex++)
|
||||
for (new volumeIndex = 0; volumeIndex < ZR_VOLUMES_MAX && volumeIndex < maxlen; volumeIndex++)
|
||||
{
|
||||
if (VolIsInUse(volumeIndex))
|
||||
if (VolInUse(volumeIndex))
|
||||
{
|
||||
// Chache volume to avoid re-indexing.
|
||||
volumeBuffer = Volumes[volumeIndex];
|
||||
|
||||
// Get min positions.
|
||||
volMinBuffer[0] = volumeBuffer[vol_x_min];
|
||||
volMinBuffer[1] = volumeBuffer[vol_y_min];
|
||||
volMinBuffer[2] = volumeBuffer[vol_z_min];
|
||||
volMinBuffer[0] = volumeBuffer[Vol_xMin];
|
||||
volMinBuffer[1] = volumeBuffer[Vol_yMin];
|
||||
volMinBuffer[2] = volumeBuffer[Vol_zMin];
|
||||
|
||||
// Get max positions.
|
||||
volMaxBuffer[0] = volumeBuffer[vol_x_min];
|
||||
volMaxBuffer[1] = volumeBuffer[vol_y_min];
|
||||
volMaxBuffer[2] = volumeBuffer[vol_z_min];
|
||||
volMaxBuffer[0] = volumeBuffer[Vol_xMax];
|
||||
volMaxBuffer[1] = volumeBuffer[Vol_yMax];
|
||||
volMaxBuffer[2] = volumeBuffer[Vol_zMax];
|
||||
|
||||
// Check the cached player location.
|
||||
if (IsPositionInLocation(VolPlayerLoc[client], volMinBuffer, volMaxBuffer))
|
||||
if (IsPointInLocation(VolPlayerLoc[client], volMinBuffer, volMaxBuffer))
|
||||
{
|
||||
// Mark player as in volume.
|
||||
buffer[volumeIndex] = true;
|
||||
@ -541,6 +694,65 @@ VolGetPlayerStates(client, bool:buffer[], maxlen)
|
||||
return volCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string into a volumetric feature type.
|
||||
*
|
||||
* @param volType String to convert. Name of type.
|
||||
* @return Volumetric feature type or VolFeature_Invalid on error.
|
||||
*/
|
||||
VolumeFeatureTypes:VolGetTypeFromString(const String:volType[])
|
||||
{
|
||||
// Check if empty.
|
||||
if (strlen(volType) == 0)
|
||||
{
|
||||
return VolFeature_Invalid;
|
||||
}
|
||||
|
||||
// Match types.
|
||||
if (StrEqual(volType, "anticamp", false))
|
||||
{
|
||||
return VolFeature_Anticamp;
|
||||
}
|
||||
else if (StrEqual(volType, "knockback", false))
|
||||
{
|
||||
return VolFeature_Knockback;
|
||||
}
|
||||
|
||||
// No match.
|
||||
return VolFeature_Invalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a volume type to a string.
|
||||
*
|
||||
* @param volType Volume type to convert.
|
||||
* @param buffer Destination string buffer.
|
||||
* @param maxlen Size of destination buffer.
|
||||
* @param shortName Optional. Write short name or human readable name.
|
||||
* Default is human readable (false).
|
||||
* @return Number of cells written.
|
||||
*/
|
||||
VolTypeToString(VolumeFeatureTypes:volType, String:buffer[], maxlen, bool:shortName = false)
|
||||
{
|
||||
switch (volType)
|
||||
{
|
||||
case VolFeature_Invalid:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "") : strcopy(buffer, maxlen, "(none)");
|
||||
}
|
||||
case VolFeature_Anticamp:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "anticamp") : strcopy(buffer, maxlen, "Anti camp");
|
||||
}
|
||||
case VolFeature_Knockback:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "knockback") : strcopy(buffer, maxlen, "Knock back modifier");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for update timer. This is the main timer in volumetric features.
|
||||
*/
|
||||
@ -562,6 +774,13 @@ public Action:Event_VolTriggerTimer(Handle:timer)
|
||||
// Loop through all volumes.
|
||||
for (new volumeIndex = 0; volumeIndex < ZR_VOLUMES_MAX; volumeIndex++)
|
||||
{
|
||||
// Check if volume is in use and enabled.
|
||||
if (!VolInUse(volumeIndex) || !VolIsEnabled(volumeIndex))
|
||||
{
|
||||
// Not in use or enabled, skip volume.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get count down value.
|
||||
countDown = VolPlayerCountDown[client][volumeIndex];
|
||||
|
||||
@ -571,15 +790,21 @@ public Action:Event_VolTriggerTimer(Handle:timer)
|
||||
// Substract by trigger interval.
|
||||
countDown -= VolTriggerInterval;
|
||||
|
||||
// Check if zero or below.
|
||||
// Check if time is up.
|
||||
if (countDown <= 0.0)
|
||||
{
|
||||
// Update cache.
|
||||
VolPlayerInVolume[client][volumeIndex] = true;
|
||||
|
||||
// Trigger volume enter event.
|
||||
VolOnPlayerEnter(client, volumeIndex);
|
||||
|
||||
// Reset count down value.
|
||||
VolPlayerCountDown[client][volumeIndex] = -1.0;
|
||||
}
|
||||
|
||||
// Update count down value and continue.
|
||||
VolPlayerCountDown[client][volumeIndex] = countDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -595,10 +820,7 @@ public VolEnabledChanged(Handle:cvar, const String:oldvalue[], const String:newv
|
||||
if (isEnabled)
|
||||
{
|
||||
// Volumetric features is enabled.
|
||||
VolEnabled = true;
|
||||
|
||||
// Start timers.
|
||||
VolStartUpdateTimer();
|
||||
VolEnable();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -44,21 +44,21 @@ stock bool:VolSetTeamString(volumeIndex, const String:team[])
|
||||
}
|
||||
|
||||
// Convert value.
|
||||
if (strcmp(team, "all", false))
|
||||
if (StrEqual(team, "all", false))
|
||||
{
|
||||
teamfilter = VolTeam_All;
|
||||
}
|
||||
else if (strcmp(team, "humans", false))
|
||||
else if (StrEqual(team, "humans", false))
|
||||
{
|
||||
teamfilter = VolTeam_Humans;
|
||||
}
|
||||
else if (strcmp(team, "zombies", false))
|
||||
else if (StrEqual(team, "zombies", false))
|
||||
{
|
||||
teamfilter = VolTeam_Zombies;
|
||||
}
|
||||
|
||||
// Apply value.
|
||||
Volumes[volumeIndex][vol_team_filter] = teamfilter;
|
||||
Volumes[volumeIndex][Vol_TeamFilter] = teamfilter;
|
||||
return true;
|
||||
|
||||
}
|
||||
@ -71,7 +71,38 @@ stock bool:VolSetTeamString(volumeIndex, const String:team[])
|
||||
*/
|
||||
stock VolSetTeam(volumeIndex, VolumeTeamFilters:team[])
|
||||
{
|
||||
Volumes[volumeIndex][vol_team_filter] = team;
|
||||
Volumes[volumeIndex][Vol_TeamFilter] = team;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a team name type to a string.
|
||||
*
|
||||
* @param team Team type to convert.
|
||||
* @param buffer Destination string buffer.
|
||||
* @param maxlen Size of destination buffer.
|
||||
* @param shortName Optional. Write short name or human readable name.
|
||||
* Default is human readable (false).
|
||||
* @return Number of cells written.
|
||||
*/
|
||||
stock VolTeamToString(VolumeTeamFilters:team, String:buffer[], maxlen, bool:shortName = false)
|
||||
{
|
||||
switch (team)
|
||||
{
|
||||
case VolTeam_All:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "all") : strcopy(buffer, maxlen, "All");
|
||||
}
|
||||
case VolTeam_Humans:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "humans") : strcopy(buffer, maxlen, "Humans");
|
||||
}
|
||||
case VolTeam_Zombies:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "zombies") : strcopy(buffer, maxlen, "Zombies");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +127,7 @@ stock bool:VolSetDelayString(volumeIndex, const String:delay[])
|
||||
triggerdelay = StringToFloat(delay);
|
||||
|
||||
// Apply value.
|
||||
Volumes[volumeIndex][vol_trigger_delay] = triggerdelay;
|
||||
Volumes[volumeIndex][Vol_TriggerDelay] = triggerdelay;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -108,7 +139,7 @@ stock bool:VolSetDelayString(volumeIndex, const String:delay[])
|
||||
*/
|
||||
stock VolSetDelay(volumeIndex, Float:delay)
|
||||
{
|
||||
Volumes[volumeIndex][vol_trigger_delay] = delay;
|
||||
Volumes[volumeIndex][Vol_TriggerDelay] = delay;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,19 +159,19 @@ stock bool:VolSetEffectString(volumeIndex, const String:effect[])
|
||||
}
|
||||
|
||||
// Check effect string values and apply them to the volume.
|
||||
if (strcmp(effect, "none", false))
|
||||
if (StrEqual(effect, "none", false))
|
||||
{
|
||||
Volumes[volumeIndex][vol_effect] = VolEffect_None;
|
||||
Volumes[volumeIndex][Vol_Effect] = VolEffect_None;
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(effect, "wireframe", false))
|
||||
else if (StrEqual(effect, "wireframe", false))
|
||||
{
|
||||
Volumes[volumeIndex][vol_effect] = VolEffect_Wireframe;
|
||||
Volumes[volumeIndex][Vol_Effect] = VolEffect_Wireframe;
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(effect, "smoke", false))
|
||||
else if (StrEqual(effect, "smoke", false))
|
||||
{
|
||||
Volumes[volumeIndex][vol_effect] = VolEffect_Smoke;
|
||||
Volumes[volumeIndex][Vol_Effect] = VolEffect_Smoke;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,7 +187,38 @@ stock bool:VolSetEffectString(volumeIndex, const String:effect[])
|
||||
*/
|
||||
stock VolSetEffect(volumeIndex, VolumeEffects:effect)
|
||||
{
|
||||
Volumes[volumeIndex][vol_effect] = effect;
|
||||
Volumes[volumeIndex][Vol_Effect] = effect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a volume effect type to a string.
|
||||
*
|
||||
* @param effect Effect type to convert.
|
||||
* @param buffer Destination string buffer.
|
||||
* @param maxlen Size of destination buffer.
|
||||
* @param shortName Optional. Write short name or human readable name.
|
||||
* Default is human readable (false).
|
||||
* @return Number of cells written.
|
||||
*/
|
||||
stock VolEffectToString(VolumeEffects:effect, String:buffer[], maxlen, bool:shortName = false)
|
||||
{
|
||||
switch (effect)
|
||||
{
|
||||
case VolEffect_None:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "none") : strcopy(buffer, maxlen, "No effect");
|
||||
}
|
||||
case VolEffect_Wireframe:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "wireframe") : strcopy(buffer, maxlen, "Wire frame");
|
||||
}
|
||||
case VolEffect_Smoke:
|
||||
{
|
||||
return shortName ? strcopy(buffer, maxlen, "smoke") : strcopy(buffer, maxlen, "Smoke");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -187,9 +249,9 @@ stock bool:VolSetEffectColorString(volumeIndex, const String:effect_color[])
|
||||
blue = StringToInt(colors[2]);
|
||||
|
||||
// Apply values.
|
||||
Volumes[volumeIndex][vol_effect_color][0] = red;
|
||||
Volumes[volumeIndex][vol_effect_color][1] = green;
|
||||
Volumes[volumeIndex][vol_effect_color][2] = blue;
|
||||
Volumes[volumeIndex][Vol_EffectColor][0] = red;
|
||||
Volumes[volumeIndex][Vol_EffectColor][1] = green;
|
||||
Volumes[volumeIndex][Vol_EffectColor][2] = blue;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -227,31 +289,31 @@ stock bool:VolSetEnabledString(volumeIndex, const String:enabled[])
|
||||
new bool:val = bool:StringToInt(enabled);
|
||||
|
||||
// Check yes or no values first.
|
||||
if (strcmp(enabled, "yes", false) == 0)
|
||||
if (StrEqual(enabled, "yes", false))
|
||||
{
|
||||
val = true;
|
||||
}
|
||||
else if (strcmp(enabled, "no", false) == 0)
|
||||
else if (StrEqual(enabled, "no", false))
|
||||
{
|
||||
val = false;
|
||||
}
|
||||
|
||||
// Check if the new value is different from the current.
|
||||
if (Volumes[volumeIndex][vol_enabled] != val)
|
||||
if (Volumes[volumeIndex][Vol_Enabled] != val)
|
||||
{
|
||||
// Forward event.
|
||||
if (val)
|
||||
{
|
||||
VolOnVolumeEnabled(volumeIndex);
|
||||
VolOnEnabled(volumeIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
VolOnVolumeDisabled(volumeIndex);
|
||||
VolOnDisabled(volumeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply converted value.
|
||||
Volumes[volumeIndex][vol_enabled] = val;
|
||||
Volumes[volumeIndex][Vol_Enabled] = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -264,7 +326,7 @@ stock bool:VolSetEnabledString(volumeIndex, const String:enabled[])
|
||||
stock VolSetEnabled(volumeIndex, bool:enabled)
|
||||
{
|
||||
// Check if the new value is different from the current.
|
||||
if (Volumes[volumeIndex][vol_enabled] != enabled)
|
||||
if (Volumes[volumeIndex][Vol_Enabled] != enabled)
|
||||
{
|
||||
// Forward event.
|
||||
if (enabled)
|
||||
@ -277,5 +339,5 @@ stock VolSetEnabled(volumeIndex, bool:enabled)
|
||||
}
|
||||
}
|
||||
|
||||
Volumes[volumeIndex][vol_enabled] = enabled;
|
||||
Volumes[volumeIndex][Vol_Enabled] = enabled;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user