Made a anticamp feature with custom hurt volumes. Reformatted changes.txt.

This commit is contained in:
richard 2009-01-19 22:45:58 +01:00
parent e3f4b4e400
commit 972136b859
7 changed files with 593 additions and 70 deletions

View File

@ -1,3 +1,7 @@
2009.01.18 - 2.5.1.24
* Created a anticamp feature that give players damage at a specified interval in custom defined volumes. Only affects humans.
* Re-formatted changes.txt.
2009.01.17 - 2.5.1.23 2009.01.17 - 2.5.1.23
* Fixed teleport location text to display as float values instead of decimal. * Fixed teleport location text to display as float values instead of decimal.

View File

@ -1,60 +1,108 @@
Behaviour changes from version 2.5.1 Changes from Zombie: Reloaded 2.5.1
===================================== ====================================
* Support for alpha values in classes. New values in classes.txt (per class): Alpha values (transparency)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Key: Value: Default: Description: Support for alpha values in classes. New values in classes.txt (per class):
alpha_spawn <0-255> 255 initial alpha value (0 = transparent)
alpha_damaged <0-255> 255 alpha value when damaged
alpha_damage <damage> 0 how much damage to do before
alpha_damaged take effect
* If classes are enabled the zr_zombie_knockback cvar is used as a multiplier. Key: Value: Default: Description:
Makes it possible to set custom knockback on maps using per-map configs. Set alpha_spawn <0-255> 255 initial alpha value (0 = transparent)
zr_zombie_knockback to 1 if you use classes and want it the way it was before. alpha_damaged <0-255> 255 alpha value when damaged
alpha_damage <damage> 0 how much damage to do before
alpha_damaged take effect
knockback = zr_zombie_knockback * class knockback Knockback multiplier
~~~~~~~~~~~~~~~~~~~~~
* Spawn protection makes the players invisible and move faster, and cannot be If classes are enabled the zr_zombie_knockback cvar is used as a multiplier.
infected during protecting time. A centered counter shows the time remaining. Makes it possible to set custom knockback on maps using per-map configs.
* Support for overrriding class nvgs with the zr_zombie_nvgs cvar: Set zr_zombie_knockback to 1 if you use classes and want it the way it was
Generally, any non-zero value is considered as on. before.
Value: Description: knockback = zr_zombie_knockback * class knockback
-1 no override (use value in classes.txt) / nvgs on
0 never give nvgs
1 always give nvgs
* Setting default class with a cvar. Works with per-map configs. Full spawn protection
~~~~~~~~~~~~~~~~~~~~~~
zr_classes_default <classname> Spawn protection makes the players invisible and move faster, and cannot be
infected during protection time.
* Zombie admin menu. Basic zombie admin commands like adjusting knockback, nvgs, A centered counter shows the time remaining.
infecting players and spawn everyone. Knockback changes are applied instantly,
useful for fine tuning live. Note that the changes are not saved. They will be
reset on map change. In the future this menu might save the changes.
Knockback multiplier Overriding class night vision
- Fine tune the knockback multiplier. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Class knockback Support for overrriding class nvgs with the zr_zombie_nvgs cvar. Generally,
- Fine tune a class knockback value. any non-zero value is considered as on.
Night vision settings Value: Description:
- Override night vision settings (explained earlier). -1 no override (use value in classes.txt) / nvgs on
0 never give nvgs
1 always give nvgs
Infect Anticamp feature
- Infect a player. Lists all players, but could be changed to only list ~~~~~~~~~~~~~~~~~
humans.
Spawn players Define hurt volumes in maps that gives x damage at a custom interval.
- Spawns all dead players (except spectactors).
(more zombie admin stuff might come...) When creating volumes they should start a little bit _below_ the floor, so it
covers the players feet.
* Console commands zr_set_class_knockback and zr_get_class_knockback. Changes The volume is rectangular and you only need two locations in the map to create
are not saved. They will be reset on map change. it; a top corner, and the bottom corner at the oposite side.
zr_anticamp_create_volume <damage> <interval> <x1> <y1> <z1> <x2> <y2> <z2>
- Create a rectangular volume between the specified locations.
zr_anticamp_remove_volume <volume id>
- Remove a volume.
zr_anticamp_list
- List existing volumes.
Set default classes
~~~~~~~~~~~~~~~~~~~~
Setting the default class with a cvar. Works with per-map configs.
zr_classes_default <classname>
Zombie admin menu
~~~~~~~~~~~~~~~~~~
Basic zombie admin commands like adjusting knockback, nvgs, infecting players
and spawn everyone.
Knockback changes are applied instantly, useful for tuning knockback in-game.
Note that the changes are not saved. They will reset on map change. In a
future version this menu might save the changes.
Knockback multiplier
- Fine tune the knockback multiplier.
Class knockback
- Fine tune a class knockback value.
Night vision settings
- Override night vision settings (explained earlier).
Infect
- Infect a player. Lists all players, but could be changed to only list
humans.
Spawn players
- Spawns all dead players (except spectactors).
(more zombie admin stuff might come...)
Set (and get) class knockback
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set or get knockback from a class. Changes are not saved. They will be reset on
map change.
zr_set_class_knockback <classname> <knockback> zr_set_class_knockback <classname> <knockback>
- Sets knockback to a specified class. Useful when using per-map configs to - Sets knockback to a specified class. Useful when using per-map configs to
@ -64,4 +112,7 @@ Behaviour changes from version 2.5.1
- Prints the current knockback of a class to the client/server console. - Prints the current knockback of a class to the client/server console.
Using the zombie admin menu to read a knockback value is easier sometimes. Using the zombie admin menu to read a knockback value is easier sometimes.
* Other minior and major bug fixes. See changelog.txt. More stuff
~~~~~~~~~~~
Other minior and major bug fixes. See changelog.txt.

