3240 lines
78 KiB
SourcePawn
3240 lines
78 KiB
SourcePawn
#pragma semicolon 1
|
|
|
|
|
|
/****** I N C L U D E S *****/
|
|
|
|
#include <sourcemod>
|
|
#include <sdktools>
|
|
#include <sdkhooks>
|
|
#include <tf2_stocks>
|
|
#include <tf2attributes>
|
|
|
|
#undef REQUIRE_PLUGIN
|
|
#include <updater>
|
|
#include <friendly>
|
|
#include <friendlysimple>
|
|
|
|
#include "rtd/#perks.sp"
|
|
|
|
|
|
/******* D E F I N E S ******/
|
|
|
|
#define PLUGIN_VERSION "1.02"
|
|
|
|
#define CHAT_PREFIX "\x07FFD700[RTD]\x01"
|
|
#define CONS_PREFIX "[RTD]"
|
|
|
|
#define PERK_MAX_COUNT 64
|
|
#define PERK_MAX_LOW 32
|
|
#define PERK_MAX_HIGH 64
|
|
#define PERK_MAX_VERYH 128
|
|
|
|
#define CHAT_AD 1
|
|
#define CHAT_APPROLLER 2
|
|
#define CHAT_APPOTHER 4
|
|
#define CHAT_REMROLLER 8
|
|
#define CHAT_REMOTHER 16
|
|
#define CHAT_REASONS 32
|
|
|
|
#define PERK_COLOR_GOOD "\x0732CD32"
|
|
#define PERK_COLOR_BAD "\x078650AC"
|
|
|
|
#define FLAG_FEIGNDEATH (1 << 5)
|
|
#define FLAGS_CVARS FCVAR_PLUGIN|FCVAR_NOTIFY
|
|
|
|
#define LASERBEAM "sprites/laserbeam.vmt"
|
|
|
|
#define UPDATE_URL "https://bitbucket.org/Phil25/rtd/raw/default/update.txt"
|
|
|
|
|
|
|
|
/********* E N U M S ********/
|
|
|
|
enum Perks{
|
|
|
|
String:sName[PERK_MAX_LOW],
|
|
bool:bGood,
|
|
String:sSound[PERK_MAX_HIGH],
|
|
String:sToken[PERK_MAX_LOW],
|
|
iTime,
|
|
iClasses,
|
|
Handle:hWeaponClasses,
|
|
String:sPref[PERK_MAX_HIGH],
|
|
Handle:hTags,
|
|
bool:bIsDisabled,
|
|
|
|
bool:bIsExternal,
|
|
Function:funcCallback,
|
|
Handle:plParent
|
|
|
|
}; int ePerks[PERK_MAX_COUNT][Perks];
|
|
|
|
enum ClientInfo{
|
|
|
|
bool:bRolling,
|
|
iLastRoll,
|
|
iLastPerk,
|
|
iGreatLastPerk,
|
|
iCurPerk,
|
|
iPerkEnd,
|
|
Handle:hPerkTimer,
|
|
Handle:hHudSync,
|
|
iGroupRollId
|
|
|
|
}; int eClients[MAXPLAYERS+1][ClientInfo];
|
|
|
|
enum GroupRolls{
|
|
|
|
bool:bActive,
|
|
iGroupPerkId,
|
|
Handle:hClientArray,
|
|
iClientCount
|
|
|
|
} int eGroup[MAXPLAYERS+1][GroupRolls];
|
|
|
|
|
|
|
|
/********* M A N A G E R ********/
|
|
|
|
#include "rtd/#manager.sp" //For info, go to the script itself
|
|
|
|
|
|
|
|
/***** V A R I A B L E S ****/
|
|
|
|
char g_sTeamColors[][] = {"\x07B2B2B2", "\x07B2B2B2", "\x07FF4040", "\x0799CCFF"};
|
|
int g_iPerkCount = 0;
|
|
int g_iCorePerkCount = 0;
|
|
bool g_bTempPrint = false;
|
|
|
|
bool g_bPluginUpdater = false;
|
|
bool g_bPluginFriendly = false;
|
|
bool g_bPluginFriendlySimple = false;
|
|
|
|
bool g_bIsRegisteringOpen = false;
|
|
bool g_bIsUpdateForced = false;
|
|
|
|
Handle g_hDescriptionMenu = INVALID_HANDLE;
|
|
|
|
bool g_bIsGameArena = false;
|
|
|
|
|
|
|
|
/***** C O N V A R S ****/
|
|
|
|
Handle g_hCvarPluginEnabled; bool g_bCvarPluginEnabled = true;
|
|
#define DESC_PLUGIN_ENABLED "0/1 - Enable or disable the plugin."
|
|
Handle g_hCvarAutoUpdate; bool g_bCvarAutoUpdate = true;
|
|
#define DESC_AUTO_UPDATE "0/1 - Enable or disable automatic updating of the plugin when Updater is installed."
|
|
Handle g_hCvarReloadUpdate; bool g_bCvarReloadUpdate = true;
|
|
#define DESC_RELOAD_UPDATE "0/1 - Enable or disable automatic plugin reloading when a new version has been downloaded."
|
|
Handle g_hCvarLog; bool g_bCvarLog = false;
|
|
#define DESC_LOG "0/1 - Log RTD actions to SourceMod logs?"
|
|
Handle g_hCvarChat; int g_iCvarChat = 63;
|
|
#define DESC_CHAT "Add/substract these values to control messages:\n1 - RTD ad (round start)\n2 - Perk applic. for rollers\n4 - P. applic. for others\n8 - P. removal for rollers\n16 - P. removal for others\n32 - Can't-roll reasons\nEXAMPLE: \"6\" - show applications only (2 + 4)"
|
|
|
|
Handle g_hCvarPerkDuration; int g_iCvarPerkDuration = 25;
|
|
#define DESC_PERK_DURATION "Default time for the perk to last. This value can be overridden for any perk in rtd2_perks.cfg"
|
|
Handle g_hCvarRollInterval; int g_iCvarRollInterval = 60;
|
|
#define DESC_ROLL_INTERVAL "Time in seconds a client has to wait to roll again after a perk has finished."
|
|
Handle g_hCvarDisabledPerks;
|
|
#define DESC_DISABLED_PERKS "Enter the effects you'd like to disable, seperated by commas. You can use IDs, tokens or tags which occur in a single perk. ('0, toxic, sandvich' disables first 3)"
|
|
|
|
Handle g_hCvarAllowed; int g_iCvarAllowed = 0;
|
|
#define DESC_ALLOWED "Admin flags which are required to use RTD. If blank, all is assumed."
|
|
Handle g_hCvarInSetup; bool g_bCvarInSetup = true;
|
|
#define DESC_IN_SETUP "0/1 - Can RTD be used during Setup?"
|
|
Handle g_hCvarTriggers; Handle g_arrCvarTriggers = INVALID_HANDLE; int g_iCvarTriggers = 2;
|
|
#define DESC_TRIGGERS "Chat triggers which will initiate rolls, seperated by comma."
|
|
Handle g_hCvarShowTriggers; bool g_bCvarShowTriggers = false;
|
|
#define DESC_SHOW_TRIGGERS "0/1 - Should the chat triggers be shown once they're typed?"
|
|
Handle g_hCvarShowTime; bool g_bCvarShowTime = false;
|
|
#define DESC_SHOW_TIME "0/1 - Should time the perk was applied for be displayed?"
|
|
|
|
Handle g_hCvarRtdTeam; int g_iCvarRtdTeam = 0;
|
|
#define DESC_RTD_TEAM "0 - both teams can roll, 1 - only RED team can roll, 2 - only BLU team can roll."
|
|
Handle g_hCvarRtdMode; int g_iCvarRtdMode = 0;
|
|
#define DESC_RTD_MODE "0 - No restrain except the interval, 1 - Limit by rollers, 2 - Limit by rollers in team."
|
|
Handle g_hCvarClientLimit; int g_iCvarClientLimit = 2;
|
|
#define DESC_CLIENT_LIMIT "How many players could use RTD at once. Active only when RTD Mode is 1"
|
|
Handle g_hCvarTeamLimit; int g_iCvarTeamLimit = 2;
|
|
#define DESC_TEAM_LIMIT "How many players in each team could use RTD at once. Active only when RTD Mode is 2"
|
|
Handle g_hCvarRespawnStuck; bool g_bCvarRespawnStuck = true;
|
|
#define DESC_RESPAWN_STUCK "0/1 - Should a player be forcibly respawned when a perk has ended and he's detected stuck?"
|
|
|
|
Handle g_hCvarCanRepeatPerk; bool g_bCvarCanRepeatPerk = false;
|
|
#define DESC_CAN_REPEAT_PERK "0/1 - Can a perk can be allowed to be rolled twice in a row."
|
|
Handle g_hCvarCanRepeatGreatPerk; bool g_bCvarCanRepeatGreatPerk = false;
|
|
#define DESC_CAN_REPEAT_GREAT_PERK "0/1 - Can a perk can be allowed to be rolled the second time in 3 rolls."
|
|
|
|
Handle g_hCvarGoodChance; float g_fCvarGoodChance = 0.5;
|
|
#define DESC_GOOD_CHANCE "0.0-1.0 - Chance of rolling a good perk. If there are no good perks available, a bad one will be tried to be rolled instead."
|
|
Handle g_hCvarGoodDonatorChance; float g_fCvarGoodDonatorChance = 0.5;
|
|
#define DESC_GOOD_DONATOR_CHANCE "0.0-1.0 - Chance of rolling a good perk if roller is a donator. If there are no good perks available, a bad one will be tried to roll instead."
|
|
Handle g_hCvarDonatorFlag; int g_iCvarDonatorFlag = 0;
|
|
#define DESC_DONATOR_FLAG "Admin flag required for donators."
|
|
|
|
Handle g_hCvarTimerPosX; float g_fCvarTimerPosX = -1.0;
|
|
#define DESC_TIMER_POS_X "0.0-1.0 - The X position of the perk HUD timer display. -1.0 to center."
|
|
Handle g_hCvarTimerPosY; float g_fCvarTimerPosY = 0.55;
|
|
#define DESC_TIMER_POS_Y "0.0-1.0 - The Y position of the perk HUD timer display. -1.0 to center."
|
|
|
|
|
|
|
|
/***** F O R W A R D S ****/
|
|
|
|
Handle g_hFwdCanRoll;
|
|
Handle g_hFwdCanForce;
|
|
Handle g_hFwdCanRemove;
|
|
Handle g_hFwdRolled;
|
|
Handle g_hFwdRemoved;
|
|
Handle g_hFwdOnRegOpen;
|
|
|
|
|
|
|
|
/********** I N F O *********/
|
|
|
|
public Plugin myinfo = {
|
|
|
|
name = "Roll The Dice (Revamped)",
|
|
author = "Phil25",
|
|
description = "Lets players roll for temporary benefits.",
|
|
version = PLUGIN_VERSION,
|
|
url = "https://forums.alliedmods.net/showthread.php?t=278579"
|
|
|
|
};
|
|
|
|
|
|
|
|
//*************************//
|
|
//---- G E N E R A L ----//
|
|
//*************************//
|
|
|
|
public APLRes AskPluginLoad2 (Handle hMyself, bool bLate, char[] sError, int iErrorSize){
|
|
|
|
char sGame[32]; sGame[0] = '\0';
|
|
GetGameFolderName(sGame, sizeof(sGame));
|
|
if(!StrEqual(sGame, "tf")){
|
|
|
|
Format(sError, iErrorSize, "%s This plugin only works for Team Fortress 2.", CONS_PREFIX);
|
|
return APLRes_Failure;
|
|
|
|
}
|
|
|
|
CreateNative("RTD2_GetClientPerkId", Native_GetClientPerkId);
|
|
CreateNative("RTD2_GetClientPerkTime", Native_GetClientPerkTime);
|
|
|
|
CreateNative("RTD2_ForcePerk", Native_ForcePerk);
|
|
CreateNative("RTD2_RollPerk", Native_RollPerk);
|
|
CreateNative("RTD2_RemovePerk", Native_RemovePerk);
|
|
|
|
CreateNative("RTD2_GetPerkOfString", Native_GetPerkOfString);
|
|
|
|
CreateNative("RTD2_RegisterPerk", Native_RegisterPerk);
|
|
CreateNative("RTD2_IsRegOpen", Native_IsRegisteringOpen);
|
|
CreateNative("RTD2_SetPerkByToken", Native_SetPerkByToken);
|
|
CreateNative("RTD2_SetPerkById", Native_SetPerkById);
|
|
CreateNative("RTD2_DefaultCorePerk", Native_DefaultCorePerk);
|
|
|
|
CreateNative("RTD2_CanPlayerBeHurt", Native_CanPlayerBeHurt);
|
|
|
|
RegPluginLibrary("RollTheDice2");
|
|
|
|
return APLRes_Success;
|
|
|
|
}
|
|
|
|
public void OnPluginStart (){
|
|
|
|
LoadTranslations("rtd2.phrases.txt");
|
|
LoadTranslations("rtd2_perks.phrases.txt");
|
|
LoadTranslations("common.phrases.txt");
|
|
|
|
if(!ParseEffects())
|
|
return;
|
|
|
|
ParseCustomEffects();
|
|
|
|
//-----[ ConVars ]-----//
|
|
CreateConVar("sm_rtd2_version", PLUGIN_VERSION, "Current RTD2 Version", FLAGS_CVARS|FCVAR_DONTRECORD|FCVAR_SPONLY);
|
|
|
|
g_hCvarPluginEnabled = CreateConVar("sm_rtd2_enabled", "1", DESC_PLUGIN_ENABLED, FLAGS_CVARS);
|
|
g_hCvarAutoUpdate = CreateConVar("sm_rtd2_autoupdate", "1", DESC_AUTO_UPDATE, FLAGS_CVARS);
|
|
g_hCvarReloadUpdate = CreateConVar("sm_rtd2_reloadupdate", "1", DESC_RELOAD_UPDATE, FLAGS_CVARS);
|
|
g_hCvarLog = CreateConVar("sm_rtd2_log", "0", DESC_LOG, FLAGS_CVARS);
|
|
g_hCvarChat = CreateConVar("sm_rtd2_chat", "63", DESC_CHAT, FLAGS_CVARS);
|
|
|
|
g_hCvarPerkDuration = CreateConVar("sm_rtd2_duration", "25", DESC_PERK_DURATION, FLAGS_CVARS);
|
|
g_hCvarRollInterval = CreateConVar("sm_rtd2_interval", "60", DESC_ROLL_INTERVAL, FLAGS_CVARS);
|
|
g_hCvarDisabledPerks = CreateConVar("sm_rtd2_disabled", "", DESC_DISABLED_PERKS, FLAGS_CVARS);
|
|
|
|
g_hCvarAllowed = CreateConVar("sm_rtd2_accessflags", "", DESC_ALLOWED, FLAGS_CVARS);
|
|
g_hCvarInSetup = CreateConVar("sm_rtd2_insetup", "0", DESC_IN_SETUP, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
g_hCvarTriggers = CreateConVar("sm_rtd2_triggers", "rtd,roll", DESC_TRIGGERS, FLAGS_CVARS);
|
|
g_hCvarShowTriggers = CreateConVar("sm_rtd2_showtriggers", "0", DESC_SHOW_TRIGGERS, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
g_hCvarShowTime = CreateConVar("sm_rtd2_showtime", "0", DESC_SHOW_TIME, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
|
|
g_hCvarRtdTeam = CreateConVar("sm_rtd2_team", "0", DESC_RTD_TEAM, FLAGS_CVARS, true, 0.0, true, 2.0);
|
|
g_hCvarRtdMode = CreateConVar("sm_rtd2_mode", "0", DESC_RTD_MODE, FLAGS_CVARS, true, 0.0, true, 2.0);
|
|
g_hCvarClientLimit = CreateConVar("sm_rtd2_playerlimit", "2", DESC_CLIENT_LIMIT, FLAGS_CVARS, true, 0.0);
|
|
g_hCvarTeamLimit = CreateConVar("sm_rtd2_teamlimit", "2", DESC_TEAM_LIMIT, FLAGS_CVARS, true, 0.0);
|
|
g_hCvarRespawnStuck = CreateConVar("sm_rtd2_respawnstuck", "1", DESC_RESPAWN_STUCK, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
|
|
g_hCvarCanRepeatPerk = CreateConVar("sm_rtd2_repeat", "0", DESC_CAN_REPEAT_PERK, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
g_hCvarCanRepeatGreatPerk = CreateConVar("sm_rtd2_repeatgreat", "0", DESC_CAN_REPEAT_GREAT_PERK, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
|
|
g_hCvarGoodChance = CreateConVar("sm_rtd2_chance", "0.5", DESC_GOOD_CHANCE, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
g_hCvarGoodDonatorChance = CreateConVar("sm_rtd2_dchance", "0.75", DESC_GOOD_DONATOR_CHANCE, FLAGS_CVARS, true, 0.0, true, 1.0);
|
|
g_hCvarDonatorFlag = CreateConVar("sm_rtd2_donatorflag", "", DESC_DONATOR_FLAG, FLAGS_CVARS);
|
|
|
|
g_hCvarTimerPosX = CreateConVar("sm_rtd2_timerpos_x", "-1.0", DESC_TIMER_POS_X, FLAGS_CVARS);
|
|
g_hCvarTimerPosY = CreateConVar("sm_rtd2_timerpos_y", "0.55", DESC_TIMER_POS_Y, FLAGS_CVARS);
|
|
|
|
|
|
//-----[ ConVars Hooking & Setting ]-----//
|
|
HookConVarChange(g_hCvarPluginEnabled, ConVarChange_Plugin ); g_bCvarPluginEnabled = GetConVarInt(g_hCvarPluginEnabled) > 0 ? true : false;
|
|
HookConVarChange(g_hCvarAutoUpdate, ConVarChange_Plugin ); g_bCvarAutoUpdate = GetConVarInt(g_hCvarAutoUpdate) > 0 ? true : false;
|
|
HookConVarChange(g_hCvarReloadUpdate, ConVarChange_Plugin ); g_bCvarReloadUpdate = GetConVarInt(g_hCvarReloadUpdate) > 0 ? true : false;
|
|
HookConVarChange(g_hCvarLog, ConVarChange_Plugin ); g_bCvarLog = GetConVarInt(g_hCvarLog) > 0 ? true : false;
|
|
HookConVarChange(g_hCvarChat, ConVarChange_Plugin ); g_iCvarChat = GetConVarInt(g_hCvarChat);
|
|
|
|
HookConVarChange(g_hCvarPerkDuration, ConVarChange_Perks ); g_iCvarPerkDuration = GetConVarInt(g_hCvarPerkDuration);
|
|
HookConVarChange(g_hCvarRollInterval, ConVarChange_Perks ); g_iCvarRollInterval = GetConVarInt(g_hCvarRollInterval);
|
|
HookConVarChange(g_hCvarDisabledPerks, ConVarChange_Perks );
|
|
|
|
HookConVarChange(g_hCvarAllowed, ConVarChange_Usage ); g_iCvarAllowed = ReadFlagFromConVar(g_hCvarAllowed);
|
|
HookConVarChange(g_hCvarInSetup, ConVarChange_Usage ); g_bCvarInSetup = GetConVarInt(g_hCvarInSetup) > 0 ? true : false;
|
|
HookConVarChange(g_hCvarTriggers, ConVarChange_Usage ); ParseTriggers();
|
|
HookConVarChange(g_hCvarShowTriggers, ConVarChange_Usage ); g_bCvarShowTriggers = GetConVarInt(g_hCvarShowTriggers) > 0 ? true : false;
|
|
HookConVarChange(g_hCvarShowTime, ConVarChange_Usage ); g_bCvarShowTime = GetConVarInt(g_hCvarShowTime) > 0 ? true : false;
|
|
|
|
HookConVarChange(g_hCvarRtdTeam, ConVarChange_Rtd ); g_iCvarRtdTeam = GetConVarInt(g_hCvarRtdTeam);
|
|
HookConVarChange(g_hCvarRtdMode, ConVarChange_Rtd ); g_iCvarRtdMode = GetConVarInt(g_hCvarRtdMode);
|
|
HookConVarChange(g_hCvarClientLimit, ConVarChange_Rtd ); g_iCvarClientLimit = GetConVarInt(g_hCvarClientLimit);
|
|
HookConVarChange(g_hCvarTeamLimit, ConVarChange_Rtd ); g_iCvarTeamLimit = GetConVarInt(g_hCvarTeamLimit);
|
|
HookConVarChange(g_hCvarRespawnStuck, ConVarChange_Rtd ); g_bCvarRespawnStuck = GetConVarInt(g_hCvarRespawnStuck) > 0 ? true : false;
|
|
|
|
HookConVarChange(g_hCvarCanRepeatPerk, ConVarChange_Repeat ); g_bCvarCanRepeatPerk = GetConVarInt(g_hCvarCanRepeatPerk) > 0 ? true : false;
|
|
HookConVarChange(g_hCvarCanRepeatGreatPerk, ConVarChange_Repeat ); g_bCvarCanRepeatGreatPerk = GetConVarInt(g_hCvarCanRepeatGreatPerk) > 0 ? true : false;
|
|
|
|
HookConVarChange(g_hCvarGoodChance, ConVarChange_Good ); g_fCvarGoodChance = GetConVarFloat(g_hCvarGoodChance);
|
|
HookConVarChange(g_hCvarGoodDonatorChance, ConVarChange_Good ); g_fCvarGoodDonatorChance = GetConVarFloat(g_hCvarGoodDonatorChance);
|
|
HookConVarChange(g_hCvarDonatorFlag, ConVarChange_Good ); g_iCvarDonatorFlag = ReadFlagFromConVar(g_hCvarDonatorFlag);
|
|
|
|
HookConVarChange(g_hCvarTimerPosX, ConVarChange_Timer ); g_fCvarTimerPosX = GetConVarFloat(g_hCvarTimerPosX);
|
|
HookConVarChange(g_hCvarTimerPosY, ConVarChange_Timer ); g_fCvarTimerPosY = GetConVarFloat(g_hCvarTimerPosY);
|
|
|
|
AutoExecConfig(true);
|
|
|
|
|
|
//-----[ Forwards ]-----//
|
|
g_hFwdCanRoll = CreateGlobalForward("RTD2_CanRollDice", ET_Event, Param_Cell );
|
|
g_hFwdCanForce = CreateGlobalForward("RTD2_CanForcePerk", ET_Event, Param_Cell, Param_Cell, Param_Cell);
|
|
g_hFwdCanRemove = CreateGlobalForward("RTD2_CanRemovePerk", ET_Event, Param_Cell, Param_Cell, Param_Cell);
|
|
g_hFwdRolled = CreateGlobalForward("RTD2_Rolled", ET_Event, Param_Cell, Param_Cell, Param_Cell);
|
|
g_hFwdRemoved = CreateGlobalForward("RTD2_Removed", ET_Event, Param_Cell, Param_Cell, Param_Cell);
|
|
g_hFwdOnRegOpen = CreateGlobalForward("RTD2_OnRegOpen", ET_Ignore );
|
|
|
|
|
|
//-----[ Commands ]-----//
|
|
RegAdminCmd("sm_rtd", Command_RTD, 0, "Roll a perk.");
|
|
RegAdminCmd("sm_perks", Command_DescMenu, 0, "Display a description menu of RTD perks.");
|
|
|
|
RegAdminCmd("sm_forcertd", Command_ForceRTD, ADMFLAG_SLAY, "Applies perk to selected player(s).");
|
|
RegAdminCmd("sm_removertd", Command_RemoveRTD, ADMFLAG_SLAY, "Removes perk from selected player(s).");
|
|
|
|
RegAdminCmd("sm_rtds", Command_PerkSearchup, ADMFLAG_SLAY, "Displays customized perk list.");
|
|
RegAdminCmd("sm_rtdsearch", Command_PerkSearchup, ADMFLAG_SLAY, "Displays customized perk list.");
|
|
|
|
RegAdminCmd("sm_reloadrtd", Command_Reload, ADMFLAG_CONFIG, "Reloads the config files.");
|
|
RegAdminCmd("sm_updatertd", Command_Update, ADMFLAG_ROOT, "Force an update check. Does nothing if Updater is not installed.");
|
|
|
|
|
|
//-----[ Listeners ]-----//
|
|
AddCommandListener(Listener_Say, "say");
|
|
AddCommandListener(Listener_Say, "say_team");
|
|
AddCommandListener(Listener_Voice, "voicemenu");
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
if(IsValidClient(i))
|
|
OnClientPutInServer(i);
|
|
|
|
}
|
|
|
|
public void OnConfigsExecuted (){
|
|
|
|
g_hDescriptionMenu = BuildDesc();
|
|
g_bIsRegisteringOpen = true;
|
|
|
|
Forward_OnRegOpen();
|
|
ParseDisabledPerks();
|
|
|
|
}
|
|
|
|
public void OnPluginEnd (){
|
|
|
|
for(int i = 1; i <= MaxClients; i++){
|
|
|
|
Forward_OnRemovePerkPre(i);
|
|
|
|
if(eClients[i][bRolling])
|
|
ForceRemovePerk(i, 0);
|
|
|
|
eClients[i][bRolling] = false;
|
|
eClients[i][iLastRoll] = 0;
|
|
eClients[i][iCurPerk] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public void OnMapStart (){
|
|
|
|
HookEvent("player_death", Event_PlayerDeath);
|
|
HookEvent("player_changeclass", Event_ClassChange);
|
|
HookEvent("teamplay_round_active", Event_RoundActive);
|
|
|
|
PrecacheModel(LASERBEAM);
|
|
|
|
Forward_OnMapStart();
|
|
PrecachePerkSounds();
|
|
|
|
g_bIsGameArena = (FindEntityByClassname(MaxClients +1, "tf_logic_arena") > MaxClients);
|
|
|
|
}
|
|
|
|
public void OnMapEnd (){
|
|
|
|
UnhookEvent("player_death", Event_PlayerDeath);
|
|
UnhookEvent("player_changeclass", Event_ClassChange);
|
|
UnhookEvent("teamplay_round_active", Event_RoundActive);
|
|
|
|
}
|
|
|
|
public void OnClientPutInServer (int client){
|
|
|
|
eClients[client][bRolling] = false;
|
|
eClients[client][iLastRoll] = 0;
|
|
eClients[client][iCurPerk] = -1;
|
|
eClients[client][hHudSync] = CreateHudSynchronizer();
|
|
|
|
Forward_OnClientPutInServer(client);
|
|
|
|
}
|
|
|
|
public void OnClientDisconnect (int client){
|
|
|
|
Forward_OnRemovePerkPre(client);
|
|
|
|
if(eClients[client][bRolling])
|
|
ForceRemovePerk(client, 4);
|
|
|
|
eClients[client][bRolling] = false;
|
|
eClients[client][iLastRoll] = 0;
|
|
eClients[client][iCurPerk] = -1;
|
|
|
|
}
|
|
|
|
public void OnAllPluginsLoaded (){
|
|
|
|
g_bPluginUpdater = LibraryExists("updater");
|
|
g_bPluginFriendly = LibraryExists("[TF2] Friendly Mode");
|
|
g_bPluginFriendlySimple = LibraryExists("Friendly Simple");
|
|
|
|
if(g_bPluginUpdater)
|
|
Updater_AddPlugin(UPDATE_URL);
|
|
|
|
}
|
|
|
|
public void OnLibraryAdded (const char[] sLibName){
|
|
|
|
if(StrEqual(sLibName, "updater"))
|
|
g_bPluginUpdater = true;
|
|
|
|
if(StrEqual(sLibName, "[TF2] Friendly Mode"))
|
|
g_bPluginFriendly = true;
|
|
|
|
if(StrEqual(sLibName, "Friendly Simple"))
|
|
g_bPluginFriendlySimple = true;
|
|
|
|
if(g_bPluginUpdater)
|
|
Updater_AddPlugin(UPDATE_URL);
|
|
|
|
}
|
|
|
|
public void OnLibraryRemoved (const char[] sLibName){
|
|
|
|
if(StrEqual(sLibName, "updater"))
|
|
g_bPluginUpdater = false;
|
|
|
|
if(StrEqual(sLibName, "[TF2] Friendly Mode"))
|
|
g_bPluginFriendly = false;
|
|
|
|
if(StrEqual(sLibName, "Friendly Simple"))
|
|
g_bPluginFriendlySimple = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//*************************//
|
|
//---- U P D A T E R ----//
|
|
//*************************//
|
|
|
|
public Action Updater_OnPluginChecking (){
|
|
|
|
if(!g_bCvarAutoUpdate && !g_bIsUpdateForced)
|
|
return Plugin_Handled;
|
|
|
|
g_bIsUpdateForced = false;
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
public int Updater_OnPluginUpdated (){
|
|
|
|
if(g_bCvarReloadUpdate)
|
|
ReloadPlugin();
|
|
|
|
}
|
|
|
|
|
|
|
|
//***************************//
|
|
//---- C O M M A N D S ----//
|
|
//***************************//
|
|
|
|
public Action Command_RTD (int client, int args){
|
|
|
|
if(IsValidClient(client))
|
|
RollPerkForClient(client);
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
public Action Command_DescMenu (int client, int args){
|
|
|
|
if(IsValidClient(client))
|
|
ShowDesc(client);
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
public Action Command_ForceRTD (int client, int args){
|
|
|
|
if(args < 1){
|
|
|
|
ReplyToCommand(client, "[SM] Usage: sm_forcertd <player> <perk id>* <time>* <override class restriction (0 / 1)>*");
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
char sTrgName[MAX_TARGET_LENGTH], sTrg[32];
|
|
int aTrgList[MAXPLAYERS], iTrgCount;
|
|
bool bNameMultiLang;
|
|
GetCmdArg(1, sTrg, sizeof(sTrg));
|
|
|
|
if((iTrgCount = ProcessTargetString(sTrg, client, aTrgList, MAXPLAYERS, COMMAND_FILTER_ALIVE, sTrgName, sizeof(sTrgName), bNameMultiLang)) <= 0){
|
|
|
|
ReplyToTargetError(client, iTrgCount);
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
int iPerkTime = -1;
|
|
bool bOverrideClass = false;
|
|
char sPerkString[16] = "-";
|
|
|
|
if(args > 1){
|
|
|
|
GetCmdArg(2, sPerkString, sizeof(sPerkString));
|
|
|
|
if(args > 2){
|
|
|
|
char sPerkTime[8];
|
|
GetCmdArg(3, sPerkTime, sizeof(sPerkTime));
|
|
iPerkTime = StringToInt(sPerkTime);
|
|
|
|
if(args > 3){
|
|
|
|
char sOverrideClass[2];
|
|
GetCmdArg(4, sOverrideClass, sizeof(sOverrideClass));
|
|
if(StringToInt(sOverrideClass) > 0)
|
|
bOverrideClass = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int iGroup = -1;
|
|
if(iTrgCount > 1){
|
|
|
|
iGroup = GetNextAvailableGroup();
|
|
|
|
if(iGroup < 0)
|
|
return Plugin_Handled;
|
|
|
|
eGroup[iGroup][bActive] = true;
|
|
eGroup[iGroup][iClientCount] = iTrgCount;
|
|
|
|
if(eGroup[iGroup][hClientArray] == INVALID_HANDLE)
|
|
eGroup[iGroup][hClientArray] = CreateArray();
|
|
|
|
ClearArray(eGroup[iGroup][hClientArray]);
|
|
|
|
}
|
|
|
|
for(int i = 0; i < iTrgCount; i++){
|
|
|
|
if(iGroup > -1)
|
|
PushArrayCell(eGroup[iGroup][hClientArray], GetClientSerial(aTrgList[i]));
|
|
|
|
eClients[aTrgList[i]][iGroupRollId] = iGroup;
|
|
ForcePerk(aTrgList[i], sPerkString, 16, iPerkTime, bOverrideClass, iGroup, client);
|
|
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
public Action Command_RemoveRTD (int client, int args){
|
|
|
|
if(args < 1){
|
|
|
|
ReplyToCommand(client, "[SM] Usage: sm_removertd <player> <\"reason\">*");
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
char sTrgName[MAX_TARGET_LENGTH], sTrg[32];
|
|
int aTrgList[MAXPLAYERS], iTrgCount;
|
|
bool bNameMultiLang;
|
|
GetCmdArg(1, sTrg, sizeof(sTrg));
|
|
|
|
if((iTrgCount = ProcessTargetString(sTrg, client, aTrgList, MAXPLAYERS, COMMAND_FILTER_ALIVE, sTrgName, sizeof(sTrgName), bNameMultiLang)) <= 0){
|
|
|
|
ReplyToTargetError(client, iTrgCount);
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
char sReason[128] = "";
|
|
if(args > 1)
|
|
GetCmdArg(2, sReason, sizeof(sReason));
|
|
|
|
bool bFuncCount = (GetForwardFunctionCount(g_hFwdCanRemove) > 0);
|
|
for(int i = 0; i < iTrgCount; i++){
|
|
|
|
if(eClients[i][bRolling])
|
|
if(bFuncCount){
|
|
|
|
Call_StartForward(g_hFwdCanRemove);
|
|
Call_PushCell(client);
|
|
Call_PushCell(aTrgList[i]);
|
|
Call_PushCell(eClients[aTrgList[i]][iCurPerk]);
|
|
Action result = Plugin_Continue;
|
|
Call_Finish(result);
|
|
|
|
if(result != Plugin_Continue)
|
|
continue;
|
|
|
|
}
|
|
|
|
Forward_OnRemovePerkPre(client);
|
|
|
|
if(eClients[aTrgList[i]][bRolling])
|
|
ForceRemovePerk(aTrgList[i], args > 1 ? 5 : 3, sReason);
|
|
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
public Action Command_PerkSearchup (int client, int args){
|
|
|
|
if(args < 1){
|
|
|
|
for(int i = 0; i < g_iPerkCount; i++){
|
|
|
|
PrintToConsole(client, "%d. %s", i, ePerks[i][sName]);
|
|
|
|
}
|
|
|
|
if(client > 0)
|
|
PrintToChat(client, "%s Perk list has been printed to your console.", CHAT_PREFIX);
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
char sTagString[64], sTagBuffer[32];
|
|
for(int i = 1; i <= args; i++){
|
|
|
|
GetCmdArg(i, sTagBuffer, sizeof(sTagBuffer));
|
|
|
|
if(i < 2){
|
|
|
|
Format(sTagString, sizeof(sTagString), "%s", sTagBuffer);
|
|
continue;
|
|
|
|
}
|
|
|
|
Format(sTagString, sizeof(sTagString), "%s|%s", sTagString, sTagBuffer);
|
|
|
|
}
|
|
|
|
int iPerksFound = 0;
|
|
for(int j = 0; j < g_iPerkCount; j++){
|
|
|
|
if(!IsPerkInTags(j, sTagString, args))
|
|
continue;
|
|
|
|
PrintToConsole(client, "%d. %s", j, ePerks[j][sName]);
|
|
iPerksFound++;
|
|
|
|
}
|
|
|
|
if(client > 0)
|
|
PrintToChat(client, "%s %d %s found matching given criteria.", CHAT_PREFIX, iPerksFound, iPerksFound != 1 ? "perks" : "perk");
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
public Action Command_Reload (int client, int args){
|
|
|
|
ParseEffects();
|
|
ParseCustomEffects();
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
public Action Command_Update (int client, int args){
|
|
|
|
if(!g_bPluginUpdater){
|
|
|
|
ReplyToCommand(client, "%s Updater is not installed.", CONS_PREFIX);
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
g_bIsUpdateForced = true;
|
|
|
|
if(Updater_ForceUpdate())
|
|
ReplyToCommand(client, "%s New RTD version available!", CONS_PREFIX);
|
|
|
|
else
|
|
ReplyToCommand(client, "%s This RTD version is up to date or unable to update.", CONS_PREFIX);
|
|
|
|
g_bIsUpdateForced = false;
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
|
|
|
|
//*****************************//
|
|
//---- L I S T E N E R S ----//
|
|
//*****************************//
|
|
|
|
public Action Listener_Say (int client, const char[] sCommand, int args){
|
|
|
|
if(!IsValidClient(client))
|
|
return Plugin_Continue;
|
|
|
|
char sText[16];
|
|
GetCmdArg(1, sText, sizeof(sText));
|
|
|
|
if(!IsArgumentTrigger(sText))
|
|
return Plugin_Continue;
|
|
|
|
RollPerkForClient(client);
|
|
|
|
return g_bCvarShowTriggers ? Plugin_Continue : Plugin_Stop;
|
|
|
|
}
|
|
|
|
public Action Listener_Voice (int client, const char[] sCommand, int args){
|
|
|
|
if(IsValidClient(client))
|
|
Forward_Voice(client);
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//***********************//
|
|
//---- C O N V A R ----//
|
|
//***********************//
|
|
|
|
public int ConVarChange_Plugin (Handle hCvar, const char[] sOld, const char[] sNew){
|
|
|
|
if(hCvar == g_hCvarPluginEnabled)
|
|
g_bCvarPluginEnabled = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
else if(hCvar == g_hCvarAutoUpdate)
|
|
g_bCvarAutoUpdate = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
else if(hCvar == g_hCvarReloadUpdate)
|
|
g_bCvarReloadUpdate = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
else if(hCvar == g_hCvarLog)
|
|
g_bCvarLog = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
else if(hCvar == g_hCvarChat)
|
|
g_iCvarChat = StringToInt(sNew);
|
|
|
|
}
|
|
|
|
public int ConVarChange_Perks (Handle hCvar, const char[] sOld, const char[] sNew){
|
|
|
|
if(hCvar == g_hCvarPerkDuration)
|
|
g_iCvarPerkDuration = StringToInt(sNew);
|
|
|
|
else if(hCvar == g_hCvarRollInterval)
|
|
g_iCvarRollInterval = StringToInt(sNew);
|
|
|
|
else if(hCvar == g_hCvarDisabledPerks)
|
|
ParseDisabledPerks();
|
|
|
|
}
|
|
|
|
public int ConVarChange_Usage (Handle hCvar, const char[] sOld, const char[] sNew){
|
|
|
|
if(hCvar == g_hCvarAllowed)
|
|
g_iCvarAllowed = ReadFlagString(sNew);
|
|
|
|
else if(hCvar == g_hCvarInSetup)
|
|
g_bCvarInSetup = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
else if(hCvar == g_hCvarTriggers)
|
|
ParseTriggers();
|
|
|
|
else if(hCvar == g_hCvarShowTriggers)
|
|
g_bCvarShowTriggers = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
else if(hCvar == g_hCvarShowTime)
|
|
g_bCvarShowTime = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
}
|
|
|
|
public int ConVarChange_Rtd (Handle hCvar, const char[] sOld, const char[] sNew){
|
|
|
|
if(hCvar == g_hCvarRtdTeam)
|
|
g_iCvarRtdTeam = StringToInt(sNew);
|
|
|
|
else if(hCvar == g_hCvarRtdMode)
|
|
g_iCvarRtdMode = StringToInt(sNew);
|
|
|
|
else if(hCvar == g_hCvarClientLimit)
|
|
g_iCvarClientLimit = StringToInt(sNew);
|
|
|
|
else if(hCvar == g_hCvarTeamLimit)
|
|
g_iCvarTeamLimit = StringToInt(sNew);
|
|
|
|
else if(hCvar == g_hCvarRespawnStuck)
|
|
g_bCvarRespawnStuck = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
}
|
|
|
|
public int ConVarChange_Repeat (Handle hCvar, const char[] sOld, const char[] sNew){
|
|
|
|
if(hCvar == g_hCvarCanRepeatPerk)
|
|
g_bCvarCanRepeatPerk = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
else if(hCvar == g_hCvarCanRepeatGreatPerk)
|
|
g_bCvarCanRepeatGreatPerk = StringToInt(sNew) > 0 ? true : false;
|
|
|
|
}
|
|
|
|
public int ConVarChange_Good (Handle hCvar, const char[] sOld, const char[] sNew){
|
|
|
|
if(hCvar == g_hCvarGoodChance)
|
|
g_fCvarGoodChance = StringToFloat(sNew);
|
|
|
|
else if(hCvar == g_hCvarGoodDonatorChance)
|
|
g_fCvarGoodDonatorChance = StringToFloat(sNew);
|
|
|
|
else if(hCvar == g_hCvarDonatorFlag)
|
|
g_iCvarDonatorFlag = ReadFlagString(sNew);
|
|
|
|
}
|
|
|
|
public int ConVarChange_Timer (Handle hCvar, const char[] sOld, const char[] sNew){
|
|
|
|
if(hCvar == g_hCvarTimerPosX)
|
|
g_fCvarTimerPosX = StringToFloat(sNew);
|
|
|
|
else if(hCvar == g_hCvarTimerPosY)
|
|
g_fCvarTimerPosY = StringToFloat(sNew);
|
|
|
|
}
|
|
|
|
|
|
|
|
//***********************//
|
|
//---- E V E N T S ----//
|
|
//***********************//
|
|
|
|
public Action Event_PlayerDeath (Handle hEvent, const char[] sEventName, bool dontBroadcast){
|
|
|
|
int client = GetClientOfUserId(GetEventInt(hEvent, "userid"));
|
|
if(!IsValidClient(client))
|
|
return Plugin_Continue;
|
|
|
|
int flags = GetEventInt(hEvent, "death_flags");
|
|
if(flags & FLAG_FEIGNDEATH)
|
|
return Plugin_Continue;
|
|
|
|
Forward_OnRemovePerkPre(client);
|
|
|
|
if(!eClients[client][bRolling])
|
|
return Plugin_Continue;
|
|
|
|
ForceRemovePerk(client, 1);
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
public Action Event_ClassChange (Handle hEvent, const char[] sEventName, bool dontBroadcast){
|
|
|
|
int client = GetClientOfUserId(GetEventInt(hEvent, "userid"));
|
|
if(!IsValidClient(client)) return Plugin_Continue;
|
|
|
|
Forward_OnRemovePerkPre(client);
|
|
|
|
if(!eClients[client][bRolling]) return Plugin_Continue;
|
|
|
|
ForceRemovePerk(client, 2);
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
public Action Event_RoundActive (Handle hEvent, const char[] sEventName, bool dontBroadcast){
|
|
|
|
if(g_bCvarPluginEnabled && (g_iCvarChat & CHAT_AD) && IsRTDInRound())
|
|
PrintToChatAll("%s %T", CHAT_PREFIX, "RTD2_Ad", LANG_SERVER, 0x03, 0x01);
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
public void OnEntityCreated (int iEnt, const char[] sClassname){
|
|
|
|
Forward_OnEntityCreated(iEnt, sClassname);
|
|
|
|
}
|
|
|
|
public void OnGameFrame (){
|
|
|
|
Forward_OnGameFrame();
|
|
|
|
}
|
|
|
|
public void TF2_OnConditionAdded (int client, TFCond condition){
|
|
|
|
Forward_OnConditionAdded(client, condition);
|
|
|
|
}
|
|
|
|
public void TF2_OnConditionRemoved (int client, TFCond condition){
|
|
|
|
Forward_OnConditionRemoved(client, condition);
|
|
|
|
}
|
|
|
|
public Action OnPlayerRunCmd (int client, int &iButtons, int &iImpulse, float fVel[3], float fAng[3], int &iWeapon){
|
|
|
|
if(!IsValidClient(client))
|
|
return Plugin_Continue;
|
|
|
|
if(Forward_OnPlayerRunCmd(client, iButtons, iImpulse, fVel, fAng, iWeapon))
|
|
return Plugin_Changed;
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
public Action TF2_CalcIsAttackCritical (int client, int iWeapon, char[] sWeaponName, bool &bResult){
|
|
|
|
if(!IsValidClient(client))
|
|
return Plugin_Continue;
|
|
|
|
if(!Forward_AttackIsCritical(client, iWeapon, sWeaponName))
|
|
return Plugin_Continue;
|
|
|
|
bResult = true;
|
|
return Plugin_Changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
//*********************//
|
|
//---- P E R K S ----//
|
|
//*********************//
|
|
|
|
//-----[ Parsing & Precaching ]-----//
|
|
|
|
void ParseTriggers (){
|
|
|
|
char sCvar[64], sBuffer[64];
|
|
GetConVarString(g_hCvarTriggers, sCvar, sizeof(sCvar));
|
|
EscapeString(sCvar, ' ', '\0', sBuffer, sizeof(sBuffer));
|
|
|
|
g_iCvarTriggers = CountCharInString(sBuffer, ',')+1;
|
|
char[][] sPieces = new char[g_iCvarTriggers][64];
|
|
|
|
ExplodeString(sBuffer, ",", sPieces, g_iCvarTriggers, 64);
|
|
|
|
if(g_arrCvarTriggers == INVALID_HANDLE)
|
|
g_arrCvarTriggers = CreateArray(16);
|
|
else
|
|
ClearArray(g_arrCvarTriggers);
|
|
|
|
for(int i = 0; i < g_iCvarTriggers; i++)
|
|
PushArrayString(g_arrCvarTriggers, sPieces[i]);
|
|
|
|
}
|
|
|
|
bool ParseEffects (){
|
|
|
|
char sPath[255];
|
|
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/rtd2_perks.default.cfg");
|
|
|
|
if(!FileExists(sPath)){
|
|
|
|
LogError("%s Failed to find rtd2_perks.default.cfg in configs/ folder!", CONS_PREFIX);
|
|
SetFailState("Failed to find rtd2_perks.default.cfg in configs/ folder!");
|
|
return false;
|
|
|
|
}
|
|
|
|
g_iPerkCount = 0;
|
|
Handle hKv = CreateKeyValues("Effects");
|
|
int iPrevId = -1, iGood = 0, iBad = 0, iWarnings = 0;
|
|
|
|
if(FileToKeyValues(hKv, sPath) && KvGotoFirstSubKey(hKv)){
|
|
|
|
char sPerkId[4], sTokenBuffer[PERK_MAX_LOW], sClassBuffer[2][PERK_MAX_LOW], sWeaponBuffer[2][PERK_MAX_HIGH], sSettingBuffer[PERK_MAX_HIGH], sTagBuffer[2][PERK_MAX_VERYH];
|
|
int iPerkId = 0, iRepeat = -1, iClassFlags = 0, iTagSize = 0;
|
|
do{
|
|
|
|
KvGetSectionName(hKv, sPerkId, sizeof(sPerkId));
|
|
iPerkId = StringToInt(sPerkId);
|
|
|
|
if(iPrevId +1 != iPerkId){
|
|
|
|
LogError("%s Disorder in rtd2_perks.default.cfg detected; aborting! (iPerkId: %d)", CONS_PREFIX, iPerkId);
|
|
SetFailState("Disorder in rtd2_perks.default.cfg detected; aborting! (iPerkId: %d)", iPerkId);
|
|
return false;
|
|
|
|
}
|
|
iPrevId++;
|
|
|
|
//----[ NAME ]----//
|
|
|
|
KvGetString(hKv, "name", ePerks[iPerkId][sName], PERK_MAX_LOW);
|
|
|
|
|
|
//----[ GOOD ]----//
|
|
|
|
ePerks[iPerkId][bGood] = KvGetNum(hKv, "good") > 0 ? true : false;
|
|
|
|
|
|
//----[ SOUND ]----//
|
|
|
|
KvGetString(hKv, "sound", ePerks[iPerkId][sSound], PERK_MAX_HIGH);
|
|
|
|
|
|
//----[ TOKEN ]----//
|
|
|
|
strcopy(sTokenBuffer, PERK_MAX_LOW, "");
|
|
KvGetString(hKv, "token", sTokenBuffer, PERK_MAX_LOW);
|
|
|
|
EscapeString(sTokenBuffer, ' ', '\0', ePerks[iPerkId][sToken], PERK_MAX_LOW);
|
|
|
|
iRepeat = FindPerkByToken(ePerks[iPerkId][sToken]);
|
|
if(iRepeat != -1){
|
|
|
|
LogError("%s Perk \"%s\" (ID:%d) and \"%s\" (ID:%d) have the same token which is forbidden.", CONS_PREFIX, ePerks[iPerkId][sName], iPerkId, ePerks[iRepeat][sName], iRepeat);
|
|
SetFailState("Perk \"%s\" (ID:%d) and \"%s\" (ID:%d) have the same token which is forbidden.", ePerks[iPerkId][sName], iPerkId, ePerks[iRepeat][sName], iRepeat);
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
//----[ TIME ]----//
|
|
|
|
ePerks[iPerkId][iTime] = KvGetNum(hKv, "time");
|
|
|
|
|
|
//----[ CLASS ]----//
|
|
|
|
strcopy(sClassBuffer[1], PERK_MAX_HIGH, "");
|
|
KvGetString(hKv, "class", sClassBuffer[0], PERK_MAX_LOW);
|
|
EscapeString(sClassBuffer[0], ' ', '\0', sClassBuffer[1], PERK_MAX_LOW);
|
|
|
|
iClassFlags = ClassStringToFlags(sClassBuffer[1]);
|
|
if(iClassFlags < 1){
|
|
|
|
PrintToServer("%s WARNING: Invalid class restriction(s) set at perk ID:%d (rtd2_perks.default.cfg). Assuming it's all-class.", CONS_PREFIX, iPerkId);
|
|
LogError("%s WARNING: Invalid class restriction(s) set at perk ID:%d (rtd2_perks.default.cfg). Assuming it's all-class.", CONS_PREFIX, iPerkId);
|
|
iWarnings++;
|
|
iClassFlags = 511;
|
|
|
|
}ePerks[iPerkId][iClasses] = iClassFlags;
|
|
|
|
|
|
//----[ WEAPONS ]----//
|
|
|
|
strcopy(sWeaponBuffer[1], PERK_MAX_HIGH, "");
|
|
KvGetString(hKv, "weapons", sWeaponBuffer[0], PERK_MAX_HIGH);
|
|
EscapeString(sWeaponBuffer[0], ' ', '\0', sWeaponBuffer[1], PERK_MAX_HIGH);
|
|
|
|
if(ePerks[iPerkId][hWeaponClasses] == INVALID_HANDLE)
|
|
ePerks[iPerkId][hWeaponClasses] = CreateArray(32);
|
|
else
|
|
ClearArray(ePerks[iPerkId][hWeaponClasses]);
|
|
|
|
if(FindCharInString(sWeaponBuffer[1], '0') < 0){
|
|
|
|
int iSize = CountCharInString(sWeaponBuffer[1], ',')+1;
|
|
char[][] sPieces = new char[iSize][32];
|
|
|
|
ExplodeString(sWeaponBuffer[1], ",", sPieces, iSize, 64);
|
|
|
|
for(int i = 0; i < iSize; i++)
|
|
PushArrayString(ePerks[iPerkId][hWeaponClasses], sPieces[i]);
|
|
|
|
}
|
|
|
|
|
|
//----[ SETTINGS ]----//
|
|
|
|
KvGetString(hKv, "settings", sSettingBuffer, PERK_MAX_HIGH);
|
|
EscapeString(sSettingBuffer, ' ', '\0', ePerks[iPerkId][sPref], PERK_MAX_HIGH);
|
|
|
|
|
|
//----[ TAGS ]----//
|
|
|
|
strcopy(sTagBuffer[1], PERK_MAX_VERYH, ""); iTagSize = 0;
|
|
KvGetString(hKv, "tags", sTagBuffer[0], PERK_MAX_VERYH);
|
|
EscapeString(sTagBuffer[0], ' ', '\0', sTagBuffer[1], PERK_MAX_VERYH);
|
|
|
|
if(ePerks[iPerkId][hTags] == INVALID_HANDLE)
|
|
ePerks[iPerkId][hTags] = CreateArray(32);
|
|
else
|
|
ClearArray(ePerks[iPerkId][hTags]);
|
|
|
|
if(strlen(sTagBuffer[1]) > 0){
|
|
|
|
iTagSize = CountCharInString(sTagBuffer[1], '|')+1;
|
|
char[][] sPieces = new char[iTagSize][24];
|
|
|
|
ExplodeString(sTagBuffer[1], "|", sPieces, iTagSize, 24);
|
|
|
|
for(int i = 0; i < iTagSize; i++)
|
|
PushArrayString(ePerks[iPerkId][hTags], sPieces[i]);
|
|
|
|
}
|
|
|
|
//----[ STATS ]----//
|
|
|
|
if(ePerks[iPerkId][bGood])
|
|
iGood++;
|
|
else
|
|
iBad++;
|
|
|
|
g_iPerkCount++;
|
|
g_iCorePerkCount++;
|
|
|
|
|
|
}while(KvGotoNextKey(hKv));
|
|
|
|
PrintToServer("%s Loaded %d %s (%d good, %d bad; with %d warnings).", CONS_PREFIX, g_iPerkCount, g_iPerkCount > 1 ? "perks" : "perk", iGood, iBad, iWarnings);
|
|
|
|
if(hKv != INVALID_HANDLE)
|
|
CloseHandle(hKv);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(hKv != INVALID_HANDLE)
|
|
CloseHandle(hKv);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
void ParseCustomEffects (){
|
|
|
|
char sPath[255];
|
|
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/rtd2_perks.custom.cfg");
|
|
|
|
if(!FileExists(sPath)){
|
|
|
|
PrecachePerkSounds();
|
|
return;
|
|
|
|
}
|
|
|
|
int iCustomPerkCount = 0;
|
|
Handle hKv = CreateKeyValues("Effects");
|
|
|
|
if(FileToKeyValues(hKv, sPath) && KvGotoFirstSubKey(hKv)){
|
|
|
|
Handle hCustomized = CreateArray();
|
|
char sPerkId[4], sClassBuffer[2][PERK_MAX_LOW], sWeaponBuffer[2][PERK_MAX_HIGH], sSettingBuffer[PERK_MAX_HIGH], sTagBuffer[2][PERK_MAX_HIGH];
|
|
int iPerkId = 0, iClassFlags = 0, iTagSize = 0;
|
|
do{
|
|
|
|
KvGetSectionName(hKv, sPerkId, sizeof(sPerkId));
|
|
iPerkId = StringToInt(sPerkId);
|
|
|
|
if(iPerkId >= g_iPerkCount || iPerkId < 0)
|
|
continue;
|
|
|
|
|
|
//----[ NAME ]----//
|
|
|
|
if(KvJumpToKey(hKv, "name")){
|
|
|
|
KvGoBack(hKv);
|
|
KvGetString(hKv, "name", ePerks[iPerkId][sName], PERK_MAX_LOW);
|
|
|
|
}
|
|
|
|
|
|
//----[ GOOD ]----//
|
|
|
|
if(KvJumpToKey(hKv, "good")){
|
|
|
|
KvGoBack(hKv);
|
|
ePerks[iPerkId][bGood] = KvGetNum(hKv, "good") > 0 ? true : false;
|
|
|
|
}
|
|
|
|
|
|
//----[ SOUND ]----//
|
|
|
|
if(KvJumpToKey(hKv, "sound")){
|
|
|
|
KvGoBack(hKv);
|
|
KvGetString(hKv, "sound", ePerks[iPerkId][sSound], PERK_MAX_HIGH);
|
|
|
|
}
|
|
|
|
|
|
//----[ TOKEN ]----//
|
|
|
|
if(KvJumpToKey(hKv, "token")){
|
|
|
|
KvGoBack(hKv);
|
|
KvGetString(hKv, "token", ePerks[iPerkId][sToken], PERK_MAX_LOW);
|
|
|
|
}
|
|
|
|
|
|
//----[ TIME ]----//
|
|
|
|
if(KvJumpToKey(hKv, "time")){
|
|
|
|
KvGoBack(hKv);
|
|
ePerks[iPerkId][iTime] = KvGetNum(hKv, "time");
|
|
|
|
}
|
|
|
|
|
|
//----[ CLASS ]----//
|
|
|
|
if(KvJumpToKey(hKv, "class")){
|
|
|
|
KvGoBack(hKv);
|
|
|
|
strcopy(sClassBuffer[1], PERK_MAX_LOW, "");
|
|
KvGetString(hKv, "class", sClassBuffer[0], PERK_MAX_LOW, "0");
|
|
EscapeString(sClassBuffer[0], ' ', '\0', sClassBuffer[1], PERK_MAX_LOW);
|
|
|
|
iClassFlags = ClassStringToFlags(sClassBuffer[1]);
|
|
if(iClassFlags < 1){
|
|
|
|
PrintToServer("%s WARNING: Invalid class restriction(s) set at perk ID:%d (rtd2_perks.custom.cfg). Assuming it's all-class. (\"%s\")", CONS_PREFIX, iPerkId, sClassBuffer[1]);
|
|
LogError("%s WARNING: Invalid class restriction(s) set at perk ID:%d (rtd2_perks.custom.cfg). Assuming it's all-class. (\"%s\")", CONS_PREFIX, iPerkId, sClassBuffer[1]);
|
|
iClassFlags = 511;
|
|
|
|
}ePerks[iPerkId][iClasses] = iClassFlags;
|
|
|
|
}
|
|
|
|
//----[ WEAPONS ]----//
|
|
|
|
if(KvJumpToKey(hKv, "weapons")){
|
|
|
|
KvGoBack(hKv);
|
|
|
|
strcopy(sWeaponBuffer[1], PERK_MAX_HIGH, "");
|
|
KvGetString(hKv, "weapons", sWeaponBuffer[0], PERK_MAX_HIGH);
|
|
EscapeString(sWeaponBuffer[0], ' ', '\0', sWeaponBuffer[1], PERK_MAX_HIGH);
|
|
|
|
ClearArray(ePerks[iPerkId][hWeaponClasses]);
|
|
|
|
if(FindCharInString(sWeaponBuffer[1], '0') < 0){
|
|
|
|
int iSize = CountCharInString(sWeaponBuffer[1], ',')+1;
|
|
char[][] sPieces = new char[iSize][32];
|
|
|
|
ExplodeString(sWeaponBuffer[1], ",", sPieces, iSize, 64);
|
|
|
|
for(int i = 0; i < iSize; i++)
|
|
PushArrayString(ePerks[iPerkId][hWeaponClasses], sPieces[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//----[ SETTINGS ]----//
|
|
|
|
if(KvJumpToKey(hKv, "settings")){
|
|
|
|
KvGoBack(hKv);
|
|
|
|
KvGetString(hKv, "settings", sSettingBuffer, PERK_MAX_HIGH);
|
|
EscapeString(sSettingBuffer, ' ', '\0', ePerks[iPerkId][sPref], PERK_MAX_HIGH);
|
|
|
|
}
|
|
|
|
|
|
//----[ TAGS ]----//
|
|
|
|
if(KvJumpToKey(hKv, "tags")){
|
|
|
|
KvGoBack(hKv);
|
|
|
|
strcopy(sTagBuffer[1], PERK_MAX_HIGH, ""); iTagSize = 0;
|
|
KvGetString(hKv, "tags", sTagBuffer[0], PERK_MAX_VERYH);
|
|
EscapeString(sTagBuffer[0], ' ', '\0', sTagBuffer[1], PERK_MAX_VERYH);
|
|
|
|
ClearArray(ePerks[iPerkId][hTags]);
|
|
|
|
if(strlen(sTagBuffer[1]) > 0){
|
|
|
|
iTagSize = CountCharInString(sTagBuffer[1], '|')+1;
|
|
char[][] sPieces = new char[iTagSize][24];
|
|
|
|
ExplodeString(sTagBuffer[1], "|", sPieces, iTagSize, 24);
|
|
|
|
for(int i = 0; i < iTagSize; i++)
|
|
PushArrayString(ePerks[iPerkId][hTags], sPieces[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(FindValueInArray(hCustomized, iPerkId) > -1)
|
|
continue;
|
|
|
|
iCustomPerkCount++;
|
|
PushArrayCell(hCustomized, iPerkId);
|
|
|
|
}while(KvGotoNextKey(hKv));
|
|
|
|
PrintToServer("%s Customized %d perk%s.", CONS_PREFIX, iCustomPerkCount, iCustomPerkCount == 1 ? "" : "s");
|
|
delete hCustomized;
|
|
|
|
}
|
|
|
|
if(hKv != INVALID_HANDLE)
|
|
CloseHandle(hKv);
|
|
|
|
PrecachePerkSounds();
|
|
|
|
}
|
|
|
|
void PrecachePerkSounds (){
|
|
|
|
for(int i = 0; i < g_iPerkCount; i++)
|
|
PrecacheSound(ePerks[i][sSound]);
|
|
|
|
}
|
|
|
|
void ParseDisabledPerks (){
|
|
|
|
for(int i = 0; i < g_iPerkCount; i++)
|
|
ePerks[i][bIsDisabled] = false;
|
|
|
|
char sDisabled[2][255];
|
|
GetConVarString(g_hCvarDisabledPerks, sDisabled[0], 255);
|
|
EscapeString(sDisabled[0], ' ', '\0', sDisabled[1], 255);
|
|
|
|
if(strlen(sDisabled[1]) == 0)
|
|
return;
|
|
|
|
int iDisabledNum = CountCharInString(sDisabled[1], ',') +1;
|
|
char[][] sDisabledPieces = new char[iDisabledNum][32];
|
|
ExplodeString(sDisabled[1], ",", sDisabledPieces, iDisabledNum, 32);
|
|
|
|
int iPerkId = -1, iArraySize = 0;
|
|
Handle hDisabledArray = CreateArray();
|
|
for(int i = 0; i < iDisabledNum; i++){
|
|
|
|
iPerkId = GetPerkOfString(sDisabledPieces[i], 32);
|
|
if(iPerkId < 0)
|
|
continue;
|
|
|
|
if(FindValueInArray(hDisabledArray, iPerkId) != -1)
|
|
continue;
|
|
|
|
ePerks[iPerkId][bIsDisabled] = true;
|
|
PushArrayCell(hDisabledArray, iPerkId);
|
|
iArraySize++;
|
|
|
|
}
|
|
|
|
switch(iArraySize){
|
|
|
|
case 0:{}
|
|
|
|
case 1:{
|
|
|
|
if(g_bCvarLog)
|
|
LogMessage("%s Perk disabled: %s.", CONS_PREFIX, ePerks[GetArrayCell(hDisabledArray, 0)][sName]);
|
|
|
|
PrintToServer("%s Perk disabled: %s.", CONS_PREFIX, ePerks[GetArrayCell(hDisabledArray, 0)][sName]);
|
|
|
|
}
|
|
|
|
default:{
|
|
|
|
if(g_bCvarLog)
|
|
LogMessage("%s %d perks disabled:", CONS_PREFIX, iArraySize);
|
|
|
|
PrintToServer("%s %d perks disabled:", CONS_PREFIX, iArraySize);
|
|
|
|
for(int i = 0; i < iArraySize; i++){
|
|
|
|
if(g_bCvarLog)
|
|
LogMessage(" • %s", ePerks[GetArrayCell(hDisabledArray, i)][sName]);
|
|
|
|
PrintToServer(" > %s", ePerks[GetArrayCell(hDisabledArray, i)][sName]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete hDisabledArray;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Applying ]-----//
|
|
|
|
void RollPerkForClient (int client){
|
|
|
|
if(!g_bCvarPluginEnabled){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_Disabled", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!IsRollerAllowed(client)){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_No_Access", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!IsRTDInRound()){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Not_In_Round", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(g_iCvarRtdTeam > 0 && g_iCvarRtdTeam == GetClientTeam(client)-1){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_Team", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(GetForwardFunctionCount(g_hFwdCanRoll) > 0){
|
|
|
|
Call_StartForward(g_hFwdCanRoll);
|
|
Call_PushCell(client);
|
|
Action result = Plugin_Continue;
|
|
Call_Finish(result);
|
|
|
|
if(result != Plugin_Continue)
|
|
return;
|
|
|
|
}
|
|
|
|
if(!IsPlayerAlive(client)){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_Alive", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(eClients[client][bRolling]){
|
|
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_Using", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int iTimeLeft = eClients[client][iLastRoll] +g_iCvarRollInterval;
|
|
if(GetTime() < iTimeLeft){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_Wait", LANG_SERVER, 0x04, iTimeLeft -GetTime(), 0x01);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch(g_iCvarRtdMode){
|
|
|
|
case 1:{
|
|
|
|
int iCount = 0;
|
|
for(int i = 1; i <= MaxClients; i++){
|
|
|
|
if(eClients[i][bRolling])
|
|
iCount++;
|
|
|
|
}
|
|
|
|
if(iCount >= g_iCvarClientLimit){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_Mode1", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case 2:{
|
|
|
|
int iCount = 0, iTeam = GetClientTeam(client);
|
|
for(int i = 1; i <= MaxClients; i++){
|
|
|
|
if(eClients[i][bRolling])
|
|
if(GetClientTeam(i) == iTeam)
|
|
iCount++;
|
|
|
|
}
|
|
|
|
if(iCount >= g_iCvarTeamLimit){
|
|
|
|
if(g_iCvarChat & CHAT_REASONS)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Cant_Roll_Mode2", LANG_SERVER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int iPerkId = RollPerk(client);
|
|
ApplyPerk(client, iPerkId);
|
|
|
|
if(g_bCvarLog)
|
|
LogMessage("%L rolled %s(ID: %d).", client, ePerks[iPerkId][sName], iPerkId);
|
|
|
|
}
|
|
|
|
int ForcePerk (int client, const char[] sPerkString, int iPerkStringSize=32, int iPerkTime=-1, bool bOverrideClass=false, int iGroup=-1, int initiator=0){
|
|
|
|
if(!IsValidClient(client))
|
|
return -4;
|
|
|
|
bool bIsValidInitiator = IsValidClient(initiator);
|
|
|
|
if(eClients[client][bRolling]){
|
|
|
|
if(iGroup < 0)
|
|
if(bIsValidInitiator)
|
|
PrintToChat(initiator, "%s %N is already using RTD.", CHAT_PREFIX, client);
|
|
else
|
|
PrintToServer("%s %N is already using RTD.", CONS_PREFIX, client);
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
if(!IsPlayerAlive(client)){
|
|
|
|
if(iGroup < 0)
|
|
if(bIsValidInitiator)
|
|
PrintToChat(initiator, "%s %N is dead.", CHAT_PREFIX, client);
|
|
else
|
|
PrintToServer("%s %N is already using RTD.", CONS_PREFIX, client);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
int iPerkId = GetPerkOfString(sPerkString, iPerkStringSize);
|
|
bool bSamePerk = true;
|
|
int iApplicats = iGroup < 0 ? 1 : eGroup[iGroup][iClientCount];
|
|
|
|
if(iPerkId < 0 || iPerkId >= g_iPerkCount){
|
|
|
|
bSamePerk = false;
|
|
|
|
if(!g_bTempPrint)
|
|
if(bIsValidInitiator)
|
|
PrintToChat(initiator, "%s Perk not found or invalid info, forcing %s.", CHAT_PREFIX, iApplicats > 1 ? "rolls" : "a roll");
|
|
else
|
|
PrintToServer("%s Perk not found or invalid info, forcing %s.", CONS_PREFIX, iApplicats > 1 ? "rolls" : "a roll");
|
|
|
|
iPerkId = RollPerk(client, true, bOverrideClass, false, false, !StrEqual(sPerkString, "-"), sPerkString);
|
|
|
|
if(iPerkId < 0){
|
|
|
|
if(bIsValidInitiator)
|
|
PrintToChat(initiator, "%s No perks available for %N.", CHAT_PREFIX, client);
|
|
else
|
|
PrintToServer("%s No perks available for %N.", CONS_PREFIX, client);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(bIsValidInitiator)
|
|
if(GetForwardFunctionCount(g_hFwdCanForce) > 0){
|
|
|
|
Call_StartForward(g_hFwdCanForce);
|
|
Call_PushCell(initiator);
|
|
Call_PushCell(client);
|
|
Call_PushCell(iPerkId);
|
|
Action result = Plugin_Continue;
|
|
Call_Finish(result);
|
|
|
|
if(result != Plugin_Continue)
|
|
return -5;
|
|
|
|
}
|
|
|
|
ApplyPerk(client, iPerkId, iPerkTime, iGroup, bSamePerk ? iPerkId : -1);
|
|
|
|
if(g_bCvarLog)
|
|
if(bIsValidInitiator)
|
|
LogMessage("A perk %s(ID: %d) has been forced on %L for %d seconds by %L.", ePerks[iPerkId][sName], iPerkId, client, iPerkTime, initiator);
|
|
else
|
|
LogMessage("A perk %s(ID: %d) has been forced on %L for %d seconds.", ePerks[iPerkId][sName], iPerkId, client, iPerkTime);
|
|
|
|
return iPerkId;
|
|
|
|
}
|
|
|
|
|
|
//-----[ General ]-----//
|
|
|
|
int RollPerk (int client=0, bool bOverrideDisabled=false, bool bOverrideClass=false, bool bCountRepeat=true, bool bCountGreatRepeat=true, bool bUseFilter=false, const char[] sTagFilter=""){
|
|
|
|
float fGoodChance = g_fCvarGoodChance;
|
|
|
|
if(IsValidClient(client) && IsRollerDonator(client))
|
|
fGoodChance = g_fCvarGoodDonatorChance;
|
|
|
|
bool bGoodPerk = fGoodChance > GetURandomFloat() ? true : false;
|
|
|
|
Handle hAvailablePerks = CreateArray();
|
|
for(int i = 0; i < g_iPerkCount; i++){
|
|
|
|
if(!bUseFilter){
|
|
|
|
if(ePerks[i][bGood] != bGoodPerk)
|
|
continue;
|
|
|
|
if(!bOverrideDisabled)
|
|
if(ePerks[i][bIsDisabled])
|
|
continue;
|
|
|
|
if(IsValidClient(client)){
|
|
|
|
if(bCountRepeat)
|
|
if(!g_bCvarCanRepeatPerk)
|
|
if(i == eClients[client][iLastPerk])
|
|
continue;
|
|
|
|
if(bCountGreatRepeat)
|
|
if(!g_bCvarCanRepeatGreatPerk)
|
|
if(i == eClients[client][iGreatLastPerk])
|
|
continue;
|
|
|
|
}
|
|
|
|
}else if(!IsPerkInTags(i, sTagFilter, CountCharInString(sTagFilter, '|')+1))
|
|
continue;
|
|
|
|
if(!bOverrideClass)
|
|
if(!PerkAllowedForClassOf(client, i))
|
|
continue;
|
|
|
|
if(!PerkAllowedForWeaponsOf(client, i))
|
|
continue;
|
|
|
|
PushArrayCell(hAvailablePerks, i);
|
|
|
|
}
|
|
|
|
int iPerkNum = GetArraySize(hAvailablePerks);
|
|
|
|
int iUsingHandle = 0;
|
|
|
|
Handle hAvailablePerks2 = CreateArray();
|
|
int iPerkNum2 = -1;
|
|
if(!iPerkNum){
|
|
|
|
for(int i = 0; i < g_iPerkCount; i++){
|
|
|
|
if(!bUseFilter){
|
|
|
|
if(ePerks[i][bGood] == bGoodPerk)
|
|
continue;
|
|
|
|
if(!bOverrideDisabled)
|
|
if(ePerks[i][bIsDisabled])
|
|
continue;
|
|
|
|
if(IsValidClient(client)){
|
|
|
|
if(bCountRepeat)
|
|
if(!g_bCvarCanRepeatPerk)
|
|
if(i == eClients[client][iLastPerk])
|
|
continue;
|
|
|
|
if(bCountGreatRepeat)
|
|
if(!g_bCvarCanRepeatGreatPerk)
|
|
if(i == eClients[client][iGreatLastPerk])
|
|
continue;
|
|
|
|
}
|
|
|
|
}else if(!IsPerkInTags(i, sTagFilter, CountCharInString(sTagFilter, ',')+1))
|
|
continue;
|
|
|
|
if(!bOverrideClass)
|
|
if(!PerkAllowedForClassOf(client, i))
|
|
continue;
|
|
|
|
if(!PerkAllowedForWeaponsOf(client, i))
|
|
continue;
|
|
|
|
PushArrayCell(hAvailablePerks2, i);
|
|
|
|
}
|
|
|
|
iPerkNum2 = GetArraySize(hAvailablePerks2);
|
|
|
|
if(iPerkNum2) iUsingHandle = 2;
|
|
|
|
}else iUsingHandle = 1;
|
|
|
|
int iPerkId = -1;
|
|
switch(iUsingHandle){
|
|
|
|
case 1:{iPerkId = GetArrayCell(hAvailablePerks, GetRandomInt(0, iPerkNum-1));}
|
|
case 2:{iPerkId = GetArrayCell(hAvailablePerks2, GetRandomInt(0, iPerkNum2-1));}
|
|
|
|
}
|
|
|
|
delete hAvailablePerks;
|
|
if(!iPerkNum) delete hAvailablePerks2;
|
|
|
|
return iPerkId;
|
|
|
|
}
|
|
|
|
void ApplyPerk (int client, int iPerk, int iPerkTime=-1, int iGroup=-1, int iSamePerk=-1){
|
|
|
|
if(!IsValidClient(client)) return;
|
|
|
|
EmitSoundToAll(ePerks[iPerk][sSound], client);
|
|
|
|
ManagePerk(client, iPerk, true);
|
|
|
|
int iDuration = -1;
|
|
if(ePerks[iPerk][iTime] > -1){
|
|
|
|
iDuration = (iPerkTime > -1) ? iPerkTime : (ePerks[iPerk][iTime] > 0) ? ePerks[iPerk][iTime] : g_iCvarPerkDuration;
|
|
int iSerial = GetClientSerial(client);
|
|
|
|
eClients[client][bRolling] = true;
|
|
eClients[client][iCurPerk] = iPerk;
|
|
eClients[client][iPerkEnd] = GetTime() + iDuration;
|
|
eClients[client][hPerkTimer]= CreateTimer(float(iDuration), Timer_RemovePerk, iSerial);
|
|
DisplayPerkTimeFrame(client);
|
|
CreateTimer(1.0, Timer_Countdown, iSerial, TIMER_REPEAT);
|
|
|
|
}else
|
|
eClients[client][iLastRoll] = GetTime();
|
|
|
|
Forward_PerkApplied(client, iPerk, iDuration);
|
|
|
|
eClients[client][iGreatLastPerk]= eClients[client][iLastPerk];
|
|
eClients[client][iLastPerk] = iPerk;
|
|
|
|
PrintToRoller(client, iPerk, iDuration);
|
|
|
|
if(iGroup < 0 || iSamePerk < 0){
|
|
|
|
PrintToNonRollers(client, iPerk, iDuration);
|
|
|
|
if(iSamePerk < 0){
|
|
|
|
g_bTempPrint = true;
|
|
CreateTimer(0.1, Timer_ReloadTempPrint);
|
|
|
|
}
|
|
|
|
if(iGroup > -1)
|
|
eGroup[iGroup][iGroupPerkId] = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(g_bTempPrint) //----- Past this point, execution happens once -----//
|
|
return;
|
|
|
|
PrintGroupRolls(eGroup[iGroup][iClientCount], iSamePerk, iDuration);
|
|
|
|
g_bTempPrint = true;
|
|
CreateTimer(0.1, Timer_ReloadTempPrint);
|
|
|
|
if(ePerks[iSamePerk][iTime] < 0)
|
|
return;
|
|
|
|
eGroup[iGroup][iGroupPerkId] = iSamePerk;
|
|
CreateTimer(float(iDuration), Timer_PrintGroupEnd, iGroup);
|
|
|
|
}
|
|
|
|
|
|
//-----[ Descriptions ]-----//
|
|
|
|
Handle BuildDesc (){
|
|
|
|
Handle hMenu = CreateMenu(ManagerDesc);
|
|
|
|
SetMenuTitle(hMenu, "%T", "RTD2_Menu_Title", LANG_SERVER);
|
|
|
|
for(int i = 0; i < g_iCorePerkCount; i++)
|
|
AddMenuItem(hMenu, "", ePerks[i][sName]);
|
|
|
|
SetMenuExitBackButton(hMenu, false);
|
|
SetMenuExitButton(hMenu, true);
|
|
|
|
return hMenu;
|
|
|
|
}
|
|
|
|
void ShowDesc (int client, int iPos=0){
|
|
|
|
if(iPos == 0)
|
|
DisplayMenu(g_hDescriptionMenu, client, MENU_TIME_FOREVER);
|
|
|
|
else
|
|
DisplayMenuAtItem(g_hDescriptionMenu, client, GetMenuSelectionPosition(), MENU_TIME_FOREVER);
|
|
|
|
|
|
}
|
|
|
|
public int ManagerDesc (Handle hMenu, MenuAction maState, int client, int iPos){
|
|
|
|
if(maState != MenuAction_Select)
|
|
return 0;
|
|
|
|
char sTranslatePos[16];
|
|
Format(sTranslatePos, sizeof(sTranslatePos), "RTD2_Desc_%d", iPos);
|
|
|
|
PrintToChat(client, "%s %s%s%c: \x03%T\x01", CHAT_PREFIX,
|
|
ePerks[iPos][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPos][sName], 0x01,
|
|
sTranslatePos, LANG_SERVER);
|
|
|
|
ShowDesc(client, iPos);
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Timers ]-----//
|
|
|
|
public Action Timer_ReloadTempPrint (Handle hTimer){
|
|
|
|
g_bTempPrint = false;
|
|
|
|
return Plugin_Stop;
|
|
|
|
}
|
|
|
|
public Action Timer_PrintGroupEnd (Handle hTimer, int iGroup){
|
|
|
|
if(!eGroup[iGroup][bActive])
|
|
return Plugin_Stop;
|
|
|
|
int iSize = eGroup[iGroup][iClientCount];
|
|
|
|
if(iSize < 1)
|
|
return Plugin_Stop;
|
|
|
|
int iPerk = eGroup[iGroup][iGroupPerkId];
|
|
|
|
if(iPerk > -1){
|
|
|
|
char sReason[128];
|
|
Format(sReason, sizeof(sReason), "%s %T", CHAT_PREFIX,
|
|
"RTD2_Remove_Perk_Group_Same", LANG_SERVER,
|
|
ePerks[iPerk][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPerk][sName],
|
|
0x01,
|
|
iSize);
|
|
|
|
PrintToChatAll(sReason);
|
|
|
|
}
|
|
|
|
eGroup[iGroup][bActive] = false;
|
|
|
|
return Plugin_Stop;
|
|
|
|
}
|
|
|
|
public Action Timer_Countdown (Handle hTimer, int iSerial){
|
|
|
|
int client = GetClientFromSerial(iSerial);
|
|
|
|
if(!IsValidClient(client))
|
|
return Plugin_Stop;
|
|
|
|
if(!eClients[client][bRolling])
|
|
return Plugin_Stop;
|
|
|
|
DisplayPerkTimeFrame(client);
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
public Action Timer_RemovePerk (Handle hTimer, int iSerial){
|
|
|
|
int client = GetClientFromSerial(iSerial);
|
|
|
|
if(!IsValidClient(client))
|
|
return Plugin_Stop;
|
|
|
|
if(g_bCvarLog)
|
|
LogMessage("Perk %s(ID: %d) ended on %L.", ePerks[eClients[client][iCurPerk]][sName], eClients[client][iCurPerk], client);
|
|
|
|
ManagePerk(client, eClients[client][iCurPerk], false);
|
|
|
|
return Plugin_Handled;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Removing ]-----//
|
|
|
|
int ForceRemovePerk (int client, int iReason=3, const char[] sReason=""){
|
|
|
|
if(!IsValidClient(client)) return -1;
|
|
int iClientPerk = eClients[client][iCurPerk];
|
|
|
|
int iGroup = eClients[client][iGroupRollId];
|
|
if(iGroup > -1){
|
|
|
|
if(eGroup[iGroup][bActive]){
|
|
|
|
int iPos = FindValueInArray(eGroup[iGroup][hClientArray], GetClientSerial(client));
|
|
|
|
if(iPos > -1){
|
|
|
|
RemoveFromArray(eGroup[iGroup][hClientArray], iPos);
|
|
eGroup[iGroup][iClientCount]--;
|
|
|
|
}
|
|
|
|
if(eGroup[iGroup][iClientCount] < 1)
|
|
eGroup[iGroup][bActive] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ManagePerk(client, iClientPerk , false, iReason, sReason);
|
|
|
|
return iClientPerk;
|
|
|
|
}
|
|
|
|
void RemovedPerk (int client, int iReason, const char[] sReason=""){
|
|
|
|
eClients[client][bRolling] = false;
|
|
eClients[client][iLastRoll] = GetTime();
|
|
|
|
Forward_PerkRemoved(client, eClients[client][iCurPerk], iReason);
|
|
|
|
eClients[client][iCurPerk] = -1;
|
|
|
|
int iGroup = eClients[client][iGroupRollId];
|
|
|
|
if(iGroup < 0)
|
|
PrintPerkEndReason(client, iReason, sReason);
|
|
else
|
|
|
|
if(eGroup[iGroup][iGroupPerkId] < 0)
|
|
PrintPerkEndReason(client, iReason, sReason);
|
|
|
|
eClients[client][iGroupRollId] = -1;
|
|
|
|
KillTimerSafe(eClients[client][hPerkTimer]);
|
|
|
|
}
|
|
|
|
|
|
//-----[ Printing ]-----//
|
|
|
|
void PrintToRoller (int client, int iPerk, int iDuration){
|
|
|
|
if(!(g_iCvarChat & CHAT_APPROLLER))
|
|
return;
|
|
|
|
if(!g_bCvarShowTime || ePerks[iPerk][iTime] == -1)
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX,
|
|
"RTD2_Rolled_Perk_Roller", LANG_SERVER,
|
|
ePerks[iPerk][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPerk][sName],
|
|
0x01);
|
|
|
|
else{
|
|
|
|
int iTrueDuration = (iDuration > -1) ? iDuration : (ePerks[iPerk][iTime] > 0) ? ePerks[iPerk][iTime] : g_iCvarPerkDuration;
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX,
|
|
"RTD2_Rolled_Perk_Roller_Time", LANG_SERVER,
|
|
ePerks[iPerk][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPerk][sName],
|
|
0x01, 0x03, iTrueDuration, 0x01);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void PrintToNonRollers (int client, int iPerk, int iDuration){
|
|
|
|
if(!(g_iCvarChat & CHAT_APPOTHER))
|
|
return;
|
|
|
|
char sOthersPrint[128], sRollerName[MAX_NAME_LENGTH];
|
|
GetClientName(client, sRollerName, sizeof(sRollerName));
|
|
|
|
if(!g_bCvarShowTime || ePerks[iPerk][iTime] == -1)
|
|
Format(sOthersPrint, sizeof(sOthersPrint), "%s %T", CHAT_PREFIX,
|
|
"RTD2_Rolled_Perk_Others", LANG_SERVER,
|
|
g_sTeamColors[GetClientTeam(client)],
|
|
sRollerName,
|
|
0x01,
|
|
ePerks[iPerk][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPerk][sName], 0x01);
|
|
|
|
else{
|
|
|
|
int iTrueDuration = (iDuration > -1) ? iDuration : (ePerks[iPerk][iTime] > 0) ? ePerks[iPerk][iTime] : g_iCvarPerkDuration;
|
|
Format(sOthersPrint, sizeof(sOthersPrint), "%s %T", CHAT_PREFIX,
|
|
"RTD2_Rolled_Perk_Others_Time", LANG_SERVER,
|
|
g_sTeamColors[GetClientTeam(client)],
|
|
sRollerName,
|
|
0x01,
|
|
ePerks[iPerk][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPerk][sName], 0x01, 0x03, iTrueDuration, 0x01);
|
|
|
|
}
|
|
|
|
PrintToChatAllExcept(client, sOthersPrint);
|
|
|
|
}
|
|
|
|
void PrintGroupRolls (int iApplications, int iPerk, int iDuration){
|
|
|
|
if(!(g_iCvarChat & CHAT_APPOTHER))
|
|
return;
|
|
|
|
char sReason[128];
|
|
|
|
if(!g_bCvarShowTime || ePerks[iPerk][iTime] == -1)
|
|
Format(sReason, sizeof(sReason), "%s %T", CHAT_PREFIX,
|
|
"RTD2_Rolled_Perk_Multi", LANG_SERVER,
|
|
iApplications,
|
|
ePerks[iPerk][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPerk][sName],
|
|
0x01);
|
|
|
|
else{
|
|
|
|
int iTrueDuration = (iDuration > -1) ? iDuration : (ePerks[iPerk][iTime] > 0) ? ePerks[iPerk][iTime] : g_iCvarPerkDuration;
|
|
Format(sReason, sizeof(sReason), "%s %T", CHAT_PREFIX,
|
|
"RTD2_Rolled_Perk_Multi_Time", LANG_SERVER,
|
|
iApplications,
|
|
ePerks[iPerk][bGood] ? PERK_COLOR_GOOD : PERK_COLOR_BAD,
|
|
ePerks[iPerk][sName],
|
|
0x01, 0x03, iTrueDuration, 0x01);
|
|
|
|
}
|
|
|
|
PrintToChatAll(sReason);
|
|
|
|
}
|
|
|
|
void PrintPerkEndReason (int client, int iReason=3, const char[] sCustomReason=""){
|
|
|
|
char sReasonSelf[32], sReasonOthers[32];
|
|
switch(iReason){
|
|
|
|
case 0:{
|
|
|
|
strcopy(sReasonSelf, sizeof(sReasonSelf), "RTD2_Remove_Perk_Unload_Self");
|
|
strcopy(sReasonOthers, sizeof(sReasonOthers), "RTD2_Remove_Perk_Unload_Others");
|
|
|
|
}
|
|
|
|
case 1:{
|
|
|
|
strcopy(sReasonSelf, sizeof(sReasonSelf), "RTD2_Remove_Perk_Died_Self");
|
|
strcopy(sReasonOthers, sizeof(sReasonOthers), "RTD2_Remove_Perk_Died_Others");
|
|
|
|
}
|
|
|
|
case 2:{
|
|
|
|
strcopy(sReasonSelf, sizeof(sReasonSelf), "RTD2_Remove_Perk_Class_Self");
|
|
strcopy(sReasonOthers, sizeof(sReasonOthers), "RTD2_Remove_Perk_Class_Others");
|
|
|
|
}
|
|
|
|
case 3:{
|
|
|
|
strcopy(sReasonSelf, sizeof(sReasonSelf), "RTD2_Remove_Perk_End_Self");
|
|
strcopy(sReasonOthers, sizeof(sReasonOthers), "RTD2_Remove_Perk_End_Others");
|
|
|
|
}
|
|
|
|
case 4:{
|
|
|
|
strcopy(sReasonSelf, sizeof(sReasonSelf), "0");
|
|
strcopy(sReasonOthers, sizeof(sReasonOthers), "RTD2_Remove_Perk_Disconnected");
|
|
|
|
}
|
|
|
|
case 5:{
|
|
|
|
strcopy(sReasonSelf, sizeof(sReasonSelf), "RTD2_Remove_Perk_Custom_Self");
|
|
strcopy(sReasonOthers, sizeof(sReasonOthers), "RTD2_Remove_Perk_Custom_Others");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(sReasonSelf[0] != '0' && (g_iCvarChat & CHAT_REMROLLER))
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, sReasonSelf, LANG_SERVER, iReason > 4 ? sCustomReason : "");
|
|
|
|
if(!(g_iCvarChat & CHAT_REMOTHER))
|
|
return;
|
|
|
|
char sPrintReasonToOthers[128];
|
|
Format(sPrintReasonToOthers, sizeof(sPrintReasonToOthers), "%s %T", CHAT_PREFIX, sReasonOthers, LANG_SERVER, g_sTeamColors[GetClientTeam(client)], client, 0x01, iReason > 4 ? sCustomReason : "");
|
|
PrintToChatAllExcept(client, sPrintReasonToOthers);
|
|
|
|
}
|
|
|
|
|
|
|
|
//*************************//
|
|
//---- N A T I V E S ----//
|
|
//*************************//
|
|
|
|
public int Native_GetClientPerkId (Handle hPlugin, int iParams){
|
|
|
|
return eClients[GetNativeCell(1)][iCurPerk];
|
|
|
|
}
|
|
|
|
public int Native_GetClientPerkTime (Handle hPlugin, int iParams){
|
|
|
|
int client = GetNativeCell(1);
|
|
return eClients[client][bRolling] ? eClients[client][iPerkEnd] -GetTime() : -1;
|
|
|
|
}
|
|
|
|
public int Native_ForcePerk (Handle hPlugin, int iParams){
|
|
|
|
char sPerkString[32]; int iStringSize = sizeof(sPerkString);
|
|
GetNativeString(2, sPerkString, iStringSize);
|
|
|
|
return ForcePerk(
|
|
GetNativeCell(1),
|
|
sPerkString,
|
|
iStringSize,
|
|
GetNativeCell(3),
|
|
GetNativeCell(4) > 0 ? true : false,
|
|
GetNativeCell(5)
|
|
);
|
|
|
|
}
|
|
|
|
public int Native_RollPerk (Handle hPlugin, int iParams){
|
|
|
|
return RollPerk(
|
|
GetNativeCell(1),
|
|
GetNativeCell(2) > 0 ? true : false,
|
|
GetNativeCell(3) > 0 ? true : false,
|
|
GetNativeCell(4) > 0 ? true : false,
|
|
GetNativeCell(5) > 0 ? true : false
|
|
);
|
|
|
|
}
|
|
|
|
public int Native_RemovePerk (Handle hPlugin, int iParams){
|
|
|
|
char sReason[32]; GetNativeString(3, sReason, sizeof(sReason));
|
|
int client = GetNativeCell(1);
|
|
|
|
Forward_OnRemovePerkPre(client);
|
|
|
|
if(!eClients[client][bRolling])
|
|
return -1;
|
|
|
|
return ForceRemovePerk(
|
|
client,
|
|
GetNativeCell(2),
|
|
sReason
|
|
);
|
|
|
|
}
|
|
|
|
public int Native_GetPerkOfString (Handle hPlugin, int iParams){
|
|
|
|
char sString[32]; int iSize = sizeof(sString);
|
|
GetNativeString(1, sString, iSize);
|
|
|
|
return GetPerkOfString(sString, iSize);
|
|
|
|
}
|
|
|
|
public int Native_RegisterPerk (Handle hPlugin, int iParams){
|
|
|
|
char sPluginName[32];
|
|
GetPluginFilename(hPlugin, sPluginName, sizeof(sPluginName));
|
|
|
|
if(!g_bIsRegisteringOpen){
|
|
|
|
ThrowNativeError(SP_ERROR_NATIVE, "%s Plugin \"%s\" is trying to register perks before it's possible.\nPlease use the forward RTD2_OnRegOpen() and native RTD2_IsRegOpen() to determine.", CONS_PREFIX, sPluginName);
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(g_iPerkCount >= PERK_MAX_COUNT-1){
|
|
|
|
ThrowNativeError(SP_ERROR_NATIVE, "%s No space for new perks.\nPlease recompile the core increasing \"PERK_MAX_COUNT\" define.", CONS_PREFIX);
|
|
return -1;
|
|
|
|
}
|
|
|
|
char sTokenBuffer[2][PERK_MAX_LOW], sClassBuffer[2][PERK_MAX_LOW], sWeaponsBuffer[2][PERK_MAX_HIGH], sTagsBuffer[2][PERK_MAX_VERYH];
|
|
|
|
|
|
//---[ Token ]---//
|
|
|
|
GetNativeString(1, sTokenBuffer[0], PERK_MAX_LOW);
|
|
EscapeString(sTokenBuffer[0], ' ', '\0', sTokenBuffer[1], PERK_MAX_LOW);
|
|
|
|
int iPerkId = FindPerkByToken(sTokenBuffer[1]);
|
|
if(iPerkId == -1){
|
|
|
|
iPerkId = g_iPerkCount;
|
|
g_iPerkCount++;
|
|
|
|
}
|
|
|
|
strcopy(ePerks[iPerkId][sToken], PERK_MAX_LOW, sTokenBuffer[1]);
|
|
|
|
|
|
//---[ Name ]---//
|
|
|
|
GetNativeString(2, ePerks[iPerkId][sName], PERK_MAX_LOW);
|
|
|
|
|
|
//---[ Good ]---//
|
|
|
|
ePerks[iPerkId][bGood] = GetNativeCell(3) > 0 ? true : false;
|
|
|
|
|
|
//---[ Sound ]---//
|
|
|
|
GetNativeString(4, ePerks[iPerkId][sSound], PERK_MAX_HIGH);
|
|
PrecacheSound(ePerks[iPerkId][sSound]);
|
|
|
|
|
|
//---[ Time ]---//
|
|
|
|
ePerks[iPerkId][iTime] = GetNativeCell(5);
|
|
|
|
|
|
//---[ Class ]---//
|
|
|
|
strcopy(sClassBuffer[1], PERK_MAX_LOW, "");
|
|
GetNativeString(6, sClassBuffer[0], PERK_MAX_LOW);
|
|
EscapeString(sClassBuffer[0], ' ', '\0', sClassBuffer[1], PERK_MAX_LOW);
|
|
|
|
int iClassFlags = ClassStringToFlags(sClassBuffer[1]);
|
|
if(iClassFlags < 1){
|
|
|
|
PrintToServer("%s WARNING: A plugin \"%s\" is registering a perk with invalid class restriction(s) for perk \"%s\". Assuming it's all-class.", CONS_PREFIX, sPluginName, ePerks[g_iPerkCount][sName]);
|
|
LogError("%s WARNING: A plugin \"%s\" is registering a perk with invalid class restriction(s) for perk \"%s\". Assuming it's all-class.", CONS_PREFIX, sPluginName, ePerks[g_iPerkCount][sName]);
|
|
iClassFlags = 511;
|
|
|
|
}
|
|
|
|
ePerks[iPerkId][iClasses] = iClassFlags;
|
|
|
|
|
|
//---[ Weapons ]---//
|
|
|
|
strcopy(sWeaponsBuffer[1], PERK_MAX_HIGH, "");
|
|
GetNativeString(7, sWeaponsBuffer[0], PERK_MAX_HIGH);
|
|
EscapeString(sWeaponsBuffer[0], ' ', '\0', sWeaponsBuffer[1], PERK_MAX_HIGH);
|
|
|
|
if(ePerks[iPerkId][hWeaponClasses] == INVALID_HANDLE)
|
|
ePerks[iPerkId][hWeaponClasses] = CreateArray(32);
|
|
else
|
|
ClearArray(ePerks[iPerkId][hWeaponClasses]);
|
|
|
|
if(FindCharInString(sWeaponsBuffer[1], '0') < 0){
|
|
|
|
int iSize = CountCharInString(sWeaponsBuffer[1], ',')+1;
|
|
char[][] sPieces = new char[iSize][32];
|
|
|
|
ExplodeString(sWeaponsBuffer[1], ",", sPieces, iSize, 64);
|
|
|
|
for(int i = 0; i < iSize; i++)
|
|
PushArrayString(ePerks[iPerkId][hWeaponClasses], sPieces[i]);
|
|
|
|
}
|
|
|
|
|
|
//---[ Tags ]---//
|
|
|
|
strcopy(sTagsBuffer[1], PERK_MAX_VERYH, "");
|
|
GetNativeString(8, sTagsBuffer[0], PERK_MAX_VERYH);
|
|
EscapeString(sTagsBuffer[0], ' ', '\0', sTagsBuffer[1], PERK_MAX_VERYH);
|
|
|
|
if(ePerks[iPerkId][hTags] == INVALID_HANDLE)
|
|
ePerks[iPerkId][hTags] = CreateArray(32);
|
|
else
|
|
ClearArray(ePerks[iPerkId][hTags]);
|
|
|
|
if(strlen(sTagsBuffer[1]) > 0){
|
|
|
|
int iTagSize = CountCharInString(sTagsBuffer[1], '|')+1;
|
|
char[][] sPieces = new char[iTagSize][24];
|
|
|
|
ExplodeString(sTagsBuffer[1], "|", sPieces, iTagSize, 24);
|
|
|
|
for(int i = 0; i < iTagSize; i++)
|
|
PushArrayString(ePerks[iPerkId][hTags], sPieces[i]);
|
|
|
|
}
|
|
|
|
|
|
//---[ The Rest ]---//
|
|
|
|
ePerks[iPerkId][bIsExternal] = true;
|
|
ePerks[iPerkId][funcCallback] = GetNativeCell(9);
|
|
ePerks[iPerkId][plParent] = hPlugin;
|
|
|
|
return iPerkId;
|
|
|
|
}
|
|
|
|
public int Native_IsRegisteringOpen (Handle hPlugin, int iParams){
|
|
|
|
return g_bIsRegisteringOpen;
|
|
|
|
}
|
|
|
|
public int Native_SetPerkByToken (Handle hPlugin, int iParams){
|
|
|
|
char sTokenBuffer[PERK_MAX_LOW];
|
|
GetNativeString(1, sTokenBuffer, PERK_MAX_LOW);
|
|
|
|
int iPerkId = FindPerkByToken(sTokenBuffer);
|
|
|
|
if(iPerkId == -1)
|
|
return -1;
|
|
|
|
int iDir = GetNativeCell(2);
|
|
|
|
if(iDir < -1)
|
|
iDir = -1;
|
|
else if(iDir > 1)
|
|
iDir = 1;
|
|
|
|
switch(iDir){
|
|
|
|
case -1:ePerks[iPerkId][bIsDisabled] = true;
|
|
case 0: ePerks[iPerkId][bIsDisabled] = ePerks[iPerkId][bIsDisabled] ? false : true;
|
|
case 1: ePerks[iPerkId][bIsDisabled] = false;
|
|
|
|
}
|
|
|
|
return iPerkId;
|
|
|
|
}
|
|
|
|
public int Native_SetPerkById (Handle hPlugin, int iParams){
|
|
|
|
int iPerkId = GetNativeCell(1);
|
|
|
|
if(iPerkId < 0 || iPerkId >= g_iPerkCount)
|
|
return -1;
|
|
|
|
int iDir = GetNativeCell(2);
|
|
|
|
if(iDir < -1)
|
|
iDir = -1;
|
|
else if(iDir > 1)
|
|
iDir = 1;
|
|
|
|
int iChange = 0;
|
|
|
|
switch(iDir){
|
|
|
|
case -1:{
|
|
|
|
if(!ePerks[iPerkId][bIsDisabled]){
|
|
|
|
ePerks[iPerkId][bIsDisabled] = true;
|
|
iChange = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case 0:{
|
|
|
|
ePerks[iPerkId][bIsDisabled] = ePerks[iPerkId][bIsDisabled] ? false : true;
|
|
iChange = 1;
|
|
|
|
}
|
|
|
|
case 1:{
|
|
|
|
if(ePerks[iPerkId][bIsDisabled]){
|
|
|
|
ePerks[iPerkId][bIsDisabled] = false;
|
|
iChange = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return iChange;
|
|
|
|
}
|
|
|
|
public int Native_DefaultCorePerk (Handle hPlugin, int iParams){
|
|
|
|
int iPerkId = GetNativeCell(1);
|
|
|
|
if(iPerkId < 0 || iPerkId >= g_iCorePerkCount){
|
|
|
|
char sTokenBuffer[PERK_MAX_LOW];
|
|
GetNativeString(2, sTokenBuffer, PERK_MAX_LOW);
|
|
|
|
if(strlen(sTokenBuffer) < 1)
|
|
return -1;
|
|
|
|
iPerkId = FindPerkByToken(sTokenBuffer);
|
|
|
|
if(iPerkId == -1)
|
|
return -1;
|
|
|
|
}
|
|
|
|
int iChange = 0;
|
|
if(ePerks[iPerkId][bIsExternal]){
|
|
|
|
iChange = 1;
|
|
ePerks[iPerkId][bIsExternal] = false;
|
|
|
|
}
|
|
|
|
return iChange;
|
|
|
|
}
|
|
|
|
public int Native_CanPlayerBeHurt (Handle hPlugin, int iParams){
|
|
|
|
int client = GetNativeCell(1);
|
|
|
|
if(client < 1 || client > MaxClients)
|
|
return 0;
|
|
|
|
if(!IsClientInGame(client))
|
|
return 0;
|
|
|
|
return view_as<int>(CanPlayerBeHurt(client, GetNativeCell(2)));
|
|
|
|
}
|
|
|
|
|
|
|
|
//***************************//
|
|
//---- F O R W A R D S ----//
|
|
//***************************//
|
|
|
|
void Forward_PerkApplied (int client, int iPerk, int iDuration){
|
|
|
|
if(GetForwardFunctionCount(g_hFwdRolled) < 1)
|
|
return;
|
|
|
|
Call_StartForward(g_hFwdRolled);
|
|
Call_PushCell(client);
|
|
Call_PushCell(iPerk);
|
|
Call_PushCell(iDuration);
|
|
Call_Finish();
|
|
|
|
}
|
|
|
|
void Forward_PerkRemoved (int client, int iPerk, int iReason){
|
|
|
|
if(GetForwardFunctionCount(g_hFwdRemoved) < 1)
|
|
return;
|
|
|
|
Call_StartForward(g_hFwdRemoved);
|
|
Call_PushCell(client);
|
|
Call_PushCell(iPerk);
|
|
Call_PushCell(iReason);
|
|
Call_Finish();
|
|
|
|
}
|
|
|
|
void Forward_OnRegOpen (){
|
|
|
|
if(GetForwardFunctionCount(g_hFwdOnRegOpen) < 1)
|
|
return;
|
|
|
|
Call_StartForward(g_hFwdOnRegOpen);
|
|
Call_Finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
//***********************//
|
|
//---- S T O C K S ----//
|
|
//***********************//
|
|
|
|
//-----[ Strings ]-----//
|
|
|
|
stock bool PerkAllowedForClassOf (int client, int iPerkId){
|
|
|
|
switch(TF2_GetPlayerClass(client)){
|
|
|
|
case TFClass_Scout: {if(ePerks[iPerkId][iClasses] & 1) return true;}
|
|
case TFClass_Soldier: {if(ePerks[iPerkId][iClasses] & 2) return true;}
|
|
case TFClass_Pyro: {if(ePerks[iPerkId][iClasses] & 4) return true;}
|
|
case TFClass_DemoMan: {if(ePerks[iPerkId][iClasses] & 8) return true;}
|
|
case TFClass_Heavy: {if(ePerks[iPerkId][iClasses] & 16) return true;}
|
|
case TFClass_Engineer: {if(ePerks[iPerkId][iClasses] & 32) return true;}
|
|
case TFClass_Medic: {if(ePerks[iPerkId][iClasses] & 64) return true;}
|
|
case TFClass_Sniper: {if(ePerks[iPerkId][iClasses] & 128) return true;}
|
|
case TFClass_Spy: {if(ePerks[iPerkId][iClasses] & 256) return true;}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stock bool PerkAllowedForWeaponsOf (int client, int iPerkId){
|
|
|
|
if(ePerks[iPerkId][hWeaponClasses] == INVALID_HANDLE)
|
|
return true;
|
|
|
|
int iSize = GetArraySize(ePerks[iPerkId][hWeaponClasses]);
|
|
|
|
if(iSize < 1)
|
|
return true;
|
|
|
|
char sClass[32], sWeapClass[32];
|
|
int iWeapon = 0;
|
|
for(int i = 0; i < 5; i++){
|
|
|
|
iWeapon = GetPlayerWeaponSlot(client, i);
|
|
|
|
if(iWeapon <= MaxClients)
|
|
continue;
|
|
|
|
if(!IsValidEntity(iWeapon))
|
|
continue;
|
|
|
|
GetEntityClassname(iWeapon, sWeapClass, 32);
|
|
|
|
for(int j = 0; j < iSize; j++){
|
|
|
|
GetArrayString(ePerks[iPerkId][hWeaponClasses], j, sClass, 32);
|
|
if(StrContains(sWeapClass, sClass, false) > -1)
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stock bool IsPerkInTags (int iPerkId, const char[] sTagString, iTagNum){
|
|
|
|
char[][] sPieces = new char[iTagNum][32];
|
|
ExplodeString(sTagString, "|", sPieces, iTagNum, 32);
|
|
|
|
int iPerkTags = GetArraySize(ePerks[iPerkId][hTags]);
|
|
char sThisTag[16];
|
|
|
|
for(int i = 0; i < iTagNum; i++)
|
|
for(int j = 0; j < iPerkTags; j++){
|
|
|
|
GetArrayString(ePerks[iPerkId][hTags], j, sThisTag, 16);
|
|
if(StrEqual(sThisTag, sPieces[i], false))
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stock int CountTagOccurences (const char[] sTag, int iTagSize){
|
|
|
|
int count = 0;
|
|
for(int i = 0; i < g_iPerkCount; i++){
|
|
|
|
if(IsPerkInTags(i, sTag, 1))
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
stock int CountCharInString (const char[] sString, char cChar){
|
|
|
|
int i = 0, count = 0;
|
|
|
|
while(sString[i] != '\0')
|
|
if(sString[i++] == cChar)
|
|
count++;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
stock int EscapeString (const char[] input, int escape, int escaper, char[] output, int maxlen){
|
|
|
|
/*
|
|
Thanks Popoklopsi for EscapeString()
|
|
https://forums.alliedmods.net/showthread.php?t=212230
|
|
*/
|
|
|
|
// Number of chars we escaped
|
|
int escaped = 0;
|
|
|
|
// Format output buffer to ""
|
|
Format(output, maxlen, "");
|
|
|
|
|
|
// For each char in the input string
|
|
for(int offset = 0; offset < strlen(input); offset++){
|
|
|
|
// Get char at the current position
|
|
int ch = input[offset];
|
|
|
|
// Found the escape or escaper char
|
|
if(ch == escape || ch == escaper){
|
|
|
|
// Escape the escape char with the escaper^^
|
|
Format(output, maxlen, "%s%c%c", output, escaper, ch);
|
|
|
|
// Increase numbers of chars we escaped
|
|
escaped++;
|
|
|
|
}else
|
|
// Add other char to output buffer
|
|
Format(output, maxlen, "%s%c", output, ch);
|
|
}
|
|
|
|
// Return escaped chars
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Feedback ]-----//
|
|
|
|
stock void PrintToChatAllExcept (int client, char[] sMessage){
|
|
|
|
for(int i = 1; i <= MaxClients; i++){
|
|
|
|
if(!IsValidClient(i) || i == client) continue;
|
|
|
|
PrintToChat(i, sMessage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stock void DisplayPerkTimeFrame (client){
|
|
|
|
int iTeam = GetClientTeam(client);
|
|
int iRed = (iTeam == 2) ? 255 : 32;
|
|
int iBlue = (iTeam == 3) ? 255 : 32;
|
|
|
|
SetHudTextParams(g_fCvarTimerPosX, g_fCvarTimerPosY, 1.0, iRed, 32, iBlue, 255);
|
|
ShowSyncHudText(client, eClients[client][hHudSync], "%s: %d", ePerks[eClients[client][iCurPerk]][sName], eClients[client][iPerkEnd] -GetTime());
|
|
|
|
}
|
|
|
|
|
|
//-----[ Perks ]-----//
|
|
|
|
stock int ClassStringToFlags (char[] sClasses){
|
|
|
|
if(FindCharInString(sClasses, '0') > -1)
|
|
return 511;
|
|
|
|
int iLength = strlen(sClasses);
|
|
if(iLength < 2){
|
|
int iClass = StringToInt(sClasses);
|
|
if(iClass < 1)
|
|
return 0;
|
|
else
|
|
return iPow(2, iClass-1);
|
|
}else{
|
|
|
|
int iCharSize = (iLength+1)/2;
|
|
char[][] sPieces = new char[iCharSize][4];
|
|
ExplodeString(sClasses, ",", sPieces, iCharSize, 4);
|
|
|
|
int iValue = 0, iPowed = 0, iFlags = 0;
|
|
for(int i = 0; i < iCharSize; i++){
|
|
|
|
iValue = StringToInt(sPieces[i]);
|
|
if(iValue > 9) continue;
|
|
|
|
iPowed = iPow(2, iValue-1);
|
|
if(iFlags & iPowed) continue;
|
|
|
|
iFlags |= iPowed;
|
|
|
|
}
|
|
|
|
return iFlags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stock int GetPerkOfString (const char[] sString, int iStringSize){
|
|
|
|
int iString = StringToInt(sString);
|
|
if(!(FindCharInString(sString, '0') < 0 && iString == 0))
|
|
return iString;
|
|
|
|
for(int i = 0; i < g_iPerkCount; i++){
|
|
|
|
if(StrEqual(sString, ePerks[i][sToken]))
|
|
return i;
|
|
|
|
}
|
|
|
|
if(CountTagOccurences(sString, iStringSize) == 1)
|
|
for(int j = 0; j < g_iPerkCount; j++){
|
|
|
|
if(IsPerkInTags(j, sString, 1))
|
|
return j;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
stock int GetPerkTime (int iPerkId){
|
|
|
|
return (ePerks[iPerkId][iTime] > 0) ? ePerks[iPerkId][iTime] : g_iCvarPerkDuration;
|
|
|
|
}
|
|
|
|
stock int GetNextAvailableGroup (){
|
|
|
|
for(int i = 0; i <= MaxClients; i++)
|
|
if(!eGroup[i][bActive])
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Miscellaneous ]-----//
|
|
|
|
stock int ReadFlagFromConVar (Handle hCvar){
|
|
|
|
char sBuffer[32];
|
|
GetConVarString(hCvar, sBuffer, sizeof(sBuffer));
|
|
|
|
return ReadFlagString(sBuffer);
|
|
|
|
}
|
|
|
|
stock int ConnectWithBeam (int iEnt, int iEnt2, int iRed=255, int iGreen=255, int iBlue=255, float fStartWidth=1.0, float fEndWidth=1.0, float fAmp=1.35){
|
|
|
|
int iBeam = CreateEntityByName("env_beam");
|
|
|
|
if(iBeam <= MaxClients)
|
|
return -1;
|
|
|
|
if(!IsValidEntity(iBeam))
|
|
return -1;
|
|
|
|
SetEntityModel(iBeam, LASERBEAM);
|
|
|
|
char sColor[16];
|
|
Format(sColor, sizeof(sColor), "%d %d %d", iRed, iGreen, iBlue);
|
|
|
|
DispatchKeyValue(iBeam, "rendercolor", sColor);
|
|
DispatchKeyValue(iBeam, "life", "0");
|
|
|
|
DispatchSpawn(iBeam);
|
|
|
|
SetEntPropEnt(iBeam, Prop_Send, "m_hAttachEntity", EntIndexToEntRef(iEnt));
|
|
SetEntPropEnt(iBeam, Prop_Send, "m_hAttachEntity", EntIndexToEntRef(iEnt2), 1);
|
|
|
|
SetEntProp(iBeam, Prop_Send, "m_nNumBeamEnts", 2);
|
|
SetEntProp(iBeam, Prop_Send, "m_nBeamType", 2);
|
|
|
|
SetEntPropFloat(iBeam, Prop_Data, "m_fWidth", 1.0);
|
|
SetEntPropFloat(iBeam, Prop_Data, "m_fEndWidth", 1.0);
|
|
|
|
SetEntPropFloat(iBeam, Prop_Data, "m_fAmplitude", 1.35);
|
|
|
|
SetVariantFloat(32.0);
|
|
AcceptEntityInput(iBeam, "Amplitude");
|
|
AcceptEntityInput(iBeam, "TurnOn");
|
|
|
|
return iBeam;
|
|
|
|
}
|
|
|
|
stock int CreateParticle (int iClient, char[] strParticle, bool bAttach=true, char[] strAttachmentPoint="", float fOffset[3]={0.0, 0.0, 36.0}){
|
|
|
|
//Thanks J-Factor for CreateParticle()
|
|
|
|
int iParticle = CreateEntityByName("info_particle_system");
|
|
if(!IsValidEdict(iParticle)) return 0;
|
|
|
|
float fPosition[3], fAngles[3], fForward[3], fRight[3], fUp[3];
|
|
|
|
// Retrieve entity's position and angles
|
|
GetClientAbsOrigin(iClient, fPosition);
|
|
GetClientAbsAngles(iClient, fAngles);
|
|
|
|
// Determine vectors and apply offset
|
|
GetAngleVectors(fAngles, fForward, fRight, fUp); // I assume 'x' is Right, 'y' is Forward and 'z' is Up
|
|
fPosition[0] += fRight[0]*fOffset[0] + fForward[0]*fOffset[1] + fUp[0]*fOffset[2];
|
|
fPosition[1] += fRight[1]*fOffset[0] + fForward[1]*fOffset[1] + fUp[1]*fOffset[2];
|
|
fPosition[2] += fRight[2]*fOffset[0] + fForward[2]*fOffset[1] + fUp[2]*fOffset[2];
|
|
|
|
// Teleport and attach to client
|
|
TeleportEntity(iParticle, fPosition, fAngles, NULL_VECTOR);
|
|
DispatchKeyValue(iParticle, "effect_name", strParticle);
|
|
|
|
if(bAttach){
|
|
|
|
SetVariantString("!activator");
|
|
AcceptEntityInput(iParticle, "SetParent", iClient, iParticle, 0);
|
|
|
|
if(!StrEqual(strAttachmentPoint, "")){
|
|
|
|
SetVariantString(strAttachmentPoint);
|
|
AcceptEntityInput(iParticle, "SetParentAttachmentMaintainOffset", iParticle, iParticle, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Spawn and start
|
|
DispatchSpawn(iParticle);
|
|
ActivateEntity(iParticle);
|
|
AcceptEntityInput(iParticle, "Start");
|
|
|
|
return iParticle;
|
|
|
|
}
|
|
|
|
stock void FixPotentialStuck (int client){
|
|
|
|
if(!g_bCvarRespawnStuck)
|
|
return;
|
|
|
|
if(client < 1 || client > MaxClients)
|
|
return;
|
|
|
|
if(!IsClientInGame(client))
|
|
return;
|
|
|
|
CreateTimer(0.1, Timer_FixStuck, GetClientSerial(client));
|
|
|
|
}
|
|
|
|
public Action Timer_FixStuck (Handle hTimer, int iSerial){
|
|
|
|
int client = GetClientFromSerial(iSerial);
|
|
|
|
if(client < 1 || client > MaxClients)
|
|
return Plugin_Stop;
|
|
|
|
if(!IsClientInGame(client))
|
|
return Plugin_Stop;
|
|
|
|
if(!IsPlayerAlive(client))
|
|
return Plugin_Stop;
|
|
|
|
if(!IsEntityStuck(client))
|
|
return Plugin_Stop;
|
|
|
|
PrintToChat(client, "%s %T", CHAT_PREFIX, "RTD2_Stuck_Respawn", LANG_SERVER);
|
|
TF2_RespawnPlayer(client);
|
|
|
|
return Plugin_Stop;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Checks ]-----//
|
|
|
|
stock int FindPerkByToken (const char[] sCheckToken){
|
|
|
|
for(int i = 0; i < g_iPerkCount; i++)
|
|
if(StrEqual(sCheckToken, ePerks[i][sToken], false))
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
stock bool IsArgumentTrigger (const char[] sArg){
|
|
|
|
char sTrigger[16];
|
|
for(int i = 0; i < g_iCvarTriggers; i++){
|
|
|
|
GetArrayString(g_arrCvarTriggers, i, sTrigger, 16);
|
|
if(StrEqual(sArg, sTrigger, false))
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stock bool IsEntityStuck (int iEntity){
|
|
|
|
float fPos[3], fMins[3], fMaxs[3];
|
|
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fPos);
|
|
GetEntPropVector(iEntity, Prop_Send, "m_vecMins", fMins);
|
|
GetEntPropVector(iEntity, Prop_Send, "m_vecMaxs", fMaxs);
|
|
|
|
TR_TraceHullFilter(fPos, fPos, fMins, fMaxs, MASK_SOLID, TraceFilterIgnoreSelf, iEntity);
|
|
return TR_DidHit();
|
|
|
|
}
|
|
|
|
stock bool IsRollerAllowed (int client){
|
|
|
|
if(g_iCvarAllowed > 0)
|
|
return view_as<bool>(GetUserFlagBits(client) & g_iCvarAllowed);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
stock bool IsRollerDonator (int client){
|
|
|
|
if(g_iCvarDonatorFlag > 0)
|
|
return view_as<bool>(GetUserFlagBits(client) & g_iCvarDonatorFlag);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stock bool CanBuildAtPos (float fPos[3], bool bSentry){
|
|
|
|
//TODO: Figure out a neat way of checking nobuild areas. I've spent 5h non stop trying to do it, help pls.
|
|
|
|
float fMins[3], fMaxs[3];
|
|
if(bSentry){
|
|
|
|
fMins[0] = -20.0;
|
|
fMins[1] = -20.0;
|
|
fMins[2] = 0.0;
|
|
|
|
fMaxs[0] = 20.0;
|
|
fMaxs[1] = 20.0;
|
|
fMaxs[2] = 66.0;
|
|
|
|
}else{
|
|
|
|
fMins[0] = -24.0;
|
|
fMins[1] = -24.0;
|
|
fMins[2] = 0.0;
|
|
|
|
fMaxs[0] = 24.0;
|
|
fMaxs[1] = 24.0;
|
|
fMaxs[2] = 55.0;
|
|
|
|
}
|
|
|
|
TR_TraceHull(fPos, fPos, fMins, fMaxs, MASK_SOLID);
|
|
return !TR_DidHit();
|
|
|
|
}
|
|
|
|
stock bool CanPlayerBeHurt (int client, int by=0){
|
|
|
|
if(IsValidClient(by))
|
|
if(GetClientTeam(by) == GetClientTeam(client))
|
|
return false;
|
|
|
|
if(IsPlayerFriendly(client))
|
|
return false;
|
|
|
|
if(TF2_IsPlayerInCondition(client, TFCond_Ubercharged))
|
|
return false;
|
|
|
|
if(GetEntProp(client, Prop_Data, "m_takedamage") != 2)
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
stock bool IsPlayerFriendly (int client){
|
|
|
|
if(g_bPluginFriendly)
|
|
if(TF2Friendly_IsFriendly(client))
|
|
return true;
|
|
|
|
if(g_bPluginFriendlySimple)
|
|
if(FriendlySimple_IsFriendly(client))
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stock bool CanEntitySeeTarget (int entity, int iTarget){
|
|
|
|
float fStart[3], fEnd[3];
|
|
|
|
if(IsValidClient(entity))
|
|
GetClientEyePosition(entity, fStart);
|
|
else
|
|
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", fStart);
|
|
|
|
if(IsValidClient(iTarget))
|
|
GetClientEyePosition(iTarget, fEnd);
|
|
else
|
|
GetEntPropVector(iTarget, Prop_Send, "m_vecOrigin", fEnd);
|
|
|
|
Handle hTrace = TR_TraceRayFilterEx(fStart, fEnd, MASK_SOLID, RayType_EndPoint, TraceFilterIgnorePlayersAndSelf, entity);
|
|
if(hTrace != INVALID_HANDLE){
|
|
|
|
if(TR_DidHit(hTrace)){
|
|
|
|
CloseHandle(hTrace);
|
|
return false;
|
|
|
|
}
|
|
|
|
CloseHandle(hTrace);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
stock bool IsRTDInRound (){
|
|
|
|
if(GameRules_GetProp("m_bInWaitingForPlayers", 1))
|
|
return false;
|
|
|
|
if(!g_bCvarInSetup){
|
|
|
|
if(g_bIsGameArena && GameRules_GetRoundState() != view_as<RoundState>(7))
|
|
return false;
|
|
|
|
if(GameRules_GetProp("m_bInSetup", 1))
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Trace ]-----//
|
|
|
|
public bool TraceFilterIgnoreSelf (int iEntity, int iContentsMask, any iTarget){
|
|
|
|
if(iEntity == iTarget)
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
public bool TraceFilterIgnorePlayers (int iEntity, int iContentsMask, any data){
|
|
|
|
if(iEntity >= 1 && iEntity <= MaxClients)
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
public bool TraceFilterIgnorePlayersAndSelf (int iEntity, int iContentsMask, any iTarget){
|
|
|
|
if(iEntity >= 1 && iEntity <= MaxClients)
|
|
return false;
|
|
|
|
if(iEntity == iTarget)
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
stock bool GetClientLookPosition (int client, float fPosition[3]){
|
|
|
|
float fPos[3], fAng[3];
|
|
GetClientEyePosition(client, fPos);
|
|
GetClientEyeAngles(client, fAng);
|
|
|
|
Handle hTrace = TR_TraceRayFilterEx(fPos, fAng, MASK_SHOT, RayType_Infinite, TraceFilterIgnorePlayers, client);
|
|
if(hTrace != INVALID_HANDLE && TR_DidHit(hTrace)){
|
|
|
|
TR_GetEndPosition(fPosition, hTrace);
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
//-----[ Helpers ]-----//
|
|
|
|
stock int AccountIDToClient (int iAccountID){
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
if(IsClientInGame(i))
|
|
if(GetSteamAccountID(i) == iAccountID)
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
stock void KillTimerSafe (Handle &hTimer){
|
|
|
|
if(hTimer == INVALID_HANDLE)
|
|
return;
|
|
|
|
KillTimer(hTimer);
|
|
hTimer = INVALID_HANDLE;
|
|
|
|
}
|
|
|
|
stock int iPow (int iValue, int iExponent){
|
|
|
|
//Thanks, D.Moder
|
|
return RoundFloat(Pow(float(iValue), float(iExponent)));
|
|
|
|
}
|
|
|
|
public bool IsValidClient (int client){
|
|
|
|
if(client > 4096){
|
|
client = EntRefToEntIndex(client);
|
|
}
|
|
|
|
if(client < 1 || client > MaxClients) return false;
|
|
|
|
if(!IsClientInGame(client)) return false;
|
|
|
|
if(IsFakeClient(client)) return false;
|
|
|
|
if(GetEntProp(client, Prop_Send, "m_bIsCoaching")) return false;
|
|
|
|
return true;
|
|
|
|
} |