sm-zombiereloaded-3/src/zr/volfeatures/volcommands.inc
richard 3794251cc5 Updated all admin console commands to check if client is privileged (so group authentication works), instead of using RegAdminCmd. Minior fixes.
Changed admin teleport command to log target names.
Cached result of privilege check instead of calling function twice (zadmin menu).
Disabled old debug commands. Do not remove, we need them for testing later.
2009-10-26 23:17:22 +01:00

768 lines
23 KiB
SourcePawn

/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: volcommands.inc
* Type: Module
* Description: Command handler for volumetric features.
*
* 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/>.
*
* ============================================================================
*/
/*
Add volume
------------
Syntax:
zr_vol_add <x1> <y1> <z1> <x2> <y2> <z2> <type> [params]
Parameters:
zn, yn, zn Max and min location.
type Feature type.
params A string with optional parameters:
team=all|humans|zombies
delay=0
effect=none|wireframe|smoke
effect_color=0,0,0
enabled=1
Example:
zr_vol_add 0 0 0 100 200 300 anticamp team=humans delay=5 amount=100
*/
/**
* Creates commands for managing volumes.
*/
VolOnCommandsCreate()
{
RegConsoleCmd("zr_vol_add", VolAddVolumeCommand, "Creates a rectangular volume in the map. Usage: zr_vol_add <x1> <y1> <z1> <x2> <y2> <z2> <type> [params]");
RegConsoleCmd("zr_vol_remove", VolRemoveVolumeCommand, "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;
// Check if privileged.
if (!ZRIsClientPrivileged(client, OperationType_Configuration))
{
TranslationReplyToCommand(client, "No access to command");
return Plugin_Handled;
}
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), " classedit\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[512];
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);
}
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);
}
// Send enable event to volume.
VolOnEnabled(volindex);
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;
// Check if privileged.
if (!ZRIsClientPrivileged(client, OperationType_Configuration))
{
TranslationReplyToCommand(client, "No access to command");
return Plugin_Handled;
}
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_ClassEdit:
{
VolClassEditDumpData(volcache[Vol_DataIndex], buffer, sizeof(buffer));
}
}
// 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;
// Check if privileged.
if (!ZRIsClientPrivileged(client, OperationType_Generic))
{
TranslationReplyToCommand(client, "No access to command");
return Plugin_Handled;
}
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;
}
/**
* Creates a new volume with minimum parameters.
*
* 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.
* @param dataIndex Data index in remote array for feature data.
*
* @return The new volume index, or -1 if failed.
*/
VolAdd(volumeIndex = -1, Float:locMin[3], Float:locMax[3], VolumeFeatureTypes:volumeType, dataIndex)
{
if (volumeIndex < 0)
{
// Get a free volume index.
volumeIndex = VolGetFreeVolume();
}
// Validate index.
if (VolIsValidIndex(volumeIndex))
{
// Mark volume as enabled and in use.
Volumes[volumeIndex][Vol_Enabled] = true;
Volumes[volumeIndex][Vol_InUse] = true;
// Set location data.
Volumes[volumeIndex][Vol_xMin] = locMin[0];
Volumes[volumeIndex][Vol_yMin] = locMin[1];
Volumes[volumeIndex][Vol_zMin] = locMin[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_DataIndex] = dataIndex;
// Update number of volumes.
VolumeCount++;
// Return the new index.
return volumeIndex;
}
else
{
// No free volumes or invalid index.
return -1;
}
}
/**
* Removes the specified volume.
*
* @param volumeIndex The volume index.
* @return True if successful, false otherwise.
*/
bool:VolRemove(volumeIndex)
{
// Validate index.
if (VolIsValidIndex(volumeIndex))
{
// Trigger event to clean up data and stop timers.
VolOnDisabled(volumeIndex);
// Clear feature data.
switch (Volumes[volumeIndex][Vol_Type])
{
case VolFeature_Anticamp:
{
VolAnticampReset(Volumes[volumeIndex][Vol_DataIndex]);
}
}
// Clear volume data.
VolClear(volumeIndex);
return true;
}
else
{
// Invalid index.
return false;
}
}
/**
* 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_Effect] = VolEffect_None;
Volumes[volumeIndex][Vol_EffectColor][0] = 0;
Volumes[volumeIndex][Vol_EffectColor][1] = 0;
Volumes[volumeIndex][Vol_EffectColor][2] = 0;
new dataindex = Volumes[volumeIndex][Vol_DataIndex];
if (dataindex >= 0)
{
switch (Volumes[volumeIndex][Vol_Type])
{
case VolFeature_Anticamp:
{
VolAnticampReset(dataindex);
}
case VolFeature_ClassEdit:
{
VolClassEditReset(dataindex);
}
}
}
Volumes[volumeIndex][Vol_Type] = VolFeature_Invalid;
Volumes[volumeIndex][Vol_DataIndex] = -1;
Volumes[volumeIndex][Vol_TeamFilter] = VolTeam_All;
Volumes[volumeIndex][Vol_TriggerDelay] = 0.0;
}
/**
* Clears all volumes.
*/
VolClearAll()
{
for (new volindex = 0; volindex < ZR_VOLUMES_MAX; volindex++)
{
VolClear(volindex);
}
}
/**
* Sets extra attributes on a volume.
*
* @param volumeIndex The volume index.
* @param attributes A string with one or more attributes in key=value
* format.
* @return Number of successful attributes set, -1 on error.
*/
VolSetAttributes(volumeIndex, const String:attributes[])
{
new attribCount;
new successfulCount;
new VolumeFeatureTypes:voltype;
new dataindex;
decl String:attribName[64];
decl String:attribValue[256];
// Validate volume index.
if (!VolIsValidIndex(volumeIndex))
{
return -1;
}
// Count attributes.
attribCount = GetParameterCount(attributes);
// Check if empty.
if (!attribCount)
{
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++)
{
// Get attribute name.
GetParameterName(attribName, sizeof(attribName), attributes, attrib);
// Get attribute value.
GetParameterValue(attribValue, sizeof(attribValue), attributes, attribName);
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))
{
successfulCount++;
}
}
else if (StrEqual(attribName, "delay", false))
{
// Parse delay string value.
if (VolSetDelayString(volumeIndex, attribValue))
{
successfulCount++;
}
}
else if (StrEqual(attribName, "effect", false))
{
// Parse effect string value.
if (VolSetEffectString(volumeIndex, attribValue))
{
successfulCount++;
}
}
else if (StrEqual(attribName, "effect_color", false))
{
// Parse effect color string value.
if (VolSetEffectColorString(volumeIndex, attribValue))
{
successfulCount++;
}
}
else if (StrEqual(attribName, "enabled", false))
{
// Parse enabled string value.
if (VolSetEnabledString(volumeIndex, attribValue))
{
successfulCount++;
}
}
// Pass attribute onto the volumetric feature attribute handler.
else
{
switch (voltype)
{
case VolFeature_Anticamp:
{
if (VolAnticampSetAttribute(dataindex, attribName, attribValue))
{
successfulCount++;
}
}
case VolFeature_ClassEdit:
{
if (VolClassEditSetAttribute(dataindex, attribName, attribValue))
{
successfulCount++;
}
}
}
}
}
// Return number of successfully attributes set.
return successfulCount;
}