View File

@ -225,6 +225,17 @@
"ru" "Неплохая попытка n00b!" "ru" "Неплохая попытка n00b!"
} }
"Unfair camping"
{
"en" "This area is marked as unfair. Move, go through or die..."
}
"Unfair camper slayed"
{
"#format" "{1:s},{2:d}"
"en" "Killed %s due to camping in a unfair area (id: %d)."
}
"DX90 not supported" "DX90 not supported"
{ {
"#format" "{1:d},{2:d}" "#format" "{1:d},{2:d}"

View File

@ -15,7 +15,7 @@
#undef REQUIRE_PLUGIN #undef REQUIRE_PLUGIN
#include <market> #include <market>
#define VERSION "2.5.1.23" #define VERSION "2.5.1.24"
#include "zr/zombiereloaded" #include "zr/zombiereloaded"
#include "zr/global" #include "zr/global"
@ -26,6 +26,7 @@
#include "zr/classes" #include "zr/classes"
#include "zr/models" #include "zr/models"
#include "zr/overlays" #include "zr/overlays"
#include "zr/anticamp"
#include "zr/teleport" #include "zr/teleport"
#include "zr/zombie" #include "zr/zombie"
#include "zr/menu" #include "zr/menu"
@ -123,6 +124,13 @@ public OnMapStart()
pClass[i] = classindex; pClass[i] = classindex;
} }
} }
Anticamp_Startup();
}
public OnMapEnd()
{
Anticamp_Disable();
} }
public OnConfigsExecuted() public OnConfigsExecuted()

437
src/zr/anticamp.inc Normal file
View File

