mirror of
https://github.com/ENSL/ensl-plugin.git
synced 2024-11-22 20:41:33 +00:00
4600 lines
132 KiB
Text
4600 lines
132 KiB
Text
/*
|
|
Plugin generated by AMXX-Studio
|
|
European Natural Selection League Plugin
|
|
|
|
Author: Ari "jiriki" Timonen
|
|
|
|
Credits:
|
|
- DarkSnow's socket example
|
|
- CAL Features by CAL-ns|Austin (xHomicide) and Jim "JazzX" Olson
|
|
- Asmodee for waypoint fixes & weaponfix & other fixes
|
|
- Multivac's Jetpack FIX
|
|
- sawce's icons plugin
|
|
- www.nsmod.org
|
|
- www.amxmodx.org
|
|
|
|
TODO:
|
|
SQLx threaded
|
|
-> gather early joining block
|
|
/mercsok not working?
|
|
amx_enslmove not working
|
|
AFK kicker
|
|
*/
|
|
|
|
#include <amxmodx>
|
|
#include <amxmisc>
|
|
#include <sockets>
|
|
#include <fakemeta>
|
|
#include <fakemeta_stocks>
|
|
#include <engine>
|
|
#include <ns>
|
|
#include <fun>
|
|
#include <nsteam>
|
|
|
|
|
|
/**************************************************************************************
|
|
* Global constants
|
|
**************************************************************************************/
|
|
|
|
// Basic constants
|
|
#define PLUGIN "ENSL"
|
|
#define VERSION "1.4"
|
|
#define AUTHOR "jiriki"
|
|
#define WEB "www.ensl.org"
|
|
#define CHANNEL "#ENSL"
|
|
#define PASSWORD "europe"
|
|
|
|
// AMX constants
|
|
#define A_LEN_CMD 32 // Maximum length of command name
|
|
#define A_LEN_CMDINFO 100 // Maximum length of command info
|
|
|
|
// Global settings
|
|
#define G_FREQ 5.0 // Global command delay
|
|
|
|
// User tracking
|
|
#define U_NUM_IDS 32 // Maximum number of users to track
|
|
|
|
// Task ID's
|
|
#define T_ADVERT 26
|
|
#define T_MAPBOOT 27 // Map boot
|
|
#define T_JPCHECK 28 // Jetpack check
|
|
#define T_STARTUP 29 // Startup
|
|
#define T_AUTH 30 // Authentication
|
|
#define T_OPTIONS 31 // Optionchecking
|
|
#define T_RATECHECK 32 // Ratechecking
|
|
#define T_FFCLOCK 33 // Forfeit clock
|
|
#define T_HLTV 36 // Query: HLTV
|
|
#define T_ESI 37 // Query: ESI
|
|
#define T_AREQ 38 // Query: Admin Request
|
|
#define T_BAN 39 // Query: Global Ban
|
|
#define T_USER 100 // Query: User
|
|
|
|
// HL/NS-related
|
|
#define HL_NUM_PLAYERS 32 // Maximum number of players
|
|
#define HL_NUM_COLUMN 10 // Maximum number of columns
|
|
#define HL_LEN_NICK 31 // Maximum length of player nick
|
|
#define HL_LEN_STEAMID 31 // Maximum length of SteamID
|
|
#define HL_LEN_IP 15 // Maximum length of IP address
|
|
#define HL_LEN_PORT 5 // Maximum length of server port
|
|
#define HL_LEN_ADDR 21 // Maximum length of server address
|
|
#define HL_LEN_DNS 50 // Maximum length of DNS
|
|
#define HL_LEN_TEAM 15 // Maxmium length of teamname
|
|
#define HL_LEN_COLUMN 20 // Maxmium length of column
|
|
#define HL_LEN_SAY 191 // Maximum length of say msg
|
|
#define HL_LEN_MSG 140 // Maximum length of console msg
|
|
#define HL_LEN_POPUP 179 // Maxmium length of popup message
|
|
#define HL_LEN_HUDMESSAGE 478 // Maxmium length of HUD message
|
|
#define HL_LEN_MAP 25 // Maximum length of mapname
|
|
#define HL_LEN_CMD 31 // Maximum length of cmdname
|
|
#define HL_LEN_INFO 127 // Maximum length of cmdinfo
|
|
#define HL_LEN_PWD 20 // Maximum length of password
|
|
#define HL_ENT_MARINES 78 // Marine team joining entity
|
|
#define HL_ENT_ALIENS 77 // Alien --
|
|
|
|
// Help
|
|
#define H_NUM_CVARS 12 // Number of CVARs
|
|
|
|
// ENSL query
|
|
#define W_IP "78.46.36.107" // Script IP
|
|
#define W_HOST "www.ensl.org" // Script hostname
|
|
#define W_PORT 80 // Script port
|
|
#define W_TIMEOUT 1 // HTTP Timeout
|
|
#define W_READS 10 // Read attempts
|
|
#define W_NEWLINE 13 // Newline character code
|
|
#define W_NUM_LINES 30 // Number of script's output lines
|
|
#define W_LEN_URL 230 // Maximum length of query's URL
|
|
#define W_LEN_QUERY 250 // Maximum length of query
|
|
#define W_LEN_INPUT 2048 // Maximum length of input buffer
|
|
#define W_LEN_MARK 10 // Maximum length of start mark
|
|
#define W_LEN_LINE 160 // Maximum length of output line
|
|
#define W_LEN_CH 10 // Maximum length of challenge code
|
|
#define W_LEN_FUNC 30 // Maximum length of handl. func.
|
|
#define W_MARK "#RESPONSE#" // General response mark
|
|
|
|
// ENSL Server Information
|
|
#define S_URL "http://www.ensl.org/plugin/esi" // Script URL (ensl server info.)
|
|
#define S_MARK "#ESI#" // Mark for found http line
|
|
#define S_NUM_LINES 4 // Number of data lines (ex. chal.)
|
|
#define S_LEN_TS 10 // Maximum length of timestamp
|
|
|
|
// ENSL Admin request
|
|
#define AR_URL "http://www.ensl.org/plugin/admin" // Script URL (adminrequest)
|
|
#define AR_LEN_MSG 100 // Maximum length of timestamp
|
|
|
|
// ENSL Global Bans
|
|
#define B_URL "http://www.ensl.org/plugin/ban/" // Script URL (global ban)
|
|
#define B_LEN_MSG 50 // Maximum length of ban reason
|
|
|
|
// ENSL HLTV
|
|
#define HT_URL "http://www.ensl.org/plugin/hltv_" // Script URL (HLTV)
|
|
#define HT_MARK "#HLTV#" // Mark for found http line
|
|
#define HT_NUM_LINES 1 // Number of data lines (ex. chal.)
|
|
#define HT_LEN_RESPONSE 160 // Maximum length of ENSL Servers
|
|
#define HT_LEN_DEMO 40 // Maximum length of demo name
|
|
|
|
// ENSL playerinfo
|
|
#define E_URL "http://www.ensl.org/plugin/user/" // Script URL (user query)
|
|
#define E_MARK "#USER#" // Mark for found HTTP line
|
|
#define E_NUM_LINES 11 // Number of data lines (ex. chal.)
|
|
#define E_LEN_NICK 50 // Maximum length of username
|
|
#define E_LEN_IP 15 // Maximum length of IP
|
|
#define E_LEN_TEAM 50 // Maximum length of teamname
|
|
#define E_LEN_LEVEL 10 // Maximum length of level
|
|
#define E_LEN_RANK 10 // Maximum length of rank
|
|
#define E_LEN_IDS 10 // Maximum length of ID's
|
|
#define E_LEVEL_USER "User" // User level: user
|
|
#define E_LEVEL_DONOR "Donor" // User level: donor
|
|
#define E_LEVEL_REFEREE "Referee" // User level: referee
|
|
#define E_LEVEL_ADMIN "Admin" // User level: admin
|
|
#define E_LEVEL_NOTFOUND "Not Found" // User level: not found
|
|
#define E_RANK_MEMBER "Member" // User level: member
|
|
#define E_RANK_DEPUTEE "Deputee" // User level: deputee
|
|
#define E_RANK_LEADER "Leader" // User level: leader
|
|
#define E_RANK_NA "N/A" // User level: not applicable
|
|
|
|
// Confirmation code
|
|
#define CC_PASSCODE1 "9WvcZ9hX" // First part
|
|
#define CC_PASSCODE2 "KF7L4luQ" // Second part
|
|
#define CC_LEN_CODE 10 // Length of result
|
|
#define CC_LEN_INPUT 250 // Length of input
|
|
#define CC_LEN_MD5 33 // Length of MD5 checksum
|
|
|
|
// Variable/rate-checking
|
|
#define RC_DISABLED 0 // Ratechecking: disabled
|
|
#define RC_ENABLED_KICK 1 // Ratechecking: enabled, kicks ON
|
|
#define RC_ENABLED_WARN 2 // Ratechecking: enabled, kicks OFF
|
|
#define RC_ENABLED_FETCH 3 // Ratechecking: enabled, fetch only
|
|
#define RC_WARN_NEGATIVE 0 // Rate warning: yes
|
|
#define RC_WARN_POSITIVE 1 // Rate warning: on
|
|
#define RC_WARN_REQUEST 2 // Rate warning: requested
|
|
#define RC_LEN_RANGE 20 // Maximum length of range string
|
|
|
|
// Server CVARs
|
|
#define C_LEN_NAME 30 // Maximum length of CVAR name
|
|
#define C_NUM_INTS 41 // Number of integer CVAR's
|
|
#define C_NUM_FLOATS 2 // Number of float CVAR's
|
|
#define C_LEVEL_MANDATORY 0 // Importance: mandatory
|
|
#define C_LEVEL_VOLUNTARY 1 // Importance: voluntary
|
|
|
|
// Referee commands
|
|
#define R_LEN_KICKREASON 30 // Maximum length of kick reason
|
|
#define R_LEN_MINS 3 // Maximum length of ban time (mins)
|
|
#define R_LEN_NUM 6 // Maximum length of a number value
|
|
#define R_MAX_MINS 180 // Maximum ban time (mins)
|
|
|
|
// Icons
|
|
#define I_AUTH_ICON 512 // Msg Type: custom icon
|
|
#define I_AUTH_NORMAL 0 // Msg Type: normal icon
|
|
#define I_LEN_ICON 35 // Maximum length of icon name
|
|
#define I_LEN_PATH 255 // Maximum length of icon name
|
|
|
|
// Flashlight block
|
|
#define F_FREQ 0.3 // Flashlight delay
|
|
#define F_IMLUPSE 100 // Flashlight impulse number
|
|
|
|
// Timetext
|
|
#define TT_LEN_OUTPUT 40 // Maximum length of time text
|
|
|
|
// Join delay
|
|
#define DD_DELAY_DIGESTED 50 // Delay when disc. from belly
|
|
|
|
// Combat
|
|
#define CO_NORMAL 0 // Normal combat
|
|
#define CO_CELERESUPPLY 1 // Celeresupply combat
|
|
#define CO_ENSL 2 // ENSL Combat
|
|
#define CO_SGSFADES 3 // SGs vs Fades
|
|
#define CO_SGSKULKS 4 // SGs vs Skulks
|
|
#define CO_LMGLERKS 5 // LMGs vs Lerks
|
|
#define CO_NUM_MODES 6 // Number of combat modes
|
|
#define CO_NUM_UPGRADES 40 // Maximum number of upgrades
|
|
|
|
// Forfeit counter
|
|
#define FF_TIME 600.0 // Forfeit counter time (secs)
|
|
|
|
// Unstuck
|
|
#define S_B MASK_PLAYER_STUNNED|MASK_ENSNARED|MASK_ALIEN_EMBRYO // Blocked masks
|
|
#define S_START_DISTANCE 32 // The first search distance
|
|
#define S_NUM_ATTEMPTS 128 // Max attempts to search free spot
|
|
#define S_NUM_DISTANCE 1000 // Max unstuck spot distance
|
|
|
|
// Waypoints
|
|
#define WP_GUARD 5 // Waypoint guard
|
|
|
|
|
|
/**************************************************************************************
|
|
* Enums
|
|
**************************************************************************************/
|
|
|
|
enum
|
|
{
|
|
SI_PLAYER = 1,
|
|
SI_SCORE,
|
|
SI_KILLS,
|
|
SI_DEATHS,
|
|
SI_LEVEL,
|
|
SI_CLASS,
|
|
SI_AUTH,
|
|
SI_TEAM,
|
|
SI_HEALTH,
|
|
SI_ICON,
|
|
SI_NUM_SCOREVARS
|
|
}
|
|
|
|
enum
|
|
{
|
|
HL_RRSPECS = 0,
|
|
HL_MARINES,
|
|
HL_ALIENS,
|
|
HL_NUM_TEAMS
|
|
}
|
|
|
|
enum
|
|
{
|
|
CT_GENERAL = 0,
|
|
CT_TEAMJOIN,
|
|
CT_NUM_CMDS
|
|
}
|
|
|
|
enum
|
|
{
|
|
W_I_ESI = 0,
|
|
W_I_HLTV,
|
|
W_I_AREQ,
|
|
W_I_BAN,
|
|
W_NUM_FUNCS
|
|
}
|
|
|
|
enum
|
|
{
|
|
I_I_DONOR = 0,
|
|
I_I_CHAMP,
|
|
I_I_REF,
|
|
I_I_ADMIN,
|
|
I_NUM_ICONS
|
|
}
|
|
|
|
enum
|
|
{
|
|
RC_I_RATE = 0,
|
|
RC_I_CMDRATE,
|
|
RC_I_UPDATERATE,
|
|
RC_I_FPS,
|
|
RC_NUM_VARS
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Global variables
|
|
**************************************************************************************/
|
|
|
|
new g_gameStarted = 0 // Game started?
|
|
new g_gameEnding = 0 // Game ending?
|
|
new g_gameModerated = 0 // Game chat moderated?
|
|
new g_gameHltvs = 0 // Number of HLTV on server
|
|
|
|
new g_pauseStatus = 0 // Game paused?
|
|
new g_pausePending = 0 // Pending pause cmd from user?
|
|
new g_pauseReq = 0 // Pause requestor?
|
|
|
|
new g_timeFetchedRemote = 0 // Remote time when time was fetched
|
|
new Float:g_timeFetchedLocal = 0.0 // Local time when time was fetched
|
|
|
|
new g_userIndex = 0 // PID table index
|
|
new g_userCount = 0 // PID table cells used
|
|
|
|
new Float:g_flashTime[HL_NUM_PLAYERS + 1] // List: User ID <-> last FL-time
|
|
new g_userAuthed[HL_NUM_PLAYERS + 1] // List: User ID <-> authenticated?
|
|
new g_userIconIndex[HL_NUM_PLAYERS + 1] // List: User ID <-> icon index
|
|
new g_userIconFlags[HL_NUM_PLAYERS + 1] // List: User ID <-> icon flags
|
|
new Float:g_userCmdTime[HL_NUM_PLAYERS + 1][CT_NUM_CMDS] // List: User ID <-> cmdId <-> time
|
|
new g_userCmdWarn[HL_NUM_PLAYERS + 1][CT_NUM_CMDS] // List: User ID <-> cmdId <-> warned?
|
|
new g_userDefendWP[HL_NUM_PLAYERS + 1] // List: User ID <-> guard waypoint
|
|
new g_userOrderType[HL_NUM_PLAYERS + 1]; // List: User ID <-> waypoint type
|
|
new g_userPidIndex[HL_NUM_PLAYERS + 1] // List: User ID <-> PID
|
|
|
|
new g_iconName[I_NUM_ICONS][I_LEN_ICON + 1] // Icon id <-> Icon name + color
|
|
new g_iconFlags[I_NUM_ICONS] // Icon id <-> Icon flag
|
|
|
|
new g_userIdIndex[U_NUM_IDS] // List: PID <-> User ID
|
|
new g_userStatus[U_NUM_IDS] // List: PID <-> On server?
|
|
new g_userName[U_NUM_IDS][HL_LEN_NICK + 1] // List: PID <-> Name
|
|
new g_userSteamID[U_NUM_IDS][HL_LEN_STEAMID + 1] // List: PID <-> Steam ID
|
|
new g_userIP[U_NUM_IDS][HL_LEN_IP + 1] // List: PID <-> IP Address
|
|
new g_userTeam[U_NUM_IDS] // List. PID <-> Team
|
|
new g_userRCVars[U_NUM_IDS][RC_NUM_VARS] // List: PID <-> var <-> value
|
|
new g_userRCWarn[U_NUM_IDS][RC_NUM_VARS] // List: PID <-> var <-> warned?
|
|
new g_userWebSocket[U_NUM_IDS] // List: PID <-> web socket
|
|
new g_userWebHex[U_NUM_IDS][CC_LEN_CODE + 1] // List: PID <-> web hex challenge
|
|
new g_userWebReads[U_NUM_IDS] // List: PID <-> web reads
|
|
new g_userWebData[U_NUM_IDS][E_NUM_LINES][W_LEN_LINE + 1] // List: PID <-> web data
|
|
new g_userWebDataLine[U_NUM_IDS] // List: PID <-> web data line idx
|
|
new g_userEnslInfo[U_NUM_IDS] // List: PID <-> Exists in ENSL DB?
|
|
new g_userEnslNick[U_NUM_IDS][E_LEN_NICK + 1] // List: PID <-> ENSL Nick
|
|
new g_userEnslIP[U_NUM_IDS][E_LEN_IP + 1] // List: PID <-> ENSL IP
|
|
new g_userEnslTeam[U_NUM_IDS][E_LEN_TEAM + 1] // List: PID <-> ENSL Team
|
|
new g_userEnslId[U_NUM_IDS] // List: PID <-> ENSL User ID
|
|
new g_userEnslTid[U_NUM_IDS] // List: PID <-> ENSL Team ID
|
|
new g_userEnslLevel[U_NUM_IDS][E_LEN_LEVEL + 1] // List: PID <-> ENSL Level
|
|
new g_userEnslRank[U_NUM_IDS][E_LEN_RANK + 1] // List: PID <-> ENSL Rank
|
|
new g_userEnslGather[U_NUM_IDS] // List: PID <-> ENSL Gather status
|
|
new g_userCode[U_NUM_IDS][CC_LEN_CODE + 1] // List: PID <-> Verification code
|
|
new g_userSSPassed[U_NUM_IDS] // List: PID <-> Deaths /wo snapshot
|
|
new g_userSSCount[U_NUM_IDS] // List: PID <-> Deaths /w snapshot
|
|
new g_userSSRand[U_NUM_IDS] // List: PID <-> Random SS count
|
|
new g_userDDTime[U_NUM_IDS] // List: PID <-> Rejoin time
|
|
new g_userMerc[U_NUM_IDS] // List: PID <-> Mercable team
|
|
new g_userGagged[U_NUM_IDS] // List: PID <-> Gagged?
|
|
new g_userVoice[U_NUM_IDS] // List: PID <-> Allowed to talk?
|
|
new g_teamPlayers[HL_NUM_TEAMS] // List: Team <-> player counts
|
|
new g_teamReady[HL_NUM_TEAMS] // List: Team <-> ready?
|
|
new g_teamNames[HL_NUM_TEAMS][HL_LEN_TEAM + 1] // List: Team <-> name
|
|
new g_teamENSLId[HL_NUM_TEAMS] // List: Team <-> ENSL ID
|
|
new g_teamENSLName[HL_NUM_TEAMS][E_LEN_TEAM + 1] // List: Team <-> ENSL Name
|
|
new g_teamMReq[HL_NUM_TEAMS] // List: Team <-> requestor merc PID
|
|
|
|
new Float:g_FFCStarted = 0.0 // Forfeit clock: time started
|
|
new g_FFCUsed = 0 // Forfeit clock: time used
|
|
|
|
new g_cvarIntIndex = 0 // Server integer CVAR index
|
|
new g_cvarIntName[C_NUM_INTS][C_LEN_NAME + 1] // Server integer CVAR names
|
|
new g_cvarIntLevel[C_NUM_INTS] // Server integer CVAR importance
|
|
new g_cvarIntValue[C_NUM_INTS] // Server integer CVAR values
|
|
new g_cvarIntPCW[C_NUM_INTS] // Server integer CVAR PCW value
|
|
new g_cvarFltIndex = 0 // Server float CVAR index
|
|
new g_cvarFltName[C_NUM_FLOATS][C_LEN_NAME + 1] // Server float CVAR names
|
|
new g_cvarFltLevel[C_NUM_FLOATS] // Server float CVAR importance
|
|
new Float:g_cvarFltValue[C_NUM_FLOATS] // Server float CVAR values
|
|
new Float:g_cvarFltPCW[C_NUM_FLOATS] // Server float CVAR PCW value
|
|
|
|
new g_coNum[CO_NUM_MODES] // Combat: mode <-> numbr. of blocks
|
|
new g_coBlocked[CO_NUM_MODES][CO_NUM_UPGRADES] // Combat: mode <-> blocked impulses
|
|
|
|
new g_refSSUser = -1 // PID of the next ref SS target
|
|
|
|
new g_webSocket[W_NUM_FUNCS] // Function ID <-> websocket
|
|
new g_webHex[W_NUM_FUNCS][CC_LEN_CODE + 1] // Function ID <-> hex challenge
|
|
new g_webReads[W_NUM_FUNCS] // Function ID <-> reads
|
|
new g_webData[W_NUM_FUNCS][W_NUM_LINES][W_LEN_LINE + 1] // Function ID <-> line ID <-> data
|
|
new g_webDataLine[W_NUM_FUNCS] // Function ID <-> data line pointer
|
|
|
|
new g_msgId_SayText // MsgID: SayText
|
|
new g_msgId_Scoreboard // MsgID: Scoreboard
|
|
new g_msgId_Waypoint // MsgID: Waypoint
|
|
new g_msgId_DeathMsg = 0; // MsgID: Death
|
|
|
|
new g_maxPlayers = 0; // Maxplayers
|
|
new g_mapBootMins = 0 // Map boot cycles
|
|
|
|
|
|
/**************************************************************************************
|
|
* CVARs
|
|
**************************************************************************************/
|
|
|
|
new g_cvar_minrate
|
|
new g_cvar_maxrate
|
|
new g_cvar_mincmdrate
|
|
new g_cvar_maxcmdrate
|
|
new g_cvar_minupdaterate
|
|
new g_cvar_maxupdaterate
|
|
new g_cvar_minfps
|
|
new g_cvar_maxfps
|
|
new g_cvar_checkids
|
|
new g_cvar_checkrates
|
|
new g_cvar_snapshots
|
|
new g_cvar_ffclock
|
|
new g_cvar_merclimit
|
|
new g_cvar_teamlimit
|
|
new g_cvar_speclimit
|
|
new g_cvar_refaccess
|
|
new g_cvar_combatmode
|
|
new g_cvar_membersonly
|
|
new g_cvar_webquery
|
|
|
|
new const g_cvarHelp[H_NUM_CVARS][HL_LEN_MSG + 1] =
|
|
{
|
|
"ensl_minrate & ensl_maxrate: Minimum and maximum rate allowed for players",
|
|
"ensl_mincmdrate & ensl_maxcmdrate: Minimum and maximum cl_cmdrate allowed for players.",
|
|
"ensl_minupdaterate & ensl_maxupdaterate: Minimum and maximum cl_updaterate allowed for players.",
|
|
"ensl_checkids [0 = off, 1 = on]: Player ID fetching from ENSL database.",
|
|
"ensl_snapshots [0 = off, 1 = on]: Player snapshots on death.",
|
|
"ensl_checkrates [0 = off, 1 = on+kick, 2 = on+warning, 3 = fetch only]: Ratechecking",
|
|
"ensl_ffclock [0 = off, 1 = on]: Forfeit clock triggered by ready.",
|
|
"ensl_merclimit [0 = off, 1 = on]: Merclimiting prevents players in dfferent ENSL team to join a team.",
|
|
"ensl_teamlimit [num]: Allows teams to play with only given number of players.",
|
|
"ensl_speclimit [0 = off, 1 = on]: Speclimiting prevents non-referees to join spectators mid-game.",
|
|
"ensl_refaccess [0 = off, 1 = on]: Toggles usage of admin commands by referees.",
|
|
"ensl_combatmode [0 = off, 1 = celeresupply, 2: ENSL-combat, 3: lifeforms]: Limits the usable combat upgrades."
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Plugin loader functions
|
|
**************************************************************************************/
|
|
|
|
// Initalize the plugin
|
|
public plugin_init()
|
|
{
|
|
// Register plugin
|
|
register_plugin(PLUGIN, VERSION, AUTHOR)
|
|
|
|
// Get Message ID's
|
|
g_msgId_SayText = get_user_msgid("SayText")
|
|
g_msgId_Scoreboard = get_user_msgid("ScoreInfo")
|
|
g_msgId_Waypoint = get_user_msgid("SetOrder")
|
|
g_msgId_DeathMsg = get_user_msgid("DeathMsg")
|
|
|
|
// Globals
|
|
g_maxPlayers = get_maxplayers();
|
|
|
|
// Register CVARs
|
|
g_cvar_minrate = register_cvar("ensl_minrate", "10000")
|
|
g_cvar_maxrate = register_cvar("ensl_maxrate", "25000")
|
|
g_cvar_mincmdrate = register_cvar("ensl_mincmdrate", "50")
|
|
g_cvar_maxcmdrate = register_cvar("ensl_maxcmdrate", "150")
|
|
g_cvar_minupdaterate = register_cvar("ensl_minupdaterate", "40")
|
|
g_cvar_maxupdaterate = register_cvar("ensl_maxupdaterate", "150")
|
|
g_cvar_minfps = register_cvar("ensl_minfps", "50")
|
|
g_cvar_maxfps = register_cvar("ensl_maxfps", "999")
|
|
g_cvar_checkids = register_cvar("ensl_checkids", "1")
|
|
g_cvar_checkrates = register_cvar("ensl_checkrates", "3")
|
|
g_cvar_snapshots = register_cvar("ensl_snapshots", "0")
|
|
g_cvar_ffclock = register_cvar("ensl_ffclock", "0")
|
|
g_cvar_merclimit = register_cvar("ensl_merclimit", "0")
|
|
g_cvar_teamlimit = register_cvar("ensl_teamlimit", "0")
|
|
g_cvar_speclimit = register_cvar("ensl_speclimit", "0")
|
|
g_cvar_refaccess = register_cvar("ensl_refaccess", "1")
|
|
g_cvar_combatmode = register_cvar("ensl_combatmode", "1")
|
|
g_cvar_membersonly = register_cvar("ensl_membersonly", "0")
|
|
g_cvar_webquery = register_cvar("ensl_webquery", "0")
|
|
|
|
// Register basic events
|
|
register_event("DeathMsg", "event_death", "a")
|
|
register_event("GameStatus","event_roundend","abc","1=2")
|
|
|
|
// Register scoreboard event for icons
|
|
register_message(g_msgId_Scoreboard, "event_scoreboard")
|
|
register_message(g_msgId_Waypoint, "func_msg_waypoint");
|
|
register_message(g_msgId_DeathMsg, "func_msg_death");
|
|
|
|
// Register team joins
|
|
register_clcmd("jointeamone", "cmd_jointeamone")
|
|
register_clcmd("jointeamtwo", "cmd_jointeamtwo")
|
|
register_clcmd("readyroom", "cmd_readyroom")
|
|
register_clcmd("impulse 5", "cmd_readyroom")
|
|
register_clcmd("spectate", "cmd_spectate")
|
|
register_clcmd("autoassign", "cmd_autoassign")
|
|
register_touch("info_spectate", "player", "touch_spectate")
|
|
register_touch("info_join_team","player","touch_teamjoin")
|
|
register_touch("info_join_autoassign","player", "touch_autoassign")
|
|
|
|
// Say commands
|
|
register_clcmd("say", "cmd_say")
|
|
register_clcmd("say /ensl", "cmd_ensl")
|
|
register_clcmd("say_team /ensl", "cmd_ensl")
|
|
register_clcmd("say /exp", "cmd_exp")
|
|
register_clcmd("say_team /exp", "cmd_exp")
|
|
register_clcmd("say /stuck", "cmd_unstuck")
|
|
register_clcmd("say_team /stuck", "cmd_unstuck")
|
|
register_clcmd("say /ok", "cmd_ok")
|
|
register_clcmd("say_team /ok", "cmd_ok")
|
|
register_clcmd("say /mercs", "cmd_mercs")
|
|
register_clcmd("say_team /mercs", "cmd_mercs")
|
|
register_clcmd("say /mercsok", "cmd_mercsok")
|
|
register_clcmd("say_team /mercsok", "cmd_mercsok")
|
|
register_clcmd("say /check", "cmd_check")
|
|
register_clcmd("say_team /check", "cmd_check")
|
|
register_clcmd("say /makeroom", "cmd_makeroom")
|
|
register_clcmd("say_team /makeroom", "cmd_makeroom")
|
|
register_clcmd("say ready", "cmd_ready")
|
|
register_clcmd("say_team ready", "cmd_ready")
|
|
register_clcmd("say notready", "cmd_notready")
|
|
register_clcmd("say_team notready", "cmd_notready")
|
|
register_clcmd("say /clearwp", "cmd_clearwp");
|
|
register_clcmd("say_team /clearwp", "cmd_clearwp");
|
|
register_clcmd("say /noweapons", "func_cmd_stripweapons");
|
|
|
|
// Console commands
|
|
register_concmd("amx_enslinfo", "cmd_enslinfo", ADMIN_USER, "[server/marines/aliens/others] (Print information)")
|
|
register_concmd("amx_enslcfg", "cmd_enslcfg", ADMIN_LEVEL_E, "[pcw] (Load ENSL official or pcw settings)")
|
|
register_concmd("amx_enslcvar", "cmd_enslcvar", ADMIN_LEVEL_E, "[name] [value] (Set server cvar)")
|
|
register_concmd("amx_enslteam", "cmd_enslteam", ADMIN_LEVEL_E, "[name/#ID] [team] (Force player to team)")
|
|
register_concmd("amx_enslkick", "cmd_enslkick", ADMIN_LEVEL_E, "[name/#ID] [bantime(mins)] [^"reason^"] (Kick/ban player)")
|
|
register_concmd("amx_enslnicks", "cmd_enslnicks", ADMIN_LEVEL_E, "(Enforce ENSL nicks on all players)")
|
|
register_concmd("amx_enslvoice", "cmd_enslvoice", ADMIN_LEVEL_E, "[empty=freetalk or name/#ID] (Limit talking)")
|
|
register_concmd("amx_enslpause", "cmd_enslpause", ADMIN_LEVEL_E, "(Pause / unpause game)")
|
|
register_concmd("amx_enslmap", "cmd_enslmap", ADMIN_LEVEL_E, "[mapname] (Change map)")
|
|
register_concmd("amx_enslclock", "cmd_enslclock", ADMIN_LEVEL_E, "[mins] [secs] (Add time to the forfeit clock")
|
|
register_concmd("amx_enslshot", "cmd_enslshot", ADMIN_LEVEL_E, "[name/#ID] (Force snapshot)")
|
|
register_concmd("amx_enslsay", "cmd_enslsay", ADMIN_LEVEL_E, "[message] (Global say)")
|
|
register_concmd("amx_enslpwd", "cmd_enslpwd", ADMIN_LEVEL_E, "[passord] (Set password)")
|
|
register_concmd("amx_enslmerc", "cmd_enslmerc", ADMIN_LEVEL_E, "[name/#ID] (Toggle mercing)")
|
|
register_concmd("amx_enslmove", "cmd_enslmove", ADMIN_LEVEL_E, "[#ID/ip:port] [password] (Connect everyone to another server)")
|
|
register_concmd("amx_enslhltv", "cmd_enslhltv", ADMIN_LEVEL_E, "[matchID/demoname/stop] (Request a HLTV.)")
|
|
register_concmd("amx_enslgag", "cmd_enslgag", ADMIN_LEVEL_E, "[name/#ID] (Prvents user from talking)")
|
|
register_concmd("amx_enslhelp", "cmd_enslhelp", ADMIN_USER, "(Show help about ENSL Plugin commands)")
|
|
register_concmd("amx_enslcvars", "cmd_enslcvars", ADMIN_USER, "(Show help about ENSL Plugin CVARs)")
|
|
|
|
// Impulset
|
|
register_impulse(81, "cmd_clearwp");
|
|
|
|
// Special
|
|
register_clcmd("pauseMark", "cmd_pause")
|
|
|
|
// Set team names
|
|
g_teamNames[HL_RRSPECS] = "RR/Specs"
|
|
g_teamNames[HL_MARINES] = "Marines"
|
|
g_teamNames[HL_ALIENS] = "Aliens"
|
|
|
|
// Set server CVARs, init combat stuff, server PID and waypoints
|
|
func_init_cvars()
|
|
func_init_co()
|
|
func_init_pid()
|
|
func_init_waypoints()
|
|
|
|
// Rate / FPS checks
|
|
set_task(10.0, "task_check_rates", T_RATECHECK, "", 0, "b", 0)
|
|
|
|
// Set a task 10s after start
|
|
set_task(10.0, "task_startup", T_STARTUP, "", 0, "a", 1)
|
|
|
|
// Set a task 10s after start
|
|
set_task(60.0, "task_mapboot", T_MAPBOOT, "", 0, "b", 0)
|
|
|
|
// Set a task 10s after start
|
|
set_task(300.0, "task_advert", T_ADVERT, "", 0, "b", 0)
|
|
}
|
|
|
|
// Force default WAD's
|
|
public plugin_precache()
|
|
{
|
|
// Force certain unmodified files
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/co_kestrel.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/hallwall_1.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns2.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_ayumi.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_bast.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_eclipse.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_eon.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_hera.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_lost.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_metal.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_nancy.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_nothing.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_shiva.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/ns_tanith.wad")
|
|
force_unmodified(force_exactfile,{0,0,0},{0,0,0},"/v_wad.wad")
|
|
|
|
// Initialize icons
|
|
func_init_icons()
|
|
|
|
// Precache custom icons
|
|
new iconName[I_LEN_ICON + 1], shortIcon[I_LEN_ICON - 2], iconPath[I_LEN_PATH + 1]
|
|
for ( new i = 0; i < I_NUM_ICONS; i++ )
|
|
{
|
|
iconName = g_iconName[i]
|
|
copy(shortIcon, strlen(iconName) - 3, iconName)
|
|
formatex(iconPath, I_LEN_PATH, "gfx/vgui/640_%s.tga", shortIcon)
|
|
precache_generic(iconPath)
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Events concerning individual player
|
|
**************************************************************************************/
|
|
|
|
// Event: player joins
|
|
public client_authorized(id)
|
|
{
|
|
// Authenticate the player
|
|
func_authenticate(id)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Event: player is connected
|
|
public client_putinserver(id)
|
|
{
|
|
// If its a hltv, announce it
|
|
if ( is_user_hltv(id) )
|
|
{
|
|
new ip[HL_LEN_IP + HL_LEN_PORT + 2]; get_user_ip(id, ip, HL_LEN_IP + HL_LEN_PORT + 1)
|
|
client_print(0, print_chat, "[ENSL] HLTV (%s) has joined the server.", ip)
|
|
g_gameHltvs++
|
|
}
|
|
|
|
// Increase RR+Spec counter
|
|
g_teamPlayers[HL_RRSPECS]++
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Event: info changes
|
|
public client_infochanged(id)
|
|
{
|
|
// Apply icon
|
|
func_apply_icon(id)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Event: player leaves
|
|
public client_disconnect(id)
|
|
{
|
|
// Authenticate if not already + get PID
|
|
new pid = func_authenticate(id)
|
|
|
|
// Reset variables
|
|
g_userIconFlags[id] = 0
|
|
g_userIconIndex[id] = -1
|
|
g_userAuthed[id] = 0
|
|
g_userStatus[pid] = 0
|
|
|
|
// Reset rates so retrying with different rates wont get kicked for rate changing
|
|
for ( new i = 0; i < RC_NUM_VARS; i++ )
|
|
{
|
|
g_userRCVars[pid][i] = 0
|
|
g_userRCWarn[pid][i] = RC_WARN_NEGATIVE
|
|
}
|
|
|
|
// If user was being digested, user has to be out alteast 50 seconds
|
|
if ( ns_get_mask(id, MASK_DIGESTING) )
|
|
{
|
|
g_userDDTime[pid] = get_systime() + DD_DELAY_DIGESTED
|
|
}
|
|
|
|
// Process team leave
|
|
func_teamleave(id, g_userTeam[pid])
|
|
g_userTeam[pid] = HL_RRSPECS
|
|
|
|
// Decrease the HLTV counter if necessary
|
|
if ( is_user_hltv(id) )
|
|
{
|
|
g_gameHltvs--
|
|
}
|
|
|
|
// Remove any authentication tasks
|
|
if ( task_exists(T_USER + pid) )
|
|
{
|
|
remove_task(T_USER + pid)
|
|
socket_close(g_userWebSocket[pid])
|
|
}
|
|
|
|
// Set last username
|
|
get_user_name(id, g_userName[pid], HL_LEN_NICK)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Event: impulse command
|
|
public client_impulse(id, impulse)
|
|
{
|
|
// Process flashlight
|
|
if ( impulse == F_IMLUPSE )
|
|
{
|
|
// If the user is trying to use the flashlight too often, abort
|
|
if ( get_gametime() - g_flashTime[id] < F_FREQ )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Set the last time flashlight was used
|
|
g_flashTime[id] = get_gametime()
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Block upgrades if celeresupply is on
|
|
new mode = get_pcvar_num(g_cvar_combatmode)
|
|
if ( ns_is_combat() && mode != CO_NORMAL && mode < CO_NUM_MODES )
|
|
{
|
|
new coNum = g_coNum[mode]
|
|
for ( new i = 0; i < coNum; i++ )
|
|
{
|
|
if ( impulse == g_coBlocked[mode][i] )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
}
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Event: player death
|
|
public event_death()
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(read_data(2))
|
|
|
|
// Take a random snapshot if necessary
|
|
if ( get_pcvar_num(g_cvar_snapshots) && func_random_snap(pid) )
|
|
{
|
|
func_snapshot(pid, 0)
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Global events
|
|
**************************************************************************************/
|
|
|
|
// Event: round start
|
|
public round_start()
|
|
{
|
|
new ratecheck; ratecheck = get_pcvar_num(g_cvar_checkrates)
|
|
|
|
// Echo the warning if rate checking is enabled w/ kick
|
|
if ( ratecheck == RC_ENABLED_KICK )
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Rate changing / breaching punishable by kick. Do not change rates.")
|
|
}
|
|
// Echo the warning if rate checking is enabled w/o kick
|
|
else if ( ratecheck == RC_ENABLED_WARN )
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Rate changing / breaching not allowed.")
|
|
}
|
|
|
|
// Reset some player settings
|
|
for ( new i = 0; i < g_userCount; i++ )
|
|
{
|
|
g_userDDTime[i] = 0
|
|
g_userSSPassed[i] = 0
|
|
g_userSSCount[i] = 0
|
|
}
|
|
|
|
// Mark game started and reset variables
|
|
g_gameStarted = 1
|
|
g_teamReady[HL_MARINES] = 0
|
|
g_teamReady[HL_ALIENS] = 0
|
|
|
|
// Stop the forfeit clock.
|
|
func_stop_ffclock(1)
|
|
|
|
// Init waypoints
|
|
func_init_waypoints()
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Event: round end
|
|
public event_roundend()
|
|
{
|
|
new playerCount, player
|
|
new players[HL_NUM_PLAYERS]; get_players(players, playerCount, "h")
|
|
|
|
// If screenshots are enabled, take the final shot
|
|
if ( get_pcvar_num(g_cvar_snapshots) )
|
|
{
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
func_snapshot(g_userPidIndex[players[i]], 1)
|
|
}
|
|
}
|
|
|
|
// Print player info to everyone
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
player = players[i]
|
|
func_print_players(player, HL_MARINES)
|
|
func_print_players(player, HL_ALIENS)
|
|
func_print_players(player, HL_RRSPECS)
|
|
}
|
|
|
|
// Reset times after snapshots
|
|
g_gameStarted = 0
|
|
g_gameEnding = 1
|
|
|
|
// Reset some values
|
|
for ( new i = 0; i < U_NUM_IDS; i++ )
|
|
{
|
|
g_userDDTime[i] = 0
|
|
g_userMerc[i] = 0
|
|
g_userSSCount[i] = 0
|
|
g_userSSPassed[i] = 0
|
|
g_userSSRand[i] = 0
|
|
}
|
|
|
|
// Reset team count, about six seconds after game-end, players are in RR
|
|
set_task(6.0, "task_roundend", 0, "", 0, "a", 1)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Global tasks
|
|
**************************************************************************************/
|
|
|
|
// Task: startup
|
|
public task_startup()
|
|
{
|
|
func_get_esi()
|
|
|
|
// Fix comm bug
|
|
set_cvar_num("sv_maxspectatorspeed", 1000)
|
|
set_cvar_num("sv_maxspeed", 4000)
|
|
}
|
|
|
|
// Task: round ends
|
|
public task_roundend()
|
|
{
|
|
func_reset_teams()
|
|
g_gameEnding = 0
|
|
}
|
|
|
|
// Task: map boot, fixes pgs
|
|
public task_mapboot()
|
|
{
|
|
if ( g_mapBootMins == 5 )
|
|
{
|
|
new mapname[HL_LEN_MAP + 1]; get_mapname(mapname, HL_LEN_MAP)
|
|
server_cmd("wait; wait; wait; wait; wait; wait; wait; wait; changelevel %s", mapname)
|
|
}
|
|
else if ( get_playersnum() <= 2 )
|
|
{
|
|
g_mapBootMins++
|
|
}
|
|
else
|
|
{
|
|
g_mapBootMins = 0
|
|
}
|
|
}
|
|
|
|
// Task: advert
|
|
public task_advert()
|
|
{
|
|
new playerCount = 0, target = 0
|
|
new players[HL_NUM_PLAYERS]; get_players(players, playerCount, "h")
|
|
|
|
new msg[HL_LEN_HUDMESSAGE + 1]
|
|
|
|
// Print the hud message including serverside info (nick, ip etc.) + gametimes
|
|
set_hudmessage(20, 120, 120, -1.0, 0.6, 0, 0.5, 10.0, 2.0, 2.0, 4)
|
|
formatex(msg, HL_LEN_HUDMESSAGE, "Welcome to ENSL Server^n^n^nYou can join pick-up games^nby registering at www.ensl.org^nand joining at www.ensl.org/gathers/latest/ns1")
|
|
|
|
// Check readyroom first
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
if ( nst_is_readyroom(players[i]) || nst_is_spectate(players[i]) )
|
|
{
|
|
target = players[i]
|
|
show_hudmessage(target, msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Icons
|
|
**************************************************************************************/
|
|
|
|
// Function: Initialize icons
|
|
public func_init_icons()
|
|
{
|
|
g_iconName[I_I_DONOR] = "ensl_12_donor999"
|
|
g_iconFlags[I_I_DONOR] = 1
|
|
g_iconName[I_I_CHAMP] = "ensl_12_champ999"
|
|
g_iconFlags[I_I_CHAMP] = 2
|
|
g_iconName[I_I_REF] = "ensl_12_ref999"
|
|
g_iconFlags[I_I_REF] = 4
|
|
g_iconName[I_I_ADMIN] = "ensl_12_admin999"
|
|
g_iconFlags[I_I_ADMIN] = 8
|
|
}
|
|
|
|
// Function: handle scoreboard call
|
|
public event_scoreboard()
|
|
{
|
|
new id = get_msg_arg_int(SI_PLAYER)
|
|
|
|
// Set custom icon if necessary
|
|
if ( g_userIconIndex[id] != -1 )
|
|
{
|
|
set_msg_arg_int(SI_AUTH, ARG_SHORT, I_AUTH_ICON)
|
|
set_msg_arg_string(SI_ICON, g_iconName[g_userIconIndex[id]])
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: enable next icon
|
|
public func_next_icon(id)
|
|
{
|
|
// Increase it as long as the icon is not allowed
|
|
do
|
|
{
|
|
g_userIconIndex[id]--
|
|
g_userIconIndex[id] = g_userIconIndex[id] == -2 ? I_NUM_ICONS - 1 : g_userIconIndex[id]
|
|
}
|
|
while ( g_userIconIndex[id] != -1 && !(g_iconFlags[g_userIconIndex[id]] & g_userIconFlags[id]) )
|
|
}
|
|
|
|
// Function: apply user's favourite icon
|
|
public func_apply_icon(id)
|
|
{
|
|
new strIcon[E_LEN_IDS + 1]; get_user_info(id, "enslicon", strIcon, E_LEN_IDS)
|
|
new intIcon = str_to_num(strIcon)
|
|
|
|
// If icon is wanted to be default, set it
|
|
if ( intIcon == -1 )
|
|
{
|
|
g_userIconIndex[id] = -1
|
|
}
|
|
// If the icon is set and within range
|
|
else if ( intIcon > 0 && intIcon <= I_NUM_ICONS && (g_iconFlags[intIcon - 1] & g_userIconFlags[id]) )
|
|
{
|
|
g_userIconIndex[id] = intIcon - 1
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Unstucking functions
|
|
**************************************************************************************/
|
|
|
|
// Command: /unstuck
|
|
public cmd_unstuck(id)
|
|
{
|
|
// Get PID
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check for too rapid action
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Execute the unstuck after a random interval
|
|
set_task(random_float(0.5,5.0), "task_unstuck", id)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Task: Unstuck a player
|
|
public task_unstuck(id)
|
|
{
|
|
new Float:origin[3], Float:newOrigin[3], hullsize, distance
|
|
|
|
// Get username
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new pid = func_authenticate(id)
|
|
|
|
// Do no not unstuck when gestating etc.
|
|
if ( ns_get_mask(id, S_B) )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] You cannot free yourself while evolving, stunned or webbed")
|
|
log_message("[ENSL] [unstuck] [%s:%s] [FAILED] [Webbed/Stunned/Evolving]", g_userSteamID[pid], name)
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Get hull size of the player and abort if invalid
|
|
switch ( ns_get_class(id) )
|
|
{
|
|
// Small lifeforms: return the smaller hull
|
|
case 1,2,3:
|
|
hullsize = HULL_HEAD
|
|
|
|
// Others: If the user is ducking, return the smaller hull, otherwise midsize
|
|
case 4,6,7,8:
|
|
hullsize = (entity_get_int(id, EV_INT_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN
|
|
|
|
// Onos: If the user is ducking, return the smaller hull, otherwise midsize
|
|
case 5:
|
|
hullsize = (entity_get_int(id, EV_INT_flags) & FL_DUCKING) ? HULL_HUMAN : HULL_LARGE
|
|
|
|
// Return, print and log error if not applicable
|
|
default:
|
|
{
|
|
client_print(id, print_chat, "[ENSL] You cannot free yourself at this time.")
|
|
log_message("[ENSL] [unstuck] [%s:%s] [FAILED] [Bad Hullsize]", g_userSteamID[pid], name)
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
}
|
|
|
|
// Get user coordinates and init default stuck distance
|
|
entity_get_vector(id, EV_VEC_origin, origin)
|
|
distance = S_START_DISTANCE
|
|
|
|
// NOTE: Distance should never be further than 1000 units
|
|
while ( distance < S_NUM_DISTANCE )
|
|
{
|
|
for ( new i = 0; i < S_NUM_ATTEMPTS; ++i )
|
|
{
|
|
// Generate new random coordinates
|
|
newOrigin[0] = random_float(origin[0]-distance, origin[0]+distance)
|
|
newOrigin[1] = random_float(origin[1]-distance ,origin[1]+distance)
|
|
newOrigin[2] = random_float(origin[2]-distance, origin[2]+distance)
|
|
|
|
// Unstuck player
|
|
if ( trace_hull(newOrigin, hullsize, id) == 0 )
|
|
{
|
|
entity_set_origin(id, newOrigin)
|
|
client_print(0, print_chat, "[ENSL] Player (%s) unstucked.", name)
|
|
log_message("[ENSL] [unstuck] [%s:%s] [OK]", g_userSteamID[pid], name)
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
}
|
|
distance += S_START_DISTANCE
|
|
}
|
|
|
|
// Echo error in case no free spot found
|
|
client_print(id, print_chat, "[ENSL] Couldn't find a free spot to move you too.")
|
|
log_message("[ENSL] [unstuck] [%s:%s] [FAILED] [No Free Spot]", g_userSteamID[pid], name)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Plugin informational commands
|
|
**************************************************************************************/
|
|
|
|
// Command: say /ensl (Print plugin info)
|
|
public cmd_ensl(id)
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(id)
|
|
|
|
// Not too rapid execution
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Print verison and settings
|
|
client_print(id, print_chat, "[ENSL] Plugin Version %s - %s - %s on IRC.Quakenet.Org", VERSION, WEB, CHANNEL)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command /say whois (Find user information
|
|
public cmd_whois(id, msg[HL_LEN_SAY + 1])
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(id)
|
|
|
|
// Fetch arguments
|
|
new nick[HL_LEN_NICK + 1]; copy(nick, HL_LEN_NICK, msg[7])
|
|
new targetID = func_get_player(id, nick)
|
|
|
|
// Not too rapid execution
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If user cannot be found, abort
|
|
if ( targetID == -1 || equal(msg[7], "") )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] User not found.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get pid and nick
|
|
new tPid = g_userPidIndex[targetID]
|
|
new name[HL_LEN_NICK + 1]; get_user_name(targetID, name, HL_LEN_NICK)
|
|
|
|
// Print nick and steamid
|
|
client_print(id, print_chat, "[ENSL] Nick: %s SteamID: %s IP: %s", name, g_userSteamID[tPid], g_userIP[tPid])
|
|
|
|
// Print possible ENSL information
|
|
if ( g_userEnslInfo[tPid] )
|
|
{
|
|
new args[2] = {0, 0}
|
|
args[0] = id
|
|
args[1] = tPid
|
|
set_task(0.1, "task_whois_ensl", 0, args, 2, "a", 1)
|
|
set_task(0.3, "task_whois_rates", 0, args, 2, "a", 1)
|
|
}
|
|
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Task: print ensl data
|
|
public task_whois_ensl(const args[])
|
|
{
|
|
client_print(args[0], print_chat, "[ENSL] [ENSL Name: %s] [ENSL Team: %s] [ENSL IP: %s]", g_userEnslNick[args[1]], g_userEnslTeam[args[1]], g_userEnslIP[args[1]])
|
|
}
|
|
|
|
// Task: print ensl data
|
|
public task_whois_rates(const args[])
|
|
{
|
|
client_print(args[0], print_chat, "[ENSL] Rates [Upd: %d Cmd: %d Rate: %dk]", g_userRCVars[args[1]][RC_I_UPDATERATE], g_userRCVars[args[1]][RC_I_CMDRATE], g_userRCVars[args[1]][RC_I_RATE] / 1000)
|
|
}
|
|
|
|
// Command: amx_enslinfo (Print miscellaenous information)
|
|
public cmd_enslinfo(id)
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(id)
|
|
|
|
// Not too rapid execution
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_console) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// In-game only specs can use it
|
|
if ( g_gameStarted && !func_is_referee(pid) )
|
|
{
|
|
console_print(id, "This command can be used only by referees when round is in progress.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check arguments
|
|
if ( read_argc() < 2 )
|
|
{
|
|
console_print(id, "Please use amx_enslinfo [server/marines/aliens/others]")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch arguments
|
|
new function[HL_LEN_TEAM + 1]; read_argv(1, function, HL_LEN_TEAM)
|
|
|
|
// Print server information when necessary
|
|
if ( equal(function, "server") )
|
|
{
|
|
func_print_server(id)
|
|
}
|
|
// Print server information when necessary
|
|
else if ( equal(function, "marines") )
|
|
{
|
|
func_print_players(id, HL_MARINES)
|
|
}
|
|
// Print marine information when necessary
|
|
else if ( equal(function, "aliens") )
|
|
{
|
|
func_print_players(id, HL_ALIENS)
|
|
}
|
|
// Print alien information when necessary
|
|
else if ( equal(function, "others") )
|
|
{
|
|
func_print_players(id, HL_RRSPECS)
|
|
}
|
|
// Or print error for wrong argument
|
|
else
|
|
{
|
|
console_print(id, "Valid values: server, marines, aliens or others")
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: print server info
|
|
public func_print_server(id)
|
|
{
|
|
// Init variables
|
|
new iInt = 0, iFlt = 0, cMandatory = 0, cVoluntary = 0, idx = 0
|
|
new wrongInts[C_NUM_INTS], wrongFloats[C_NUM_FLOATS]
|
|
|
|
// Check server integers
|
|
for ( new i = 0; i < C_NUM_INTS; i++ )
|
|
{
|
|
// If an incorrect settings is found..
|
|
if ( get_cvar_num(g_cvarIntName[i]) != g_cvarIntValue[i] )
|
|
{
|
|
// Advance the mandatory cvar violation counter
|
|
if ( g_cvarIntLevel[i] == C_LEVEL_MANDATORY )
|
|
{
|
|
cMandatory++
|
|
}
|
|
// Or increase the voluntary cvar violation counter
|
|
else
|
|
{
|
|
cVoluntary++
|
|
}
|
|
|
|
// Record it: increase index + counter
|
|
wrongInts[iInt] = i
|
|
iInt++
|
|
}
|
|
}
|
|
|
|
// Check server floats
|
|
for ( new i = 0; i < C_NUM_FLOATS; i++ )
|
|
{
|
|
// If an incorrect settings is found, record it and increase index + counter
|
|
if ( get_cvar_float(g_cvarFltName[i]) != g_cvarFltValue[i] )
|
|
{
|
|
// Advance the mandatory cvar violation counter
|
|
if ( g_cvarFltLevel[i] == C_LEVEL_MANDATORY )
|
|
{
|
|
cMandatory++
|
|
}
|
|
// Or increase the voluntary cvar violation counter
|
|
else
|
|
{
|
|
cVoluntary++
|
|
}
|
|
|
|
// Record it: increase index + counter
|
|
wrongFloats[iFlt] = i
|
|
iFlt++
|
|
}
|
|
}
|
|
|
|
// Check server settings, mandatory ones
|
|
if ( cMandatory > 0 )
|
|
{
|
|
console_print(id, "Server has %d settings in unapproved position:", cMandatory)
|
|
|
|
// Print integers cvars
|
|
for ( new i = 0; i < iInt; i++ )
|
|
{
|
|
idx = wrongInts[i]
|
|
|
|
if ( g_cvarIntLevel[idx] == C_LEVEL_MANDATORY )
|
|
{
|
|
console_print(id, "%s = %d (should be %d)", g_cvarIntName[idx], get_cvar_num(g_cvarIntName[idx]), g_cvarIntValue[idx])
|
|
}
|
|
}
|
|
|
|
// Print float cvars
|
|
for ( new i = 0; i < iFlt; i++ )
|
|
{
|
|
idx = wrongFloats[i]
|
|
|
|
if ( g_cvarFltLevel[idx] == C_LEVEL_MANDATORY )
|
|
{
|
|
console_print(id, "%s = %f (should be %f)", g_cvarFltName[idx], get_cvar_float(g_cvarFltName[idx]), g_cvarFltValue[idx])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check server settings, voluntary ones
|
|
if ( cVoluntary > 0 )
|
|
{
|
|
console_print(id, "^nServer has %d settings in non-recommended position:", cVoluntary)
|
|
|
|
// Print integers cvars
|
|
for ( new i = 0; i < iInt; i++ )
|
|
{
|
|
idx = wrongInts[i]
|
|
|
|
if ( g_cvarIntLevel[idx] == C_LEVEL_VOLUNTARY )
|
|
{
|
|
console_print(id, "%s = %d (should be %d)", g_cvarIntName[idx], get_cvar_num(g_cvarIntName[idx]), g_cvarIntValue[idx])
|
|
}
|
|
}
|
|
|
|
// Print float cvars
|
|
for ( new i = 0; i < iFlt; i++ )
|
|
{
|
|
idx = wrongFloats[i]
|
|
|
|
if ( g_cvarFltLevel[idx] == C_LEVEL_VOLUNTARY )
|
|
{
|
|
console_print(id, "%s = %f (should be %f)", g_cvarFltName[idx], get_cvar_float(g_cvarFltName[idx]), g_cvarFltValue[idx])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Print rules
|
|
if ( cMandatory > 0 )
|
|
{
|
|
console_print(id, "^nSince there are unapproved settings, match can only be played if both teams agree (say ready).")
|
|
console_print(id, "If either of the teams disagree, contact server admin or use another server.")
|
|
}
|
|
else if ( cVoluntary == 0 )
|
|
{
|
|
console_print(id, "All settings OK.")
|
|
}
|
|
else
|
|
{
|
|
console_print(id, "Mandatory official settings OK.")
|
|
}
|
|
}
|
|
|
|
// Print team's player information
|
|
public func_print_players(id, team)
|
|
{
|
|
// Ignore if the team does't have players
|
|
if ( g_teamPlayers[team] == 0 )
|
|
{
|
|
console_print(id, "No players found of the given team.")
|
|
return
|
|
}
|
|
|
|
// Generate header
|
|
new columns[HL_NUM_COLUMN][HL_LEN_COLUMN + 1], header[HL_LEN_MSG + 1]
|
|
copy(columns[0], 15, "Name")
|
|
copy(columns[1], 15, "SteamID")
|
|
copy(columns[2], 15, "IP Address")
|
|
copy(columns[3], 15, "ENSL Name")
|
|
copy(columns[4], 15, "ENSL IP")
|
|
copy(columns[5], 15, "ENSL Team")
|
|
copy(columns[6], 15, "ENSL Level")
|
|
copy(columns[7], 15, "Upd/Cmd/Rat/FPS")
|
|
func_gentable(8, 15, columns, header)
|
|
console_print(id, "-- %s --", g_teamNames[team])
|
|
console_print(id, "%s", header)
|
|
|
|
// Print players
|
|
for ( new p = 1; p < g_userCount; p++ )
|
|
{
|
|
if ( g_userStatus[p] && g_userTeam[p] == team )
|
|
{
|
|
func_print_player(id, p)
|
|
}
|
|
}
|
|
|
|
// If requestor has referee access, print past players
|
|
if ( team == HL_RRSPECS && func_is_referee(g_userPidIndex[id]) )
|
|
{
|
|
// Print headers
|
|
console_print(id, "^n -- Past Players --")
|
|
console_print(id, "%s", header)
|
|
|
|
// Print players, exclude server itself
|
|
for ( new p = 1; p < g_userCount && p < 10; p++ )
|
|
{
|
|
if ( !g_userStatus[p] )
|
|
{
|
|
func_print_player(id, p)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function: print players' playerinfo on 1 line
|
|
public func_print_player(id, pid)
|
|
{
|
|
new values[HL_NUM_COLUMN][HL_LEN_COLUMN + 1], output[HL_LEN_MSG + 1]
|
|
|
|
// Get/generate username + rates + shots
|
|
new name[HL_LEN_NICK + 1]
|
|
new rates[16]; formatex(rates, 15, "%d/%d/%dk/%d", g_userRCVars[pid][RC_I_UPDATERATE], g_userRCVars[pid][RC_I_CMDRATE], g_userRCVars[pid][RC_I_RATE] / 1000, g_userRCVars[pid][RC_I_FPS])
|
|
|
|
// Get username
|
|
if ( g_userStatus[pid] )
|
|
{
|
|
get_user_name(g_userIdIndex[pid], name, HL_LEN_NICK)
|
|
}
|
|
else
|
|
{
|
|
copy(name, HL_LEN_NICK, g_userName[pid])
|
|
}
|
|
|
|
// Insert values
|
|
add(values[0], 15, name, 15)
|
|
add(values[1], 15, g_userSteamID[pid], 15)
|
|
add(values[2], 15, g_userIP[pid], HL_LEN_IP)
|
|
add(values[3], 15, g_userEnslNick[pid], 15)
|
|
add(values[4], 15, g_userEnslIP[pid], E_LEN_IP)
|
|
add(values[5], 15, g_userEnslTeam[pid], 15)
|
|
add(values[6], 15, g_userEnslLevel[pid], E_LEN_LEVEL)
|
|
add(values[7], 15, rates, 15)
|
|
|
|
// Add info if user is CL
|
|
if ( equal(g_userEnslRank[pid], E_RANK_LEADER, 1) )
|
|
{
|
|
add(values[5], E_LEN_TEAM, " (CL)", 15)
|
|
}
|
|
// Or deputee
|
|
else if ( equal(g_userEnslRank[pid], E_RANK_DEPUTEE, 1) )
|
|
{
|
|
add(values[5], E_LEN_TEAM, " (D)", 15)
|
|
}
|
|
|
|
// Print output
|
|
func_gentable(8, 15, values, output)
|
|
console_print(id, output)
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Combat stuff
|
|
**************************************************************************************/
|
|
|
|
// Command: say /exp (giv exp)
|
|
public cmd_exp(id, level, cid)
|
|
{
|
|
// Authenticate the player
|
|
new pid = func_authenticate(id)
|
|
|
|
// Not too rapid execution
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
new mode = get_pcvar_num(g_cvar_combatmode)
|
|
if ( ns_is_combat() && mode > CO_ENSL )
|
|
{
|
|
ns_set_exp(id, 9999.0)
|
|
}
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Admin request
|
|
**************************************************************************************/
|
|
|
|
// Function: say /ensl [msg] (Send ENSL admin request)
|
|
public cmd_adminrequest(id, msg[HL_LEN_SAY + 1])
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Prevent multirun
|
|
if ( task_exists(T_AREQ) )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Admin request already running, please wait and try again.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch arguments
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new nameParsed[HL_LEN_NICK + 1]; func_urlencode(name, nameParsed, HL_LEN_NICK)
|
|
new addr[HL_LEN_ADDR + 1]; get_user_ip(0, addr, HL_LEN_ADDR)
|
|
new pwd[HL_LEN_PWD + 1]; get_cvar_string("sv_password", pwd, HL_LEN_PWD)
|
|
new msgParsed[HL_LEN_SAY + 1]; func_urlencode(msg[7], msgParsed, HL_LEN_SAY)
|
|
new url[W_LEN_URL + 1]; formatex(url, W_LEN_URL, "%s?addr=%s&pwd=%s&msg=%s&player=%s&user=%d", AR_URL, addr, pwd, msgParsed, nameParsed, g_userEnslId[pid])
|
|
|
|
// Schedule the query function
|
|
set_task(0.5, "task_web_areq", T_AREQ, url, W_LEN_URL)
|
|
client_print(id, print_chat, "[ENSL] Admin request sent.")
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Task: Send admin request
|
|
public task_web_areq(url[W_LEN_URL + 1])
|
|
{
|
|
new webquery = get_pcvar_num(g_cvar_webquery)
|
|
if ( webquery != 0 )
|
|
{
|
|
func_write_web(g_webSocket[W_I_AREQ], url)
|
|
socket_close(g_webSocket[W_I_AREQ])
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Miscellaeonus referee commands
|
|
**************************************************************************************/
|
|
|
|
// Command: amx_enslmap [mapname] (change map)
|
|
public cmd_enslmap(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch arguments
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new mapname[HL_LEN_MAP + 1]; read_argv(1, mapname, HL_LEN_MAP)
|
|
|
|
// Check if the map is valid
|
|
if ( !is_map_valid(mapname) )
|
|
{
|
|
console_print(id, "Map not found: %s", mapname)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Change map
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) changed map to %s", name, mapname)
|
|
log_message("[ENSL] [enslmap] [%s:%s] [%s]", g_userSteamID[pid], name, mapname)
|
|
server_cmd("wait; wait; wait; wait; wait; wait; wait; wait; changelevel %s", mapname)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: amx_enslteam [name/#ID] [team] (Force player to a team)
|
|
public cmd_enslteam(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 2) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch arguments
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new target[HL_LEN_NICK + 1]; read_argv(1, target, HL_LEN_NICK); remove_quotes(target)
|
|
new team[HL_LEN_TEAM +1]; read_argv(2, team, HL_LEN_TEAM); remove_quotes(team)
|
|
new targetID = func_get_player(id, target)
|
|
|
|
// If user cannot be found, abort
|
|
if ( targetID == -1 || equal(target, "") )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get target user's name and PdI
|
|
new targetName[HL_LEN_NICK + 1]; get_user_name(targetID, targetName, HL_LEN_NICK)
|
|
new targetPid = func_authenticate(targetID)
|
|
|
|
// If team is marines..
|
|
if ( equal(team, g_teamNames[HL_MARINES]) )
|
|
{
|
|
engclient_cmd(targetID, "jointeamone")
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) enforced player %s to join marines.", name, targetName)
|
|
}
|
|
// If team is aliens..
|
|
else if ( equal(team, g_teamNames[HL_ALIENS]) )
|
|
{
|
|
engclient_cmd(targetID, "jointeamtwo")
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) enforced player %s to join aliens.", name, targetName)
|
|
}
|
|
// If team is random..
|
|
else if ( equal(team, "random") )
|
|
{
|
|
// Get random team. Don't trust autoassign.
|
|
if ( random(2) == 0 )
|
|
{
|
|
engclient_cmd(targetID, "jointeamone")
|
|
}
|
|
else
|
|
{
|
|
engclient_cmd(targetID, "jointeamtwo")
|
|
}
|
|
|
|
// Output
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) enforced player %s to join random team.", name, targetName)
|
|
}
|
|
// Instructions for lowsy arguments
|
|
else
|
|
{
|
|
console_print(id, "Please give either Marines, Aliens or random.")
|
|
}
|
|
|
|
// Log event
|
|
log_message("[ENSL] [enslteam] [%s:%s] [%d:%s] [%s]", g_userSteamID[pid], name, g_userSteamID[targetPid], targetName, team)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: amx_enslkick [name/#ID] [bantime(min)] [reason] (kick user)
|
|
public cmd_enslkick(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Prevent multirun
|
|
if ( task_exists(T_BAN) )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Ban being processed, please wait.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch arguments
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new target[HL_LEN_NICK + 1]; read_argv(1, target, HL_LEN_NICK); remove_quotes(target)
|
|
new sMins[R_LEN_MINS +1]; read_argv(2, sMins, R_LEN_MINS); remove_quotes(sMins)
|
|
new reason[R_LEN_KICKREASON + 1]; read_argv(3, reason, R_LEN_KICKREASON); remove_quotes(reason)
|
|
new mins = str_to_num(sMins)
|
|
new targetID = func_get_player(id, target)
|
|
|
|
// Parse reason for security purposes
|
|
func_parse_string(reason, R_LEN_KICKREASON)
|
|
|
|
// If user cannot be found, abort
|
|
if ( targetID == -1 || equal(target, "") )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get user ID
|
|
new targetName[HL_LEN_NICK + 1]; get_user_name(targetID, targetName, HL_LEN_NICK)
|
|
new targetUID = get_user_userid(targetID)
|
|
new targetPid = func_authenticate(targetID)
|
|
|
|
// Ban player if minutes specified
|
|
if ( mins > 0 )
|
|
{
|
|
// Ban only for maximum minutes
|
|
mins = mins > R_MAX_MINS ? R_MAX_MINS : mins
|
|
|
|
// Generate variables
|
|
new addr[HL_LEN_ADDR + 1]; get_user_ip(0, addr, HL_LEN_ADDR)
|
|
new eReason[HL_LEN_SAY + 1]; func_urlencode(reason, eReason, HL_LEN_SAY)
|
|
new ts = func_get_time()
|
|
new chal[CC_LEN_INPUT + 1]; formatex(chal, CC_LEN_INPUT, "%s%d", g_userSteamID[pid], ts)
|
|
new sign[CC_LEN_CODE + 1]; func_crypt(chal, sign)
|
|
new url[W_LEN_URL + 1]; formatex(url, W_LEN_URL, "%s%s?len=%d&user=%d&addr=%s&reason=%s&ts=%d&sign=%s", B_URL, g_userSteamID[targetPid], mins, g_userEnslId[pid], addr, eReason, ts, sign)
|
|
|
|
// Schedule the sending and reading function
|
|
set_task(0.5, "task_web_ban", T_BAN, url, W_LEN_URL)
|
|
|
|
// Ban player
|
|
server_cmd("banid %d #%d; wait; kick #%d ^"BANNED: %s^"", mins, targetUID, targetUID, reason)
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) banned player %s for %d minutes", name, targetName, mins)
|
|
log_message("[ENSL] [enslban] [%s:%s] [%d:%s] [%sm] [%s]", g_userSteamID[pid], name, g_userSteamID[targetPid], targetName, mins, reason)
|
|
}
|
|
// Otherwise just kick the player
|
|
else
|
|
{
|
|
server_cmd("kick #%d ^"%s^"", targetUID, reason)
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) kicked player %s", name, targetName)
|
|
log_message("[ENSL] [enslkick] [%s:%s] [%d:%s] [%s]", g_userSteamID[pid], name, g_userSteamID[targetPid], targetName, reason)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
|
|
// Task: Send ban query
|
|
public task_web_ban(url[W_LEN_URL + 1])
|
|
{
|
|
new webquery = get_pcvar_num(g_cvar_webquery)
|
|
if ( webquery != 0 )
|
|
{
|
|
func_write_web(g_webSocket[W_I_BAN], url)
|
|
socket_close(g_webSocket[W_I_BAN])
|
|
}
|
|
}
|
|
|
|
// Function: enforce real nicks
|
|
public cmd_enslnicks(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 0) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Go through all players
|
|
new name[HL_LEN_NICK + 1]
|
|
for ( new i = 1; i < g_userCount; i++ )
|
|
{
|
|
// If player is on server
|
|
if ( g_userStatus[i] )
|
|
{
|
|
// Get player name
|
|
name = "^0"; get_user_name(g_userIdIndex[i], name, HL_LEN_NICK)
|
|
|
|
// If the name is wrong, fix it
|
|
if ( g_userEnslInfo[i] && containi(name, g_userEnslNick[i]) == -1 )
|
|
{
|
|
client_cmd(g_userIdIndex[i], "name ^"%s^"", g_userEnslNick[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Announce
|
|
name = "^0"; get_user_name(id, name, HL_LEN_NICK)
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) enforced ENSL nicks.", name)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: amx_enslsay [message] (Global say)
|
|
public cmd_enslsay(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Say colored message
|
|
new msg[HL_LEN_SAY + 1]; read_args(msg, HL_LEN_SAY); remove_quotes(msg)
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
|
|
// Print the message
|
|
client_print(0, print_chat, "%s : %s", name, msg[1])
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: amx_enslpwd [password] (Set password)
|
|
public cmd_enslpwd(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Init variables
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new pwd[HL_LEN_PWD + 1]; read_args(pwd, HL_LEN_PWD); remove_quotes(pwd)
|
|
|
|
// Parse the password
|
|
func_parse_string(pwd, HL_LEN_PWD)
|
|
|
|
// Say the message
|
|
set_cvar_string("sv_password", pwd)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: amx_enslmove [#ID/ip:port] [password] (Connect everyone to another server)
|
|
public cmd_enslmove(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Init variables
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new addr[HL_LEN_ADDR + 1]; get_user_ip(0, addr, HL_LEN_ADDR)
|
|
new newaddr[HL_LEN_DNS + 1]; read_argv(1, newaddr, HL_LEN_DNS + 1); remove_quotes(newaddr)
|
|
new pwd[HL_LEN_PWD + 1], port[HL_LEN_PORT + 1]
|
|
|
|
// Set port and password correctly if port is given (amxx splits args. by :)
|
|
new delim[2]; read_argv(2, delim, 1); remove_quotes(delim)
|
|
if ( equal(delim, ":") )
|
|
{
|
|
read_argv(3, port, HL_LEN_PORT); remove_quotes(port)
|
|
add(newaddr, HL_LEN_DNS, delim, 1)
|
|
add(newaddr, HL_LEN_DNS, port, HL_LEN_PORT)
|
|
read_argv(4, pwd, HL_LEN_PWD); remove_quotes(pwd)
|
|
}
|
|
// Normal procedure without port
|
|
else
|
|
{
|
|
add(newaddr, HL_LEN_DNS, ":27015")
|
|
read_argv(2, pwd, HL_LEN_PWD); remove_quotes(pwd)
|
|
}
|
|
|
|
// Inform people and log
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) is moving everyone to server: %s", name, newaddr)
|
|
log_message("[ENSL] [enslmove] [%s:%s] [%s]", g_userSteamID[pid], name, addr)
|
|
|
|
// Move everyone
|
|
new cmd[HL_LEN_MSG + 1]; formatex(cmd, HL_LEN_MSG, " connect %s", newaddr)
|
|
log_message("[DEBUG] enslmove: %s", cmd)
|
|
set_task(5.0, "task_enslmove", 0, cmd, HL_LEN_MSG, "b", 1)
|
|
|
|
// Move the HLTV if necessary
|
|
if ( g_gameHltvs > 0 )
|
|
{
|
|
new url[W_LEN_URL + 1], readargs[1]; readargs[0] = id
|
|
formatex(url, W_LEN_URL, "%smove?addr=%s&newaddr=%s&newpwd=%s", HT_URL, addr, newaddr, pwd)
|
|
new webquery = get_pcvar_num(g_cvar_webquery)
|
|
if ( webquery != 0 )
|
|
{
|
|
func_write_web(g_webSocket[W_I_HLTV], url)
|
|
set_task(0.5, "task_web_hltv_send", 0, url, W_LEN_URL)
|
|
set_task(1.0, "task_web_hltv", T_HLTV, readargs, 1)
|
|
}
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Task: move everyone to another server
|
|
public task_enslmove(args[])
|
|
{
|
|
client_cmd(0, args)
|
|
}
|
|
|
|
// Function: amx_enslhelp (Show help about ENSL Plugin commands)
|
|
public cmd_enslhelp(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 0) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Show information about all commands
|
|
new cmd[A_LEN_CMD + 1], info[A_LEN_CMDINFO + 1], flags
|
|
for ( new i = 0; get_concmd(i, cmd, A_LEN_CMD, flags, info, A_LEN_CMDINFO, -1, 1); i++)
|
|
{
|
|
console_print(id, "%s %s", cmd, info)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: amx_enslcvars (Show help about ENSL Plugin CVARs)
|
|
public cmd_enslcvars(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 0) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Show information about all cvars
|
|
for ( new i = 0; i < H_NUM_CVARS; i++)
|
|
{
|
|
console_print(id, "%s", g_cvarHelp[i])
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: amx_enslgag [name/#ID] (Prvents user from talking)
|
|
public cmd_enslgag(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch arguments
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new target[HL_LEN_NICK + 1]; read_argv(1, target, HL_LEN_NICK)
|
|
new targetID = func_get_player(id, target)
|
|
|
|
// If user cannot be found, abort
|
|
if ( targetID == -1 || equal(target, "") )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get user ID
|
|
new targetName[HL_LEN_NICK + 1]; get_user_name(targetID, targetName, HL_LEN_NICK)
|
|
new targetPid = func_authenticate(targetID)
|
|
|
|
// If user is gagged...
|
|
if ( g_userGagged[targetPid] )
|
|
{
|
|
// Ungag
|
|
g_userGagged[targetPid] = 0
|
|
|
|
// Log and inform people
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) ungagged player: %s", name, targetName)
|
|
log_message("[ENSL] [enslgag] [%s:%s] [%d:%s]", g_userSteamID[pid], name, g_userSteamID[targetPid], targetName)
|
|
}
|
|
// If user is not gaggged..
|
|
else
|
|
{
|
|
// Gag
|
|
g_userGagged[targetPid] = 1
|
|
|
|
// Log and inform people
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) gagged player: %s", name, targetName)
|
|
log_message("[ENSL] [enslgag] [ungag] [%s:%s] [%d:%s]", g_userSteamID[pid], name, g_userSteamID[targetPid], targetName)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* HLTV handling
|
|
**************************************************************************************/
|
|
|
|
// Function: amx_enslhltv [matchID/demoname/stop] (Request a HLTV.)
|
|
public cmd_enslhltv(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Prevent multirun
|
|
if ( task_exists(T_HLTV) )
|
|
{
|
|
console_print(id, "HLTV query already running, please wait and try again.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch arguments
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new arg[HT_LEN_DEMO + 1]; read_argv(1, arg, HT_LEN_DEMO); remove_quotes(arg)
|
|
new addr[HL_LEN_IP + HL_LEN_PORT + 2]; get_user_ip(0, addr, HL_LEN_IP + HL_LEN_PORT + 1)
|
|
new url[W_LEN_URL + 1], Float:delay = 0.0
|
|
|
|
// If stop-command was requested, generate stop query
|
|
if ( equal(arg, "shoutcast") )
|
|
{
|
|
new pwd[HL_LEN_PWD + 1]; get_cvar_string("sv_password", pwd, HL_LEN_PWD)
|
|
console_print(id, "Requesting a shoutcast HLTV to this server (%s pwd: %s)", addr, pwd)
|
|
formatex(url, W_LEN_URL, "%sshoutcast?addr=%s&pwd=%s", HT_URL, addr, pwd)
|
|
}
|
|
else if ( equal(arg, "stop") )
|
|
{
|
|
console_print(id, "HLTV will be stopped in 90 seconds.")
|
|
formatex(url, W_LEN_URL, "%sstop?addr=%s", HT_URL, addr)
|
|
delay = 90.0
|
|
}
|
|
// If immediate stop was requested, generate stop query
|
|
else if ( equal(arg, "stopnow") )
|
|
{
|
|
console_print(id, "HLTV will be stopped now.")
|
|
formatex(url, W_LEN_URL, "%sstop?addr=%s", HT_URL, addr)
|
|
}
|
|
// Otherwise send normal request
|
|
else
|
|
{
|
|
new pwd[HL_LEN_PWD + 1]; get_cvar_string("sv_password", pwd, HL_LEN_PWD)
|
|
new challenge[CC_LEN_INPUT + 1]; copy(challenge, CC_LEN_INPUT, arg)
|
|
new sign[CC_LEN_CODE + 1]; func_crypt(challenge, sign)
|
|
console_print(id, "Requesting a HLTV to this server (%s pwd: %s) for game: %s", addr, pwd, arg)
|
|
formatex(url, W_LEN_URL, "%sreq?game=%s&addr=%s&pwd=%s&user=%d&sign=%s", HT_URL, arg, addr, pwd, g_userEnslId[pid], sign)
|
|
}
|
|
|
|
// Schedule the sending and reading functions
|
|
new readargs[1]; readargs[0] = id
|
|
set_task(delay, "task_web_hltv_send", 0, url, W_LEN_URL)
|
|
set_task(delay + 0.5, "task_web_hltv", T_HLTV, readargs, 1)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Task: Send HLTV command
|
|
public task_web_hltv_send(url[W_LEN_URL + 1])
|
|
{
|
|
func_write_web(g_webSocket[W_I_HLTV], url)
|
|
}
|
|
|
|
// Function: Reads HLTV response from the web
|
|
public task_web_hltv(args[])
|
|
{
|
|
// Increase reads
|
|
g_webReads[W_I_HLTV]++
|
|
|
|
// If there's data in the socket, read it.
|
|
if ( socket_change(g_webSocket[W_I_HLTV], 200) )
|
|
{
|
|
func_read_web(g_webSocket[W_I_HLTV], HT_MARK, HT_NUM_LINES, g_webData[W_I_HLTV], g_webDataLine[W_I_HLTV])
|
|
}
|
|
|
|
// If socket hasn't finished, retry
|
|
if ( g_webDataLine[W_I_HLTV] != HT_NUM_LINES && g_webReads[W_I_HLTV] < W_READS )
|
|
{
|
|
set_task(0.5, "task_web_hltv", T_HLTV, args, 1)
|
|
return
|
|
}
|
|
|
|
// Print output to user if there's data
|
|
if ( g_webDataLine[W_I_HLTV] > 0 )
|
|
{
|
|
console_print(args[0], "[HLTV] %s", g_webData[W_I_HLTV][0])
|
|
}
|
|
|
|
// Finally close the socket and reset vars
|
|
socket_close(g_webSocket[W_I_HLTV])
|
|
g_webReads[W_I_HLTV] = 0
|
|
g_webDataLine[W_I_HLTV] = 0
|
|
|
|
// Reset data
|
|
for ( new i = 0; i < W_NUM_LINES; i++ )
|
|
{
|
|
g_webData[W_I_HLTV][i] = "^0"
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Game pausing
|
|
**************************************************************************************/
|
|
|
|
// Command: pause
|
|
public cmd_pause(id)
|
|
{
|
|
// If pausing or unpausing is not awaited, ignore
|
|
if ( !g_pausePending )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get ref's name and say the message
|
|
new name[HL_LEN_NICK + 1]; get_user_name(g_pauseReq, name, HL_LEN_NICK)
|
|
|
|
// Disable pause wait
|
|
g_pauseReq = 0
|
|
g_pausePending = 0
|
|
server_cmd("pausable 0")
|
|
|
|
// If already paused, this will be unpause
|
|
if ( g_pauseStatus )
|
|
{
|
|
g_pauseStatus = 0
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) has unpaused the game", name)
|
|
}
|
|
// Otherwise this will be pause
|
|
else
|
|
{
|
|
g_pauseStatus = 1
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) has pause the game", name)
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: amx_enslpause (Pause / unpause)
|
|
public cmd_enslpause(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 0) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Init variables
|
|
new pauser = find_player("h")
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
|
|
// If pausable player cannot be found, abort
|
|
if ( !pauser )
|
|
{
|
|
console_print(id, "Unable to (un)pause")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Set the plugin to wait for pause from client
|
|
g_pauseReq = id
|
|
g_pausePending = 1
|
|
server_cmd("pausable 1")
|
|
client_cmd(pauser, "pause; pauseMark")
|
|
log_message("[ENSL] [enslpause] [%s:%s] [status=%d]", g_userSteamID[pid], name, g_pauseStatus)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Voice blocking
|
|
**************************************************************************************/
|
|
|
|
// Command: public say
|
|
public cmd_say(id)
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(id)
|
|
|
|
// Get the message
|
|
new msg[HL_LEN_SAY + 1]; read_args(msg, HL_LEN_SAY); remove_quotes(msg)
|
|
|
|
// Check if its a whois query
|
|
if ( contain(msg, "/whois") == 0 )
|
|
{
|
|
cmd_whois(id, msg)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check if user is disallowed to talk
|
|
if ( g_gameModerated && !g_userVoice[pid] && !func_is_referee(pid) )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Public chat is moderated and you are not allowed to talk.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check if user has been disallowed to talk
|
|
if ( g_userGagged[pid] )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] You have been gagged by a referee.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check if user has global talk features
|
|
if ( g_userTeam[pid] == HL_RRSPECS )
|
|
{
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
client_print(0, print_chat, "%s : %s", name, msg)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Command: empty=freetalk or [name/#ID] (Limit talking)
|
|
public cmd_enslvoice(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 0) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Initialize variables
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new userStr[HL_LEN_MSG + 1], userNum = 0, argC = read_argc()
|
|
new userSearch[HL_LEN_NICK + 1], userName[HL_LEN_NICK + 1], userId, userPid
|
|
|
|
// Take action if arguments are specified
|
|
if ( argC > 1 )
|
|
{
|
|
// Loop through the arguments
|
|
for ( new i = 1; i < argC; i++ )
|
|
{
|
|
// Fetch the given users
|
|
userSearch = "^0"; read_argv(i, userSearch, HL_LEN_NICK)
|
|
userId = func_get_player(id, userSearch)
|
|
|
|
// If user can be found..
|
|
if ( userId != -1 )
|
|
{
|
|
// Authenticate + fetch username & pid
|
|
userName = "^0"; get_user_name(userId, userName, HL_LEN_NICK)
|
|
userPid = func_authenticate(userId)
|
|
|
|
// If user is voiced, unvoice user
|
|
if ( g_userVoice[userPid] )
|
|
{
|
|
g_userVoice[userPid] = 0
|
|
console_print(id, "Talk privilege revoked from: %s", userName)
|
|
log_message("[ENSL] [enslvoice] [%s:%s] [revoke] [%s:%s]", g_userSteamID[pid], name, userName, g_userSteamID[userPid])
|
|
}
|
|
// If user is not voiced, voice user
|
|
else
|
|
{
|
|
g_userVoice[userPid] = 1
|
|
console_print(id, "Talk privilege granted to: %s", userName)
|
|
log_message("[ENSL] [enslvoice] [%s:%s] [grant] [%s:%s]", g_userSteamID[pid], name, userName, g_userSteamID[userPid])
|
|
|
|
// If moderation is enabled, add user to the list of privileged people
|
|
if ( g_gameModerated )
|
|
{
|
|
add(userStr, HL_LEN_MSG, " [", 2)
|
|
add(userStr, HL_LEN_MSG, userName, HL_LEN_NICK)
|
|
add(userStr, HL_LEN_MSG, "]", 1)
|
|
userNum++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set moderation if arguments specified or it already disabled
|
|
if ( !g_gameModerated || argC > 1 )
|
|
{
|
|
// Find users who may talk. if we are enabling the chat moderation
|
|
if ( !g_gameModerated )
|
|
{
|
|
for ( new i = 1; i < g_userCount; i++ )
|
|
{
|
|
// If user is on server and is able talk, add user
|
|
if ( g_userStatus[i] && g_userVoice[i] )
|
|
{
|
|
userName = "^0"; get_user_name(g_userIdIndex[i], userName, HL_LEN_NICK)
|
|
add(userStr, HL_LEN_MSG, " [", 2)
|
|
add(userStr, HL_LEN_MSG, userName, HL_LEN_NICK)
|
|
add(userStr, HL_LEN_MSG, "]", 1)
|
|
userNum++
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set moderation
|
|
g_gameModerated = 1
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) has enabled chat moderation.", name)
|
|
log_message("[ENSL] [enslvoice] [%s:%s] [ENABLE]", g_userSteamID[pid], name)
|
|
|
|
// Echo who may talk
|
|
if ( userNum > 0 )
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Chat allowed for:%s", userStr)
|
|
}
|
|
}
|
|
// Otherwise ...
|
|
else
|
|
{
|
|
// Remove voice privilege
|
|
for ( new i = 1; i < g_userCount; i++ )
|
|
{
|
|
g_userVoice[i] = 0
|
|
}
|
|
|
|
// Unset moderation
|
|
g_gameModerated = 0
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) has disabled chat moderation.", name)
|
|
log_message("[ENSL] [enslvoice] [%s:%s] [DISABLED]", g_userSteamID[pid], name)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* ENSL Official Match setting CVAR enforcement
|
|
**************************************************************************************/
|
|
|
|
// Function: initialize server CVARs
|
|
public func_init_cvars()
|
|
{
|
|
// Integers
|
|
func_add_int_cvar("mp_blockscripts", 0)
|
|
func_add_int_cvar("mp_consistency", 1)
|
|
func_add_int_cvar("mp_combattime", 15)
|
|
func_add_int_cvar("mp_drawdamage", 0)
|
|
func_add_int_cvar("mp_falldamage", 1)
|
|
func_add_int_cvar("mp_flashlight", 1)
|
|
func_add_int_cvar("mp_footsteps", 1)
|
|
func_add_int_cvar("mp_friendlyfire", 1)
|
|
func_add_int_cvar("mp_killdelay", 3)
|
|
func_add_int_cvar("mp_team1damagepercent", 100)
|
|
func_add_int_cvar("mp_team2damagepercent", 100)
|
|
func_add_int_cvar("mp_timelimit", 0)
|
|
func_add_int_cvar("mp_tournamentmode", 1)
|
|
func_add_int_cvar("pausable", 0)
|
|
func_add_int_cvar("sv_aim", 0)
|
|
func_add_int_cvar("sv_cheats", 0)
|
|
func_add_int_cvar("sv_maxspeed", 4000)
|
|
func_add_int_cvar("sv_minrate", 10000)
|
|
func_add_int_cvar("sv_maxrate", 20000)
|
|
func_add_int_cvar("sv_minupdaterate", 40)
|
|
func_add_int_cvar("sv_maxupdaterate", 100)
|
|
func_add_int_cvar("sv_proxies", 5)
|
|
func_add_int_cvar("ensl_minrate", 10000)
|
|
func_add_int_cvar("ensl_maxrate", 25000)
|
|
func_add_int_cvar("ensl_mincmdrate", 50)
|
|
func_add_int_cvar("ensl_maxcmdrate", 150)
|
|
func_add_int_cvar("ensl_minupdaterate", 40)
|
|
func_add_int_cvar("ensl_maxupdaterate", 150)
|
|
func_add_int_cvar("ensl_minfps", 50)
|
|
func_add_int_cvar("ensl_maxfps", 999)
|
|
func_add_int_cvar("ensl_snapshots", 1, 0)
|
|
func_add_int_cvar("ensl_checkids", 1, 1)
|
|
func_add_int_cvar("ensl_checkrates", 1, RC_ENABLED_FETCH)
|
|
func_add_int_cvar("ensl_ffclock", 1, 0)
|
|
func_add_int_cvar("ensl_merclimit", 1, 0)
|
|
func_add_int_cvar("ensl_teamlimit", 6, 0)
|
|
func_add_int_cvar("ensl_speclimit", 1, 0)
|
|
func_add_int_cvar("ensl_refaccess", 1, 1)
|
|
func_add_int_cvar("ensl_combatmode", 2, 1)
|
|
|
|
// Floats
|
|
func_add_flt_cvar("mp_countdowntime", 0.2)
|
|
func_add_flt_cvar("sv_clienttrace", 3.5)
|
|
}
|
|
|
|
// Command: amx_enslcfg (Execute ENSL Match Settings)
|
|
public cmd_enslcfg(id, level, cid)
|
|
{
|
|
// Authenticate user if necessary + get username
|
|
new pid = func_authenticate(id)
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 0) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If it is pcw mode, run pcw mode settings
|
|
new mode[4]; read_argv(1, mode, 3); new pcw = equal(mode, "pcw")
|
|
|
|
// Set Server ENSL Cvars, integers
|
|
for ( new i = 0; i < C_NUM_INTS; i++ )
|
|
{
|
|
set_cvar_num(g_cvarIntName[i], pcw ? g_cvarIntPCW[i] : g_cvarIntValue[i])
|
|
}
|
|
|
|
// Set Server ENSL Cvars, floats
|
|
for ( new i = 0; i < C_NUM_FLOATS; i++ )
|
|
{
|
|
set_cvar_float(g_cvarFltName[i], pcw ? g_cvarFltPCW[i] : g_cvarFltValue[i])
|
|
}
|
|
|
|
// Log and announce the event
|
|
if ( pcw )
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Version %s PCW Settings Loaded", VERSION)
|
|
}
|
|
else
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Version %s OFFICIAL Settings Loaded", VERSION)
|
|
}
|
|
|
|
// Log it
|
|
log_message("[ENSL] [enslcfg] [%s:%s] [%d]", g_userSteamID[pid], name, pcw)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: amx_enslcvar (Change CVAR value)
|
|
public cmd_enslcvar(id, level, cid)
|
|
{
|
|
// Authenticate user if necessary
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 2) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get referee name and argument
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new cvarName[C_LEN_NAME + 1]; read_argv(1, cvarName, C_LEN_NAME)
|
|
new cvarValue[R_LEN_NUM + 1]; read_argv(2, cvarValue, R_LEN_NUM)
|
|
|
|
// Find the CVAR, integers
|
|
for ( new i = 0; i < C_NUM_INTS; i++ )
|
|
{
|
|
// If found, set it
|
|
if ( equal(g_cvarIntName[i], cvarName) )
|
|
{
|
|
// Format values for an integer cvar
|
|
new intValue = str_to_num(cvarValue), oldValue = get_cvar_num(g_cvarIntName[i])
|
|
set_cvar_num(g_cvarIntName[i], intValue)
|
|
|
|
// Announce it, log it and exit
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) changed %s from %d to %d", name, cvarName, oldValue, intValue)
|
|
log_message("[ENSL] [cvar] [%s:%s] [%s] %d -> %d", g_userSteamID[pid], name, cvarName, oldValue, intValue)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
}
|
|
|
|
// Find the CVAR, floats
|
|
for ( new i = 0; i < C_NUM_FLOATS; i++ )
|
|
{
|
|
// If found, set it
|
|
if ( equal(g_cvarFltName[i], cvarName) )
|
|
{
|
|
// Format values for a float cvar
|
|
new Float:fltValue = str_to_float(cvarValue), Float:oldValue = get_cvar_float(g_cvarFltName[i])
|
|
set_cvar_float(g_cvarFltName[i], fltValue)
|
|
|
|
// Announce it, log it and exit
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) changed %s from %.1f to %.1f", name, cvarName, oldValue, fltValue)
|
|
log_message("[ENSL] [cvar] [%s:%s] [%s] %f -> %f", g_userSteamID[pid], name, cvarName, oldValue, fltValue)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
}
|
|
|
|
// Otherwise abort since cvar was not found
|
|
console_print(id, "CVAR not found.")
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: add integer cvar
|
|
stock func_add_int_cvar(name[C_LEN_NAME + 1], value = 0, pcw = -1, level = C_LEVEL_MANDATORY)
|
|
{
|
|
// Don't add over borders
|
|
if ( g_cvarIntIndex == sizeof(g_cvarIntName) )
|
|
{
|
|
return g_cvarIntIndex
|
|
}
|
|
|
|
g_cvarIntName[g_cvarIntIndex] = name
|
|
g_cvarIntValue[g_cvarIntIndex] = value
|
|
g_cvarIntPCW[g_cvarIntIndex] = pcw != -1 ? pcw : value
|
|
g_cvarIntLevel[g_cvarIntIndex] = level
|
|
g_cvarIntIndex++
|
|
|
|
return g_cvarIntIndex - 1
|
|
}
|
|
|
|
// Function: add float cvar
|
|
stock func_add_flt_cvar(name[C_LEN_NAME + 1], Float:value = 0.0, Float:pcw = -1.0, level = C_LEVEL_MANDATORY)
|
|
{
|
|
// Don't add over borders
|
|
if ( g_cvarFltIndex == sizeof(g_cvarFltName) )
|
|
{
|
|
return g_cvarFltIndex
|
|
}
|
|
|
|
g_cvarFltName[g_cvarFltIndex] = name
|
|
g_cvarFltValue[g_cvarFltIndex] = value
|
|
g_cvarFltPCW[g_cvarFltIndex] = pcw != -1.0 ? pcw : value
|
|
g_cvarFltLevel[g_cvarFltIndex] = level
|
|
g_cvarFltIndex++
|
|
|
|
return g_cvarFltIndex - 1
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Spectation block
|
|
**************************************************************************************/
|
|
|
|
// Command: spectate
|
|
public cmd_spectate(id)
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check for too rapid action
|
|
if ( func_check_cmdtime(pid, CT_TEAMJOIN, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check if user can join
|
|
if ( get_pcvar_num(g_cvar_speclimit) && !func_is_referee(pid) )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] You cannot join spectators. Only referees and admins allowed.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Touch: spectate
|
|
public touch_spectate(ent, id)
|
|
{
|
|
return cmd_spectate(id)
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Team management functions
|
|
**************************************************************************************/
|
|
|
|
// Event: player changes team
|
|
public client_changeteam(id, newTeam, oldTeam)
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(id)
|
|
|
|
// Set the new team and increase the playercount
|
|
g_userTeam[pid] = newTeam
|
|
g_teamPlayers[newTeam]++
|
|
|
|
// Waypoint target
|
|
g_userDefendWP[id] = 0;
|
|
|
|
// Process team leave
|
|
func_teamleave(id, oldTeam)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Entity catches
|
|
public touch_teamjoin(ent, id)
|
|
{
|
|
if ( ent == HL_ENT_MARINES )
|
|
{
|
|
return cmd_jointeamone(id)
|
|
}
|
|
else if ( ent == HL_ENT_ALIENS )
|
|
{
|
|
return cmd_jointeamtwo(id)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Entity catch for autoassign
|
|
public touch_autoassign(ent, id)
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Autoassign disabled.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: autoassign
|
|
public cmd_autoassign(id)
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Autoassign disabled.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: jointeamone (marine join)
|
|
// NOTE: This doesn't cover all teamchanges -> counters not updated here
|
|
public cmd_jointeamone(id)
|
|
{
|
|
// Authenticate player
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user was digested
|
|
if ( g_userDDTime[pid] != 0 && g_userDDTime[pid] > get_systime() )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Please wait %d seconds before joining.", g_userDDTime[pid] - get_systime())
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check if user can join (merclimit)
|
|
return func_teamjoin(id, HL_MARINES)
|
|
}
|
|
|
|
// Command: jointeamtwo (alien join)
|
|
// NOTE: This doesn't cover all teamchanges -> counters not updated here
|
|
public cmd_jointeamtwo(id)
|
|
{
|
|
// Authenticate player
|
|
func_authenticate(id)
|
|
|
|
return func_teamjoin(id, HL_ALIENS)
|
|
}
|
|
|
|
// Command: enter readyroom
|
|
public cmd_readyroom(id)
|
|
{
|
|
// Authenticate
|
|
new pid = func_authenticate(id)
|
|
|
|
// Allow f4f1
|
|
g_userCmdTime[pid][CT_TEAMJOIN] = get_gametime() - G_FREQ
|
|
|
|
// Reset rates so user can change them
|
|
for ( new i = 0; i < RC_NUM_VARS; i++ )
|
|
{
|
|
g_userRCVars[pid][i] = 0
|
|
g_userRCWarn[pid][i] = RC_WARN_NEGATIVE
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: player tries to join a team (marines/aliens)
|
|
public func_teamjoin(id, newTeam)
|
|
{
|
|
new maxPlayers = get_pcvar_num(g_cvar_teamlimit), pid = g_userPidIndex[id], otherTeam = newTeam == HL_ALIENS ? HL_MARINES : HL_ALIENS
|
|
|
|
// Limit spamming
|
|
if ( func_check_cmdtime(pid, CT_TEAMJOIN, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check if member limit is one
|
|
if ( func_check_membersonly(id, pid) == 0 )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If player is already on a proper team, ignore it
|
|
if ( g_userTeam[pid] != HL_RRSPECS )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] You are already on a team")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If game has started, also limit player count if enabled
|
|
if ( g_gameStarted && maxPlayers > 0 && g_teamPlayers[newTeam] >= maxPlayers )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Player limiting is enabled. You cannot join. Maximum is %d players.", maxPlayers)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Check if user is allowed to merc
|
|
if ( (g_gameStarted || g_teamReady[newTeam]) && get_pcvar_num(g_cvar_merclimit) && g_userMerc[pid] != newTeam && g_userEnslTid[pid] != g_teamENSLId[newTeam] )
|
|
{
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
client_print(0, print_chat, "[ENSL] %s is trying to merc for %s. %s can approve it by typing /ok", name, g_teamNames[newTeam], g_teamNames[otherTeam])
|
|
g_teamMReq[newTeam] = pid
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function:process player leave from team
|
|
public func_teamleave(id, oldTeam)
|
|
{
|
|
// Decrease the player count
|
|
g_teamPlayers[oldTeam]--
|
|
|
|
// For marines & aliens
|
|
if ( oldTeam == HL_MARINES || oldTeam == HL_ALIENS )
|
|
{
|
|
// If game has not started...
|
|
if ( !g_gameStarted && !g_gameEnding )
|
|
{
|
|
// If neither of teams have players, stop the clock
|
|
if ( g_teamPlayers[HL_MARINES] == 0 && g_teamPlayers[HL_ALIENS] == 0 )
|
|
{
|
|
func_stop_ffclock(0)
|
|
func_reset_teams()
|
|
}
|
|
// If only the team which was left, is empty, reset its vars
|
|
else if ( g_teamPlayers[oldTeam] == 0 )
|
|
{
|
|
func_reset_team(oldTeam)
|
|
}
|
|
// Otherwise force unready
|
|
else if ( g_teamReady[oldTeam] )
|
|
{
|
|
// Loop through all players
|
|
for ( new pid = 1; pid < g_userCount; pid++ )
|
|
{
|
|
// Unready the first player, who is on server, of the team given
|
|
if ( g_userStatus[pid] && g_userTeam[pid] == oldTeam )
|
|
{
|
|
client_print(g_userIdIndex[pid], print_chat, "[ENSL] A player left your team and auto-unready is forced.")
|
|
client_cmd(g_userIdIndex[pid], "say notready")
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Command: allow mercs of opponent team to play
|
|
public cmd_mercsok(id)
|
|
{
|
|
// Authenticate and get team ids
|
|
new pid = func_authenticate(id)
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new team = g_userTeam[pid], other = team == HL_ALIENS ? HL_MARINES : HL_ALIENS
|
|
new userNum = 0, userStr[HL_LEN_MSG + 1]
|
|
|
|
// Check for too rapid action
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Do not accept it from other than aliens / marines before game start
|
|
if ( (team != HL_MARINES && team!= HL_ALIENS) || g_gameStarted )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Only marines/aliens can approve mercs before game start.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If merclimiting is off, ignore it
|
|
if ( get_pcvar_num(g_cvar_merclimit) == 0 )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Merclimiting is not enabled.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If opponent hasn't registered yet, don't bother
|
|
if ( g_teamENSLId[other] == 0 )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Other team has not registered yet.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Go through all players
|
|
for ( new i = 1; i < g_userCount; i++ )
|
|
{
|
|
// Check if the player on the other team is a merc
|
|
if ( g_userStatus[i] && g_userTeam[i] == other && g_userEnslTid[i] != g_teamENSLId[other] && g_userMerc[i] != other )
|
|
{
|
|
// Allow mercing
|
|
g_userMerc[i] = other
|
|
|
|
// Add seperating comma for 2nd+ mercs
|
|
if ( userNum > 0 )
|
|
{
|
|
add(userStr, HL_LEN_MSG, ", ", 2)
|
|
}
|
|
|
|
// Add player name to the list
|
|
new userName[HL_LEN_NICK]; get_user_name(g_userIdIndex[i], userName, HL_LEN_NICK)
|
|
add(userStr, HL_LEN_MSG, userName, 15)
|
|
userNum++
|
|
}
|
|
}
|
|
|
|
// If no mercs were found, ignore it
|
|
if ( userNum == 0 )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] No mercs were found from %s.", g_teamNames[other])
|
|
}
|
|
// Otherwise announce it
|
|
else
|
|
{
|
|
client_print(0, print_chat, "[ENSL] %s allowed mercs: %s.", g_teamNames[team], userStr)
|
|
log_message("[ENSL] [mercsok] [%s:%s] [%s]", g_userSteamID[pid], userStr)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: list mercs of the opposite team
|
|
public cmd_mercs(id)
|
|
{
|
|
// Authenticate and get team ids
|
|
new pid = func_authenticate(id)
|
|
new team = g_userTeam[pid], other = team == HL_ALIENS ? HL_MARINES : HL_ALIENS
|
|
new userNum = 0, userStr[HL_LEN_MSG + 1]
|
|
|
|
// Check for too rapid action
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Do not accept it from other than aliens / marines before game start
|
|
if ( (team != HL_MARINES && team!= HL_ALIENS) || g_gameStarted )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Only marines/aliens can list mercs before game start.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If opponent hasn't registered yet, don't bother
|
|
if ( g_teamENSLId[other] == 0 )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Other team has not registered yet.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Go through all players
|
|
for ( new i = 1; i < g_userCount; i++ )
|
|
{
|
|
// Check if the player on the other team is a merc
|
|
if ( g_userStatus[i] && g_userTeam[i] == other && g_userEnslTid[i] != g_teamENSLId[other] )
|
|
{
|
|
// Add seperating comma for 2nd+ mercs
|
|
if ( userNum > 0 )
|
|
{
|
|
add(userStr, HL_LEN_MSG, ", ", 2)
|
|
}
|
|
|
|
// Add player name to the list
|
|
new userName[HL_LEN_NICK]; get_user_name(g_userIdIndex[i], userName, HL_LEN_NICK)
|
|
add(userStr, HL_LEN_MSG, userName, 15)
|
|
userNum++
|
|
}
|
|
}
|
|
|
|
// If no mercs were found, say it
|
|
if ( userNum == 0 )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] No mercs were found from %s.", g_teamNames[other])
|
|
}
|
|
// Otherwise announce it
|
|
else
|
|
{
|
|
client_print(id, print_chat, "[ENSL] %s' mercs: %s.", g_teamNames[other], userStr)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: approve single merc
|
|
public cmd_ok(id)
|
|
{
|
|
// Authenticate and get team ids
|
|
new pid = func_authenticate(id)
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new team = g_userTeam[pid], other = team == HL_ALIENS ? HL_MARINES : HL_ALIENS
|
|
new merc = g_teamMReq[other]
|
|
|
|
// Do not accept it from othe than aliens / marines
|
|
if ( team != HL_MARINES && team!= HL_ALIENS )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If a merc has requested to join
|
|
if ( merc != -1 && g_userMerc[merc] != other && g_userStatus[merc] )
|
|
{
|
|
// Allowd mercing, reset requestor spot
|
|
g_userMerc[merc] = other
|
|
g_teamMReq[other] = -1
|
|
|
|
// Announce it
|
|
new mercName[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[merc], mercName, HL_LEN_NICK)
|
|
client_print(0, print_chat, "[ENSL] %s has been allowed to merc for %s.", mercName, g_teamNames[other])
|
|
log_message("[ENSL] [mercok] [%s:%s] [%s:%s] [%d]", g_userSteamID[pid], name, g_userSteamID[merc], mercName, team)
|
|
}
|
|
// Otherwise print error
|
|
else
|
|
{
|
|
client_print(id, print_chat, "[ENSL] No merc requests found.")
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Command: [user/#ID] [team] (toggle mercing)
|
|
public cmd_enslmerc(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 1) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Initialize variables
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new strMerc[HL_LEN_NICK + 1]; read_argv(1, strMerc, HL_LEN_NICK)
|
|
new mercId = func_get_player(id, strMerc)
|
|
|
|
// Check that player is found, not already mercing and on server
|
|
if ( mercId == -1 )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get PID
|
|
new mercPid = func_authenticate(mercId)
|
|
|
|
// If merc has been granted access, revoke it
|
|
if ( g_userMerc[mercPid] )
|
|
{
|
|
// Revoke mercing
|
|
g_userMerc[mercPid] = 0
|
|
|
|
// Announec and log it
|
|
new mercName[HL_LEN_NICK + 1]; get_user_name(mercId, mercName, HL_LEN_NICK)
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) has disallowed %s's mercing.", name, mercName)
|
|
log_message("[ENSL] [enslmerc] [%s:%s] [%s:%s] [REVOKE]", g_userSteamID[pid], name, g_userSteamID[mercPid], mercName)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch team
|
|
new strTeam[HL_LEN_TEAM + 1]; read_argv(2, strTeam, HL_LEN_TEAM)
|
|
new team = func_get_team(id, strTeam)
|
|
|
|
// Abort it team cannot be found
|
|
if ( team == -1 )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Allow mercing, reset requestor spot
|
|
g_userMerc[mercPid] = team
|
|
|
|
// Announec and log it
|
|
new mercName[HL_LEN_NICK + 1]; get_user_name(mercId, mercName, HL_LEN_NICK)
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) has allowed %s to merc for %s.", name, mercName, g_teamNames[team])
|
|
log_message("[ENSL] [enslmerc] [%s:%s] [%s:%s] [%d] [PERMIT]", g_userSteamID[pid], name, g_userSteamID[mercPid], mercName, team)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: reset team variables at round end
|
|
public func_reset_team(team)
|
|
{
|
|
// Reset teams (marines & aliens)
|
|
g_teamReady[team] = 0
|
|
g_teamENSLId[team] = 0
|
|
g_teamENSLName[team] = "^0"
|
|
g_teamMReq[team] = -1
|
|
}
|
|
|
|
// Task: reset both teams
|
|
public func_reset_teams()
|
|
{
|
|
// Reset teams
|
|
func_reset_team(HL_MARINES)
|
|
func_reset_team(HL_ALIENS)
|
|
|
|
// Remove merc status
|
|
for ( new i = 1; i < U_NUM_IDS; i++ )
|
|
{
|
|
g_userMerc[i] = 0
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Ready related functions & forfeitclock
|
|
**************************************************************************************/
|
|
|
|
// Command: say ready
|
|
public cmd_ready(id)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Initialize variables
|
|
new team = g_userTeam[pid], maxPlayers = get_pcvar_num(g_cvar_teamlimit)
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
|
|
// If game has started, requester is spec or team is already ready, skip process
|
|
if ( g_gameStarted || team == HL_RRSPECS || g_teamReady[team] )
|
|
{
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// If pause is on, dont allow ready
|
|
if ( g_pauseStatus )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] You cannot ready while game is paused.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Regenerate the player count
|
|
g_teamPlayers[team] = 0
|
|
for ( new i = 0; i < U_NUM_IDS; i++ )
|
|
{
|
|
if ( g_userTeam[i] == team )
|
|
{
|
|
g_teamPlayers[team]++
|
|
}
|
|
}
|
|
|
|
// If teams are limited, check players
|
|
if ( !ns_is_combat() && maxPlayers != 0 && g_teamPlayers[team] != maxPlayers )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] You can only ready with %d players on your team.", maxPlayers)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// If mercliming is on...
|
|
if ( get_pcvar_num(g_cvar_merclimit) )
|
|
{
|
|
// If user is unteamed, abort
|
|
if ( !g_userEnslTid[pid] )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] Unteamed players are not allowed to ready when merclimiting is enabled.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Register requestor's team as team's choice and announce team registration
|
|
g_teamENSLId[team] = g_userEnslTid[pid]
|
|
g_teamENSLName[team] = g_userEnslTeam[pid]
|
|
client_print(id, print_chat, "[ENSL] You are registered as ^"%s^".", g_teamENSLName[team])
|
|
|
|
// Loop through all players
|
|
for ( new iPid = 1; iPid < g_userCount; iPid++ )
|
|
{
|
|
// If the marine / alien has different ENSL team..
|
|
if ( g_userStatus[iPid] && g_userTeam[iPid] == team && g_userEnslTid[iPid] != g_teamENSLId[team] && !g_userMerc[iPid] )
|
|
{
|
|
// Fetch the name
|
|
new iName[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[iPid], iName, HL_LEN_NICK)
|
|
|
|
// Echo warning and abort
|
|
client_print(id, print_chat, "[ENSL] Player ^"%s^" isn't on your ENSL roster.", iName)
|
|
return PLUGIN_HANDLED
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mark team ready
|
|
g_teamReady[team] = 1
|
|
log_message("[ENSL] [ready] [%s:%s] [%s] [%d:%s]", g_userSteamID[pid], name, g_teamNames[team], g_teamENSLId[team], g_teamENSLName[team])
|
|
|
|
// If both teams are ready...
|
|
if ( g_teamReady[HL_MARINES] && g_teamReady[HL_ALIENS] )
|
|
{
|
|
// Stop the clock
|
|
func_stop_ffclock(0)
|
|
|
|
// Set game started
|
|
g_gameStarted = 1
|
|
}
|
|
// Otherwise start it
|
|
else
|
|
{
|
|
func_start_ffclock()
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Command: not ready
|
|
public cmd_notready(id)
|
|
{
|
|
// Authenticate user and get team
|
|
new pid = func_authenticate(id)
|
|
new team = g_userTeam[pid]
|
|
|
|
// Mark team unready if its aliens or marines
|
|
if ( !g_gameStarted && team > HL_RRSPECS )
|
|
{
|
|
g_teamReady[team] = 0
|
|
|
|
// Pause the forfeit clock if both teams are unready
|
|
if ( !g_teamReady[HL_MARINES] && !g_teamReady[HL_ALIENS] )
|
|
{
|
|
func_pause_ffclock()
|
|
}
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Command: amx_enslclock [mins] [secs] (add extra time to the forfeit clock)
|
|
public cmd_enslclock(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command and game is not running
|
|
if ( !func_check_access(id, level, cid, 1) || g_gameStarted || !get_pcvar_num(g_cvar_ffclock) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Init variables
|
|
new secs = 0
|
|
new strMins[R_LEN_MINS + 1]; read_argv(1, strMins, R_LEN_MINS); secs += str_to_num(strMins) * 60
|
|
new strSecs[R_LEN_MINS + 1]; read_argv(2, strSecs, R_LEN_MINS); secs += str_to_num(strSecs)
|
|
new timeText[TT_LEN_OUTPUT + 1]; func_format_time(secs+0.0, timeText)
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
|
|
// Or add extra time
|
|
g_FFCUsed -= secs
|
|
client_print(0, print_chat, "[ENSL] Referee (%s) has %s the forfeit clock by %s", name, secs < 0 ? "decreased" : "increased", timeText)
|
|
log_message("[ENSL] [enslclock] [%s:%s] [%s]", g_userSteamID[pid], name, timeText)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: start the forfeit clock
|
|
// Requirements: 1 team is ready
|
|
public func_start_ffclock()
|
|
{
|
|
// Do not start if the task exists
|
|
if ( task_exists(T_FFCLOCK) || !get_pcvar_num(g_cvar_ffclock) || g_gameStarted )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Start the clock
|
|
g_FFCStarted = get_gametime()
|
|
set_task(1.0, "task_ffclock", T_FFCLOCK, "", 0, "b")
|
|
|
|
// Print the start message
|
|
new other = g_teamReady[HL_ALIENS] ? HL_MARINES : HL_ALIENS
|
|
new timeText[TT_LEN_OUTPUT + 1]; func_format_time(FF_TIME - g_FFCUsed, timeText)
|
|
client_print(0, print_chat, "[ENSL] Forfeit clock started. %s have %s to ready.", g_teamNames[other], timeText)
|
|
log_message("[ENSL] [enslclock] [START] [%s] [%s]", timeText, g_teamNames[other])
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: pause the forfeit clock
|
|
public func_pause_ffclock()
|
|
{
|
|
// Exit if the task doesn't exist
|
|
if ( !task_exists(T_FFCLOCK) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Save the used forfeit time. If it is zero or negative, give 1min extra
|
|
g_FFCUsed = floatround(get_gametime() - g_FFCStarted + g_FFCUsed, floatround_floor)
|
|
g_FFCUsed = g_FFCUsed <= 0 ? floatround(FF_TIME) - 60 : g_FFCUsed
|
|
remove_task(T_FFCLOCK)
|
|
|
|
// Announce it
|
|
new timeText[TT_LEN_OUTPUT + 1]; func_format_time(FF_TIME - g_FFCUsed, timeText)
|
|
client_print(0, print_chat, "[ENSL] Forfeit clock has paused with %s left. Type ready to start it again.", timeText)
|
|
log_message("[ENSL] [enslclock] [PAUSE] [%s]", timeText)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: stop the forfeit clock
|
|
public func_stop_ffclock(silent)
|
|
{
|
|
// If the task exists, stop it
|
|
if ( task_exists(T_FFCLOCK) )
|
|
{
|
|
remove_task(T_FFCLOCK)
|
|
}
|
|
|
|
// Reset timers
|
|
g_FFCStarted = 0.0
|
|
g_FFCUsed = 0
|
|
|
|
// Announce it if not silent stop
|
|
if ( !silent )
|
|
{
|
|
client_print(0, print_console, "[ENSL] Forfeit clock has been stopped and timers have been reset.")
|
|
}
|
|
|
|
// Log the event
|
|
log_message("[ENSL] [enslclock] [STOP]")
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Task: forfeit clock
|
|
public task_ffclock()
|
|
{
|
|
new timeText[TT_LEN_OUTPUT + 1]
|
|
|
|
// Calculate the remaining time
|
|
new Float:remaining = FF_TIME - get_gametime() + g_FFCStarted - g_FFCUsed
|
|
|
|
// If the time is out, announce the forfeit
|
|
if ( remaining <= 0 )
|
|
{
|
|
// Give the forfeit
|
|
if ( !g_teamReady[HL_MARINES] )
|
|
{
|
|
client_print(0, print_chat, "Marines (%s) have received the forfeit loss.", g_teamENSLName[1])
|
|
}
|
|
else if ( !g_teamReady[HL_ALIENS] )
|
|
{
|
|
client_print(0, print_chat, "Aliens (%s) have received the forfeit loss.", g_teamENSLName[2])
|
|
}
|
|
|
|
// Remove the task, reset variables and quit
|
|
remove_task(T_FFCLOCK)
|
|
g_FFCStarted = 0.0
|
|
g_FFCUsed = 0
|
|
|
|
// Run through and give everyone a final snapshot
|
|
for ( new pid = 1; pid < g_userCount; pid++ )
|
|
{
|
|
// Ignore RR+Specs
|
|
if ( g_userStatus[pid] && g_userTeam[pid] > 0 )
|
|
{
|
|
func_snapshot(pid, 1)
|
|
}
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Format unready team and timetext
|
|
new team = !g_teamReady[HL_MARINES] ? HL_MARINES : HL_ALIENS
|
|
func_format_time(remaining, timeText)
|
|
|
|
// Announce the team lacking players
|
|
for ( new pid = 1; pid < g_userCount; pid++ )
|
|
{
|
|
// Print it to everyone on the server
|
|
if ( g_userStatus[pid] )
|
|
{
|
|
set_hudmessage(255, 0, 0, -1.0, 0.9, 0, 0.0, 0.9, 0.0, 0.0)
|
|
show_hudmessage(g_userIdIndex[pid], "%s have %s to ready.", g_teamNames[team], timeText)
|
|
}
|
|
}
|
|
|
|
// Print casual message every 30 seconds
|
|
if ( floatround(remaining) % 30 == 0 )
|
|
{
|
|
client_print(0, print_chat, "%s have %s to ready.", g_teamNames[team], timeText)
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Combat modes
|
|
**************************************************************************************/
|
|
|
|
public func_init_co()
|
|
{
|
|
// If its not combat, don't bother
|
|
if ( !ns_is_combat() )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
register_event("WeapPickup", "evolve_lerk", "b", "1=6")
|
|
|
|
// Normal combat
|
|
g_coNum[CO_NORMAL] = 0
|
|
g_coBlocked[CO_NORMAL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
|
|
// Celeresupply
|
|
g_coNum[CO_CELERESUPPLY] = 31
|
|
g_coBlocked[CO_CELERESUPPLY] = {20, 21, 22, 23, 24, 25, 27, 33, 37, 38, 39, 53, 61, 62, 64, 65, 66, 101, 102, 103, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
|
|
// ENSL combat
|
|
g_coNum[CO_ENSL] = 5
|
|
g_coBlocked[CO_ENSL] = {38, 39, 117, 126, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
|
|
// SGs vs Fades
|
|
g_coNum[CO_SGSFADES] = 21
|
|
g_coBlocked[CO_SGSFADES] = {65, 66, 38, 39, 27, 53, 33, 126, 114, 115, 117, 101, 102, 103, 108, 109, 110, 111, 112, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
|
|
// SGs vs Leap Skulks
|
|
g_coNum[CO_SGSKULKS] = 27
|
|
g_coBlocked[CO_SGSKULKS] = {20, 21, 22, 24, 25, 27, 33, 37, 38, 39, 53, 61, 62, 65, 66, 102, 103, 108, 109, 110, 111, 112, 114, 115, 116, 117, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
|
|
// LMGs vs Cele Lerks
|
|
g_coNum[CO_LMGLERKS] = 26
|
|
g_coBlocked[CO_LMGLERKS] = {21, 22, 27, 33, 37, 38, 39, 53, 61, 62, 64, 65, 66, 101, 102, 103, 108, 109, 110, 111, 112, 114, 116, 117, 118, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
public evolve_lerk(id)
|
|
{
|
|
if ( get_pcvar_num(g_cvar_combatmode) == CO_LMGLERKS )
|
|
{
|
|
strip_user_weapons(id);
|
|
ns_give_item(id, "weapon_bite2gun");
|
|
}
|
|
}
|
|
|
|
public func_cmd_stripweapons(id)
|
|
{
|
|
strip_user_weapons(id);
|
|
ns_give_item(id, "weapon_knife");
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Extra user kicker, slot maker, widow maker, roommaker
|
|
**************************************************************************************/
|
|
|
|
// Command: /say /makeroom (kick specs)
|
|
public cmd_makeroom(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check for too rapid action
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
if ( get_maxplayers() > get_playersnum(1) )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] There is still room. No-one kicked.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
new playerCount = 0, target = 0, maxTime = 0
|
|
new players[HL_NUM_PLAYERS]; get_players(players, playerCount, "h")
|
|
|
|
// Check readyroom first
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
if ( nst_is_readyroom(players[i]) && (target == 0 || get_user_time(players[i]) < maxTime) )
|
|
{
|
|
target = players[i]
|
|
maxTime = get_user_time(players[i])
|
|
}
|
|
}
|
|
|
|
// Then go to specs
|
|
if ( target == 0 )
|
|
{
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
if ( nst_is_spectate(players[i]) && (target == 0 || get_user_time(players[i]) < maxTime) )
|
|
{
|
|
target = players[i]
|
|
maxTime = get_user_time(players[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( target == 0 )
|
|
{
|
|
client_print(id, print_chat, "[ENSL] No suitable player found, contact admin.")
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
new targetUID = get_user_userid(target)
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new targetName[HL_LEN_NICK + 1]; get_user_name(target, targetName, HL_LEN_NICK)
|
|
server_cmd("kick #%d ^"Room needed for players.^"", targetUID)
|
|
client_print(0, print_chat, "[ENSL] Player (%s) kicked spec: %s", name, targetName)
|
|
log_message("[ENSL] [makeroom] [%s:%s] [%d:%s]", g_userSteamID[g_userPidIndex[id]], name, g_userSteamID[g_userPidIndex[target]], targetName)
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Client rate and variable checking functions
|
|
**************************************************************************************/
|
|
|
|
// Task: check all players' rates
|
|
public task_check_rates()
|
|
{
|
|
// Fetch players (non-dead, non-hltv, non-bots)
|
|
new playerCount, players[HL_NUM_PLAYERS]; get_players(players, playerCount, "ch")
|
|
|
|
// Loop through all players
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
func_check_rates(players[i])
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Command: check own rates
|
|
public cmd_check(id)
|
|
{
|
|
// Check that user is authenticated
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check for too rapid action
|
|
if ( func_check_cmdtime(pid, CT_GENERAL, print_chat) == PLUGIN_HANDLED )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Set requested ratecheck
|
|
for ( new i = 0; i < RC_NUM_VARS; i++ )
|
|
{
|
|
g_userRCWarn[pid][i] = RC_WARN_REQUEST
|
|
}
|
|
|
|
// Inform user
|
|
client_print(id, print_chat, "[ENSL] Checking your rates...")
|
|
|
|
// Check rates manually
|
|
func_check_rates(id)
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: check player's rates and variables
|
|
public func_check_rates(id)
|
|
{
|
|
// Check that user is authenticated
|
|
new pid = func_authenticate(id)
|
|
|
|
// Don't bother with players on HLTV, dead, RR or Spec
|
|
if ( g_userTeam[pid] == HL_RRSPECS || ns_get_class(id) >= 11 )
|
|
{
|
|
return
|
|
}
|
|
|
|
// Check for illegal values
|
|
query_client_cvar(id, "rate", "func_check_rate", 1, {RC_I_RATE})
|
|
query_client_cvar(id, "cl_updaterate", "func_check_rate", 1, {RC_I_UPDATERATE})
|
|
query_client_cvar(id, "cl_cmdrate", "func_check_rate", 1, {RC_I_CMDRATE})
|
|
query_client_cvar(id, "fps_max", "func_check_rate", 1, {RC_I_FPS})
|
|
}
|
|
|
|
// Function: check player's rate CVAR
|
|
public func_check_rate(id, const cvar[], const value[], const args[])
|
|
{
|
|
new tMin = 0, tMax = 500, pid = g_userPidIndex[id], nValue = str_to_num(value), pValue = g_userRCVars[pid][args[0]]
|
|
|
|
// Get min and max values
|
|
switch ( args[0] )
|
|
{
|
|
case RC_I_RATE:
|
|
{
|
|
tMin = get_pcvar_num(g_cvar_minrate)
|
|
tMax = get_pcvar_num(g_cvar_maxrate)
|
|
}
|
|
case RC_I_UPDATERATE:
|
|
{
|
|
tMin = get_pcvar_num(g_cvar_minupdaterate)
|
|
tMax = get_pcvar_num(g_cvar_maxupdaterate)
|
|
}
|
|
case RC_I_CMDRATE:
|
|
{
|
|
tMin = get_pcvar_num(g_cvar_mincmdrate)
|
|
tMax = get_pcvar_num(g_cvar_maxcmdrate)
|
|
}
|
|
case RC_I_FPS:
|
|
{
|
|
tMin = get_pcvar_num(g_cvar_minfps)
|
|
tMax = get_pcvar_num(g_cvar_maxfps)
|
|
|
|
// TODO: check marine team
|
|
// Remove jetpack
|
|
if ( tMax < str_to_num(value) && pev(id, pev_team) == 1 && is_user_alive(id) && tMax != 0 )
|
|
{
|
|
ns_set_mask(id, MASK_JETPACK, 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the value is out of range...
|
|
if ( nValue < tMin || nValue > tMax )
|
|
{
|
|
new range[RC_LEN_RANGE + 1]; formatex(range, RC_LEN_RANGE, "%d - %d", tMin, tMax)
|
|
func_illegal_value(pid, cvar, nValue, range, args[0])
|
|
}
|
|
// If the value has been changed...
|
|
else if ( nValue != pValue && pValue != 0 && g_gameStarted && get_pcvar_num(g_cvar_checkrates) == RC_ENABLED_KICK )
|
|
{
|
|
func_illegal_change(pid, cvar, pValue, nValue)
|
|
}
|
|
|
|
// Save the value
|
|
g_userRCVars[pid][args[0]] = nValue
|
|
}
|
|
|
|
// Function: Action when illegal rate/var value is found
|
|
public func_illegal_value(pid, const cvar[], const value, const range[RC_LEN_RANGE + 1], index)
|
|
{
|
|
// Get playername and userID
|
|
new name[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[pid], name, HL_LEN_NICK)
|
|
new rc = get_pcvar_num(g_cvar_checkrates), userId = get_user_userid(g_userIdIndex[pid])
|
|
|
|
// Kick if necessary
|
|
if ( rc == RC_ENABLED_KICK && g_gameStarted )
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Player (%s) was kicked for illegal %s value %d. Correct: %s.", name, cvar, value, range)
|
|
server_cmd("kick #%d ^"[ENSL] CVAR violation (%s set to %d). Correct: %s^"", userId, cvar, value, range)
|
|
log_message("[ENSL] [ratecheck] [%s:%s] [ILLEGAL VALUE] [%s=%d] [KICKED]", g_userSteamID[pid], name, cvar, value)
|
|
}
|
|
// Global warning if necessary
|
|
else if ( (rc == RC_ENABLED_WARN || rc == RC_ENABLED_KICK) && (g_userRCWarn[pid][index] == RC_WARN_NEGATIVE || g_userRCWarn[pid][index] == RC_WARN_REQUEST || g_userRCVars[pid][index] != value) )
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Player (%s) has illegally %s set to %d. Correct: %s.", name, cvar, value, range)
|
|
log_message("[ENSL] [ratecheck] [%s:%s] [ILLEGAL VALUE] [%s=%d]", g_userSteamID[pid], name, cvar, value)
|
|
g_userRCWarn[pid][index] = RC_WARN_POSITIVE
|
|
}
|
|
// Personal warning if necessary
|
|
else if ( g_userRCWarn[pid][index] == RC_WARN_REQUEST )
|
|
{
|
|
client_print(g_userIdIndex[pid], print_chat, "[ENSL] Illegal CVAR value (%s set to %d) / Correct: %s", cvar, value, range)
|
|
g_userRCWarn[pid][index] = RC_WARN_POSITIVE
|
|
}
|
|
}
|
|
|
|
// Function: Action when rate changed
|
|
public func_illegal_change(pid, const cvar[], const oldValue, const newValue)
|
|
{
|
|
// Get playername and userID
|
|
new name[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[pid], name, HL_LEN_NICK)
|
|
new userId = get_user_userid(g_userIdIndex[pid])
|
|
|
|
// Perform the kick
|
|
client_print(0, print_chat, "[ENSL] Player (%s) kicked for changing %s from %d to %d.", name, cvar, oldValue, newValue)
|
|
server_cmd("kick #%d ^"[ENSL] CVAR (%s) changed in-game.^"", userId, cvar)
|
|
log_message("[ENSL] [ratecheck] [%s:%s] [ILLEGAL CHANGE] [%s] [%d->%d] [KICKED]", g_userSteamID[pid], name, cvar, oldValue, newValue)
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Snapshot functions
|
|
**************************************************************************************/
|
|
|
|
// Command: amx_enslshot [name/ID] (force snapshot)
|
|
public cmd_enslshot(id, level, cid)
|
|
{
|
|
// Authenticate user
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check if user can access the command
|
|
if ( !func_check_access(id, level, cid, 0) )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Get referee name + fetch arguments
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
new target[HL_LEN_NICK + 1]; read_argv(1, target, HL_LEN_NICK)
|
|
new targetID = read_argc() > 1 ? func_get_player(id, target) : g_refSSUser
|
|
|
|
// If user was searched and the ID is not found, abort
|
|
if ( read_argc() > 1 && targetID == -1 )
|
|
{
|
|
return PLUGIN_HANDLED
|
|
}
|
|
// If random was requested but not yet set it
|
|
else if ( read_argc() == 1 && g_refSSUser == -1 )
|
|
{
|
|
// Find the first user on marines/aliens to get the snapshot
|
|
for ( new i = 1; i < U_NUM_IDS; i++ )
|
|
{
|
|
if ( g_userStatus[i] && g_userTeam[i] > HL_RRSPECS )
|
|
{
|
|
g_refSSUser = i
|
|
g_userSSRand[i]++
|
|
break
|
|
}
|
|
}
|
|
|
|
// Say if a a proper player cannot be found
|
|
if ( g_refSSUser == -1 )
|
|
{
|
|
client_print(pid, print_chat, "[ENSL] Cannot find any aliens/marines.")
|
|
client_print(pid, print_console, "Cannot find any aliens/marines.")
|
|
}
|
|
// Otherwise print it
|
|
else
|
|
{
|
|
new targetName[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[g_refSSUser], targetName, HL_LEN_NICK)
|
|
client_print(pid, print_chat, "[ENSL] Next random snapshot goes to: %s", targetName)
|
|
client_print(pid, print_console, "Next random snapshot goes to: %s", targetName)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Fetch target's pid & name
|
|
new targetPID = func_authenticate(targetID)
|
|
new targetName[HL_LEN_NICK + 1]; get_user_name(targetID, targetName, HL_LEN_NICK)
|
|
|
|
// Take snaphsot
|
|
func_snapshot(targetPID, 0)
|
|
client_print(targetID, print_chat, "[ENSL] Referee enforced snapshot was taken.")
|
|
|
|
// If random snapshot was taken
|
|
if ( read_argc() == 1 )
|
|
{
|
|
new lowestUser = -1, lowestLevel = -1
|
|
|
|
// Find the user with lowest number of random ref shots
|
|
for ( new i = 0; i < U_NUM_IDS; i++ )
|
|
{
|
|
// If player is in game and on marines/aliens
|
|
if ( g_userStatus[i] && g_userTeam[i] > HL_RRSPECS )
|
|
{
|
|
// Check if user's count is lower or equal to the lowest count
|
|
if ( g_userSSRand[i] < lowestLevel || lowestLevel == -1 )
|
|
{
|
|
lowestUser = i
|
|
lowestLevel = g_userSSRand[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the lowest user was found, set the player as the next victim
|
|
if ( lowestUser != -1 )
|
|
{
|
|
g_refSSUser = lowestUser
|
|
g_userSSRand[lowestUser]++
|
|
|
|
// Print it
|
|
new targetName[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[g_refSSUser], targetName, HL_LEN_NICK)
|
|
client_print(pid, print_chat, "[ENSL] Next random snapshot goes to: %s", targetName)
|
|
client_print(pid, print_console, "Next random snapshot goes to: %s", targetName)
|
|
}
|
|
// Otherwise print it
|
|
else
|
|
{
|
|
g_refSSUser = -1
|
|
client_print(pid, print_chat, "[ENSL] Cannot find any aliens/marines.")
|
|
client_print(pid, print_console, "Cannot find any aliens/marines.")
|
|
}
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Function: check if user is next on line for random snapshot
|
|
public func_random_snap(pid)
|
|
{
|
|
// Check if user won the snapshot prize
|
|
if ( random_num(1, 3 - g_userSSPassed[pid] + g_userSSCount[pid] * 4) == 1 )
|
|
{
|
|
return true
|
|
}
|
|
|
|
// Otherwise just increase the passed death counter
|
|
g_userSSPassed[pid]++
|
|
return false
|
|
}
|
|
|
|
// Take a snapshot
|
|
public func_snapshot(pid, extra)
|
|
{
|
|
// Initialize variables
|
|
new msg[2][HL_LEN_HUDMESSAGE + 1], num = 0
|
|
new watermark[] = "`xxxxxxxxx``xx````xx```xxxxxxx``xx```````^n`xx`````````xxx```xx``xx````````xx```````^n`xx`````````xx`x``xx``xx````````xx```````^n`xxxxxx`````xx`x``xx``xxxxxxx```xx```````^n`xx`````````xx``x`xx````````xx``xx```````^n`xx`````````xx``x`xx````````xx``xx```````^n`xxxxxxxxx``xx````xx``xxxxxxx```xxxxxxxx`"
|
|
new name[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[pid], name, HL_LEN_NICK)
|
|
new strTime[18]; format_time(strTime, 17, "%d.%m.%y %H:%M", func_get_time())
|
|
|
|
// Increase the shot counter
|
|
g_userSSCount[pid]++
|
|
|
|
// If its endsnapshot, print count
|
|
if ( extra )
|
|
{
|
|
// Generate teammate info
|
|
for ( new i = 0; i < U_NUM_IDS && num < 6; i++ )
|
|
{
|
|
// If user is on server and in the same aetm
|
|
if ( g_userStatus[i] && g_userTeam[i] == g_userTeam[pid] )
|
|
{
|
|
// Generate name and cast integers to string
|
|
new iName[HL_LEN_NICK + 1]; get_user_name(g_userIdIndex[i], iName, HL_LEN_NICK)
|
|
new sId[E_LEN_IDS + 1]; num_to_str(g_userEnslId[i], sId, E_LEN_IDS)
|
|
new sTid[E_LEN_IDS + 1]; num_to_str(g_userEnslTid[i], sTid, E_LEN_IDS)
|
|
|
|
// Insert values
|
|
add(msg[0], HL_LEN_HUDMESSAGE, iName, 15)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, " ", 2)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userSteamID[i], 15)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, " ", 2)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userIP[i], HL_LEN_IP)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, "^n", 1)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userEnslNick[i], 15)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, " (", 3)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, sId, E_LEN_IDS)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, "/", 1)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, sTid, E_LEN_IDS)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, ") ", 3)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userCode[i], CC_LEN_CODE)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, "^n^n")
|
|
|
|
num++
|
|
}
|
|
}
|
|
|
|
// Print snapshot count in the last shot
|
|
client_print(g_userIdIndex[pid], print_chat, "[ENSL] %d snapshots were taken.", g_userSSCount[pid])
|
|
}
|
|
// Otherwise just input the specific player
|
|
else
|
|
{
|
|
// Cast integers ot string
|
|
new sId[E_LEN_IDS + 1]; num_to_str(g_userEnslId[pid], sId, E_LEN_IDS)
|
|
new sTid[E_LEN_IDS + 1]; num_to_str(g_userEnslTid[pid], sTid, E_LEN_IDS)
|
|
|
|
// Insert values
|
|
add(msg[0], HL_LEN_HUDMESSAGE, name, 15)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, " ", 2)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userSteamID[pid], 15)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, " ", 2)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userIP[pid], HL_LEN_IP)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, "^n", 1)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userEnslNick[pid], 15)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, " (", 3)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, sId, E_LEN_IDS)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, "/", 1)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, sTid, E_LEN_IDS)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, ") ", 3)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, g_userCode[pid], CC_LEN_CODE)
|
|
add(msg[0], HL_LEN_HUDMESSAGE, "^n^n")
|
|
}
|
|
|
|
// Print teammate info
|
|
set_hudmessage(50, 50, 50, -1.0, 0.05, 0, 0.0, 2.0, 0.0, 0.2, 1)
|
|
show_hudmessage(g_userIdIndex[pid], msg[0])
|
|
|
|
// Print the hud message including serverside info (nick, ip etc.) + gametimes
|
|
set_hudmessage(120, 0, 0, -1.0, 0.6, 0, 0.0, 2.0, 0.0, 0.2, 4)
|
|
formatex(msg[1], HL_LEN_HUDMESSAGE, "^n%s^n%s^n%s^nSnapshot #%d^n^n%s", name, g_userSteamID[pid], strTime, g_userSSCount[pid], watermark)
|
|
show_hudmessage(g_userIdIndex[pid], msg[1])
|
|
|
|
// Take the actual snapshot
|
|
client_cmd(g_userIdIndex[pid], "wait; wait; snapshot")
|
|
|
|
// Log the event
|
|
log_message("[ENSL] [snapshot] [%s:%s]", g_userSteamID[pid], name)
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Authentication / Player tracking functions
|
|
**************************************************************************************/
|
|
|
|
// Function: init server pid
|
|
public func_init_pid()
|
|
{
|
|
// Set appropiate values
|
|
g_userIndex = 1
|
|
g_userCount = 1
|
|
g_userAuthed[0] = 1
|
|
g_userIdIndex[0] = 0
|
|
g_userPidIndex[0] = 0
|
|
g_userStatus[0] = 0
|
|
g_userSteamID[0] = "SERVER"
|
|
g_userIP[0] = "127.0.0.1"
|
|
g_userTeam[0] = HL_RRSPECS
|
|
}
|
|
|
|
// Function: authenticate a player
|
|
public func_authenticate(id)
|
|
{
|
|
// Do not dbl authenticate
|
|
if ( g_userAuthed[id] )
|
|
{
|
|
new tempsteamid[HL_LEN_STEAMID];
|
|
get_user_authid(id, tempsteamid, HL_LEN_STEAMID);
|
|
replace(tempsteamid, HL_LEN_STEAMID, "STEAM_", "");
|
|
new temppid = g_userPidIndex[id];
|
|
|
|
if (!equal(tempsteamid, g_userSteamID[temppid]))
|
|
{
|
|
log_message("[ENSL ERROR CHECK] [func_authenticate fail] [%s:%s]", tempsteamid, g_userSteamID[temppid]);
|
|
}
|
|
|
|
return g_userPidIndex[id]
|
|
}
|
|
|
|
// Initialize variables
|
|
new pid = -1, steamid[HL_LEN_STEAMID + 1]; get_user_authid(id, steamid, HL_LEN_STEAMID)
|
|
|
|
// Remove prefix from steam ID
|
|
replace(steamid, HL_LEN_STEAMID, "STEAM_", "")
|
|
|
|
// Search for an existing history entry
|
|
for ( new i = 0; i < U_NUM_IDS; i++ )
|
|
{
|
|
// Find a match
|
|
if ( equal(steamid, g_userSteamID[i]) )
|
|
{
|
|
pid = i;
|
|
}
|
|
}
|
|
|
|
// If the user is not found, create a new entry
|
|
if ( pid == -1 )
|
|
{
|
|
// If history is full..
|
|
if ( g_userCount == U_NUM_IDS )
|
|
{
|
|
// Search for the first entry of a player not on server..
|
|
for ( new i = 1; i < U_NUM_IDS; i++ )
|
|
{
|
|
// Exclude players who are playing
|
|
if ( !g_userStatus[i] )
|
|
{
|
|
// Use it and reset variables so old data won't be used
|
|
// NOTE: No need to format variables twice
|
|
g_userIndex = i
|
|
g_userName[i] = "^0"
|
|
g_userSteamID[i] = "^0"
|
|
g_userIP[id] = "^0"
|
|
g_userName[i] = "^0"
|
|
g_userEnslInfo[i] = 0
|
|
g_userEnslNick[i] = "^0"
|
|
g_userEnslTeam[i] = "^0"
|
|
g_userEnslIP[i] = "^0"
|
|
g_userEnslId[i] = 0
|
|
g_userEnslTid[i] = 0
|
|
g_userEnslLevel[i] = "^0"
|
|
g_userEnslGather[i] = 0
|
|
g_userEnslRank[i] = "^0"
|
|
g_userCode[i] = "^0"
|
|
g_userSSPassed[i] = 0
|
|
g_userSSCount[i] = 0
|
|
g_userSSRand[i] = 0
|
|
g_userVoice[i] = 0
|
|
g_userGagged[i] = 0
|
|
g_userDDTime[i] = 0
|
|
g_userMerc[i] = 0
|
|
g_userWebHex[i] = "^0"
|
|
g_userWebReads[i] = 0
|
|
g_userWebSocket[i] = 0
|
|
|
|
// Reset rates
|
|
for ( new n = 0; n < RC_NUM_VARS; n++ )
|
|
{
|
|
g_userRCVars[i][n] = 0
|
|
g_userRCWarn[i][n] = 0
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use the marked entry, save it
|
|
pid = g_userIndex
|
|
|
|
if (pid >= U_NUM_IDS)
|
|
{
|
|
log_message("[ENSL ERROR CHECK] [pid overflow] [%d]", pid);
|
|
}
|
|
|
|
copy(g_userSteamID[pid], HL_LEN_STEAMID, steamid)
|
|
|
|
// Advance the index and the counter
|
|
g_userCount = ( g_userCount < U_NUM_IDS ) ? g_userCount + 1 : U_NUM_IDS
|
|
g_userIndex++
|
|
}
|
|
|
|
// Save user's information
|
|
g_userPidIndex[id] = pid
|
|
g_userAuthed[id] = 1
|
|
g_userIdIndex[pid] = id
|
|
g_userStatus[pid] = 1
|
|
|
|
// Save IP
|
|
get_user_ip(id, g_userIP[pid], HL_LEN_IP, 1)
|
|
|
|
// Reset icon data
|
|
g_userIconFlags[id] = 0
|
|
g_userIconIndex[id] = -1
|
|
|
|
// Fetch player info when id checking is enabled
|
|
if ( get_pcvar_num(g_cvar_checkids) )
|
|
{
|
|
// Empty existing data if necessary
|
|
if ( g_userEnslInfo[pid] || equal(g_userEnslNick[pid], "") )
|
|
{
|
|
g_userEnslNick[pid] = "^0"
|
|
g_userEnslIP[pid] = "^0"
|
|
g_userEnslTeam[pid] = "^0"
|
|
g_userEnslId[pid] = 0
|
|
g_userEnslTid[pid] = 0
|
|
g_userEnslLevel[pid] = "^0"
|
|
g_userEnslGather[pid] = 0
|
|
g_userEnslRank[pid] = "^0"
|
|
}
|
|
|
|
// Fetch ensl info
|
|
func_get_enslinfo(pid)
|
|
}
|
|
|
|
// Log the event
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
log_message("[ENSL] [authenticate] [%s:%s]", g_userSteamID[pid], name)
|
|
|
|
return pid
|
|
}
|
|
|
|
|
|
// Function: check if user has access to this command
|
|
public func_check_access(id, level, cid, params)
|
|
{
|
|
// Get user's pid
|
|
new pid = func_authenticate(id)
|
|
|
|
// Check param count
|
|
if ( read_argc() - 1 < params )
|
|
{
|
|
new cmd[HL_LEN_CMD + 1], info[HL_LEN_INFO + 1], cflags
|
|
get_clcmd(cid, cmd, HL_LEN_CMD, cflags, info, HL_LEN_INFO, level)
|
|
console_print(id, "Wrong parameter count. Usage: %s %s", cmd, info)
|
|
return false
|
|
}
|
|
|
|
// Check user's access
|
|
if ( (level == ADMIN_LEVEL_E && !func_is_referee(pid)) && !(get_user_flags(id) & level) )
|
|
{
|
|
console_print(id, "You don't have access to that command")
|
|
return false
|
|
}
|
|
|
|
// Check if ref commands are allowed
|
|
if ( level == ADMIN_LEVEL_E && !get_pcvar_num(g_cvar_refaccess) )
|
|
{
|
|
console_print(id, "Referee admin access is disabled by server")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Function: check if player is referee
|
|
public func_is_referee(pid)
|
|
{
|
|
// Ref or admin is okay
|
|
if ( equal(g_userEnslLevel[pid], E_LEVEL_REFEREE, 1) || equal(g_userEnslLevel[pid], E_LEVEL_ADMIN, 1) )
|
|
{
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* ENSL web query handling functions
|
|
**************************************************************************************/
|
|
|
|
// Function: Fetches ENSL Server information
|
|
public func_get_esi()
|
|
{
|
|
// Initialize variables
|
|
func_get_randhex(W_LEN_CH, g_webHex[W_I_ESI])
|
|
new url[W_LEN_URL + 1]; formatex(url, W_LEN_URL, "%s?ch=%s", S_URL, g_webHex[W_I_ESI])
|
|
|
|
// Write web and start the reading function
|
|
new webquery = get_pcvar_num(g_cvar_webquery)
|
|
if ( webquery != 0 )
|
|
{
|
|
func_write_web(g_webSocket[W_I_ESI], url)
|
|
set_task(0.5, "task_web_esi", T_ESI)
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: Reads ENSL Server information from web
|
|
public task_web_esi()
|
|
{
|
|
// Increase reads
|
|
g_webReads[W_I_ESI]++
|
|
|
|
// If there's data in the socket, read it.
|
|
if ( socket_change(g_webSocket[W_I_ESI], W_TIMEOUT) )
|
|
{
|
|
func_read_web(g_webSocket[W_I_ESI], S_MARK, S_NUM_LINES, g_webData[W_I_ESI], g_webDataLine[W_I_ESI])
|
|
}
|
|
|
|
// If socket hasn't finished, retry
|
|
if ( g_webDataLine[W_I_ESI] != S_NUM_LINES && g_webReads[W_I_ESI] < W_READS )
|
|
{
|
|
set_task(0.5, "task_web_esi", T_ESI)
|
|
return
|
|
}
|
|
|
|
// Finally close the socket and reset vars
|
|
socket_close(g_webSocket[W_I_ESI])
|
|
g_webReads[W_I_ESI] = 0
|
|
|
|
// Exit if there is no data
|
|
if ( g_webDataLine[W_I_ESI] == 0 )
|
|
{
|
|
return
|
|
}
|
|
|
|
// Set time
|
|
g_timeFetchedRemote = str_to_num(g_webData[W_I_ESI][1])
|
|
g_timeFetchedLocal = get_gametime()
|
|
|
|
// Set ENSL Plugin version
|
|
if ( strcmp(VERSION, g_webData[W_I_ESI][2]) != 0 )
|
|
{
|
|
client_print(0, print_chat, "[ENSL] Plugin is outdated, please update.")
|
|
}
|
|
|
|
// Reset data
|
|
g_webDataLine[W_I_ESI] = 0
|
|
for ( new i = 0; i < W_NUM_LINES; i++ )
|
|
{
|
|
g_webData[W_I_ESI][i] = "^0"
|
|
}
|
|
|
|
}
|
|
|
|
// Function: Fetches playerinfo from ENSL DB
|
|
public func_get_enslinfo(pid)
|
|
{
|
|
// If task exists, abort
|
|
if ( task_exists(T_USER + pid) )
|
|
{
|
|
return
|
|
}
|
|
|
|
// Set task for data send
|
|
new args[1]; args[0] = pid
|
|
new webquery = get_pcvar_num(g_cvar_webquery)
|
|
|
|
if ( webquery != 0 )
|
|
{
|
|
set_task(0.1, "task_send_enslinfo", T_USER + pid, args, 1)
|
|
}
|
|
}
|
|
|
|
// Task: Open and send socket data to ENSL DB
|
|
public task_send_enslinfo(args[])
|
|
{
|
|
new pid = args[0], url[W_LEN_URL + 1]
|
|
|
|
// Set URL and webhex
|
|
func_get_randhex(W_LEN_CH, g_userWebHex[pid])
|
|
formatex(url, W_LEN_URL, "%s%s?ch=%s", E_URL, g_userSteamID[pid], g_userWebHex[pid])
|
|
// log_message("[DEBUG] url: %s", url)
|
|
|
|
// Open socket and write to the web
|
|
func_write_web(g_userWebSocket[pid], url)
|
|
|
|
// Start reading function
|
|
set_task(0.5, "task_web_enslinfo", T_USER + pid, args, 1)
|
|
}
|
|
|
|
// Task: Attempt to read playerdata from ENSL DB
|
|
public task_web_enslinfo(args[])
|
|
{
|
|
new pid = args[0]
|
|
|
|
// Increase reads
|
|
g_userWebReads[pid]++
|
|
|
|
// If there's data in the socket, read it.
|
|
if ( socket_change(g_userWebSocket[pid], W_TIMEOUT) )
|
|
{
|
|
// log_message("[DEBUG] reading data...")
|
|
func_read_web(g_userWebSocket[pid], E_MARK, E_NUM_LINES, g_userWebData[pid], g_userWebDataLine[pid])
|
|
}
|
|
|
|
// If socket hasn't finished, retry
|
|
if ( g_userWebDataLine[pid] != E_NUM_LINES && g_userWebReads[pid] < W_READS )
|
|
{
|
|
// log_message("[DEBUG] waiting for data...")
|
|
set_task(0.5, "task_web_enslinfo", T_USER + pid, args, 1)
|
|
return
|
|
}
|
|
|
|
// Finally close the socket and reset vars
|
|
socket_close(g_userWebSocket[pid])
|
|
g_userWebReads[pid] = 0
|
|
|
|
// Exit if there is no data
|
|
if ( g_userWebDataLine[pid] == 0 )
|
|
{
|
|
return
|
|
}
|
|
|
|
// Check if user is banned
|
|
if ( contain(g_userWebData[pid][0], "BANNED") != -1 )
|
|
{
|
|
// Ban user + call disconnect manually since its not called for some reason
|
|
new uid = get_user_userid(g_userIdIndex[pid])
|
|
new mins = (str_to_num(g_userWebData[pid][1]) - func_get_time()) / 60
|
|
log_message("user %s banned for %d mins (time: %d, %s)", g_userSteamID[pid], mins, func_get_time(), g_userWebData[pid][1])
|
|
server_cmd("banid %d STEAM_%s; wait; kick #%d ^"Banned: %.20s^"", mins, g_userSteamID[pid], uid, g_userWebData[pid][2])
|
|
client_disconnect(g_userIdIndex[pid])
|
|
|
|
// Reset data
|
|
g_userWebDataLine[pid] = 0
|
|
for ( new i = 0; i < E_NUM_LINES; i++ )
|
|
{
|
|
g_userWebData[pid][i] = "^0"
|
|
}
|
|
return
|
|
}
|
|
|
|
// Set data..
|
|
copy(g_userEnslNick[pid], E_LEN_NICK, g_userWebData[pid][2])
|
|
copy(g_userEnslIP[pid], E_LEN_IP, g_userWebData[pid][3])
|
|
copy(g_userEnslTeam[pid], E_LEN_TEAM, g_userWebData[pid][4])
|
|
g_userEnslId[pid] = str_to_num(g_userWebData[pid][5])
|
|
g_userEnslTid[pid] = str_to_num(g_userWebData[pid][6])
|
|
copy(g_userEnslLevel[pid], E_LEN_LEVEL, g_userWebData[pid][7])
|
|
copy(g_userEnslRank[pid], E_LEN_RANK, g_userWebData[pid][8])
|
|
g_userIconFlags[g_userIdIndex[pid]] = str_to_num(g_userWebData[pid][9])
|
|
g_userEnslGather[g_userIdIndex[pid]] = str_to_num(g_userWebData[pid][10])
|
|
g_userEnslInfo[pid] = 1
|
|
|
|
// Enable icon
|
|
g_userIconIndex[g_userIdIndex[pid]] = -1
|
|
func_next_icon(g_userIdIndex[pid])
|
|
func_apply_icon(g_userIdIndex[pid])
|
|
|
|
// Calculate verification code
|
|
new challenge[CC_LEN_INPUT + 1]
|
|
new sId[E_LEN_IDS + 1]; num_to_str(g_userEnslId[pid], sId, E_LEN_IDS)
|
|
new sTid[E_LEN_IDS + 1]; num_to_str(g_userEnslTid[pid], sTid, E_LEN_IDS)
|
|
add(challenge, CC_LEN_INPUT, g_userSteamID[pid], HL_LEN_STEAMID)
|
|
add(challenge, CC_LEN_INPUT, g_userIP[pid], HL_LEN_IP)
|
|
add(challenge, CC_LEN_INPUT, sId, E_LEN_IDS)
|
|
add(challenge, CC_LEN_INPUT, sTid, E_LEN_IDS)
|
|
func_crypt(challenge, g_userCode[pid])
|
|
|
|
// Reset data
|
|
g_userWebDataLine[pid] = 0
|
|
for ( new i = 0; i < E_NUM_LINES; i++ )
|
|
{
|
|
g_userWebData[pid][i] = "^0"
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Web queyring functions
|
|
**************************************************************************************/
|
|
|
|
// Function: write to web
|
|
public func_write_web(&websocket, url[W_LEN_URL + 1])
|
|
{
|
|
// Open HTTP socket connection
|
|
new error; websocket = socket_open(W_IP, W_PORT, SOCKET_TCP, error)
|
|
|
|
// Process any errors
|
|
if ( websocket <= 0 )
|
|
{
|
|
// Log it
|
|
switch ( error )
|
|
{
|
|
case 1: { log_message("[ENSL] Error creating socket"); }
|
|
case 2: { log_message("[ENSL] Error resolving remote hostname"); }
|
|
case 3: { log_message("[ENSL] Error connecting socket"); }
|
|
}
|
|
|
|
// Print to players
|
|
client_print(0, print_chat, "[ENSL] Unable to connect to ENSL database")
|
|
}
|
|
|
|
// Write data
|
|
new output[W_LEN_QUERY + 1]; formatex(output, W_LEN_QUERY, "GET %s HTTP/1.1^r^n", url)
|
|
socket_send(websocket, output, W_LEN_INPUT)
|
|
output = "^0"; formatex(output, W_LEN_QUERY, "Host: %s^r^n^r^n", W_HOST)
|
|
socket_send(websocket, output, W_LEN_INPUT)
|
|
}
|
|
|
|
// Function: read from web
|
|
public func_read_web(&websocket, mark[W_LEN_MARK + 1], lines, data[][W_LEN_LINE + 1], &pointer)
|
|
{
|
|
// Receive the HTTP data
|
|
new input[W_LEN_INPUT + 1], numChars = socket_recv(websocket, input, W_LEN_INPUT)
|
|
if ( numChars == 0 )
|
|
{
|
|
return 0
|
|
}
|
|
|
|
// Go through all lines
|
|
new line[W_LEN_LINE + 1], i = 0, numCopied = 0, found = 0;
|
|
|
|
// If no data has been fetched before, find the start mark
|
|
if ( pointer == 0 )
|
|
{
|
|
// Search until end of data
|
|
while ( numCopied < numChars )
|
|
{
|
|
// Copy the line to a variable.Increase copy char ocunter + 1 (newline)
|
|
line = "^0"; numCopied += copyc(line, W_LEN_LINE, input[numCopied], W_NEWLINE) + 1
|
|
|
|
// If the matching line is found, stop here
|
|
if ( strfind(line, mark) != -1 )
|
|
{
|
|
found = 1
|
|
break
|
|
}
|
|
}
|
|
|
|
// Exit if the marker was not found
|
|
if ( found == 0 )
|
|
{
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// Get data line by line
|
|
for ( i = pointer; i < W_NUM_LINES && i < lines && numCopied < numChars; i++ )
|
|
{
|
|
numCopied += copyc(data[i], W_LEN_LINE, input[numCopied], W_NEWLINE) + 1
|
|
}
|
|
|
|
// Save the data line pointer and return number of copied lines
|
|
new numLines = i - pointer;
|
|
pointer = i
|
|
return numLines
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Waypoint fix by Asmodee
|
|
**************************************************************************************/
|
|
|
|
public func_init_waypoints()
|
|
{
|
|
for ( new i = 0; i <= g_maxPlayers; i++ )
|
|
{
|
|
g_userOrderType[i] = 0;
|
|
}
|
|
}
|
|
|
|
public func_msg_waypoint()
|
|
{
|
|
new id = get_msg_arg_int(1);
|
|
g_userOrderType[id] = get_msg_arg_int(2);
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
public cmd_clearwp(id)
|
|
{
|
|
if ( pev(id, pev_team) == 1 )
|
|
{
|
|
new type = g_userOrderType[id];
|
|
if ( type )
|
|
{
|
|
message_begin(MSG_ONE, g_msgId_Waypoint, _, id);
|
|
write_byte(id);
|
|
write_byte(type);
|
|
if ( (type == 5) || (type == 3) )
|
|
{
|
|
write_short(0);
|
|
}
|
|
else
|
|
{
|
|
write_coord(0);
|
|
write_coord(0);
|
|
write_coord(0);
|
|
}
|
|
write_byte(0);
|
|
write_byte(0);
|
|
write_byte(1);
|
|
message_end();
|
|
g_userOrderType[id] = 0;
|
|
}
|
|
}
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Teamjoining limit for ENSL members
|
|
**************************************************************************************/
|
|
|
|
public func_check_membersonly(id, pid)
|
|
{
|
|
if ( get_pcvar_num(g_cvar_membersonly) == 1 && g_userEnslId[pid] == 0 && g_userEnslGather[pid] > 0 )
|
|
{
|
|
client_print(id, print_center, "^n^n^n^n^n^n Only registered ENSL members who are in THIS gather can play. ^n^n Plese register at www.ensl.org. ^n^n ..and join at www.ensl.org/gather")
|
|
return 0
|
|
}
|
|
return 1
|
|
}
|
|
|
|
/**************************************************************************************
|
|
* Floating gun fix
|
|
**************************************************************************************/
|
|
|
|
public func_msg_death()
|
|
{
|
|
new victim = get_msg_arg_int(2);
|
|
if ( pev(victim, pev_team) == 1 )
|
|
{
|
|
func_fix_guns(victim);
|
|
}
|
|
}
|
|
|
|
public func_fix_guns(id)
|
|
{
|
|
new Float:oPlayer[3];
|
|
pev(id, pev_origin, oPlayer);
|
|
|
|
new classname[32];
|
|
|
|
new entid = -1;
|
|
while ((entid = EF_FindEntityInSphere(entid, oPlayer, 128.0)) > 0)
|
|
{
|
|
pev(entid, pev_classname, classname, 31);
|
|
if (equal(classname, "weapon_shotgun")||
|
|
equal(classname, "weapon_welder") ||
|
|
equal(classname, "weapon_heavymachinegun") ||
|
|
equal(classname, "weapon_mine") ||
|
|
equal(classname, "weapon_grenadegun"))
|
|
{
|
|
EF_DropToFloor(entid);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************
|
|
* Helper functions
|
|
**************************************************************************************/
|
|
|
|
// Function: color message
|
|
stock func_color_msg(id, msg[])
|
|
{
|
|
new name[HL_LEN_NICK + 1]; get_user_name(id, name, HL_LEN_NICK)
|
|
|
|
// If user is referee, make comments red
|
|
if ( func_is_referee(g_userPidIndex[id]) )
|
|
{
|
|
format(msg, HL_LEN_SAY, "^x04%s: ^x01%s", name, msg)
|
|
}
|
|
|
|
// Send it to all
|
|
new playerCount, player, players[HL_NUM_PLAYERS]; get_players(players, playerCount)
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
player = players[i]
|
|
message_begin(MSG_ALL, g_msgId_SayText, {0,0,0}, player)
|
|
write_byte(player)
|
|
write_string(msg)
|
|
message_end()
|
|
}
|
|
}
|
|
|
|
// Function: check that command isn't used too quickly
|
|
public func_check_cmdtime(pid, cmdId, type)
|
|
{
|
|
// Get elapsed time since last slow ENSL cmd
|
|
new Float:elapsed = get_gametime() - g_userCmdTime[pid][cmdId]
|
|
|
|
// If the user is trying to use the command too often, abort
|
|
if ( elapsed < G_FREQ )
|
|
{
|
|
// Print message when appropiate
|
|
if ( type != 0 && !g_userCmdWarn[pid][cmdId] )
|
|
{
|
|
g_userCmdWarn[pid][cmdId] = 1
|
|
client_print(g_userIdIndex[pid], type, "[ENSL] Please wait %.1fs before using this command.", G_FREQ - elapsed)
|
|
}
|
|
|
|
return PLUGIN_HANDLED
|
|
}
|
|
|
|
// Set the last time command used
|
|
g_userCmdTime[pid][cmdId] = get_gametime()
|
|
g_userCmdWarn[pid][cmdId] = 0
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Print a table of data
|
|
stock func_gentable(numColumn, lenColumn, data[HL_NUM_COLUMN][HL_LEN_COLUMN + 1], output[HL_LEN_MSG + 1])
|
|
{
|
|
// Go through all columns
|
|
for ( new i = 0; i < numColumn; i++ )
|
|
{
|
|
// Calculate number of space needed
|
|
new space[HL_LEN_COLUMN + 1], numSpace = lenColumn - strlen(data[i])
|
|
|
|
// Add the space
|
|
for ( new n = 0; n < numSpace; n++ )
|
|
{
|
|
add(space, lenColumn, " ")
|
|
}
|
|
|
|
// Join the data and space
|
|
add(output, HL_LEN_MSG, data[i])
|
|
add(output, HL_LEN_MSG, space)
|
|
}
|
|
}
|
|
|
|
// Function: format time: eg. 2 minutes 10 seconds
|
|
stock func_format_time(Float:inSecs, timeText[TT_LEN_OUTPUT + 1])
|
|
{
|
|
// Calculate result. Minutes have to be floored obviously
|
|
new Float:fMins = floatdiv(floatabs(inSecs), 60.0)
|
|
new outMins = floatround(fMins, floatround_floor)
|
|
new outSecs = floatround(floatfract(fMins) * 60, floatround_round)
|
|
|
|
// Change 1min 60 secs -> 2mins
|
|
if ( outSecs == 60 )
|
|
{
|
|
outMins++
|
|
outSecs = 0
|
|
}
|
|
|
|
// Print different text if seconds is zero
|
|
if ( outSecs == 0 )
|
|
{
|
|
formatex(timeText, TT_LEN_OUTPUT, "%d mins", outMins)
|
|
}
|
|
else if ( outMins == 0 )
|
|
{
|
|
formatex(timeText, TT_LEN_OUTPUT, "%d secs", outSecs)
|
|
}
|
|
else
|
|
{
|
|
formatex(timeText, TT_LEN_OUTPUT, "%d mins and %d secs", outMins, outSecs)
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: print confirmation code
|
|
stock func_crypt(input[CC_LEN_INPUT + 1], output[CC_LEN_CODE + 1])
|
|
{
|
|
// Init variables
|
|
new chars[6] = { 'A', 'B', 'C', 'D', 'E', 'F'}, nums[10], curChar[2], curPos = 0, curNum = 0
|
|
new md5input[HL_LEN_MSG + 1]; formatex(md5input, HL_LEN_MSG, "%s%s%s", CC_PASSCODE1, input, CC_PASSCODE2)
|
|
new sum[CC_LEN_MD5 + 1]; md5(md5input, sum); strtoupper(sum)
|
|
new lastChar[2]; copy(lastChar, 1, sum[31])
|
|
new lastPos = str_to_num(lastChar)
|
|
|
|
// Puzl it
|
|
for ( new i = 0; i < CC_LEN_CODE; i++ )
|
|
{
|
|
// Get the current character and position out of it
|
|
copy(curChar, 1, sum[i])
|
|
curPos = str_to_num(curChar)
|
|
|
|
// Edit the position depending on the value
|
|
if ( curPos == 0 )
|
|
{
|
|
curPos = power(lastPos, i % 4)
|
|
}
|
|
else if ( (curPos % 4) == 0 )
|
|
{
|
|
curPos = curPos * lastPos + i
|
|
}
|
|
else if ( (curPos % 3) == 0 )
|
|
{
|
|
curPos = power(curPos, i % 4)
|
|
}
|
|
else if ( (curPos % 2) == 0 )
|
|
{
|
|
curPos = curPos * i + curPos
|
|
}
|
|
|
|
// Decrease the position if it is over the top
|
|
if ( curPos > 31 )
|
|
{
|
|
curPos = curPos % 32
|
|
}
|
|
|
|
// Save the character by position
|
|
copy(curChar, 1, sum[CC_LEN_MD5 - 2 - curPos])
|
|
curNum = str_to_num(curChar)
|
|
|
|
// If the code has been used before, mix it more
|
|
if ( nums[curNum] > 0 )
|
|
{
|
|
// If it is letter or zero
|
|
if ( curNum == 0 )
|
|
{
|
|
copy(curChar, 1, chars[curPos % 6])
|
|
curNum = str_to_num(curChar)
|
|
}
|
|
// Or if it is a number
|
|
else
|
|
{
|
|
num_to_str(curPos % 10, curChar, 1)
|
|
curNum = str_to_num(curChar)
|
|
}
|
|
|
|
}
|
|
|
|
// Save the final result
|
|
nums[curNum]++
|
|
add(output, CC_LEN_CODE, curChar, 1)
|
|
copy(lastChar, 1, curChar)
|
|
lastPos = curPos
|
|
}
|
|
|
|
return PLUGIN_CONTINUE
|
|
}
|
|
|
|
// Function: generate a random hex value
|
|
stock func_get_randhex(length, output[])
|
|
{
|
|
static hex[6][2] = { "A", "B", "C", "D", "E", "F" }
|
|
|
|
for ( new i = 0; i < length; i++ )
|
|
{
|
|
new num = random(15), str[2]
|
|
|
|
// Add character value
|
|
if ( num > 9 )
|
|
{
|
|
add(output, length, hex[num - 10], 1)
|
|
}
|
|
// Or number value
|
|
else
|
|
{
|
|
num_to_str(num, str, 1)
|
|
add(output, length, str, 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function: search for a player by username / ID
|
|
stock func_get_player(id, target[HL_LEN_NICK + 1])
|
|
{
|
|
new targetID = -1
|
|
|
|
// Check if hash can be found -> ID search
|
|
if ( strfind(target, "#", 0, 0) != -1 )
|
|
{
|
|
// Get numerical value
|
|
targetID = str_to_num(target[1])
|
|
|
|
// Check player ID
|
|
if ( !is_user_connected(targetID) )
|
|
{
|
|
console_print(id, "Unable to find username by user ID: %d", targetID)
|
|
return -1
|
|
}
|
|
}
|
|
// Otherwise its a string search for playernames
|
|
else
|
|
{
|
|
// Fetch players (non-dead, non-hltv, non-bots)
|
|
new playerCount, players[HL_NUM_PLAYERS], targetName[HL_LEN_NICK + 1]
|
|
get_players(players, playerCount)
|
|
|
|
// Loop through all players.
|
|
// NOTE: ID list also includes non-authed players
|
|
for ( new i = 0; i < playerCount; i++ )
|
|
{
|
|
// Fetch playername
|
|
targetName = "^0"; get_user_name(players[i], targetName, HL_LEN_NICK)
|
|
|
|
// If it matches...
|
|
if ( strfind(targetName, target) != -1 && players[i] != 0 )
|
|
{
|
|
// If the string is in 2+ players' name
|
|
if ( targetID != -1 )
|
|
{
|
|
console_print(id, "Two users match, aborting.")
|
|
return -1
|
|
}
|
|
// Otherwise just save it
|
|
else
|
|
{
|
|
targetID = players[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
// If not found, announce it
|
|
if ( targetID == -1 )
|
|
{
|
|
console_print(id, "Unable to find user by username: %s", target)
|
|
}
|
|
}
|
|
|
|
return targetID
|
|
}
|
|
|
|
// Function: check team
|
|
stock func_get_team(id, input[HL_LEN_TEAM + 1])
|
|
{
|
|
new intTarget = str_to_num(input)
|
|
|
|
// Check if it is a valid team
|
|
if ( intTarget != 1 && intTarget != 2 )
|
|
{
|
|
console_print(id, "Invalid team. Please enter: 1=marines or 2=aliens")
|
|
return -1
|
|
}
|
|
|
|
return intTarget
|
|
}
|
|
|
|
// Function: parse arguments
|
|
stock func_parse_string(string[], len)
|
|
{
|
|
replace_all(string, len, ";", "")
|
|
replace_all(string, len, "^2", "")
|
|
replace_all(string, len, "'", "")
|
|
|
|
return true
|
|
}
|
|
|
|
// Function: URL encode a string
|
|
stock func_urlencode(input[], output[], outLen)
|
|
{
|
|
new c, inLen = strlen(input), letter1, letter2, hex[3]
|
|
|
|
for ( new i = 0; i < inLen; i++ )
|
|
{
|
|
c = input[i]
|
|
|
|
// Find non-alphanumeric characters, and replace them with %ASCIIHEX
|
|
if ( c < 48 || (c > 57 && c < 65) || (c > 90 && c < 97) || c > 122 )
|
|
{
|
|
letter1 = c/16; letter2 = c % 16
|
|
hex[0] = (letter1 < 10) ? letter1 + 48 : letter1 + 55
|
|
hex[1] = (letter2 < 10) ? letter2 + 48 : letter2 + 55
|
|
add(output, outLen, "%", 1)
|
|
add(output, outLen, hex, 2)
|
|
}
|
|
// Add other characters normally
|
|
else
|
|
{
|
|
add(output, outLen, input[i], 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function: get most precise time
|
|
stock func_get_time()
|
|
{
|
|
// If ENSL time has been fetched, use it
|
|
if ( g_timeFetchedRemote > 0 )
|
|
{
|
|
return floatround(g_timeFetchedRemote + (get_gametime() - g_timeFetchedLocal), floatround_ceil)
|
|
}
|
|
|
|
// Otherwise use unreliable system time
|
|
return get_systime()
|
|
}
|
|
|
|
// Convert decimal to hex
|
|
stock func_dec_to_hex(dec, hex[3])
|
|
{
|
|
static l
|
|
hex[0] = (letter1 < 10) ? letter1+48 : letter1+55
|
|
hex[1] = (letter2 < 10) ? letter2+48 : letter2+55
|
|
}
|