@ -0,0 +1,437 @@
/**
* ====================
* Zombie:Reloaded
* File: anticamp.inc
* Authors: Richard Helgeby
* ====================
*/
#define MAX_VOLUMES 32
enum volume
{
Float:x_min,
Float:x_max,
Float:y_min,
Float:y_max,
Float:z_min,
Float:z_max,
volume_damage,
Float:volume_interval,
Handle:volume_timer,
bool:volume_in_use
}
new volumes[MAX_VOLUMES][volume];
new volume_count;
new Float:player_loc[MAXPLAYERS][3];
new Handle:hUpdateTimer;
Anticamp_Startup(bool:no_reset = false)
{
new Float:interval = GetConVarFloat(gCvars[CVAR_ANTICAMP_UPDATE_INTERVAL]);
// Create timer for updating player locations.
if (hUpdateTimer != INVALID_HANDLE)
{
KillTimer(hUpdateTimer);
hUpdateTimer = INVALID_HANDLE;
}
if (interval > 0.0)
{
hUpdateTimer = CreateTimer(interval, Event_UpdatePlayerLocations, 0, TIMER_REPEAT);
}
if (no_reset)
{
// Start existing hurt timers.
for (new vol_index = 0; vol_index < MAX_VOLUMES; vol_index++)
{
if (volumes[vol_index][volume_in_use])
{
if (volumes[vol_index][volume_timer] != INVALID_HANDLE)
{
KillTimer(volumes[vol_index][volume_timer]);
}
volumes[vol_index][volume_timer] = CreateTimer(volumes[vol_index][volume_interval], Event_HurtPlayers, vol_index, TIMER_REPEAT);
}
}
}
else
{
ResetVolumes();
}
}
Anticamp_Disable()
{
// Kill update timer.
if (hUpdateTimer != INVALID_HANDLE)
{
KillTimer(hUpdateTimer);
hUpdateTimer = INVALID_HANDLE;
}
// Kill hurt timers.
for (new vol = 0; vol < MAX_VOLUMES; vol++)
{
if (volumes[vol][volume_timer] != INVALID_HANDLE)
{
KillTimer(volumes[vol][volume_timer]);
volumes[vol][volume_timer] = INVALID_HANDLE;
}
}
}
public UpdateIntervalHook(Handle:convar, const String:oldValue[], const String:newValue[])
{
new Float:interval = StringToFloat(newValue);
if (hUpdateTimer != INVALID_HANDLE)
{
KillTimer(hUpdateTimer);
hUpdateTimer = INVALID_HANDLE;
}
if (interval > 0.0)
{
hUpdateTimer = CreateTimer(interval, Event_UpdatePlayerLocations, 0, TIMER_REPEAT);
}
}
public AnticampHook(Handle:convar, const String:oldValue[], const String:newValue[])
{
new anticamp_enabled = StringToInt(newValue);
if (anticamp_enabled)
{
Anticamp_Startup(true);
}
else
{
Anticamp_Disable();
}
}
public Action:Command_AnticampCreateVolume(client, argc)
{
// Get a unused volume index.
new vol_index = GetFreeVolumeIndex();
if (vol_index == -1)
{
ReplyToCommand(client, "Maximum volumes reached. Max: %d", MAX_VOLUMES);
return Plugin_Handled;
}
// Check arguments.
if (argc < 8)
{
ReplyToCommand(client, "Too few parameters specified. Usage: zr_anticamp_create_volume <damage> <interval> <x1> <y1> <z1> <x2> <y2> <z2>");
return Plugin_Handled;
}
decl String:arg_buffer[32];
new vol_damage;
new Float:vol_interval;
new Float:x1;
new Float:y1;
new Float:z1;
new Float:x2;
new Float:y2;
new Float:z2;
// Get arguments.
GetCmdArg(1, arg_buffer, sizeof(arg_buffer));
vol_damage = StringToInt(arg_buffer);
GetCmdArg(2, arg_buffer, sizeof(arg_buffer));
vol_interval = StringToFloat(arg_buffer);
GetCmdArg(3, arg_buffer, sizeof(arg_buffer));
x1 = StringToFloat(arg_buffer);
GetCmdArg(4, arg_buffer, sizeof(arg_buffer));
y1 = StringToFloat(arg_buffer);
GetCmdArg(5, arg_buffer, sizeof(arg_buffer));
z1 = StringToFloat(arg_buffer);
GetCmdArg(6, arg_buffer, sizeof(arg_buffer));
x2 = StringToFloat(arg_buffer);
GetCmdArg(7, arg_buffer, sizeof(arg_buffer));
y2 = StringToFloat(arg_buffer);
GetCmdArg(8, arg_buffer, sizeof(arg_buffer));
z2 = StringToFloat(arg_buffer);
// Check damage.
if (vol_damage == 0)
{
ReplyToCommand(client, "The damage specified is zero or invalid.");
return Plugin_Handled;
}
// Check interval.
if (vol_interval <= 0.0)
{
ReplyToCommand(client, "The interval specified is zero or invalid.");
return Plugin_Handled;
}
// 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 hurt volume. Both locations are equal.");
return Plugin_Handled;
}
}
}
// Sort out max and min values.
if (FloatCompare(x1, x2) == 1)
{
volumes[vol_index][x_max] = x1;
volumes[vol_index][x_min] = x2;
}
else
{
volumes[vol_index][x_max] = x2;
volumes[vol_index][x_min] = x1;
}
if (FloatCompare(y1, y2) == 1)
{
volumes[vol_index][y_max] = y1;
volumes[vol_index][y_min] = y2;
}
else
{
volumes[vol_index][y_max] = y2;
volumes[vol_index][y_min] = y1;
}
if (FloatCompare(z1, z2) == 1)
{
volumes[vol_index][z_max] = z1;
volumes[vol_index][z_min] = z2;
}
else
{
volumes[vol_index][z_max] = z2;
volumes[vol_index][z_min] = z1;
}
volumes[vol_index][volume_damage] = vol_damage;
volumes[vol_index][volume_interval] = vol_interval;
volumes[vol_index][volume_timer] = CreateTimer(vol_interval, Event_HurtPlayers, vol_index, TIMER_REPEAT);
volumes[vol_index][volume_in_use] = true;
ReplyToCommand(client, "Volume created:\nid: %d\nx min:%f\ny min:%f\nz min:%f\nx max:%f\ny max:%f\nz max:%f",
vol_index,
volumes[vol_index][x_min],
volumes[vol_index][y_min],
volumes[vol_index][z_min],
volumes[vol_index][x_max],
volumes[vol_index][y_max],
volumes[vol_index][z_max]);
volume_count++;
return Plugin_Handled;
}
public Action:Command_AnticampRemoveVolume(client, argc)
{
new vol_index;
decl String:arg_buffer[32];
new Handle:vol_timer;
if (argc < 1)
{
ReplyToCommand(client, "Volume ID not specified. Usage: zr_anticamp_remove_volume <volume id>");
return Plugin_Handled;
}
GetCmdArg(1, arg_buffer, sizeof(arg_buffer));
vol_index = StringToInt(arg_buffer);
if (IsValidVolume(vol_index))
{
vol_timer = volumes[vol_index][volume_timer];
if (vol_timer != INVALID_HANDLE)
{
KillTimer(vol_timer);
volumes[vol_index][volume_timer] = INVALID_HANDLE;
}
volumes[vol_index][volume_in_use] = false;
ReplyToCommand(client, "Removed volume %d.", vol_index);
}
else
{
ReplyToCommand(client, "Invalid volume ID.");
return Plugin_Handled;
}
return Plugin_Handled;
}
public Action:Command_AnticampList(client, argc)
{
decl String:buffer[2048];
decl String:line[192];
buffer[0] = 0;
StrCat(buffer, sizeof(buffer), "id damage interval x_min y_min z_min x_max y_max z_max\n");
for (new vol_index = 0; vol_index < MAX_VOLUMES; vol_index++)
{
if (volumes[vol_index][volume_in_use])
{
Format(line, sizeof(line), "%d %d %f %f %f %f %f %f %f\n",
vol_index,
volumes[vol_index][volume_damage],
volumes[vol_index][volume_interval],
volumes[vol_index][x_min],
volumes[vol_index][y_min],
volumes[vol_index][z_min],
volumes[vol_index][x_max],
volumes[vol_index][y_max],
volumes[vol_index][y_max]);
StrCat(buffer, sizeof(buffer), line);
}
}
ReplyToCommand(client, buffer);
}
UpdatePlayerLocations()
{
new client;
for (client = 1; client <= maxclients; client++)
{
if (IsClientConnected(client) && IsClientInGame(client))
{
GetClientAbsOrigin(client, player_loc[client]);
}
}
}
HurtPlayersInVolume(volume_index)
{
new client;
new client_health;
decl String:client_name[64];
decl String:buffer[192];
new anticamp_echo = GetConVarBool(gCvars[CVAR_ANTICAMP_ECHO]);
for (client = 1; client <= maxclients; client++)
{
if (IsClientConnected(client) &&
IsClientInGame(client) &&
IsPlayerAlive(client) &&
IsPlayerHuman(client))
{
if (IsPlayerInVolume(client, volume_index))
{
ZR_PrintToChat(client, "Unfair camping");
client_health = GetClientHealth(client) - volumes[volume_index][volume_damage];
if (client_health > 0)
{
SetEntityHealth(client, client_health);
}
else
{
ForcePlayerSuicide(client);
GetClientName(client, client_name, sizeof(client_name));
SetGlobalTransTarget(client);
Format(buffer, sizeof(buffer), "%T", "Unfair camper slayed", LANG_SERVER, client_name, volume_index);
LogAction(client, client, buffer);
if (anticamp_echo)
{
FormatTextString(buffer, sizeof(buffer));
ZR_PrintToAdminChat(buffer);
}
}
}
}
}
}
bool:IsPlayerInVolume(client, volume_index)
{
new Float:player_loc_x = player_loc[client][0];
new Float:player_loc_y = player_loc[client][1];
new Float:player_loc_z = player_loc[client][2];
new debug_flags = GetConVarInt(gCvars[CVAR_DEBUG]);
if ((player_loc_x >= volumes[volume_index][x_min]) && (player_loc_x <= volumes[volume_index][x_max]))
{
if (debug_flags & 4) PrintToChatAll("[ZR] Debug, Anticamp -- IsPlayerInVolume: Client %d matches X values.", client);
if ((player_loc_y >= volumes[volume_index][y_min]) && (player_loc_y <= volumes[volume_index][y_max]))
{
if (debug_flags & 4) PrintToChatAll("[ZR] Debug, Anticamp -- IsPlayerInVolume: Client %d matches Y values.", client);
if ((player_loc_z >= volumes[volume_index][z_min]) && (player_loc_z <= volumes[volume_index][z_max]))
{
if (debug_flags & 4) PrintToChatAll("[ZR] Debug, Anticamp -- IsPlayerInVolume: Client %d matches Z values.", client);
return true;
}
}
}
return false;
}
GetFreeVolumeIndex()
{
for(new vol_index = 0; vol_index < MAX_VOLUMES; vol_index++)
{
if (!volumes[vol_index][volume_in_use])
{
return vol_index;
}
}
return -1;
}
bool:IsValidVolume(vol_index)
{
if (vol_index >= 0 && vol_index < MAX_VOLUMES)
{
return true;
}
else
{
return false;
}
}
ResetVolumes()
{
for (new vol_index = 0; vol_index < MAX_VOLUMES; vol_index++)
{
volumes[vol_index][volume_in_use] = false;
if (volumes[vol_index][volume_timer] != INVALID_HANDLE)
{
KillTimer(volumes[vol_index][volume_timer]);
volumes[vol_index][volume_timer] = INVALID_HANDLE;
}
}
}
public Action:Event_UpdatePlayerLocations(Handle:Timer)
{
UpdatePlayerLocations();
}
public Action:Event_HurtPlayers(Handle:Timer, any:volume_index)
{
HurtPlayersInVolume(volume_index);
}

View File

@ -25,6 +25,10 @@ CreateCommands()
RegAdminCmd("zr_admin", Command_AdminMenu, ADMFLAG_GENERIC, "Displays the admin menu for Zombie: Reloaded."); RegAdminCmd("zr_admin", Command_AdminMenu, ADMFLAG_GENERIC, "Displays the admin menu for Zombie: Reloaded.");
RegAdminCmd("zr_knockback_m", Command_KnockbackMMenu, ADMFLAG_GENERIC, "Displays the knockback multiplier menu."); RegAdminCmd("zr_knockback_m", Command_KnockbackMMenu, ADMFLAG_GENERIC, "Displays the knockback multiplier menu.");
RegAdminCmd("zr_teleadmin", Command_TeleMenu, ADMFLAG_GENERIC, "Displays the teleport admin menu for Zombie: Reloaded."); RegAdminCmd("zr_teleadmin", Command_TeleMenu, ADMFLAG_GENERIC, "Displays the teleport admin menu for Zombie: Reloaded.");
RegAdminCmd("zr_anticamp_create_volume", Command_AnticampCreateVolume, ADMFLAG_GENERIC, "Creates a rectangular hurt volume between two points. Usage: ht_create_volume <damage> <interval> <x1> <y1> <z1> <x2> <y2> <z2>");
RegAdminCmd("zr_anticamp_remove_volume", Command_AnticampRemoveVolume, ADMFLAG_GENERIC, "Removes a volume. Use zr_anticamp_list to list volumes. Usage: zr_anticamp_remove_volume <volume index>");
RegAdminCmd("zr_anticamp_list", Command_AnticampList, ADMFLAG_GENERIC, "List current volumes.");
} }
public Action:Command_Infect(client, argc) public Action:Command_Infect(client, argc)

View File

@ -81,7 +81,10 @@ enum ZRSettings
Handle:CVAR_INFECT_SHAKE_AMP, Handle:CVAR_INFECT_SHAKE_AMP,
Handle:CVAR_INFECT_SHAKE_FREQUENCY, Handle:CVAR_INFECT_SHAKE_FREQUENCY,
Handle:CVAR_INFECT_SHAKE_DURATION, Handle:CVAR_INFECT_SHAKE_DURATION,
Handle:CVAR_INFECT_ANTISTICK_FORCE Handle:CVAR_INFECT_ANTISTICK_FORCE,
Handle:CVAR_ANTICAMP,
Handle:CVAR_ANTICAMP_UPDATE_INTERVAL,
Handle:CVAR_ANTICAMP_ECHO
} }
new gCvars[ZRSettings]; new gCvars[ZRSettings];
@ -162,8 +165,13 @@ CreateCvars()
gCvars[CVAR_INFECT_SHAKE_FREQUENCY] = CreateConVar("zr_infect_shake_frequency", "1.0", "Frequency of the shake, when zr_infect_shake is 1"); gCvars[CVAR_INFECT_SHAKE_FREQUENCY] = CreateConVar("zr_infect_shake_frequency", "1.0", "Frequency of the shake, when zr_infect_shake is 1");
gCvars[CVAR_INFECT_SHAKE_DURATION] = CreateConVar("zr_infect_shake_duration", "5.0", "Duration of the shake, when zr_infect_shake is 1"); gCvars[CVAR_INFECT_SHAKE_DURATION] = CreateConVar("zr_infect_shake_duration", "5.0", "Duration of the shake, when zr_infect_shake is 1");
gCvars[CVAR_INFECT_ANTISTICK_FORCE] = CreateConVar("zr_infect_antistick_force", "-160.0", "Force to push away players from eachother on infection. Negative values push away, positive values pull. (0: Disable)"); gCvars[CVAR_INFECT_ANTISTICK_FORCE] = CreateConVar("zr_infect_antistick_force", "-160.0", "Force to push away players from eachother on infection. Negative values push away, positive values pull. (0: Disable)");
gCvars[CVAR_ANTICAMP] = CreateConVar("zr_anticamp", "1", "Enables or disables hurt volumes for preventing unfair camping. (0: Disable)");
gCvars[CVAR_ANTICAMP_UPDATE_INTERVAL] = CreateConVar("zr_anticamp_update_interval", "1", "How often to update player locations (in seconds).");
gCvars[CVAR_ANTICAMP_ECHO] = CreateConVar("zr_anticamp_echo", "1", "Log kills done by anticamp to admin chat.");
HookConVarChange(gCvars[CVAR_ENABLE], EnableHook); HookConVarChange(gCvars[CVAR_ENABLE], EnableHook);
HookConVarChange(gCvars[CVAR_ANTICAMP], AnticampHook);
HookConVarChange(gCvars[CVAR_ANTICAMP_UPDATE_INTERVAL], UpdateIntervalHook);
AutoExecConfig(true, "zombiereloaded", "sourcemod/zombiereloaded"); AutoExecConfig(true, "zombiereloaded", "sourcemod/zombiereloaded");
} }