From 1d5d4a94b0e46c0091ea28cc9dd760da18166e8a Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sun, 30 Dec 2018 03:28:14 -0800 Subject: [PATCH 01/29] Add whitelist, add mindmedia support --- configs/proxychecker.cfg | 6 ++ configs/proxywhitelist.cfg | 9 +++ scripting/ngs_proxychecker.sp | 113 +++++++++++++++++++++++++++++++++- 3 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 configs/proxywhitelist.cfg diff --git a/configs/proxychecker.cfg b/configs/proxychecker.cfg index 0ec8e70..6fd6dbb 100644 --- a/configs/proxychecker.cfg +++ b/configs/proxychecker.cfg @@ -13,4 +13,10 @@ "requestspermin" "90" "requestsperday" "1000" } + "proxy-mind-media" + { + "url" "http://proxy.mind-media.com/block/proxycheck.php?ip={CLIENTIP}" + "requestspermin" "15" + "requesstsperday" "500" + } } diff --git a/configs/proxywhitelist.cfg b/configs/proxywhitelist.cfg new file mode 100644 index 0000000..98b9bd8 --- /dev/null +++ b/configs/proxywhitelist.cfg @@ -0,0 +1,9 @@ +// This is the whitelist file. On each line, provide an IPv4. +// For each IP after a line beginning with w, the IP will be +// whitelisted, and for each IP after a line beginning with b, +// the IP will be blacklisted. + +w +// 1.1.1.1 +b +// 2.2.2.2 \ No newline at end of file diff --git a/scripting/ngs_proxychecker.sp b/scripting/ngs_proxychecker.sp index 3256618..7ce955f 100644 --- a/scripting/ngs_proxychecker.sp +++ b/scripting/ngs_proxychecker.sp @@ -40,12 +40,12 @@ StringMap requestCache; int vpnToUse; // an index of vpnList int twentyFourHourTimeStamp; -char getIPIntelURL[1024], proxyCheckIOURL[1024]; +char getIPIntelURL[1024], proxyCheckIOURL[1024], mindMediaURL[1024]; // VPN METHODMAP methodmap VPN < StringMap { - public VPN(const char[] type, const char[] url, int requestsPerMin, int requestsPerDay, float probability=-1.0) + public VPN(const char[] type, const char[] url, int requestsPerMin, int requestsPerDay, any probability=-1.0) { StringMap coolBean = new StringMap(); coolBean.SetString("type", type); @@ -224,6 +224,10 @@ void ReadProxyConfigFile(const char[] configPath, const char[] cachePath, bool s { strcopy(proxyCheckIOURL, sizeof(proxyCheckIOURL), url); } + else if (StrEqual(buffer, "proxy-mind-media")) + { + strcopy(mindMediaURL, sizeof(mindMediaURL), url); + } if (!lowestPerMin || lowestPerMin > perMin) { lowestPerMin = float(perMin); @@ -408,6 +412,10 @@ void SendCheckRequest(DataPack pack) { SendProxyCheckIORequest(pack); } + else if (StrEqual(type, "proxy-mind-media")) + { + SendMindMediaRequest(pack); + } int soFarToday, allowedPerDay; vpn.GetValue("perDaySoFar", soFarToday); vpn.SetValue("perDaySoFar", soFarToday + 1); @@ -470,13 +478,43 @@ public void OnGetIPIntelRequestDone(SWHTTPRequest hRequest, bool bFailure, bool char[] buffer = new char[hRequest.ResponseSize + 1]; hRequest.GetBodyData(buffer, hRequest.ResponseSize); float response = StringToFloat(buffer); - LogError("Get IP Intel request failed for userid %d! Check GetIPIntel for error code %.0f with status 400!", userid, response); + switch(response) { + case -1: { + LogError("Get IP Intel request failed for userid %d! Invalid no input!", userid); + } + case -2: { + LogError("Get IP Intel request failed for userid %d! Invalid IP address!", userid); + } + case -3: { + LogError("Get IP Intel request failed for userid %d! Unroutable address / private address!", userid); + } + case -4: { + LogError("Get IP Intel request failed for userid %d! Unable to reach database, most likely the database is being updated. Keep an eye on twitter for more information!", userid); + } + case -5: { + LogError("Get IP Intel request failed for userid %d! Your connecting IP has been banned from the system or you do not have permission to access a particular service. Did you exceed your query limits? Did you use an invalid email address? If you want more information, contact GetIPIntel using the links at http://getipintel.net/#Contact . Rolling over to next VPN.", userid); + // Apply the maxed out queries to the VPN in case of caching + VPN vpn = vpnList.Get(vpnToUse); + int allowedPerDay; + vpn.GetValue("perDay", allowedPerDay); + vpn.SetValue("perDaySoFar", allowedPerDay); + vpnToUse++; + } + case -6: { + LogError("Get IP Intel request failed for userid %d! You did not provide any contact information with your query or the contact information is invalid! Rolling over!", userid); + vpnToUse++; + } + default: { + LogError("Get IP Intel request failed for userid %d! Check GetIPIntel for error code %.0f with status 400!", userid, response); + } + } delete pack; } else if (eStatusCode == k_EHTTPStatusCode429TooManyRequests) { LogError("Get IP Intel request failed for userid %d! There were too many requests, please investigate this!", userid); processQueue.Enqueue(pack); + vpnToUse++; } else { @@ -600,3 +638,72 @@ public void OnProxyCheckIORequestDone(SWHTTPRequest hRequest, bool bFailure, boo reponse.Cleanup(); delete reponse; } + +void SendMindMediaRequest(DataPack pack) +{ + char ip[24], formatURL[1024]; + pack.Reset(); + pack.ReadCell(); + pack.ReadString(ip, sizeof(ip)); + strcopy(formatURL, sizeof(formatURL), proxyCheckIOURL); + ReplaceString(formatURL, sizeof(formatURL), "{CLIENTIP}", ip); + SWHTTPRequest request = new SWHTTPRequest(k_EHTTPMethodGET, formatURL); + request.SetContextValue(pack); + request.SetCallbacks(OnMindMediaRequestDone); + request.Send(); + PrintToServerDebug("Sending mindmedia request at url %s .", formatURL); +} + +public void OnMindMediaRequestDone(SWHTTPRequest hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, DataPack pack) +{ + pack.Reset(); + int userid = pack.ReadCell(); + char ip[24]; + pack.ReadString(ip, sizeof(ip)); + if(eStatusCode != k_EHTTPStatusCode200OK || !bRequestSuccessful) + { + LogError("Mind-Media request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); + processQueue.Enqueue(pack); // deprioritize this + delete hRequest; + return; + } + + int client = 0; + if (userid != 0) + { + client = GetClientOfUserId(userid); + } + + char[] buffer = new char[hRequest.ResponseSize + 1]; + hRequest.GetBodyData(buffer, hRequest.ResponseSize); + delete hRequest; + + TrimString(buffer); + PrintToServerDebug("Mind-Media request returned %s", buffer); + + int bufferLen = strlen(buffer); // retrieving new size after trim + + if (bufferLen == 0 || bufferLen > 1 || buffer[0] == 'X') + { + LogError("Mind-Media errored with response %s!", buffer); + processQueue.Enqueue(pack); + } + else + { + if (StrEqual(buffer, "Y")) + { + ServerCommand("sm_banip %s 0 Suspicion of proxy", ip); + if (userid != 0 && client != 0) // might be redundant, only client is needed. + { + KickClient(client, "Suspicion of proxy server!"); + } + requestCache.SetValue(ip, false); // TODO: Make cache erase after a while + } + else + { + requestCache.SetValue(ip, true); // TODO: Make cache erase after a while + } + PrintToServerDebug("Caching suspicion of %s for ip %s.", buffer, ip); + delete pack; + } +} \ No newline at end of file From fb8ce59c73eb3196f43094b3215a9b3cbcb08cae Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:05:57 -0800 Subject: [PATCH 02/29] Fix request sending + add steamrep request --- plugins/ngs_tradeprotect.smx | Bin 44758 -> 45829 bytes scripting/include/ngsutils.inc | 1 + scripting/ngs_tradeprotect.sp | 162 +++++++++++++-------------------- updater/ngs_tradeprotect.txt | 8 +- 4 files changed, 70 insertions(+), 101 deletions(-) diff --git a/plugins/ngs_tradeprotect.smx b/plugins/ngs_tradeprotect.smx index 1db38b4cfead4188d8005eeaa10ddcfd5cd6da4e..9de10ae2437cc28b38a38d710fdd78cb06e99044 100644 GIT binary patch literal 45829 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 Wf3(Kg^w5a9CkluEucv9b`~LtfE;9E3 literal 44758 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 #tryinclude #tryinclude +#tryinclude #tryinclude /** diff --git a/scripting/ngs_tradeprotect.sp b/scripting/ngs_tradeprotect.sp index 692496d..1fe5d68 100644 --- a/scripting/ngs_tradeprotect.sp +++ b/scripting/ngs_tradeprotect.sp @@ -26,19 +26,14 @@ #undef REQUIRE_PLUGIN #include #include -#include +#include #define REQUIRE_PLUGIN #include #include #define BACKPACKTF_URL "https://backpack.tf/api/IGetUsers/v3" - -enum LogLevel { - Log_Error = 0, - Log_Info, - Log_Debug -} +#define STEAMREP_URL "http://steamrep.com/id2rep.php" enum TagType { TagType_None = 0, @@ -52,7 +47,7 @@ public Plugin myinfo = { name = "[NGS] Trade Protect", author = "Dr. McKay / TheXeon", description = "Checks a user's Rep/Trade status upon connection. Plugin based on steamrep checker redux.", - version = "1.0.2", + version = "1.0.3", url = "https://www.neogenesisnetwork.net" } @@ -67,7 +62,7 @@ ConVar cvarExcludedTags; ConVar cvarEnableExclusion; ConVar cvarTagChangeDealMethod; ConVar cvarSpawnMessage; -ConVar cvarLogLevel; +ConVar cvarSendSteamRepIP; TagType clientTag[MAXPLAYERS + 1]; bool messageDisplayed[MAXPLAYERS + 1]; @@ -77,6 +72,7 @@ public void OnPluginStart() { AutoExecConfig_SetCreateFile(true); bool appended; + Timber.plantToFile(appended); cvarDealMethod = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_deal_method", "5", "How to deal with reported scammers.\n0 = Disabled\n1 = Prefix chat with [SCAMMER] tag and warn users in chat (requires Custom Chat Colors)\n2 = Kick\n3 = Ban Steam ID\n4 = Ban IP\n5 = Ban Steam ID + IP", _, true, 0.0, true, 5.0); cvarSteamIDBanLength = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_steamid_ban_length", "0", "Duration in minutes to ban Steam IDs for if trade_protect_deal_method = 3 or 5 (0 = permanent)", _, true, 0.0); cvarIPBanLength = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_ip_ban_length", "0", "Duration in minutes to ban IP addresses for if trade_protect_deal_method = 4 or 5 (0 = permanent)"); @@ -88,7 +84,7 @@ public void OnPluginStart() { cvarEnableExclusion = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_exclusion", "1", "Allow exclusion via SkipSR override?", _, true, 0.0, true, 1.0); cvarExcludedTags = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_untrusted_tags", "", "Input the tags of any community whose bans you do not trust here."); cvarSpawnMessage = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_spawn_message", "1", "Display messages upon first spawn that this server is protected by SteamRep?", _, true, 0.0, true, 1.0); - cvarLogLevel = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_log_level", "1", "Level of logging\n0 = Errors only\n1 = Info + errors\n2 = Info, errors, and debug", _, true, 0.0, true, 2.0); + cvarSendSteamRepIP = AutoExecConfig_CreateConVarCheckAppend(appended, "trade_protect_send_sr_ip", "1", "Send connecting client's IP to SteamRep?", _, true, 0.0, true, 1.0); AutoExecConfig_ExecAndClean(appended); HookEvent("player_spawn", Event_PlayerSpawn); @@ -114,19 +110,30 @@ public void OnClientPostAdminCheck(int client) char auth[32]; if (GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth))) { - char excludedTags[64]; - cvarExcludedTags.GetString(excludedTags, sizeof(excludedTags)); - SWHTTPRequest request = new SWHTTPRequest(k_EHTTPMethodGET, BACKPACKTF_URL); - request.SetParam("steamid", auth); - request.SetContextValue(GetClientUserId(client)); - request.SetHeaderValue("Accept", "application/json"); - request.SetCallbacks(OnBackpackTFChecked); - request.Send(); - LogItem(Log_Debug, "Sending HTTP request for %L", client); + SWHTTPRequest bpRequest = new SWHTTPRequest(k_EHTTPMethodGET, BACKPACKTF_URL); + bpRequest.SetParam("steamid", auth); + bpRequest.SetContextValue(GetClientUserId(client)); + bpRequest.SetHeaderValue("Accept", "application/json"); + bpRequest.SetCallbacks(OnBackpackTFChecked); + bpRequest.Send(); + Timber.d("Sending backpack.tf HTTP request for %L", client); + + if (cvarSendSteamRepIP.BoolValue) + { + char clientIP[32], excludedTags[128]; + cvarExcludedTags.GetString(excludedTags, sizeof(excludedTags)); + GetClientIP(client, clientIP, sizeof(clientIP)); + SWHTTPRequest srRequest = new SWHTTPRequest(k_EHTTPMethodGET, STEAMREP_URL); + srRequest.SetParam("steamID32", auth); + srRequest.SetParam("IP", clientIP); + srRequest.SetCallbacks(OnSRRequestComplete); + srRequest.Send(); + Timber.d("Sending SteamRep HTTP request for %L", client); + } } else { - LogItem(Log_Error, "Could not get SteamID2 for client %L!", client); + Timber.e("Could not get SteamID2 for client %L!", client); } } @@ -170,12 +177,12 @@ void PerformKicks() { public void OnBackpackTFChecked(SWHTTPRequest request, bool bFailure, bool successful, EHTTPStatusCode code, any userid) { int client = GetClientOfUserId(userid); if (client == 0) { - LogItem(Log_Debug, "Client with User ID %d left.", userid); + Timber.d("Client with User ID %d left.", userid); delete request; return; } if (!successful || code != k_EHTTPStatusCode200OK) { - LogItem(Log_Error, "Error checking SteamRep for client %L. Status code: %d, Successful: %s", client, view_as(code), successful ? "true" : "false"); + Timber.e("Error checking BackpackTF for client %L. Status code: %d, Successful: %s", client, view_as(code), successful ? "true" : "false"); delete request; return; } @@ -185,10 +192,10 @@ public void OnBackpackTFChecked(SWHTTPRequest request, bool bFailure, bool succe JSON_Object obj = new JSON_Object(); obj.Decode(data); - LogItem(Log_Debug, "Received response for %L: \'%s\'", client, data); + Timber.d("Received response for %L: \'%s\'", client, data); JSON_Object response = obj.GetObject("response"); - if (response.GetInt("status") != 1) { - LogItem(Log_Debug, "Status for %L is not 1, returning!", client); + if (!response.HasKey("success") || response.GetInt("success") != 1) { + Timber.d("Success for %L is not 1, returning!", client); } else { char auth[24]; if (GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth))) { @@ -211,15 +218,22 @@ public void OnBackpackTFChecked(SWHTTPRequest request, bool bFailure, bool succe delete obj; } +public void OnSRRequestComplete(SWHTTPRequest request, bool bFailure, bool successful, EHTTPStatusCode code) { + if (!successful || code != k_EHTTPStatusCode200OK) { + Timber.e("Error sending SteamRep client's IP. Status code: %d, Successful: %b", view_as(code), successful); + } + delete request; +} + void HandleScammer(int client, const char[] auth) { char clientAuth[32]; if (!GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth))) { - LogItem(Log_Error, "Error handling potential scammer. (Unverified) Auth is %s.", auth); + Timber.e("Error handling potential scammer. (Unverified) Auth is %s.", auth); return; } if(!StrEqual(auth, clientAuth)) { - LogItem(Log_Error, "Steam ID for %L (%s) didn't match SteamRep's response (%s)", client, clientAuth, auth); + Timber.e("Steam ID for %L (%s) didn't match SteamRep's response (%s)", client, clientAuth, auth); return; } switch(cvarDealMethod.IntValue) { @@ -229,30 +243,30 @@ void HandleScammer(int client, const char[] auth) { case 1: { // Chat tag if(!LibraryExists("scp")) { - LogItem(Log_Info, "Simple Chat Processor (Redux) is not loaded, so tags will not be colored in chat.", client); + Timber.i("Simple Chat Processor (Redux) is not loaded, so tags will not be colored in chat.", client); return; } - LogItem(Log_Info, "Tagged %L as a scammer", client); + Timber.i("Tagged %L as a scammer", client); SetClientTag(client, TagType_Scammer); } case 2: { // Kick - LogItem(Log_Info, "Kicked %L as a scammer", client); + Timber.i("Kicked %L as a scammer", client); KickClient(client, "You are a reported scammer. Visit http://www.steamrep.com for more information"); } case 3: { // Ban Steam ID - LogItem(Log_Info, "Banned %L by Steam ID as a scammer", client); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, "Player is a reported scammer via SteamRep.com"); + Timber.i("Banned %L by Steam ID as a scammer", client); + if(GetFeatureStatus(FeatureType_Native, "SBPP_BanPlayer") == FeatureStatus_Available) { + SBPP_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, "Player is a reported scammer via SteamRep.com"); } else { BanClient(client, cvarSteamIDBanLength.IntValue, BANFLAG_AUTHID, "Player is a reported scammer via SteamRep.com", "You are a reported scammer. Visit http://www.steamrep.com for more information", "ngs_tradeprotect"); } } case 4: { // Ban IP - LogItem(Log_Info, "Banned %L by IP as a scammer", client); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { + Timber.i("Banned %L by IP as a scammer", client); + if(GetFeatureStatus(FeatureType_Native, "SBPP_BanPlayer") == FeatureStatus_Available) { // SourceBans doesn't currently expose a native to ban an IP! char ip[64]; GetClientIP(client, ip, sizeof(ip)); @@ -265,11 +279,11 @@ void HandleScammer(int client, const char[] auth) { } case 5: { // Ban Steam ID + IP - LogItem(Log_Info, "Banned %L by Steam ID and IP as a scammer", client); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { + Timber.i("Banned %L by Steam ID and IP as a scammer", client); + if(GetFeatureStatus(FeatureType_Native, "SBPP_BanPlayer") == FeatureStatus_Available) { char ip[64]; GetClientIP(client, ip, sizeof(ip)); - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, "Player is a reported scammer via SteamRep.com"); + SBPP_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, "Player is a reported scammer via SteamRep.com"); ServerCommand("sm_banip \"%s\" %d A scammer has connected from this IP. Steam ID: %s", ip, cvarIPBanLength.IntValue, clientAuth); } else { BanClient(client, cvarSteamIDBanLength.IntValue, BANFLAG_AUTHID, "Player is a reported scammer via SteamRep.com", "You are a reported scammer. Visit http://www.steamrep.com for more information", "ngs_tradeprotect"); @@ -310,24 +324,24 @@ void HandleBackpackTFPlayer(int client, const char[] clientAuth, TagType playerT case 1: { // Chat tag if(!LibraryExists("scp")) { - LogItem(Log_Info, "Simple Chat Processor (Redux) is not loaded, so tags will not be colored in chat.", client); + Timber.i("Simple Chat Processor (Redux) is not loaded, so tags will not be colored in chat.", client); return; } - LogItem(Log_Info, "Tagged %L as %s", client, playerStatus); + Timber.i("Tagged %L as %s", client, playerStatus); SetClientTag(client, playerTag); } case 2: { // Kick - LogItem(Log_Info, "Kicked %L as %s", client, playerStatus); + Timber.i("Kicked %L as %s", client, playerStatus); KickClient(client, "You are %s", playerStatus); } case 3: { // Ban Steam ID - LogItem(Log_Info, "Banned %L by Steam ID as %s", client, playerStatus); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { + Timber.i("Banned %L by Steam ID as %s", client, playerStatus); + if(GetFeatureStatus(FeatureType_Native, "SBPP_BanPlayer") == FeatureStatus_Available) { char message[256]; Format(message, sizeof(message), "Player is %s", playerStatus); - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, message); + SBPP_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, message); } else { char message[256], kickMessage[256]; Format(message, sizeof(message), "Player is %s", playerStatus); @@ -337,8 +351,8 @@ void HandleBackpackTFPlayer(int client, const char[] clientAuth, TagType playerT } case 4: { // Ban IP - LogItem(Log_Info, "Banned %L by IP as %s", client, playerStatus); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { + Timber.i("Banned %L by IP as %s", client, playerStatus); + if(GetFeatureStatus(FeatureType_Native, "SBPP_BanPlayer") == FeatureStatus_Available) { // SourceBans doesn't currently expose a native to ban an IP! ServerCommand("sm_banip #%d %d A %s has connected from this IP. Steam ID: %s", playerStatus, GetClientUserId(client), cvarIPBanLength.IntValue, clientAuth); } else { @@ -350,11 +364,11 @@ void HandleBackpackTFPlayer(int client, const char[] clientAuth, TagType playerT } case 5: { // Ban Steam ID + IP - LogItem(Log_Info, "Banned %L by Steam ID and IP as %s", client, playerStatus); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { + Timber.i("Banned %L by Steam ID and IP as %s", client, playerStatus); + if(GetFeatureStatus(FeatureType_Native, "SBPP_BanPlayer") == FeatureStatus_Available) { char message[256]; Format(message, sizeof(message), "Player is %s", playerStatus); - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, message); + SBPP_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, message); ServerCommand("sm_banip #%d %d A %s has connected from this IP. Steam ID: %s", playerWithStatus, GetClientUserId(client), cvarIPBanLength.IntValue, clientAuth); } else { char message[256], kickMessage[256]; @@ -473,7 +487,7 @@ public Action Command_Rep(int client, int args) { } else { char arg1[MAX_NAME_LENGTH]; GetCmdArg(1, arg1, sizeof(arg1)); - target = FindTargetEx(client, arg1, true, false, false); + target = FindTarget(client, arg1, true, false); if(target == -1) { DisplayClientMenu(client); return Plugin_Handled; @@ -510,7 +524,7 @@ public Action Command_SteamRep(int client, int args) { } else { char arg1[MAX_NAME_LENGTH]; GetCmdArg(1, arg1, sizeof(arg1)); - target = FindTargetEx(client, arg1, true, false, false); + target = FindTarget(client, arg1, true, false); if(target == -1) { DisplayClientMenu(client, true); return Plugin_Handled; @@ -583,49 +597,3 @@ public int Handler_RepClientMenu(Menu menu, MenuAction action, int client, int p FakeClientCommand(client, "sm_rep #%s", selection); } } - -int FindTargetEx(int client, const char[] target, bool nobots = false, bool immunity = true, bool replyToError = true) { - char target_name[MAX_TARGET_LENGTH]; - int target_list[1], target_count; - bool tn_is_ml; - - int flags = COMMAND_FILTER_NO_MULTI; - if(nobots) { - flags |= COMMAND_FILTER_NO_BOTS; - } - if(!immunity) { - flags |= COMMAND_FILTER_NO_IMMUNITY; - } - - if((target_count = ProcessTargetString( - target, - client, - target_list, - 1, - flags, - target_name, - sizeof(target_name), - tn_is_ml)) > 0) - { - return target_list[0]; - } else { - if(replyToError) { - ReplyToTargetError(client, target_count); - } - return -1; - } -} - -void LogItem(LogLevel level, const char[] format, any ...) -{ - int logLevel = cvarLogLevel.IntValue; - if(logLevel < view_as(level)) - { - return; - } - char logPrefixes[][] = {"[ERROR]", "[INFO]", "[DEBUG]"}; - char buffer[512], file[PLATFORM_MAX_PATH]; - VFormat(buffer, sizeof(buffer), format, 3); - BuildPath(Path_SM, file, sizeof(file), "logs/ngs_tradeprotect.log"); - LogToFileEx(file, "%s %s", logPrefixes[view_as(level)], buffer); -} diff --git a/updater/ngs_tradeprotect.txt b/updater/ngs_tradeprotect.txt index 11fecd2..0c6a71e 100644 --- a/updater/ngs_tradeprotect.txt +++ b/updater/ngs_tradeprotect.txt @@ -4,12 +4,12 @@ { "Version" { - "Latest" "1.0.2" + "Latest" "1.0.3" } - "Notes" "Add updater support!" - "Notes" "Fixed stack size not compensating enough!" - "Notes" "Fixed deleting an already-deleted *invalid* handle!" + "Notes" "Added trade_protect_send_sr_ip to configure sending SteamRep client's IPs!" + "Notes" "Fixed backpack.tf request to actually handle scammers!" + "Notes" "Changed logging to use Timber include. We can now set it to log to a file or not." } "Files" From ed459afc4465ccf947a4deba5d8986794dc85c5c Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:07:04 -0800 Subject: [PATCH 03/29] Remove steamrep in favor of trade protect --- scripting/include/admin.inc | 775 ++++++++++++ scripting/include/adminmenu.inc | 152 +++ scripting/include/adt.inc | 40 + scripting/include/adt_array.inc | 455 +++++++ scripting/include/adt_stack.inc | 240 ++++ scripting/include/adt_trie.inc | 317 +++++ scripting/include/banning.inc | 156 +++ scripting/include/basecomm.inc | 109 ++ scripting/include/bitbuffer.inc | 470 +++++++ scripting/include/clientprefs.inc | 282 +++++ scripting/include/clients.inc | 811 ++++++++++++ scripting/include/commandfilters.inc | 161 +++ scripting/include/commandline.inc | 86 ++ scripting/include/console.inc | 668 ++++++++++ scripting/include/convars.inc | 498 ++++++++ scripting/include/core.inc | 317 +++++ scripting/include/cstrike.inc | 458 +++++++ scripting/include/customkeyvalues.inc | 26 + scripting/include/datapack.inc | 225 ++++ scripting/include/datetime.inc | 274 ++++ scripting/include/dbi.inc | 1066 ++++++++++++++++ scripting/include/entity.inc | 759 +++++++++++ scripting/include/entity_prop_stocks.inc | 594 +++++++++ scripting/include/events.inc | 340 +++++ scripting/include/files.inc | 618 +++++++++ scripting/include/float.inc | 436 +++++++ scripting/include/functions.inc | 541 ++++++++ scripting/include/geoip.inc | 102 ++ scripting/include/halflife.inc | 706 +++++++++++ scripting/include/handles.inc | 97 ++ scripting/include/hashes.inc | 0 scripting/include/helpers.inc | 279 ++++ scripting/include/keyvalues.inc | 707 +++++++++++ scripting/include/lang.inc | 134 ++ scripting/include/logging.inc | 135 ++ scripting/include/mapchooser.inc | 159 +++ scripting/include/menus.inc | 1121 +++++++++++++++++ scripting/include/nextmap.inc | 82 ++ scripting/include/ngs_votes.inc | 43 + scripting/include/profiler.inc | 97 ++ scripting/include/protobuf.inc | 572 +++++++++ scripting/include/regex.inc | 275 ++++ scripting/include/sdkhooks.inc | 412 ++++++ scripting/include/sdktools.inc | 229 ++++ scripting/include/sdktools_client.inc | 50 + scripting/include/sdktools_engine.inc | 66 + scripting/include/sdktools_entinput.inc | 51 + scripting/include/sdktools_entoutput.inc | 108 ++ scripting/include/sdktools_functions.inc | 352 ++++++ scripting/include/sdktools_gamerules.inc | 197 +++ scripting/include/sdktools_hooks.inc | 96 ++ scripting/include/sdktools_sound.inc | 725 +++++++++++ scripting/include/sdktools_stocks.inc | 75 ++ scripting/include/sdktools_stringtables.inc | 180 +++ scripting/include/sdktools_tempents.inc | 232 ++++ .../include/sdktools_tempents_stocks.inc | 443 +++++++ scripting/include/sdktools_trace.inc | 368 ++++++ scripting/include/sdktools_variant_t.inc | 93 ++ scripting/include/sdktools_voice.inc | 122 ++ scripting/include/sorting.inc | 169 +++ scripting/include/sourcebanspp.inc | 106 ++ scripting/include/sourcemod.inc | 681 ++++++++++ scripting/include/store/store-stocks.inc | 142 +++ scripting/include/string.inc | 548 ++++++++ scripting/include/testing.inc | 72 ++ scripting/include/textparse.inc | 243 ++++ scripting/include/tf2.inc | 493 ++++++++ scripting/include/tf2_stocks.inc | 637 ++++++++++ scripting/include/timber.inc | 124 ++ scripting/include/timers.inc | 209 +++ scripting/include/topmenus.inc | 434 +++++++ scripting/include/usermessages.inc | 257 ++++ scripting/include/vector.inc | 179 +++ scripting/include/version.inc | 49 + scripting/include/version_auto.inc | 15 + scripting/include/vgui_motd_stocks.inc | 87 ++ scripting/include/websocket.inc | 182 +++ scripting/ngs_steamrepchecker.sp | 561 --------- 78 files changed, 23809 insertions(+), 561 deletions(-) create mode 100644 scripting/include/admin.inc create mode 100644 scripting/include/adminmenu.inc create mode 100644 scripting/include/adt.inc create mode 100644 scripting/include/adt_array.inc create mode 100644 scripting/include/adt_stack.inc create mode 100644 scripting/include/adt_trie.inc create mode 100644 scripting/include/banning.inc create mode 100644 scripting/include/basecomm.inc create mode 100644 scripting/include/bitbuffer.inc create mode 100644 scripting/include/clientprefs.inc create mode 100644 scripting/include/clients.inc create mode 100644 scripting/include/commandfilters.inc create mode 100644 scripting/include/commandline.inc create mode 100644 scripting/include/console.inc create mode 100644 scripting/include/convars.inc create mode 100644 scripting/include/core.inc create mode 100644 scripting/include/cstrike.inc create mode 100644 scripting/include/customkeyvalues.inc create mode 100644 scripting/include/datapack.inc create mode 100644 scripting/include/datetime.inc create mode 100644 scripting/include/dbi.inc create mode 100644 scripting/include/entity.inc create mode 100644 scripting/include/entity_prop_stocks.inc create mode 100644 scripting/include/events.inc create mode 100644 scripting/include/files.inc create mode 100644 scripting/include/float.inc create mode 100644 scripting/include/functions.inc create mode 100644 scripting/include/geoip.inc create mode 100644 scripting/include/halflife.inc create mode 100644 scripting/include/handles.inc create mode 100644 scripting/include/hashes.inc create mode 100644 scripting/include/helpers.inc create mode 100644 scripting/include/keyvalues.inc create mode 100644 scripting/include/lang.inc create mode 100644 scripting/include/logging.inc create mode 100644 scripting/include/mapchooser.inc create mode 100644 scripting/include/menus.inc create mode 100644 scripting/include/nextmap.inc create mode 100644 scripting/include/ngs_votes.inc create mode 100644 scripting/include/profiler.inc create mode 100644 scripting/include/protobuf.inc create mode 100644 scripting/include/regex.inc create mode 100644 scripting/include/sdkhooks.inc create mode 100644 scripting/include/sdktools.inc create mode 100644 scripting/include/sdktools_client.inc create mode 100644 scripting/include/sdktools_engine.inc create mode 100644 scripting/include/sdktools_entinput.inc create mode 100644 scripting/include/sdktools_entoutput.inc create mode 100644 scripting/include/sdktools_functions.inc create mode 100644 scripting/include/sdktools_gamerules.inc create mode 100644 scripting/include/sdktools_hooks.inc create mode 100644 scripting/include/sdktools_sound.inc create mode 100644 scripting/include/sdktools_stocks.inc create mode 100644 scripting/include/sdktools_stringtables.inc create mode 100644 scripting/include/sdktools_tempents.inc create mode 100644 scripting/include/sdktools_tempents_stocks.inc create mode 100644 scripting/include/sdktools_trace.inc create mode 100644 scripting/include/sdktools_variant_t.inc create mode 100644 scripting/include/sdktools_voice.inc create mode 100644 scripting/include/sorting.inc create mode 100644 scripting/include/sourcebanspp.inc create mode 100644 scripting/include/sourcemod.inc create mode 100644 scripting/include/store/store-stocks.inc create mode 100644 scripting/include/string.inc create mode 100644 scripting/include/testing.inc create mode 100644 scripting/include/textparse.inc create mode 100644 scripting/include/tf2.inc create mode 100644 scripting/include/tf2_stocks.inc create mode 100644 scripting/include/timber.inc create mode 100644 scripting/include/timers.inc create mode 100644 scripting/include/topmenus.inc create mode 100644 scripting/include/usermessages.inc create mode 100644 scripting/include/vector.inc create mode 100644 scripting/include/version.inc create mode 100644 scripting/include/version_auto.inc create mode 100644 scripting/include/vgui_motd_stocks.inc create mode 100644 scripting/include/websocket.inc delete mode 100644 scripting/ngs_steamrepchecker.sp diff --git a/scripting/include/admin.inc b/scripting/include/admin.inc new file mode 100644 index 0000000..17d2c99 --- /dev/null +++ b/scripting/include/admin.inc @@ -0,0 +1,775 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _admin_included + #endinput +#endif +#define _admin_included + +/** + * Access levels (flags) for admins. + */ +enum AdminFlag +{ + Admin_Reservation = 0, /**< Reserved slot */ + Admin_Generic, /**< Generic admin abilities */ + Admin_Kick, /**< Kick another user */ + Admin_Ban, /**< Ban another user */ + Admin_Unban, /**< Unban another user */ + Admin_Slay, /**< Slay/kill/damage another user */ + Admin_Changemap, /**< Change the map */ + Admin_Convars, /**< Change basic convars */ + Admin_Config, /**< Change configuration */ + Admin_Chat, /**< Special chat privileges */ + Admin_Vote, /**< Special vote privileges */ + Admin_Password, /**< Set a server password */ + Admin_RCON, /**< Use RCON */ + Admin_Cheats, /**< Change sv_cheats and use its commands */ + Admin_Root, /**< All access by default */ + Admin_Custom1, /**< First custom flag type */ + Admin_Custom2, /**< Second custom flag type */ + Admin_Custom3, /**< Third custom flag type */ + Admin_Custom4, /**< Fourth custom flag type */ + Admin_Custom5, /**< Fifth custom flag type */ + Admin_Custom6, /**< Sixth custom flag type */ + /* --- */ +}; + +#define AdminFlags_TOTAL 21 /**< Total number of admin flags */ + +/** + * @section Bitwise values definitions for admin flags. + */ +#define ADMFLAG_RESERVATION (1<<0) /**< Convenience macro for Admin_Reservation as a FlagBit */ +#define ADMFLAG_GENERIC (1<<1) /**< Convenience macro for Admin_Generic as a FlagBit */ +#define ADMFLAG_KICK (1<<2) /**< Convenience macro for Admin_Kick as a FlagBit */ +#define ADMFLAG_BAN (1<<3) /**< Convenience macro for Admin_Ban as a FlagBit */ +#define ADMFLAG_UNBAN (1<<4) /**< Convenience macro for Admin_Unban as a FlagBit */ +#define ADMFLAG_SLAY (1<<5) /**< Convenience macro for Admin_Slay as a FlagBit */ +#define ADMFLAG_CHANGEMAP (1<<6) /**< Convenience macro for Admin_Changemap as a FlagBit */ +#define ADMFLAG_CONVARS (1<<7) /**< Convenience macro for Admin_Convars as a FlagBit */ +#define ADMFLAG_CONFIG (1<<8) /**< Convenience macro for Admin_Config as a FlagBit */ +#define ADMFLAG_CHAT (1<<9) /**< Convenience macro for Admin_Chat as a FlagBit */ +#define ADMFLAG_VOTE (1<<10) /**< Convenience macro for Admin_Vote as a FlagBit */ +#define ADMFLAG_PASSWORD (1<<11) /**< Convenience macro for Admin_Password as a FlagBit */ +#define ADMFLAG_RCON (1<<12) /**< Convenience macro for Admin_RCON as a FlagBit */ +#define ADMFLAG_CHEATS (1<<13) /**< Convenience macro for Admin_Cheats as a FlagBit */ +#define ADMFLAG_ROOT (1<<14) /**< Convenience macro for Admin_Root as a FlagBit */ +#define ADMFLAG_CUSTOM1 (1<<15) /**< Convenience macro for Admin_Custom1 as a FlagBit */ +#define ADMFLAG_CUSTOM2 (1<<16) /**< Convenience macro for Admin_Custom2 as a FlagBit */ +#define ADMFLAG_CUSTOM3 (1<<17) /**< Convenience macro for Admin_Custom3 as a FlagBit */ +#define ADMFLAG_CUSTOM4 (1<<18) /**< Convenience macro for Admin_Custom4 as a FlagBit */ +#define ADMFLAG_CUSTOM5 (1<<19) /**< Convenience macro for Admin_Custom5 as a FlagBit */ +#define ADMFLAG_CUSTOM6 (1<<20) /**< Convenience macro for Admin_Custom6 as a FlagBit */ + +/** + * @endsection + */ + +/** + * @section Hardcoded authentication methods + */ +#define AUTHMETHOD_STEAM "steam" /**< SteamID based authentication */ +#define AUTHMETHOD_IP "ip" /**< IP based authentication */ +#define AUTHMETHOD_NAME "name" /**< Name based authentication */ + +/** + * @endsection + */ + +/** + * Access override types. + */ +enum OverrideType +{ + Override_Command = 1, /**< Command */ + Override_CommandGroup, /**< Command group */ +}; + +/** + * Access override rules. + */ +enum OverrideRule +{ + Command_Deny = 0, + Command_Allow = 1, +}; + +/** + * DEPRECATED, do not use. + */ +enum ImmunityType +{ + Immunity_Default = 1, /**< Deprecated. */ + Immunity_Global, /**< Deprecated. */ +}; + +/** + * Identifies a unique entry in the group permissions cache. These are not Handles. + */ +enum GroupId +{ + INVALID_GROUP_ID = -1, /**< An invalid/non-existent group */ +}; + +/** + * Identifies a unique entry in the admin permissions cache. These are not Handles. + */ +enum AdminId +{ + INVALID_ADMIN_ID = -1, /**< An invalid/non-existent admin */ +}; + +/** + * Methods of computing access permissions. + */ +enum AdmAccessMode +{ + Access_Real, /**< Access the user has inherently */ + Access_Effective, /**< Access the user has from their groups */ +}; + +/** + * Represents the various cache regions. + */ +enum AdminCachePart +{ + AdminCache_Overrides = 0, /**< Global overrides */ + AdminCache_Groups = 1, /**< All groups (automatically invalidates admins too) */ + AdminCache_Admins = 2, /**< All admins */ +}; + +methodmap AdminId { + // Retrieves an admin's user name as made with CreateAdmin(). + // + // @note This function can return UTF-8 strings, and will safely chop UTF-8 strings. + // + // @param name String buffer to store name. + // @param maxlength Maximum size of string buffer. + // @return Number of bytes written. + public native void GetUsername(char[] name, int maxlength); + + // Binds an admin to an identity for fast lookup later on. The bind must be unique. + // + // @param authMethod Auth method to use, predefined or from RegisterAuthIdentType(). + // @param ident String containing the arbitrary, unique identity. + // @return True on success, false if the auth method was not found, + // ident was already taken, or ident invalid for auth method. + public native bool BindIdentity(const char[] authMethod, const char[] ident); + + // Sets whether or not a flag is enabled on an admin. + // + // @param flag Admin flag to use. + // @param enabled True to enable, false to disable. + public native void SetFlag(AdminFlag flag, bool enabled); + + // Returns whether or not a flag is enabled on an admin. + // + // @param flag Admin flag to use. + // @param mode Access mode to check. + // @return True if enabled, false otherwise. + public native bool HasFlag(AdminFlag flag, AdmAccessMode mode=Access_Effective); + + // Returns the bitstring of access flags on an admin. + // + // @param mode Access mode to use. + // @return A bitstring containing which flags are enabled. + public native int GetFlags(AdmAccessMode mode); + + // Adds a group to an admin's inherited group list. Any flags the group has + // will be added to the admin's effective flags. + // + // @param gid GroupId index of the group. + // @return True on success, false on invalid input or duplicate membership. + public native bool InheritGroup(GroupId gid); + + // Returns group information from an admin. + // + // @param index Group number to retrieve, from 0 to N-1, where N + // is the value of the GroupCount property. + // @param name Buffer to store the group's name. + // Note: This will safely chop UTF-8 strings. + // @param maxlength Maximum size of the output name buffer. + // @return A GroupId index and a name pointer, or + // INVALID_GROUP_ID and NULL if an error occurred. + public native GroupId GetGroup(int index, const char[] name, int maxlength); + + // Sets a password on an admin. + // + // @param password String containing the password. + public native void SetPassword(const char[] password); + + // Gets an admin's password. + // + // @param buffer Optional buffer to store the admin's password. + // @param maxlength Maximum size of the output name buffer. + // Note: This will safely chop UTF-8 strings. + // @return True if there was a password set, false otherwise. + public native bool GetPassword(char[] buffer="", int maxlength=0); + + // Tests whether one admin can target another. + // + // The heuristics for this check are as follows: + // 0. If the targeting AdminId is INVALID_ADMIN_ID, targeting fails. + // 1. If the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds. + // 2. If the targeted AdminId is the same as the targeting AdminId, + // (self) targeting succeeds. + // 3. If the targeting admin is root, targeting succeeds. + // 4. If the targeted admin has access higher (as interpreted by + // (sm_immunity_mode) than the targeting admin, then targeting fails. + // 5. If the targeted admin has specific immunity from the + // targeting admin via group immunities, targeting fails. + // 6. Targeting succeeds. + // + // @param target Target admin (may be INVALID_ADMIN_ID). + // @return True if targetable, false if immune. + public native bool CanTarget(AdminId other); + + // The number of groups of which this admin is a member. + property int GroupCount { + public native get(); + } + + // Immunity level used for targetting. + property int ImmunityLevel { + public native get(); + public native set(int level); + } +} + +methodmap GroupId { + // Gets whether or not a flag is enabled on a group's flag set. + // + // @param flag Admin flag to retrieve. + // @return True if enabled, false otherwise, + public native bool HasFlag(AdminFlag flag); + + // Adds or removes a flag from a group's flag set. + // + // @param flag Admin flag to toggle. + // @param enabled True to set the flag, false to unset/disable. + public native void SetFlag(AdminFlag flag, bool enabled); + + // Returns the flag set that is added to users from this group. + // + // @return Bitstring containing the flags enabled. + public native int GetFlags(); + + // Returns a group that this group is immune to given an index. + // + // @param number Index from 0 to N-1, from GroupImmunitiesCount. + // @return GroupId that this group is immune to, or INVALID_GROUP_ID on failure. + public native GroupId GetGroupImmunity(int index); + + // Adds immunity to a specific group. + // + // @param other Group id to receive immunity to. + public native void AddGroupImmunity(GroupId other); + + // Retrieves a group-specific command override. + // + // @param name String containing command name (case sensitive). + // @param type Override type (specific command or group). + // @param rule Optional pointer to store allow/deny setting. + // @return True if an override exists, false otherwise. + public native bool GetCommandOverride(const char[] name, OverrideType type, OverrideRule &rule); + + // Adds a group-specific override type. + // + // @param name String containing command name (case sensitive). + // @param type Override type (specific command or group). + // @param rule Override allow/deny setting. + public native void AddCommandOverride(const char[] name, OverrideType type, OverrideRule rule); + + // Number of specific group immunities + property int GroupImmunitiesCount { + public native get(); + } + + // Immunity level used for targetting. + property int ImmunityLevel { + public native get(); + public native set(int level); + } +} + +/** + * Called when part of the cache needs to be rebuilt. + * + * @param part Part of the admin cache to rebuild. + */ +forward void OnRebuildAdminCache(AdminCachePart part); + +/** + * Tells the admin system to dump a portion of the cache. + * + * @param part Part of the cache to dump. Specifying groups also dumps admins. + * @param rebuild If true, the rebuild forwards will fire. + */ +native void DumpAdminCache(AdminCachePart part, bool rebuild); + +/** + * Adds a global command flag override. Any command registered with this name + * will assume the new flag. This is applied retroactively as well. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param flags New admin flag. + */ +native void AddCommandOverride(const char[] cmd, OverrideType type, int flags); + +/** + * Returns a command override. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param flags By-reference cell to store the flag (undefined if not found). + * @return True if there is an override, false otherwise. + */ +native bool GetCommandOverride(const char[] cmd, OverrideType type, int &flags); + +/** + * Unsets a command override. + * + * @param cmd String containing command name (case sensitive). + * @param type Override type (specific command or group). + */ +native void UnsetCommandOverride(const char[] cmd, OverrideType type); + +/** + * Adds a new group. Name must be unique. + * + * @param group_name String containing the group name. + * @return A new group id, INVALID_GROUP_ID if it already exists. + */ +native GroupId CreateAdmGroup(const char[] group_name); + +/** + * Finds a group by name. + * + * @param group_name String containing the group name. + * @return A group id, or INVALID_GROUP_ID if not found. + */ +native GroupId FindAdmGroup(const char[] group_name); + +/** + * Adds or removes a flag from a group's flag set. + * @note These are called "add flags" because they add to a user's flags. + * + * @param id Group id. + * @param flag Admin flag to toggle. + * @param enabled True to set the flag, false to unset/disable. + */ +native void SetAdmGroupAddFlag(GroupId id, AdminFlag flag, bool enabled); + +/** + * Gets the set value of an add flag on a group's flag set. + * @note These are called "add flags" because they add to a user's flags. + * + * @param id Group id. + * @param flag Admin flag to retrieve. + * @return True if enabled, false otherwise, + */ +native bool GetAdmGroupAddFlag(GroupId id, AdminFlag flag); + +/** + * Returns the flag set that is added to a user from their group. + * @note These are called "add flags" because they add to a user's flags. + * + * @param id GroupId of the group. + * @return Bitstring containing the flags enabled. + */ +native int GetAdmGroupAddFlags(GroupId id); + +/** + * @deprecated Functionality removed. + */ +#pragma deprecated Use SetAdmGroupImmunityLevel() instead. +native void SetAdmGroupImmunity(GroupId id, ImmunityType type, bool enabled); + +/** + * @deprecated Functionality removed. + */ +#pragma deprecated Use GetAdmGroupImmunityLevel() instead. +native bool GetAdmGroupImmunity(GroupId id, ImmunityType type); + +/** + * Adds immunity to a specific group. + * + * @param id Group id. + * @param other_id Group id to receive immunity to. + */ +native void SetAdmGroupImmuneFrom(GroupId id, GroupId other_id); + +/** + * Returns the number of specific group immunities. + * + * @param id Group id. + * @return Number of group immunities. + */ +native int GetAdmGroupImmuneCount(GroupId id); + +/** + * Returns a group that this group is immune to given an index. + * + * @param id Group id. + * @param number Index from 0 to N-1, from GetAdmGroupImmuneCount(). + * @return GroupId that this group is immune to, or INVALID_GROUP_ID on failure. + */ +native GroupId GetAdmGroupImmuneFrom(GroupId id, int number); + +/** + * Adds a group-specific override type. + * + * @param id Group id. + * @param name String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param rule Override allow/deny setting. + */ +native void AddAdmGroupCmdOverride(GroupId id, const char[] name, OverrideType type, OverrideRule rule); + +/** + * Retrieves a group-specific command override. + * + * @param id Group id. + * @param name String containing command name (case sensitive). + * @param type Override type (specific command or group). + * @param rule Optional pointer to store allow/deny setting. + * @return True if an override exists, false otherwise. + */ +native bool GetAdmGroupCmdOverride(GroupId id, const char[] name, OverrideType type, OverrideRule &rule); + +/** + * Registers an authentication identity type. You normally never need to call this except for + * very specific systems. + * + * @param name Codename to use for your authentication type. + */ +native void RegisterAuthIdentType(const char[] name); + +/** + * Creates a new admin entry in the permissions cache. + * + * @param name Name for this entry (does not have to be unique). + * Specify an empty string for an anonymous admin. + */ +native AdminId CreateAdmin(const char[] name=""); + +/** + * Retrieves an admin's user name as made with CreateAdmin(). + * + * @note This function can return UTF-8 strings, and will safely chop UTF-8 strings. + * + * @param id AdminId of the admin. + * @param name String buffer to store name. + * @param maxlength Maximum size of string buffer. + * @return Number of bytes written. + */ +native int GetAdminUsername(AdminId id, char[] name, int maxlength); + +/** + * Binds an admin to an identity for fast lookup later on. The bind must be unique. + * + * @param id AdminId of the admin. + * @param auth Auth method to use, predefined or from RegisterAuthIdentType(). + * @param ident String containing the arbitrary, unique identity. + * @return True on success, false if the auth method was not found, + * ident was already taken, or ident invalid for auth method. + */ +native bool BindAdminIdentity(AdminId id, const char[] auth, const char[] ident); + +/** + * Sets whether or not a flag is enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param enabled True to enable, false to disable. + */ +native void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled); + +/** + * Returns whether or not a flag is enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param mode Access mode to check. + * @return True if enabled, false otherwise. + */ +native bool GetAdminFlag(AdminId id, AdminFlag flag, AdmAccessMode mode=Access_Effective); + +/** + * Returns the bitstring of access flags on an admin. + * + * @param id AdminId index of the admin. + * @param mode Access mode to use. + * @return A bitstring containing which flags are enabled. + */ +native int GetAdminFlags(AdminId id, AdmAccessMode mode); + +/** + * Adds a group to an admin's inherited group list. Any flags the group has + * will be added to the admin's effective flags. + * + * @param id AdminId index of the admin. + * @param gid GroupId index of the group. + * @return True on success, false on invalid input or duplicate membership. + */ +native bool AdminInheritGroup(AdminId id, GroupId gid); + +/** + * Returns the number of groups this admin is a member of. + * + * @param id AdminId index of the admin. + * @return Number of groups this admin is a member of. + */ +native int GetAdminGroupCount(AdminId id); + +/** + * Returns group information from an admin. + * + * @param id AdminId index of the admin. + * @param index Group number to retrieve, from 0 to N-1, where N + * is the value of GetAdminGroupCount(id). + * @param name Buffer to store the group's name. + * Note: This will safely chop UTF-8 strings. + * @param maxlength Maximum size of the output name buffer. + * @return A GroupId index and a name pointer, or + * INVALID_GROUP_ID and NULL if an error occurred. + */ +native GroupId GetAdminGroup(AdminId id, int index, const char[] name, int maxlength); + +/** + * Sets a password on an admin. + * + * @param id AdminId index of the admin. + * @param password String containing the password. + */ +native void SetAdminPassword(AdminId id, const char[] password); + +/** + * Gets an admin's password. + * + * @param id AdminId index of the admin. + * @param buffer Optional buffer to store the admin's password. + * @param maxlength Maximum size of the output name buffer. + * Note: This will safely chop UTF-8 strings. + * @return True if there was a password set, false otherwise. + */ +native bool GetAdminPassword(AdminId id, char[] buffer="", int maxlength=0); + +/** + * Attempts to find an admin by an auth method and an identity. + * + * @param auth Auth method to try. + * @param identity Identity string to look up. + * @return An AdminId index if found, INVALID_ADMIN_ID otherwise. + */ +native AdminId FindAdminByIdentity(const char[] auth, const char[] identity); + +/** + * Removes an admin entry from the cache. + * + * @note This will remove any bindings to a specific user. + * + * @param id AdminId index to remove/invalidate. + * @return True on success, false otherwise. + */ +native bool RemoveAdmin(AdminId id); + +/** + * Converts a flag bit string to a bit array. + * + * @param bits Bit string containing the flags. + * @param array Array to write the flags to. Enabled flags will be 'true'. + * @param maxSize Maximum number of flags the array can store. + * @return Number of flags written. + */ +native int FlagBitsToBitArray(int bits, bool[] array, int maxSize); + +/** + * Converts a flag array to a bit string. + * + * @param array Array containing true or false for each AdminFlag. + * @param maxSize Maximum size of the flag array. + * @return A bit string composed of the array bits. + */ +native int FlagBitArrayToBits(const bool[] array, int maxSize); + +/** + * Converts an array of flags to bits. + * + * @param array Array containing flags that are enabled. + * @param numFlags Number of flags in the array. + * @return A bit string composed of the array flags. + */ +native int FlagArrayToBits(const AdminFlag[] array, int numFlags); + +/** + * Converts a bit string to an array of flags. + * + * @param bits Bit string containing the flags. + * @param array Output array to write flags. + * @param maxSize Maximum size of the flag array. + * @return Number of flags written. + */ +native int FlagBitsToArray(int bits, AdminFlag[] array, int maxSize); + +/** + * Finds a flag by its string name. + * + * @param name Flag name (like "kick"), case sensitive. + * @param flag Variable to store flag in. + * @return True on success, false if not found. + */ +native bool FindFlagByName(const char[] name, AdminFlag &flag); + +/** + * Finds a flag by a given character. + * + * @param c Flag ASCII character/token. + * @param flag Variable to store flag in. + * @return True on success, false if not found. + */ +native bool FindFlagByChar(int c, AdminFlag &flag); + +/** + * Finds the flag char for a given admin flag. + * + * @param flag Flag to look up. + * @param c Variable to store flag char. + * @return True on success, false if not found. + */ +native bool FindFlagChar(AdminFlag flag, int &c); + +/** + * Converts a string of flag characters to a bit string. + * + * @param flags Flag ASCII string. + * @param numchars Optional variable to store the number of bytes read. + * @return Bit string of ADMFLAG values. + */ +native int ReadFlagString(const char[] flags, int &numchars=0); + +/** + * Tests whether one admin can target another. + * + * The heuristics for this check are as follows: + * 0. If the targeting AdminId is INVALID_ADMIN_ID, targeting fails. + * 1. If the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds. + * 2. If the targeted AdminId is the same as the targeting AdminId, + * (self) targeting succeeds. + * 3. If the targeting admin is root, targeting succeeds. + * 4. If the targeted admin has access higher (as interpreted by + * (sm_immunity_mode) than the targeting admin, then targeting fails. + * 5. If the targeted admin has specific immunity from the + * targeting admin via group immunities, targeting fails. + * 6. Targeting succeeds. + * + * @param admin Admin doing the targetting (may be INVALID_ADMIN_ID). + * @param target Target admin (may be INVALID_ADMIN_ID). + * @return True if targetable, false if immune. + */ +native bool CanAdminTarget(AdminId admin, AdminId target); + +/** + * Creates an admin auth method. This does not need to be called more than once + * per method, ever. + * + * @param method Name of the authentication method. + * @return True on success, false on failure. + */ +native bool CreateAuthMethod(const char[] method); + +/** + * Sets a group's immunity level. + * + * @param gid Group Id. + * @param level Immunity level value. + * @return Old immunity level value. + */ +native int SetAdmGroupImmunityLevel(GroupId gid, int level); + +/** + * Gets a group's immunity level (defaults to 0). + * + * @param gid Group Id. + * @return Immunity level value. + */ +native int GetAdmGroupImmunityLevel(GroupId gid); + +/** + * Sets an admin's immunity level. + * + * @param id Admin Id. + * @param level Immunity level value. + * @return Old immunity level value. + */ +native int SetAdminImmunityLevel(AdminId id, int level); + +/** + * Gets an admin's immunity level. + * + * @param id Admin Id. + * @return Immunity level value. + */ +native int GetAdminImmunityLevel(AdminId id); + +/** + * Converts a flag to its single bit. + * + * @param flag Flag to convert. + * @return Bit representation of the flag. + */ +stock int FlagToBit(AdminFlag flag) +{ + return (1 << view_as(flag)); +} + +/** + * Converts a bit to an AdminFlag. + * + * @param bit Bit to convert. + * @param flag Stores the converted flag by reference. + * @return True on success, false otherwise. + */ +stock bool BitToFlag(int bit, AdminFlag &flag) +{ + AdminFlag array[1]; + + if (FlagBitsToArray(bit, array, 1)) + { + flag = array[0]; + return true; + } + + return false; +} diff --git a/scripting/include/adminmenu.inc b/scripting/include/adminmenu.inc new file mode 100644 index 0000000..a3cb617 --- /dev/null +++ b/scripting/include/adminmenu.inc @@ -0,0 +1,152 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _adminmenu_included + #endinput +#endif +#define _adminmenu_included + +/* Decide whether topmenus should be required */ +#if !defined REQUIRE_PLUGIN + #if defined REQUIRE_EXTENSIONS + #define TEMP_REQUIRE_EXTENSIONS + #undef REQUIRE_EXTENSIONS + #endif +#endif + +#include + +/* Restore old REQUIRE_EXTENSIONS value if necessary */ +#if defined TEMP_REQUIRE_EXTENSIONS + #define REQUIRE_EXTENSIONS + #undef TEMP_REQUIRE_EXTENSIONS +#endif + +/** Category for player commands. */ +#define ADMINMENU_PLAYERCOMMANDS "PlayerCommands" +/** Category for server commands. */ +#define ADMINMENU_SERVERCOMMANDS "ServerCommands" +/** Category for voting commands. */ +#define ADMINMENU_VOTINGCOMMANDS "VotingCommands" + +/** + * Called when the admin menu is created and 3rd party plugins can grab + * the Handle or add categories. + * + * @param topmenu Handle to the admin menu's TopMenu. + */ +forward void OnAdminMenuCreated(Handle topmenu); + +/** + * Called when the admin menu is ready to have items added. + * + * @param topmenu Handle to the admin menu's TopMenu. + */ +forward void OnAdminMenuReady(Handle topmenu); + +/** + * Retrieves the Handle to the admin top menu. + * + * @return Handle to the admin menu's TopMenu, + * or INVALID_HANDLE if not created yet. + */ +native TopMenu GetAdminTopMenu(); + +/** + * Adds targets to an admin menu. + * + * Each client is displayed as: name (userid) + * Each item contains the userid as a string for its info. + * + * @param menu Menu Handle. + * @param source_client Source client, or 0 to ignore immunity. + * @param in_game_only True to only select in-game players. + * @param alive_only True to only select alive players. + * @return Number of clients added. + */ +native int AddTargetsToMenu(Handle menu, + int source_client, + bool in_game_only=true, + bool alive_only=false); + +/** + * Adds targets to an admin menu. + * + * Each client is displayed as: name (userid) + * Each item contains the userid as a string for its info. + * + * @param menu Menu Handle. + * @param source_client Source client, or 0 to ignore immunity. + * @param flags COMMAND_FILTER flags from commandfilters.inc. + * @return Number of clients added. + */ +native int AddTargetsToMenu2(Handle menu, int source_client, int flags); + +/** + * Re-displays the admin menu to a client after selecting an item. + * Auto-aborts if the Handle is invalid. + * + * @param topmenu TopMenu Handle. + * @param client Client index. + * @return True on success, false on failure. + */ +stock bool RedisplayAdminMenu(Handle topmenu, int client) +{ + if (topmenu == INVALID_HANDLE) + { + return false; + } + + return DisplayTopMenu(topmenu, client, TopMenuPosition_LastCategory); +} + +/* DO NOT EDIT BELOW THIS LINE */ + +public SharedPlugin __pl_adminmenu = +{ + name = "adminmenu", + file = "adminmenu.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_adminmenu_SetNTVOptional() +{ + MarkNativeAsOptional("GetAdminTopMenu"); + MarkNativeAsOptional("AddTargetsToMenu"); + MarkNativeAsOptional("AddTargetsToMenu2"); +} +#endif diff --git a/scripting/include/adt.inc b/scripting/include/adt.inc new file mode 100644 index 0000000..1727fc9 --- /dev/null +++ b/scripting/include/adt.inc @@ -0,0 +1,40 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _adt_included + #endinput +#endif +#define _adt_included + +#include +#include +#include diff --git a/scripting/include/adt_array.inc b/scripting/include/adt_array.inc new file mode 100644 index 0000000..043898d --- /dev/null +++ b/scripting/include/adt_array.inc @@ -0,0 +1,455 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _adt_array_included + #endinput +#endif +#define _adt_array_included + +/** + * Given a maximum string size (including the null terminator), + * returns the number of cells required to fit that string. + * + * @param size Number of bytes. + * @return Minimum number of cells required to fit the byte count. + */ +stock int ByteCountToCells(int size) +{ + if (!size) + return 1; + return (size + 3) / 4; +} + +methodmap ArrayList < Handle { + // Creates a dynamic global cell array. While slower than a normal array, + // it can be used globally AND dynamically, which is otherwise impossible. + // + // The contents of the array are uniform; i.e. storing a string at index X + // and then retrieving it as an integer is NOT the same as StringToInt()! + // The "blocksize" determines how many cells each array slot has; it cannot + // be changed after creation. + // + // @param blocksize The number of cells each member of the array can + // hold. For example, 32 cells is equivalent to: + // new Array[X][32] + // @param startsize Initial size of the array. Note that data will + // NOT be auto-initialized. + // @return New Handle to the array object. + public native ArrayList(int blocksize=1, int startsize=0); + + // Clears an array of all entries. This is the same as Resize(0). + public native void Clear(); + + // Clones an array, returning a new handle with the same size and data. + // This should NOT be confused with CloneHandle. This is a completely new + // handle with the same data but no relation to the original. It should + // closed when no longer needed. + // + // @return New handle to the cloned array object + public native ArrayList Clone(); + + // Resizes an array. If the size is smaller than the current size, the + // array is truncated. If the size is larger than the current size, + // the data at the additional indexes will not be initialized. + // + // @param newsize New size. + public native void Resize(int newsize); + + // Pushes a value onto the end of an array, adding a new index. + // + // This may safely be used even if the array has a blocksize greater + // than 1. + // + // @param value Value to push. + // @return Index of the new entry. + // @error Invalid Handle or out of memory. + // + public native int Push(any value); + + // Pushes a string onto the end of an array, truncating it if it is too big. + // + // @param value String to push. + // @return Index of the new entry. + public native int PushString(const char[] value); + + // Pushes an array of cells onto the end of an array. The cells + // are pushed as a block (i.e. the entire array sits at the index), + // rather than pushing each cell individually. + // + // @param values Block of values to copy. + // @param size If not set, the number of elements copied from the array + // will be equal to the blocksize. If set higher than the + // blocksize, the operation will be truncated. + // @return Index of the new entry. + public native int PushArray(const any[] values, int size=-1); + + // Retrieves a cell value from an array. + // + // @param index Index in the array. + // @param block Optionally specify which block to read from + // (useful if the blocksize > 0). + // @param asChar Optionally read as a byte instead of a cell. + // @return Value read. + // @error Invalid index. + public native any Get(int index, int block=0, bool asChar=false); + + // Retrieves a string value from an array. + // + // @param index Index in the array. + // @param buffer Buffer to copy to. + // @param maxlength Maximum size of the buffer. + // @return Number of characters copied. + // @error Invalid index. + public native int GetString(int index, char[] buffer, int maxlength); + + // Retrieves an array of cells from an array. + // + // @param index Index in the array. + // @param buffer Buffer to store the array in. + // @param size If not set, assumes the buffer size is equal to the + // blocksize. Otherwise, the size passed is used. + // @return Number of cells copied. + // @error Invalid index. + public native int GetArray(int index, any[] buffer, int size=-1); + + // Sets a cell value in an array. + // + // @param index Index in the array. + // @param value Cell value to set. + // @param block Optionally specify which block to write to + // (useful if the blocksize > 0). + // @param asChar Optionally set as a byte instead of a cell. + // @error Invalid index, or invalid block. + public native void Set(int index, any value, int block=0, bool asChar=false); + + // Sets a string value in an array. + // + // @param index Index in the array. + // @param value String value to set. + // @return Number of characters copied. + // @error Invalid index. + public native void SetString(int index, const char[] value); + + // Sets an array of cells in an array. + // + // @param index Index in the array. + // @param values Array to copy. + // @param size If not set, assumes the buffer size is equal to the + // blocksize. Otherwise, the size passed is used. + // @return Number of cells copied. + // @error Invalid index. + public native void SetArray(int index, const any[] values, int size=-1); + + // Shifts an array up. All array contents after and including the given + // index are shifted up by one, and the given index is then "free." + // After shifting, the contents of the given index is undefined. + // + // @param index Index in the array to shift up from. + // @error Invalid index. + public native void ShiftUp(int index); + + // Removes an array index, shifting the entire array down from that position + // on. For example, if item 8 of 10 is removed, the last 3 items will then be + // (6,7,8) instead of (7,8,9), and all indexes before 8 will remain unchanged. + // + // @param index Index in the array to remove at. + // @error Invalid index. + public native void Erase(int index); + + // Swaps two items in the array. + // + // @param index1 First index. + // @param index2 Second index. + // @error Invalid index. + public native void SwapAt(int index1, int index2); + + // Returns the index for the first occurrence of the provided string. If + // the string cannot be located, -1 will be returned. + // + // @param item String to search for + // @return Array index, or -1 on failure + public native int FindString(const char[] item); + + // Returns the index for the first occurrence of the provided value. If the + // value cannot be located, -1 will be returned. + // + // @param item Value to search for + // @param block Optionally which block to search in + // @return Array index, or -1 on failure + // @error Invalid block index + public native int FindValue(any item, int block=0); + + // Retrieve the size of the array. + property int Length { + public native get(); + } + + // Retrieve the blocksize the array was created with. + property int BlockSize { + public native get(); + } +}; + +/** + * Creates a dynamic global cell array. While slower than a normal array, + * it can be used globally AND dynamically, which is otherwise impossible. + * + * The contents of the array are uniform; i.e. storing a string at index X + * and then retrieving it as an integer is NOT the same as StringToInt()! + * The "blocksize" determines how many cells each array slot has; it cannot + * be changed after creation. + * + * @param blocksize The number of cells each member of the array can + * hold. For example, 32 cells is equivalent to: + * new Array[X][32] + * @param startsize Initial size of the array. Note that data will + * NOT be auto-initialized. + * @return New Handle to the array object. + */ +native ArrayList CreateArray(int blocksize=1, int startsize=0); + +/** + * Clears an array of all entries. This is the same as ResizeArray(0). + * + * @param array Array Handle. + * @error Invalid Handle. + */ +native void ClearArray(Handle array); + +/** + * Clones an array, returning a new handle with the same size and data. This should NOT + * be confused with CloneHandle. This is a completely new handle with the same data but + * no relation to the original. You MUST close it. + * + * @param array Array handle to be cloned + * @return New handle to the cloned array object + * @error Invalid Handle + */ +native Handle CloneArray(Handle array); + +/** + * Resizes an array. If the size is smaller than the current size, + * the array is truncated. If the size is larger than the current size, + * the data at the additional indexes will not be initialized. + * + * @param array Array Handle. + * @param newsize New size. + * @error Invalid Handle or out of memory. + */ +native void ResizeArray(Handle array, int newsize); + +/** + * Returns the array size. + * + * @param array Array Handle. + * @return Number of elements in the array. + * @error Invalid Handle. + */ +native int GetArraySize(Handle array); + +/** + * Pushes a value onto the end of an array, adding a new index. + * + * This may safely be used even if the array has a blocksize + * greater than 1. + * + * @param array Array Handle. + * @param value Value to push. + * @return Index of the new entry. + * @error Invalid Handle or out of memory. + */ +native int PushArrayCell(Handle array, any value); + +/** + * Pushes a string onto the end of an array, truncating it + * if it is too big. + * + * @param array Array Handle. + * @param value String to push. + * @return Index of the new entry. + * @error Invalid Handle or out of memory. + */ +native int PushArrayString(Handle array, const char[] value); + +/** + * Pushes an array of cells onto the end of an array. The cells + * are pushed as a block (i.e. the entire array sits at the index), + * rather than pushing each cell individually. + * + * @param array Array Handle. + * @param values Block of values to copy. + * @param size If not set, the number of elements copied from the array + * will be equal to the blocksize. If set higher than the + * blocksize, the operation will be truncated. + * @return Index of the new entry. + * @error Invalid Handle or out of memory. + */ +native int PushArrayArray(Handle array, const any[] values, int size=-1); + +/** + * Retrieves a cell value from an array. + * + * @param array Array Handle. + * @param index Index in the array. + * @param block Optionally specify which block to read from + * (useful if the blocksize > 0). + * @param asChar Optionally read as a byte instead of a cell. + * @return Value read. + * @error Invalid Handle, invalid index, or invalid block. + */ +native any GetArrayCell(Handle array, int index, int block=0, bool asChar=false); + +/** + * Retrieves a string value from an array. + * + * @param array Array Handle. + * @param index Index in the array. + * @param buffer Buffer to copy to. + * @param maxlength Maximum size of the buffer. + * @return Number of characters copied. + * @error Invalid Handle or invalid index. + */ +native int GetArrayString(Handle array, int index, char[] buffer, int maxlength); + +/** + * Retrieves an array of cells from an array. + * + * @param array Array Handle. + * @param index Index in the array. + * @param buffer Buffer to store the array in. + * @param size If not set, assumes the buffer size is equal to the + * blocksize. Otherwise, the size passed is used. + * @return Number of cells copied. + * @error Invalid Handle or invalid index. + */ +native int GetArrayArray(Handle array, int index, any[] buffer, int size=-1); + +/** + * Sets a cell value in an array. + * + * @param array Array Handle. + * @param index Index in the array. + * @param value Cell value to set. + * @param block Optionally specify which block to write to + * (useful if the blocksize > 0). + * @param asChar Optionally set as a byte instead of a cell. + * @error Invalid Handle, invalid index, or invalid block. + */ +native void SetArrayCell(Handle array, int index, any value, int block=0, bool asChar=false); + +/** + * Sets a string value in an array. + * + * @param array Array Handle. + * @param index Index in the array. + * @param value String value to set. + * @return Number of characters copied. + * @error Invalid Handle or invalid index. + */ +native int SetArrayString(Handle array, int index, const char[] value); + +/** + * Sets an array of cells in an array. + * + * @param array Array Handle. + * @param index Index in the array. + * @param values Array to copy. + * @param size If not set, assumes the buffer size is equal to the + * blocksize. Otherwise, the size passed is used. + * @return Number of cells copied. + * @error Invalid Handle or invalid index. + */ +native int SetArrayArray(Handle array, int index, const any[] values, int size=-1); + +/** + * Shifts an array up. All array contents after and including the given + * index are shifted up by one, and the given index is then "free." + * After shifting, the contents of the given index is undefined. + * + * @param array Array Handle. + * @param index Index in the array to shift up from. + * @error Invalid Handle or invalid index. + */ +native void ShiftArrayUp(Handle array, int index); + +/** + * Removes an array index, shifting the entire array down from that position + * on. For example, if item 8 of 10 is removed, the last 3 items will then be + * (6,7,8) instead of (7,8,9), and all indexes before 8 will remain unchanged. + * + * @param array Array Handle. + * @param index Index in the array to remove at. + * @error Invalid Handle or invalid index. + */ +native void RemoveFromArray(Handle array, int index); + +/** + * Swaps two items in the array. + * + * @param array Array Handle. + * @param index1 First index. + * @param index2 Second index. + * @error Invalid Handle or invalid index. + */ +native void SwapArrayItems(Handle array, int index1, int index2); + +/** + * Returns the index for the first occurrence of the provided string. If the string + * cannot be located, -1 will be returned. + * + * @param array Array Handle. + * @param item String to search for + * @return Array index, or -1 on failure + * @error Invalid Handle + */ +native int FindStringInArray(Handle array, const char[] item); + +/** + * Returns the index for the first occurrence of the provided value. If the value + * cannot be located, -1 will be returned. + * + * @param array Array Handle. + * @param item Value to search for + * @param block Optionally which block to search in + * @return Array index, or -1 on failure + * @error Invalid Handle or invalid block + */ +native int FindValueInArray(Handle array, any item, int block=0); + +/** + * Returns the blocksize the array was created with. + * + * @param array Array Handle. + * @return The blocksize of the array. + * @error Invalid Handle + */ +native int GetArrayBlockSize(Handle array); diff --git a/scripting/include/adt_stack.inc b/scripting/include/adt_stack.inc new file mode 100644 index 0000000..b841a0a --- /dev/null +++ b/scripting/include/adt_stack.inc @@ -0,0 +1,240 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _adt_stack_included + #endinput +#endif +#define _adt_stack_included + +methodmap ArrayStack < Handle +{ + // Creates a stack structure. A stack is a LIFO (last in, first out) + // vector (array) of items. It has O(1) insertion and O(1) removal. + // + // Stacks have two operations: Push (adding an item) and Pop (removes + // items in reverse-push order). + // + // The contents of the stack are uniform; i.e. storing a string and then + // retrieving it as an integer is NOT the same as StringToInt()! + // + // The "blocksize" determines how many cells each slot has; it cannot + // be changed after creation. + // + // @param blocksize The number of cells each entry in the stack can + // hold. For example, 32 cells is equivalent to: + // new Array[X][32] + public native ArrayStack(int blocksize=1); + + // Pushes a value onto the end of the stack, adding a new index. + // + // This may safely be used even if the stack has a blocksize + // greater than 1. + // + // @param value Value to push. + public native void Push(any value); + + // Pushes a copy of a string onto the end of a stack, truncating it if it + // is too big. + // + // @param value String to push. + public native void PushString(const char[] value); + + // Pushes a copy of an array of cells onto the end of a stack. The cells + // are pushed as a block (i.e. the entire array takes up one stack slot), + // rather than pushing each cell individually. + // + // @param stack Stack Handle. + // @param values Block of values to copy. + // @param size If not set, the number of elements copied from the array + // will be equal to the blocksize. If set higher than the + // blocksize, the operation will be truncated. + public native void PushArray(const any[] values, int size=-1); + + // Pops a cell value from a stack. + // + // @param block Optionally specify which block to read from + // (useful if the blocksize > 0). + // @param asChar Optionally read as a byte instead of a cell. + // @return True on success, false if the stack is empty. + // @error The stack is empty. + public native any Pop(int block=0, bool asChar=false); + + // Pops a string value from a stack. + // + // @param buffer Buffer to store string. + // @param maxlength Maximum size of the buffer. + // @oaram written Number of characters written to buffer, not including + // the null terminator. + // @error The stack is empty. + public native void PopString(char[] buffer, int maxlength, int &written = 0); + + // Pops an array of cells from a stack. + // + // @param buffer Buffer to store the array in. + // @param size If not set, assumes the buffer size is equal to the + // blocksize. Otherwise, the size passed is used. + // @error The stack is empty. + public native void PopArray(any[] buffer, int size=-1); + + // Returns true if the stack is empty, false otherwise. + property bool Empty { + public native get(); + } + + // Retrieve the blocksize the stack was created with. + property int BlockSize { + public native get(); + } +}; + +/** + * Creates a stack structure. A stack is a LIFO (last in, first out) + * vector (array) of items. It has O(1) insertion and O(1) removal. + * + * Stacks have two operations: Push (adding an item) and Pop (removes + * items in reverse-push order). + * + * The contents of the stack are uniform; i.e. storing a string and then + * retrieving it as an integer is NOT the same as StringToInt()! + * + * The "blocksize" determines how many cells each slot has; it cannot + * be changed after creation. + * + * @param blocksize The number of cells each entry in the stack can + * hold. For example, 32 cells is equivalent to: + * new Array[X][32] + * @return New stack Handle. + */ +native ArrayStack CreateStack(int blocksize=1); + +/** + * Pushes a value onto the end of the stack, adding a new index. + * + * This may safely be used even if the stack has a blocksize + * greater than 1. + * + * @param stack Stack Handle. + * @param value Value to push. + * @error Invalid Handle or out of memory. + */ +native void PushStackCell(Handle stack, any value); + +/** + * Pushes a copy of a string onto the end of a stack, truncating it if it is + * too big. + * + * @param stack Stack Handle. + * @param value String to push. + * @error Invalid Handle or out of memory. + */ +native void PushStackString(Handle stack, const char[] value); + +/** + * Pushes a copy of an array of cells onto the end of a stack. The cells + * are pushed as a block (i.e. the entire array takes up one stack slot), + * rather than pushing each cell individually. + * + * @param stack Stack Handle. + * @param values Block of values to copy. + * @param size If not set, the number of elements copied from the array + * will be equal to the blocksize. If set higher than the + * blocksize, the operation will be truncated. + * @error Invalid Handle or out of memory. + */ +native void PushStackArray(Handle stack, const any[] values, int size=-1); + +/** + * Pops a cell value from a stack. + * + * @param stack Stack Handle. + * @param value Variable to store the value. + * @param block Optionally specify which block to read from + * (useful if the blocksize > 0). + * @param asChar Optionally read as a byte instead of a cell. + * @return True on success, false if the stack is empty. + * @error Invalid Handle. + */ +native bool PopStackCell(Handle stack, any &value, int block=0, bool asChar=false); + +/** + * Pops a string value from a stack. + * + * @param stack Stack Handle. + * @param buffer Buffer to store string. + * @param maxlength Maximum size of the buffer. + * @return True on success, false if the stack is empty. + * @error Invalid Handle. + */ +native bool PopStackString(Handle stack, char[] buffer, int maxlength, int &written=0); + +/** + * Pops an array of cells from a stack. + * + * @param stack Stack Handle. + * @param buffer Buffer to store the array in. + * @param size If not set, assumes the buffer size is equal to the + * blocksize. Otherwise, the size passed is used. + * @return True on success, false if the stack is empty. + * @error Invalid Handle. + */ +native bool PopStackArray(Handle stack, any[] buffer, int size=-1); + +/** + * Checks if a stack is empty. + * + * @param stack Stack Handle. + * @return True if empty, false if not empty. + * @error Invalid Handle. + */ +native bool IsStackEmpty(Handle stack); + +/** + * Pops a value off a stack, ignoring it completely. + * + * @param stack Stack Handle. + * @return True if something was popped, false otherwise. + * @error Invalid Handle. + */ +stock bool PopStack(Handle stack) +{ + int value; + return PopStackCell(stack, value); +} + +/** + * Returns the blocksize the stack was created with. + * + * @param stack Stack Handle. + * @return The blocksize of the stack. + * @error Invalid Handle + */ +native int GetStackBlockSize(Handle stack); diff --git a/scripting/include/adt_trie.inc b/scripting/include/adt_trie.inc new file mode 100644 index 0000000..44548ab --- /dev/null +++ b/scripting/include/adt_trie.inc @@ -0,0 +1,317 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _adt_trie_included + #endinput +#endif +#define _adt_trie_included + +/* Object-oriented wrapper for maps. */ +methodmap StringMap < Handle +{ + // Creates a hash map. A hash map is a container that can map strings (called + // "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map + // are unique. That is, there is at most one entry in the map for a given key. + // + // Insertion, deletion, and lookup in a hash map are all considered to be fast + // operations, amortized to O(1), or constant time. + // + // The word "Trie" in this API is historical. As of SourceMod 1.6, tries have + // been internally replaced with hash tables, which have O(1) insertion time + // instead of O(n). + // + // The StringMap must be freed via delete or CloseHandle(). + public native StringMap(); + + // Sets a value in a hash map, either inserting a new entry or replacing an old one. + // + // @param key Key string. + // @param value Value to store at this key. + // @param replace If false, operation will fail if the key is already set. + // @return True on success, false on failure. + public native bool SetValue(const char[] key, any value, bool replace=true); + + // Sets an array value in a Map, either inserting a new entry or replacing an old one. + // + // @param key Key string. + // @param array Array to store. + // @param num_items Number of items in the array. + // @param replace If false, operation will fail if the key is already set. + // @return True on success, false on failure. + public native bool SetArray(const char[] key, const any[] array, int num_items, bool replace=true); + + // Sets a string value in a Map, either inserting a new entry or replacing an old one. + // + // @param key Key string. + // @param value String to store. + // @param replace If false, operation will fail if the key is already set. + // @return True on success, false on failure. + public native bool SetString(const char[] key, const char[] value, bool replace=true); + + // Retrieves a value in a Map. + // + // @param key Key string. + // @param value Variable to store value. + // @return True on success. False if the key is not set, or the key is set + // as an array or string (not a value). + public native bool GetValue(const char[] key, any &value); + + // Retrieves an array in a Map. + // + // @param map Map Handle. + // @param key Key string. + // @param array Buffer to store array. + // @param max_size Maximum size of array buffer. + // @param size Optional parameter to store the number of elements written to the buffer. + // @return True on success. False if the key is not set, or the key is set + // as a value or string (not an array). + public native bool GetArray(const char[] key, any[] array, int max_size, int &size=0); + + // Retrieves a string in a Map. + // + // @param key Key string. + // @param value Buffer to store value. + // @param max_size Maximum size of string buffer. + // @param size Optional parameter to store the number of bytes written to the buffer. + // @return True on success. False if the key is not set, or the key is set + // as a value or array (not a string). + public native bool GetString(const char[] key, char[] value, int max_size, int &size=0); + + // Removes a key entry from a Map. + // + // @param key Key string. + // @return True on success, false if the value was never set. + public native bool Remove(const char[] key); + + // Clears all entries from a Map. + public native void Clear(); + + // Create a snapshot of the map's keys. See StringMapSnapshot. + public native StringMapSnapshot Snapshot(); + + // Retrieves the number of elements in a map. + property int Size { + public native get(); + } +}; + +// A StringMapSnapshot is created via StringMap.Snapshot(). It captures the +// keys on a map so they can be read. Snapshots must be freed with delete or +// CloseHandle(). +methodmap StringMapSnapshot < Handle +{ + // Returns the number of keys in the map snapshot. + property int Length { + public native get(); + } + + // Returns the buffer size required to store a given key. That is, it + // returns the length of the key plus one. + // + // @param index Key index (starting from 0). + // @return Buffer size required to store the key string. + // @error Index out of range. + public native int KeyBufferSize(int index); + + // Retrieves the key string of a given key in a map snapshot. + // + // @param index Key index (starting from 0). + // @param buffer String buffer. + // @param maxlength Maximum buffer length. + // @return Number of bytes written to the buffer. + // @error Index out of range. + public native int GetKey(int index, char[] buffer, int maxlength); +}; + +/** + * Creates a hash map. A hash map is a container that can map strings (called + * "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map + * are unique. That is, there is at most one entry in the map for a given key. + * + * Insertion, deletion, and lookup in a hash map are all considered to be fast + * operations, amortized to O(1), or constant time. + * + * The word "Trie" in this API is historical. As of SourceMod 1.6, tries have + * been internally replaced with hash tables, which have O(1) insertion time + * instead of O(n). + * + * @return New Map Handle, which must be freed via CloseHandle(). + */ +native StringMap CreateTrie(); + +/** + * Sets a value in a hash map, either inserting a new entry or replacing an old one. + * + * @param map Map Handle. + * @param key Key string. + * @param value Value to store at this key. + * @param replace If false, operation will fail if the key is already set. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool SetTrieValue(Handle map, const char[] key, any value, bool replace=true); + +/** + * Sets an array value in a Map, either inserting a new entry or replacing an old one. + * + * @param map Map Handle. + * @param key Key string. + * @param array Array to store. + * @param num_items Number of items in the array. + * @param replace If false, operation will fail if the key is already set. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool SetTrieArray(Handle map, const char[] key, const any[] array, int num_items, bool replace=true); + +/** + * Sets a string value in a Map, either inserting a new entry or replacing an old one. + * + * @param map Map Handle. + * @param key Key string. + * @param value String to store. + * @param replace If false, operation will fail if the key is already set. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool SetTrieString(Handle map, const char[] key, const char[] value, bool replace=true); + +/** + * Retrieves a value in a Map. + * + * @param map Map Handle. + * @param key Key string. + * @param value Variable to store value. + * @return True on success. False if the key is not set, or the key is set + * as an array or string (not a value). + * @error Invalid Handle. + */ +native bool GetTrieValue(Handle map, const char[] key, any &value); + +/** + * Retrieves an array in a Map. + * + * @param map Map Handle. + * @param key Key string. + * @param array Buffer to store array. + * @param max_size Maximum size of array buffer. + * @param size Optional parameter to store the number of elements written to the buffer. + * @return True on success. False if the key is not set, or the key is set + * as a value or string (not an array). + * @error Invalid Handle. + */ +native bool GetTrieArray(Handle map, const char[] key, any[] array, int max_size, int &size=0); + +/** + * Retrieves a string in a Map. + * + * @param map Map Handle. + * @param key Key string. + * @param value Buffer to store value. + * @param max_size Maximum size of string buffer. + * @param size Optional parameter to store the number of bytes written to the buffer. + * @return True on success. False if the key is not set, or the key is set + * as a value or array (not a string). + * @error Invalid Handle. + */ +native bool GetTrieString(Handle map, const char[] key, char[] value, int max_size, int &size=0); + +/** + * Removes a key entry from a Map. + * + * @param map Map Handle. + * @param key Key string. + * @return True on success, false if the value was never set. + * @error Invalid Handle. + */ +native bool RemoveFromTrie(Handle map, const char[] key); + +/** + * Clears all entries from a Map. + * + * @param map Map Handle. + * @error Invalid Handle. + */ +native void ClearTrie(Handle map); + +/** + * Retrieves the number of elements in a map. + * + * @param map Map Handle. + * @return Number of elements in the trie. + * @error Invalid Handle. + */ +native int GetTrieSize(Handle map); + +/** + * Creates a snapshot of all keys in the map. If the map is changed after this + * call, the changes are not reflected in the snapshot. Keys are not sorted. + * + * @param map Map Handle. + * @return New Map Snapshot Handle, which must be closed via CloseHandle(). + * @error Invalid Handle. + */ +native Handle CreateTrieSnapshot(Handle map); + +/** + * Returns the number of keys in a map snapshot. Note that this may be + * different from the size of the map, since the map can change after the + * snapshot of its keys was taken. + * + * @param snapshot Map snapshot. + * @return Number of keys. + * @error Invalid Handle. + */ +native int TrieSnapshotLength(Handle snapshot); + +/** + * Returns the buffer size required to store a given key. That is, it returns + * the length of the key plus one. + * + * @param snapshot Map snapshot. + * @param index Key index (starting from 0). + * @return Buffer size required to store the key string. + * @error Invalid Handle or index out of range. + */ +native int TrieSnapshotKeyBufferSize(Handle snapshot, int index); + +/** + * Retrieves the key string of a given key in a map snapshot. + * + * @param snapshot Map snapshot. + * @param index Key index (starting from 0). + * @param buffer String buffer. + * @param maxlength Maximum buffer length. + * @return Number of bytes written to the buffer. + * @error Invalid Handle or index out of range. + */ +native int GetTrieSnapshotKey(Handle snapshot, int index, char[] buffer, int maxlength); diff --git a/scripting/include/banning.inc b/scripting/include/banning.inc new file mode 100644 index 0000000..424753e --- /dev/null +++ b/scripting/include/banning.inc @@ -0,0 +1,156 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _banning_included + #endinput +#endif +#define _banning_included + +#define BANFLAG_AUTO (1<<0) /**< Auto-detects whether to ban by steamid or IP */ +#define BANFLAG_IP (1<<1) /**< Always ban by IP address */ +#define BANFLAG_AUTHID (1<<2) /**< Always ban by authstring (for BanIdentity) if possible */ +#define BANFLAG_NOKICK (1<<3) /**< Does not kick the client */ + +/** + * Called for calls to BanClient() with a non-empty command. + * + * @param client Client being banned. + * @param time Time the client is being banned for (0 = permanent). + * @param flags One if AUTHID or IP will be enabled. If AUTO is also + * enabled, it means Core autodetected which to use. + * @param reason Reason passed via BanClient(). + * @param kick_message Kick message passed via BanClient(). + * @param command Command string to identify the ban source. + * @param source Source value passed via BanClient(). + * @return Plugin_Handled to block the actual server banning. + * Kicking will still occur. + */ +forward Action OnBanClient(int client, + int time, + int flags, + const char[] reason, + const char[] kick_message, + const char[] command, + any source); + +/** + * Called for calls to BanIdentity() with a non-empty command. + * + * @param identity Identity string being banned (authstring or ip). + * @param time Time the client is being banned for (0 = permanent). + * @param flags Ban flags (only IP or AUTHID are valid here). + * @param reason Reason passed via BanIdentity(). + * @param command Command string to identify the ban source. + * @param source Source value passed via BanIdentity(). + * @return Plugin_Handled to block the actual server banning. + */ +forward Action OnBanIdentity(const char[] identity, + int time, + int flags, + const char[] reason, + const char[] command, + any source); + +/** + * Called for calls to RemoveBan() with a non-empty command. + * + * @param identity Identity string being banned (authstring or ip). + * @param flags Ban flags (only IP or AUTHID are valid here). + * @param command Command string to identify the ban source. + * @param source Source value passed via BanIdentity(). + * @return Plugin_Handled to block the actual unbanning. + */ +forward Action OnRemoveBan(const char[] identity, + int flags, + const char[] command, + any source); + +/** + * Bans a client. + * + * @param client Client being banned. + * @param time Time (in minutes) to ban (0 = permanent). + * @param flags Flags for controlling the ban mechanism. If AUTHID + * is set and no AUTHID is available, the ban will fail + * unless AUTO is also flagged. + * @param reason Reason to ban the client for. + * @param kick_message Message to display to the user when kicking. + * @param command Command string to identify the source. If this is left + * empty, then the OnBanClient forward will not be called. + * @param source A source value that could be interpreted as a player + * index of any sort (not actually checked by Core). + * @return True on success, false on failure. + * @error Invalid client index or client not in game. + */ +native bool BanClient(int client, + int time, + int flags, + const char[] reason, + const char[] kick_message="", + const char[] command="", + any source=0); + +/** + * Bans an identity (either an IP address or auth string). + * + * @param identity String to ban (ip or authstring). + * @param time Time to ban for (0 = permanent). + * @param flags Flags (only IP and AUTHID are valid flags here). + * @param reason Ban reason string. + * @param command Command string to identify the source. If this is left + * empty, then the OnBanIdentity forward will not be called. + * @param source A source value that could be interpreted as a player + * index of any sort (not actually checked by Core). + * @return True on success, false on failure. + */ +native bool BanIdentity(const char[] identity, + int time, + int flags, + const char[] reason, + const char[] command="", + any source=0); + +/** + * Removes a ban that was written to the server (either in memory or on disk). + * + * @param identity String to unban (ip or authstring). + * @param flags Flags (only IP and AUTHID are valid flags here). + * @param command Command string to identify the source. If this is left + * empty, then OnRemoveBan will not be called. + * @param source A source value that could be interpreted as a player + * index of any sort (not actually checked by Core). + * @return True on success, false on failure. + */ +native bool RemoveBan(const char[] identity, + int flags, + const char[] command="", + any source=0); diff --git a/scripting/include/basecomm.inc b/scripting/include/basecomm.inc new file mode 100644 index 0000000..54545c8 --- /dev/null +++ b/scripting/include/basecomm.inc @@ -0,0 +1,109 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _basecomm_included + #endinput +#endif +#define _basecomm_included + +/** + * Called when a client is muted or unmuted + * + * @param client Client index + * @param muteState True if client was muted, false otherwise + */ + forward void BaseComm_OnClientMute(int client, bool muteState); + + /** + * Called when a client is gagged or ungagged + * + * @param client Client index + * @param gagState True if client was gaged, false otherwise + */ + forward void BaseComm_OnClientGag(int client, bool gagState); + +/** + * Returns whether or not a client is gagged + * + * @param client Client index. + * @return True if client is gagged, false otherwise. + */ +native bool BaseComm_IsClientGagged(int client); + +/** + * Returns whether or not a client is muted + * + * @param client Client index. + * @return True if client is muted, false otherwise. + */ +native bool BaseComm_IsClientMuted(int client); + +/** + * Sets a client's gag state + * + * @param client Client index. + * @param gagState True to gag client, false to ungag. + * @return True if this caused a change in gag state, false otherwise. + */ +native bool BaseComm_SetClientGag(int client, bool gagState); + +/** + * Sets a client's mute state + * + * @param client Client index. + * @param muteState True to mute client, false to unmute. + * @return True if this caused a change in mute state, false otherwise. + */ +native bool BaseComm_SetClientMute(int client, bool muteState); + +/* DO NOT EDIT BELOW THIS LINE */ + +public SharedPlugin __pl_basecomm = +{ + name = "basecomm", + file = "basecomm.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_basecomm_SetNTVOptional() +{ + MarkNativeAsOptional("BaseComm_IsClientGagged"); + MarkNativeAsOptional("BaseComm_IsClientMuted"); + MarkNativeAsOptional("BaseComm_SetClientGag"); + MarkNativeAsOptional("BaseComm_SetClientMute"); +} +#endif diff --git a/scripting/include/bitbuffer.inc b/scripting/include/bitbuffer.inc new file mode 100644 index 0000000..1de58a5 --- /dev/null +++ b/scripting/include/bitbuffer.inc @@ -0,0 +1,470 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _bitbuffer_included + #endinput +#endif +#define _bitbuffer_included + +methodmap BfWrite < Handle +{ + // Writes a single bit to a writable bitbuffer (bf_write). + // + // @param bit Bit to write (true for 1, false for 0). + public native void WriteBool(bool bit); + + // Writes a byte to a writable bitbuffer (bf_write). + // + // @param byte Byte to write (value will be written as 8bit). + public native void WriteByte(int byte); + + // Writes a byte to a writable bitbuffer (bf_write). + // + // @param chr Character to write. + public native void WriteChar(int chr); + + // Writes a 16bit integer to a writable bitbuffer (bf_write). + // + // @param num Integer to write (value will be written as 16bit). + public native void WriteShort(int num); + + // Writes a 16bit unsigned integer to a writable bitbuffer (bf_write). + // + // @param num Integer to write (value will be written as 16bit). + public native void WriteWord(int num); + + // Writes a normal integer to a writable bitbuffer (bf_write). + // + // @param num Integer to write (value will be written as 32bit). + public native void WriteNum(int num); + + // Writes a floating point number to a writable bitbuffer (bf_write). + // + // @param num Number to write. + public native void WriteFloat(float num); + + // Writes a string to a writable bitbuffer (bf_write). + // + // @param string Text string to write. + public native void WriteString(const char[] string); + + // Writes an entity to a writable bitbuffer (bf_write). + // + // @param ent Entity index to write. + public native void WriteEntity(int ent); + + // Writes a bit angle to a writable bitbuffer (bf_write). + // + // @param angle Angle to write. + // @param numBits Optional number of bits to use. + public native void WriteAngle(float angle, int numBits=8); + + // Writes a coordinate to a writable bitbuffer (bf_write). + // + // @param coord Coordinate to write. + public native void WriteCoord(float coord); + + // Writes a 3D vector of coordinates to a writable bitbuffer (bf_write). + // + // @param coord Coordinate array to write. + public native void WriteVecCoord(float coord[3]); + + // Writes a 3D normal vector to a writable bitbuffer (bf_write). + // + // @param vec Vector to write. + public native void WriteVecNormal(float vec[3]); + + // Writes a 3D angle vector to a writable bitbuffer (bf_write). + // + // @param angles Angle vector to write. + public native void WriteAngles(float angles[3]); +}; + +methodmap BfRead < Handle +{ + // Reads a single bit from a readable bitbuffer (bf_read). + // + // @return Bit value read. + public native bool ReadBool(); + + // Reads a byte from a readable bitbuffer (bf_read). + // + // @return Byte value read (read as 8bit). + public native int ReadByte(); + + // Reads a character from a readable bitbuffer (bf_read). + // + // @return Character value read. + public native int ReadChar(); + + // Reads a 16bit integer from a readable bitbuffer (bf_read). + // + // @param bf bf_read handle to read from. + // @return Integer value read (read as 16bit). + public native int ReadShort(); + + // Reads a 16bit unsigned integer from a readable bitbuffer (bf_read). + // + // @param bf bf_read handle to read from. + // @return Integer value read (read as 16bit). + public native int ReadWord(); + + // Reads a normal integer to a readable bitbuffer (bf_read). + // + // @return Integer value read (read as 32bit). + public native int ReadNum(); + + // Reads a floating point number from a readable bitbuffer (bf_read). + // + // @return Floating point value read. + public native float ReadFloat(); + + // Reads a string from a readable bitbuffer (bf_read). + // + // @param buffer Destination string buffer. + // @param maxlength Maximum length of output string buffer. + // @param line If true the buffer will be copied until it reaches a '\n' or a null terminator. + // @return Number of bytes written to the buffer. If the bitbuffer stream overflowed, + // that is, had no terminator before the end of the stream, then a negative + // number will be returned equal to the number of characters written to the + // buffer minus 1. The buffer will be null terminated regardless of the + // return value. + public native int ReadString(char[] buffer, int maxlength, bool line=false); + + // Reads an entity from a readable bitbuffer (bf_read). + // + // @return Entity index read. + public native int ReadEntity(); + + // Reads a bit angle from a readable bitbuffer (bf_read). + // + // @param numBits Optional number of bits to use. + // @return Angle read. + public native float ReadAngle(int numBits=8); + + // Reads a coordinate from a readable bitbuffer (bf_read). + // + // @return Coordinate read. + public native float ReadCoord(); + + // Reads a 3D vector of coordinates from a readable bitbuffer (bf_read). + // + // @param coord Destination coordinate array. + public native void ReadVecCoord(float coord[3]); + + // Reads a 3D normal vector from a readable bitbuffer (bf_read). + // + // @param vec Destination vector array. + public native void ReadVecNormal(float vec[3]); + + // Reads a 3D angle vector from a readable bitbuffer (bf_read). + // + // @param angles Destination angle vector. + public native void ReadAngles(float angles[3]); + + // Returns the number of bytes left in a readable bitbuffer (bf_read). + property int BytesLeft { + public native get(); + } +}; + +/** + * Writes a single bit to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param bit Bit to write (true for 1, false for 0). + * @error Invalid or incorrect Handle. + */ +native void BfWriteBool(Handle bf, bool bit); + +/** + * Writes a byte to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param byte Byte to write (value will be written as 8bit). + * @error Invalid or incorrect Handle. + */ +native void BfWriteByte(Handle bf, int byte); + +/** + * Writes a byte to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param chr Character to write. + * @error Invalid or incorrect Handle. + */ +native void BfWriteChar(Handle bf, int chr); + +/** + * Writes a 16bit integer to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Integer to write (value will be written as 16bit). + * @error Invalid or incorrect Handle. + */ +native void BfWriteShort(Handle bf, int num); + +/** + * Writes a 16bit unsigned integer to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Integer to write (value will be written as 16bit). + * @error Invalid or incorrect Handle. + */ +native void BfWriteWord(Handle bf, int num); + +/** + * Writes a normal integer to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Integer to write (value will be written as 32bit). + * @error Invalid or incorrect Handle. + */ +native void BfWriteNum(Handle bf, int num); + +/** + * Writes a floating point number to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param num Number to write. + * @error Invalid or incorrect Handle. + */ +native void BfWriteFloat(Handle bf, float num); + +/** + * Writes a string to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param string Text string to write. + * @error Invalid or incorrect Handle. + */ +native void BfWriteString(Handle bf, const char[] string); + +/** + * Writes an entity to a writable bitbuffer (bf_write). + * @note This is a wrapper around BfWriteShort(). + * + * @param bf bf_write handle to write to. + * @param ent Entity index to write. + * @error Invalid or incorrect Handle, or invalid entity. + */ +native void BfWriteEntity(Handle bf, int ent); + +/** + * Writes a bit angle to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param angle Angle to write. + * @param numBits Optional number of bits to use. + * @error Invalid or incorrect Handle. + */ +native void BfWriteAngle(Handle bf, float angle, int numBits=8); + +/** + * Writes a coordinate to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param coord Coordinate to write. + * @error Invalid or incorrect Handle. + */ +native void BfWriteCoord(Handle bf, float coord); + +/** + * Writes a 3D vector of coordinates to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param coord Coordinate array to write. + * @error Invalid or incorrect Handle. + */ +native void BfWriteVecCoord(Handle bf, float coord[3]); + +/** + * Writes a 3D normal vector to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param vec Vector to write. + * @error Invalid or incorrect Handle. + */ +native void BfWriteVecNormal(Handle bf, float vec[3]); + +/** + * Writes a 3D angle vector to a writable bitbuffer (bf_write). + * + * @param bf bf_write handle to write to. + * @param angles Angle vector to write. + * @error Invalid or incorrect Handle. + */ +native void BfWriteAngles(Handle bf, float angles[3]); + +/** + * Reads a single bit from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Bit value read. + * @error Invalid or incorrect Handle. + */ +native bool BfReadBool(Handle bf); + +/** + * Reads a byte from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Byte value read (read as 8bit). + * @error Invalid or incorrect Handle. + */ +native int BfReadByte(Handle bf); + +/** + * Reads a character from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Character value read. + * @error Invalid or incorrect Handle. + */ +native int BfReadChar(Handle bf); + +/** + * Reads a 16bit integer from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Integer value read (read as 16bit). + * @error Invalid or incorrect Handle. + */ +native int BfReadShort(Handle bf); + +/** + * Reads a 16bit unsigned integer from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Integer value read (read as 16bit). + * @error Invalid or incorrect Handle. + */ +native int BfReadWord(Handle bf); + +/** + * Reads a normal integer to a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Integer value read (read as 32bit). + * @error Invalid or incorrect Handle. + */ +native int BfReadNum(Handle bf); + +/** + * Reads a floating point number from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Floating point value read. + * @error Invalid or incorrect Handle. + */ +native float BfReadFloat(Handle bf); + +/** + * Reads a string from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param line If true the buffer will be copied until it reaches a '\n' or a null terminator. + * @return Number of bytes written to the buffer. If the bitbuffer stream overflowed, + * that is, had no terminator before the end of the stream, then a negative + * number will be returned equal to the number of characters written to the + * buffer minus 1. The buffer will be null terminated regardless of the + * return value. + * @error Invalid or incorrect Handle. + */ +native int BfReadString(Handle bf, char[] buffer, int maxlength, bool line=false); + +/** + * Reads an entity from a readable bitbuffer (bf_read). + * @note This is a wrapper around BfReadShort(). + * + * @param bf bf_read handle to read from. + * @return Entity index read. + * @error Invalid or incorrect Handle. + */ +native int BfReadEntity(Handle bf); + +/** + * Reads a bit angle from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param numBits Optional number of bits to use. + * @return Angle read. + * @error Invalid or incorrect Handle. + */ +native float BfReadAngle(Handle bf, int numBits=8); + +/** + * Reads a coordinate from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Coordinate read. + * @error Invalid or incorrect Handle. + */ +native float BfReadCoord(Handle bf); + +/** + * Reads a 3D vector of coordinates from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param coord Destination coordinate array. + * @error Invalid or incorrect Handle. + */ +native void BfReadVecCoord(Handle bf, float coord[3]); + +/** + * Reads a 3D normal vector from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param vec Destination vector array. + * @error Invalid or incorrect Handle. + */ +native void BfReadVecNormal(Handle bf, float vec[3]); + +/** + * Reads a 3D angle vector from a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @param angles Destination angle vector. + * @error Invalid or incorrect Handle. + */ +native void BfReadAngles(Handle bf, float angles[3]); + +/** + * Returns the number of bytes left in a readable bitbuffer (bf_read). + * + * @param bf bf_read handle to read from. + * @return Number of bytes left unread. + * @error Invalid or incorrect Handle. + */ +native int BfGetNumBytesLeft(Handle bf); diff --git a/scripting/include/clientprefs.inc b/scripting/include/clientprefs.inc new file mode 100644 index 0000000..bdd6e53 --- /dev/null +++ b/scripting/include/clientprefs.inc @@ -0,0 +1,282 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _clientprefs_included + #endinput +#endif +#define _clientprefs_included + +/** + * Cookie access types for client viewing + */ +enum CookieAccess +{ + CookieAccess_Public, /**< Visible and Changeable by users */ + CookieAccess_Protected, /**< Read only to users */ + CookieAccess_Private, /**< Completely hidden cookie */ +}; + +/** + * Cookie Prefab menu types + */ +enum CookieMenu +{ + CookieMenu_YesNo, /**< Yes/No menu with "yes"/"no" results saved into the cookie */ + CookieMenu_YesNo_Int, /**< Yes/No menu with 1/0 saved into the cookie */ + CookieMenu_OnOff, /**< On/Off menu with "on"/"off" results saved into the cookie */ + CookieMenu_OnOff_Int, /**< On/Off menu with 1/0 saved into the cookie */ +}; + +enum CookieMenuAction +{ + /** + * An option is being drawn for a menu. + * + * INPUT : Client index and data if available. + * OUTPUT: Buffer for rendering, maxlength of buffer. + */ + CookieMenuAction_DisplayOption = 0, + + /** + * A menu option has been selected. + * + * INPUT : Client index and any data if available. + */ + CookieMenuAction_SelectOption = 1, +}; + +/** + * Note: + * + * A successful return value/result on any client prefs native only guarantees that the local cache has been updated. + * Database connection problems can still prevent the data from being permanently saved. Connection problems will be logged as + * errors by the clientprefs extension. + */ + +/** + * Creates a new Client preference cookie. + * + * Handles returned by RegClientCookie can be closed via CloseHandle() when + * no longer needed. + * + * @param name Name of the new preference cookie. + * @param description Optional description of the preference cookie. + * @param access What CookieAccess level to assign to this cookie. + * @return A handle to the newly created cookie. If the cookie already + * exists, a handle to it will still be returned. + * @error Cookie name is blank. + */ +native Handle RegClientCookie(const char[] name, const char[] description, CookieAccess access); + +/** + * Searches for a Client preference cookie. + * + * Handles returned by FindClientCookie can be closed via CloseHandle() when + * no longer needed. + * + * @param name Name of cookie to find. + * @return A handle to the cookie if it is found. INVALID_HANDLE otherwise. + */ +native Handle FindClientCookie(const char[] name); + +/** + * Set the value of a Client preference cookie. + * + * @param client Client index. + * @param cookie Client preference cookie handle. + * @param value String value to set. + * @error Invalid cookie handle or invalid client index. + */ +native void SetClientCookie(int client, Handle cookie, const char[] value); + +/** + * Retrieve the value of a Client preference cookie. + * + * @param client Client index. + * @param cookie Client preference cookie handle. + * @param buffer Copyback buffer for value. + * @param maxlen Maximum length of the buffer. + * @error Invalid cookie handle or invalid client index. + */ +native void GetClientCookie(int client, Handle cookie, char[] buffer, int maxlen); + +/** + * Sets the value of a Client preference cookie based on an authID string. + * + * @param authID String Auth/STEAM ID of player to set. + * @param cookie Client preference cookie handle. + * @param value String value to set. + * @error Invalid cookie handle. + */ +native void SetAuthIdCookie(const char[] authID, Handle cookie, const char[] value); + +/** + * Checks if a clients cookies have been loaded from the database. + * + * @param client Client index. + * @return True if loaded, false otherwise. + * @error Invalid client index. + */ +native bool AreClientCookiesCached(int client); + +/** + * Called once a client's saved cookies have been loaded from the database. + * + * @param client Client index. + */ +forward void OnClientCookiesCached(int client); + +/** + * Cookie Menu Callback prototype + * + * @param client Client index. + * @param action CookieMenuAction being performed. + * @param info Info data passed. + * @param buffer Outbut buffer. + * @param maxlen Max length of the output buffer. + */ +typedef CookieMenuHandler = function void ( + int client, + CookieMenuAction action, + any info, + char[] buffer, + int maxlen +); + +/** + * Add a new prefab item to the client cookie settings menu. + * + * Note: This handles everything automatically and does not require a callback + * + * @param cookie Client preference cookie handle. + * @param type A CookieMenu prefab menu type. + * @param display Text to show on the menu. + * @param handler Optional handler callback for translations and output on selection + * @param info Info data to pass to the callback. + * @error Invalid cookie handle. + */ +native void SetCookiePrefabMenu(Handle cookie, CookieMenu type, const char[] display, CookieMenuHandler handler=INVALID_FUNCTION, any info=0); + +/** + * Adds a new item to the client cookie settings menu. + * + * Note: This only adds the top level menu item. You need to handle any submenus from the callback. + * + * @param handler A MenuHandler callback function. + * @param info Data to pass to the callback. + * @param display Text to show on the menu. + * @error Invalid cookie handle. + */ +native void SetCookieMenuItem(CookieMenuHandler handler, any info, const char[] display); + +/** + * Displays the settings menu to a client. + * + * @param client Client index. + */ +native void ShowCookieMenu(int client); + +/** + * Gets a cookie iterator. Must be freed with CloseHandle(). + * + * @return A new cookie iterator. + */ +native Handle GetCookieIterator(); + +/** + * Reads a cookie iterator, then advances to the next cookie if any. + * + * @param iter Cookie iterator Handle. + * @param name Name buffer. + * @param nameLen Name buffer size. + * @param access Access level of the cookie. + * @param desc Cookie description buffer. + * @param descLen Cookie description buffer size. + * @return True on success, false if there are no more commands. + */ +native bool ReadCookieIterator(Handle iter, + char[] name, + int nameLen, + CookieAccess &access, + char[] desc="", + int descLen=0); + +/** + * Returns the access level of a cookie + * + * @param cookie Client preference cookie handle. + * @return CookieAccess access level. + * @error Invalid cookie handle. + */ +native CookieAccess GetCookieAccess(Handle cookie); + +/** + * Returns the last updated timestamp for a client cookie + * + * @param client Client index. + * @param cookie Cookie handle. + * @return Last updated timestamp. + */ +native int GetClientCookieTime(int client, Handle cookie); + +/** + * Do not edit below this line! + */ +public Extension __ext_cprefs = +{ + name = "Client Preferences", + file = "clientprefs.ext", + autoload = 1, +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public void __ext_cprefs_SetNTVOptional() +{ + MarkNativeAsOptional("RegClientCookie"); + MarkNativeAsOptional("FindClientCookie"); + MarkNativeAsOptional("SetClientCookie"); + MarkNativeAsOptional("GetClientCookie"); + MarkNativeAsOptional("AreClientCookiesCached"); + MarkNativeAsOptional("SetCookiePrefabMenu"); + MarkNativeAsOptional("SetCookieMenuItem"); + MarkNativeAsOptional("ShowCookieMenu"); + MarkNativeAsOptional("GetCookieIterator"); + MarkNativeAsOptional("ReadCookieIterator"); + MarkNativeAsOptional("GetCookieAccess"); + MarkNativeAsOptional("GetClientCookieTime"); +} +#endif diff --git a/scripting/include/clients.inc b/scripting/include/clients.inc new file mode 100644 index 0000000..77bb236 --- /dev/null +++ b/scripting/include/clients.inc @@ -0,0 +1,811 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _clients_included + #endinput +#endif +#define _clients_included + +/** + * Network flow directions. + */ +enum NetFlow +{ + NetFlow_Outgoing = 0, /**< Outgoing traffic */ + NetFlow_Incoming, /**< Incoming traffic */ + NetFlow_Both, /**< Both values added together */ +}; + +/** + * Auth string types. + * + * Note that for the Steam2 and Steam3 types, the following ids are + * also valid values: + * "STEAM_ID_PENDING" - Authentication is pending. + * "STEAM_ID_LAN" - Authentication is disabled because of being on a LAN server. + * "BOT" - The client is a bot. + */ +enum AuthIdType +{ + AuthId_Engine = 0, /**< The game-specific auth string as returned from the engine */ + + // The following are only available on games that support Steam authentication. + AuthId_Steam2, /**< Steam2 rendered format, ex "STEAM_1:1:4153990" */ + AuthId_Steam3, /**< Steam3 rendered format, ex "[U:1:8307981]" */ + AuthId_SteamID64, /**< A SteamID64 (uint64) as a String, ex "76561197968573709" */ +}; + +/** + * MAXPLAYERS is not the same as MaxClients. + * MAXPLAYERS is a hardcoded value as an upper limit. MaxClients changes based on the server. + */ + +#define MAXPLAYERS 65 /**< Maximum number of players SourceMod supports */ +#define MAX_NAME_LENGTH 32 /**< Maximum buffer required to store a client name */ + +public const int MaxClients; /**< Maximum number of players the server supports (dynamic) */ + +/** + * Called on client connection. If you return true, the client will be allowed in the server. + * If you return false (or return nothing), the client will be rejected. If the client is + * rejected by this forward or any other, OnClientDisconnect will not be called. + * + * Note: Do not write to rejectmsg if you plan on returning true. If multiple plugins write + * to the string buffer, it is not defined which plugin's string will be shown to the client, + * but it is guaranteed one of them will. + * + * @param client Client index. + * @param rejectmsg Buffer to store the rejection message when the connection is refused. + * @param maxlen Maximum number of characters for rejection buffer. + * @return True to validate client's connection, false to refuse it. + */ +forward bool OnClientConnect(int client, char[] rejectmsg, int maxlen); + +/** + * Called once a client successfully connects. This callback is paired with OnClientDisconnect. + * + * @param client Client index. + */ +forward void OnClientConnected(int client); + +/** + * Called when a client is entering the game. + * + * Whether a client has a steamid is undefined until OnClientAuthorized + * is called, which may occur either before or after OnClientPutInServer. + * Similarly, use OnClientPostAdminCheck() if you need to verify whether + * connecting players are admins. + * + * GetClientCount() will include clients as they are passed through this + * function, as clients are already in game at this point. + * + * @param client Client index. + */ +forward void OnClientPutInServer(int client); + +/** + * Called when a client is disconnecting from the server. + * + * @param client Client index. + */ +forward void OnClientDisconnect(int client); + +/** + * Called when a client is disconnected from the server. + * + * @param client Client index. + */ +forward void OnClientDisconnect_Post(int client); + +/** + * Called when a client is sending a command. + * + * As of SourceMod 1.3, the client is guaranteed to be in-game. + * Use command listeners (console.inc) for more advanced hooks. + * + * @param client Client index. + * @param args Number of arguments. + * @return Plugin_Handled blocks the command from being sent, + * and Plugin_Continue resumes normal functionality. + */ +forward Action OnClientCommand(int client, int args); + +/** + * Called when a client is sending a KeyValues command. + * + * @param client Client index. + * @param kv Editable KeyValues data to be sent as the command. + * (This handle should not be stored and will be closed + * after this forward completes.) + * @return Plugin_Handled blocks the command from being sent, + * and Plugin_Continue resumes normal functionality. + */ +forward Action OnClientCommandKeyValues(int client, KeyValues kv); + +/** + * Called after a client has sent a KeyValues command. + * + * @param client Client index. + * @param kv KeyValues data sent as the command. + * (This handle should not be stored and will be closed + * after this forward completes.) + */ +forward void OnClientCommandKeyValues_Post(int client, KeyValues kv); + +/** + * Called whenever the client's settings are changed. + * + * @param client Client index. + */ +forward void OnClientSettingsChanged(int client); + +/** + * Called when a client receives an auth ID. The state of a client's + * authorization as an admin is not guaranteed here. Use + * OnClientPostAdminCheck() if you need a client's admin status. + * + * This is called by bots, but the ID will be "BOT". + * + * @param client Client index. + * @param auth Client Steam2 id, if available, else engine auth id. + */ +forward void OnClientAuthorized(int client, const char[] auth); + +/** + * Called once a client is authorized and fully in-game, but + * before admin checks are done. This can be used to override + * the default admin checks for a client. You should only use + * this for overriding; use OnClientPostAdminCheck() instead + * if you want notification. + * + * Note: If handled/blocked, PostAdminCheck must be signalled + * manually via NotifyPostAdminCheck(). + * + * This callback is guaranteed to occur on all clients, and always + * after each OnClientPutInServer() call. + * + * @param client Client index. + * @return Plugin_Handled to block admin checks. + */ +forward Action OnClientPreAdminCheck(int client); + +/** + * Called directly before OnClientPostAdminCheck() as a method to + * alter administrative permissions before plugins perform final + * post-connect operations. + * + * In general, do not use this function unless you are specifically + * attempting to change access permissions. Use OnClientPostAdminCheck() + * instead if you simply want to perform post-connect authorization + * routines. + * + * See OnClientPostAdminCheck() for more information. + * + * @param client Client index. + */ +forward void OnClientPostAdminFilter(int client); + +/** + * Called once a client is authorized and fully in-game, and + * after all post-connection authorizations have been performed. + * + * This callback is guaranteed to occur on all clients, and always + * after each OnClientPutInServer() call. + * + * @param client Client index. + */ +forward void OnClientPostAdminCheck(int client); + +/** + * This function will be deprecated in a future release. Use the MaxClients variable instead. + * + * Returns the maximum number of clients allowed on the server. This may + * return 0 if called before OnMapStart(), and thus should not be called + * in OnPluginStart(). + * + * You should not globally cache the value to GetMaxClients() because it can change from + * SourceTV or TF2's arena mode. Use the "MaxClients" dynamic variable documented at the + * top of this file. + * + * @return Maximum number of clients allowed. + */ +native int GetMaxClients(); + +/** + * Returns the maximum number of human players allowed on the server. This is + * a game-specific function used on newer games to limit the number of humans + * that can join a game and can be lower than MaxClients. It is the number often + * reflected in the server browser or when viewing the output of the status command. + * On unsupported games or modes without overrides, it will return the same value + * as MaxClients. + * + * You should not globally cache the value to GetMaxHumanPlayers() because it can change across + * game modes. You may still cache it locally. + * + * @return Maximum number of humans allowed. + */ +native int GetMaxHumanPlayers(); + +/** + * Returns the client count put in the server. + * + * @param inGameOnly If false connecting players are also counted. + * @return Client count in the server. + */ +native int GetClientCount(bool inGameOnly=true); + +/** + * Returns the client's name. + * + * @param client Player index. + * @param name Buffer to store the client's name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @return True on success, false otherwise. + * @error If the client is not connected an error will be thrown. + */ +native bool GetClientName(int client, char[] name, int maxlen); + +/** + * Retrieves a client's IP address. + * + * @param client Player index. + * @param ip Buffer to store the client's ip address. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param remport Remove client's port from the ip string (true by default). + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. + */ +native bool GetClientIP(int client, char[] ip, int maxlen, bool remport=true); + +/** + * Retrieves a client's authentication string (SteamID). + * + * @param client Player index. + * @param auth Buffer to store the client's auth string. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param validate Check backend validation status. + * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, + * You WILL KNOW if you need to use this, MOST WILL NOT. + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. + */ +#pragma deprecated Use GetClientAuthId +native bool GetClientAuthString(int client, char[] auth, int maxlen, bool validate=true); + +/** + * Retrieves a client's authentication string (SteamID). + * + * @param client Player index. + * @param authType Auth id type and format to use. + * @param auth Buffer to store the client's auth id. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param validate Check backend validation status. + * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, + * You WILL KNOW if you need to use this, MOST WILL NOT. + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. + */ +native bool GetClientAuthId(int client, AuthIdType authType, char[] auth, int maxlen, bool validate=true); + +/** + * Returns the client's Steam account ID, a number uniquely identifying a given Steam account. + * This number is the basis for the various display SteamID forms, see the AuthIdType enum for examples. + * + * @param client Client Index. + * @param validate Check backend validation status. + * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, + * You WILL KNOW if you need to use this, MOST WILL NOT. + * @return Steam account ID or 0 if not available. + * @error If the client is not connected or the index is invalid. + */ +native int GetSteamAccountID(int client, bool validate=true); + +/** + * Retrieves a client's user id, which is an index incremented for every client + * that joins the server. + * + * @param client Player index. + * @return User id of the client. + * @error If the client is not connected or the index is invalid. + */ +native int GetClientUserId(int client); + +/** + * Returns if a certain player is connected. + * + * @param client Player index. + * @return True if player is connected to the server, false otherwise. + */ +native bool IsClientConnected(int client); + +/** + * Returns if a certain player has entered the game. + * + * @param client Player index (index does not have to be connected). + * @return True if player has entered the game, false otherwise. + * @error Invalid client index. + */ +native bool IsClientInGame(int client); + +/** + * Returns if a client is in the "kick queue" (i.e. the client will be kicked + * shortly and thus they should not appear as valid). + * + * @param client Player index (must be connected). + * @return True if in the kick queue, false otherwise. + * @error Invalid client index. + */ +native bool IsClientInKickQueue(int client); + +/** + * Backwards compatibility stock - use IsClientInGame + * @deprecated Renamed to IsClientInGame + */ +#pragma deprecated Use IsClientInGame() instead +stock bool IsPlayerInGame(int client) +{ + return IsClientInGame(client); +} + +/** + * Returns if a certain player has been authenticated. + * + * @param client Player index. + * @return True if player has been authenticated, false otherwise. + */ +native bool IsClientAuthorized(int client); + +/** + * Returns if a certain player is a fake client. + * + * @param client Player index. + * @return True if player is a fake client, false otherwise. + */ +native bool IsFakeClient(int client); + +/** + * Returns if a certain player is the SourceTV bot. + * + * @param client Player index. + * @return True if player is the SourceTV bot, false otherwise. + */ +native bool IsClientSourceTV(int client); + +/** + * Returns if a certain player is the Replay bot. + * + * @param client Player index. + * @return True if player is the Replay bot, false otherwise. + */ +native bool IsClientReplay(int client); + +/** + * Returns if a certain player is an observer/spectator. + * + * @param client Player index. + * @return True if player is an observer, false otherwise. + */ +native bool IsClientObserver(int client); + +/** + * Returns if the client is alive or dead. + * + * Note: This function was originally in SDKTools and was moved to core. + * + * @param client Player's index. + * @return True if the client is alive, false otherwise. + * @error Invalid client index, client not in game, or no mod support. + */ +native bool IsPlayerAlive(int client); + +/** + * Retrieves values from client replicated keys. + * + * @param client Player's index. + * @param key Key string. + * @param value Buffer to store value. + * @param maxlen Maximum length of valve (UTF-8 safe). + * @return True on success, false otherwise. + * @error Invalid client index, or client not connected. + */ +native bool GetClientInfo(int client, const char[] key, char[] value, int maxlen); + +/** + * Retrieves a client's team index. + * + * @param client Player's index. + * @return Team index the client is on (mod specific). + * @error Invalid client index, client not in game, or no mod support. + */ +native int GetClientTeam(int client); + +/** + * Sets a client's AdminId. + * + * @param client Player's index. + * @param id AdminId to set. INVALID_ADMIN_ID removes admin permissions. + * @param temp True if the id should be freed on disconnect. + * @error Invalid client index, client not connected, or bogus AdminId. + */ +native void SetUserAdmin(int client, AdminId id, bool temp=false); + +/** + * Retrieves a client's AdminId. + * + * @param client Player's index. + * @return AdminId of the client, or INVALID_ADMIN_ID if none. + * @error Invalid client index, or client not connected. + */ +native AdminId GetUserAdmin(int client); + +/** + * Sets access flags on a client. If the client is not an admin, + * a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param ... Flags to set on the client. + * @error Invalid client index, or client not connected. + */ +native void AddUserFlags(int client, AdminFlag ...); + +/** + * Removes flags from a client. If the client is not an admin, + * this has no effect. + * + * @param client Player's index. + * @param ... Flags to remove from the client. + * @error Invalid client index, or client not connected. + */ +native void RemoveUserFlags(int client, AdminFlag ...); + +/** + * Sets access flags on a client using bits instead of flags. If the + * client is not an admin, and flags not 0, a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param flags Bitstring of flags to set on client. + */ +native void SetUserFlagBits(int client, int flags); + +/** + * Returns client access flags. If the client is not an admin, + * the result is always 0. + * + * @param client Player's index. + * @return Flags + * @error Invalid client index, or client not connected. + */ +native int GetUserFlagBits(int client); + +/** + * Returns whether a user can target another user. + * This is a helper function for CanAdminTarget. + * + * @param client Player's index. + * @param target Target player's index. + * @return True if target is targettable by the player, false otherwise. + * @error Invalid or unconnected player indexers. + */ +native bool CanUserTarget(int client, int target); + +/** + * Runs through the Core-defined admin authorization checks on a player. + * Has no effect if the player is already an admin. + * + * Note: This function is based on the internal cache only. + * + * @param client Client index. + * @return True if access was changed, false if it did not. + * @error Invalid client index or client not in-game AND authorized. + */ +native bool RunAdminCacheChecks(int client); + +/** + * Signals that a player has completed post-connection admin checks. + * Has no effect if the player has already had this event signalled. + * + * Note: This must be sent even if no admin id was assigned. + * + * @param client Client index. + * @error Invalid client index or client not in-game AND authorized. + */ +native void NotifyPostAdminCheck(int client); + +/** + * Creates a fake client. + * + * @param name Name to use. + * @return Client index on success, 0 otherwise. + */ +native int CreateFakeClient(const char[] name); + +/** + * Sets a convar value on a fake client. + * + * @param client Client index. + * @param cvar ConVar name. + * @param value ConVar value. + * @error Invalid client index, client not connected, + * or client not a fake client. + */ +native void SetFakeClientConVar(int client, const char[] cvar, const char[] value); + +/** + * Returns the client's health. + * + * @param client Player's index. + * @return Health value. + * @error Invalid client index, client not in game, or no mod support. + */ +native int GetClientHealth(int client); + +/** + * Returns the client's model name. + * + * @param client Player's index. + * @param model Buffer to store the client's model name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @error Invalid client index, client not in game, or no mod support. + */ +native void GetClientModel(int client, char[] model, int maxlen); + +/** + * Returns the client's weapon name. + * + * @param client Player's index. + * @param weapon Buffer to store the client's weapon name. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @error Invalid client index, client not in game, or no mod support. + */ +native void GetClientWeapon(int client, char[] weapon, int maxlen); + +/** + * Returns the client's max size vector. + * + * @param client Player's index. + * @param vec Destination vector to store the client's max size. + * @error Invalid client index, client not in game, or no mod support. + */ +native void GetClientMaxs(int client, float vec[3]); + +/** + * Returns the client's min size vector. + * + * @param client Player's index. + * @param vec Destination vector to store the client's min size. + * @error Invalid client index, client not in game, or no mod support. + */ +native void GetClientMins(int client, float vec[3]); + +/** + * Returns the client's position angle. + * + * @param client Player's index. + * @param ang Destination vector to store the client's position angle. + * @error Invalid client index, client not in game, or no mod support. + */ +native void GetClientAbsAngles(int client, float ang[3]); + +/** + * Returns the client's origin vector. + * + * @param client Player's index. + * @param vec Destination vector to store the client's origin vector. + * @error Invalid client index, client not in game, or no mod support. + */ +native void GetClientAbsOrigin(int client, float vec[3]); + +/** + * Returns the client's armor. + * + * @param client Player's index. + * @return Armor value. + * @error Invalid client index, client not in game, or no mod support. + */ +native int GetClientArmor(int client); + +/** + * Returns the client's death count. + * + * @param client Player's index. + * @return Death count. + * @error Invalid client index, client not in game, or no mod support. + */ +native int GetClientDeaths(int client); + +/** + * Returns the client's frag count. + * + * @param client Player's index. + * @return Frag count. + * @error Invalid client index, client not in game, or no mod support. + */ +native int GetClientFrags(int client); + +/** + * Returns the client's send data rate in bytes/sec. + * + * @param client Player's index. + * @return Data rate. + * @error Invalid client index, client not connected, or fake client. + */ +native int GetClientDataRate(int client); + +/** + * Returns if a client is timing out + * + * @param client Player's index. + * @return True if client is timing out, false otherwise. + * @error Invalid client index, client not connected, or fake client. + */ +native bool IsClientTimingOut(int client); + +/** + * Returns the client's connection time in seconds. + * + * @param client Player's index. + * @return Connection time. + * @error Invalid client index, client not connected, or fake client. + */ +native float GetClientTime(int client); + +/** + * Returns the client's current latency (RTT), more accurate than GetAvgLatency but jittering. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Latency, or -1 if network info is not available. + * @error Invalid client index, client not connected, or fake client. + */ +native float GetClientLatency(int client, NetFlow flow); + +/** + * Returns the client's average packet latency in seconds. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Latency, or -1 if network info is not available. + * @error Invalid client index, client not connected, or fake client. + */ +native float GetClientAvgLatency(int client, NetFlow flow); + +/** + * Returns the client's average packet loss, values go from 0 to 1 (for percentages). + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Average packet loss, or -1 if network info is not available. + * @error Invalid client index, client not connected, or fake client. + */ +native float GetClientAvgLoss(int client, NetFlow flow); + +/** + * Returns the client's average packet choke, values go from 0 to 1 (for percentages). + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Average packet loss, or -1 if network info is not available. + * @error Invalid client index, client not connected, or fake client. + */ +native float GetClientAvgChoke(int client, NetFlow flow); + +/** + * Returns the client's data flow in bytes/sec. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Data flow. + * @error Invalid client index, client not connected, or fake client. + */ +native float GetClientAvgData(int client, NetFlow flow); + +/** + * Returns the client's average packet frequency in packets/sec. + * + * @param client Player's index. + * @param flow Traffic flowing direction. + * @return Packet frequency. + * @error Invalid client index, client not connected, or fake client. + */ +native float GetClientAvgPackets(int client, NetFlow flow); + +/** + * Translates an userid index to the real player index. + * + * @param userid Userid value. + * @return Client value. + * @error Returns 0 if invalid userid. + */ +native int GetClientOfUserId(int userid); + +/** + * Disconnects a client from the server as soon as the next frame starts. + * + * Note: Originally, KickClient() was immediate. The delay was introduced + * because despite warnings, plugins were using it in ways that would crash. + * The new safe version can break cases that rely on immediate disconnects, + * but ensures that plugins do not accidentally cause crashes. + * + * If you need immediate disconnects, use KickClientEx(). + * + * Note: IsClientInKickQueue() will return true before the kick occurs. + * + * @param client Client index. + * @param format Optional formatting rules for disconnect reason. + * Note that a period is automatically appended to the string by the engine. + * @param ... Variable number of format parameters. + * @error Invalid client index, or client not connected. + */ +native void KickClient(int client, const char[] format="", any ...); + +/** + * Immediately disconnects a client from the server. + * + * Kicking clients from certain events or callbacks may cause crashes. If in + * doubt, create a short (0.1 second) timer to kick the client in the next + * available frame. + * + * @param client Client index. + * @param format Optional formatting rules for disconnect reason. + * Note that a period is automatically appended to the string by the engine. + * @param ... Variable number of format parameters. + * @error Invalid client index, or client not connected. + */ +native void KickClientEx(int client, const char[] format="", any ...); + +/** + * Changes a client's team through the mod's generic team changing function. + * On CS:S, this will kill the player. + * + * @param client Client index. + * @param team Mod-specific team index. + * @error Invalid client index, client not connected, or lack of + * mod support. + */ +native void ChangeClientTeam(int client, int team); + +/** + * Returns the clients unique serial identifier. + * + * @param client Client index. + * @return Serial number. + * @error Invalid client index, or client not connected. + */ +native int GetClientSerial(int client); + +/** + * Returns the client index by its serial number. + * + * @param serial Serial number. + * @return Client index, or 0 for invalid serial. + */ +native int GetClientFromSerial(int serial); diff --git a/scripting/include/commandfilters.inc b/scripting/include/commandfilters.inc new file mode 100644 index 0000000..67e1e5c --- /dev/null +++ b/scripting/include/commandfilters.inc @@ -0,0 +1,161 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _commandfilters_included + #endinput +#endif +#define _commandfilters_included + +#define MAX_TARGET_LENGTH 64 + +#define COMMAND_FILTER_ALIVE (1<<0) /**< Only allow alive players */ +#define COMMAND_FILTER_DEAD (1<<1) /**< Only filter dead players */ +#define COMMAND_FILTER_CONNECTED (1<<2) /**< Allow players not fully in-game */ +#define COMMAND_FILTER_NO_IMMUNITY (1<<3) /**< Ignore immunity rules */ +#define COMMAND_FILTER_NO_MULTI (1<<4) /**< Do not allow multiple target patterns */ +#define COMMAND_FILTER_NO_BOTS (1<<5) /**< Do not allow bots to be targetted */ + +#define COMMAND_TARGET_NONE 0 /**< No target was found */ +#define COMMAND_TARGET_NOT_ALIVE -1 /**< Single client is not alive */ +#define COMMAND_TARGET_NOT_DEAD -2 /**< Single client is not dead */ +#define COMMAND_TARGET_NOT_IN_GAME -3 /**< Single client is not in game */ +#define COMMAND_TARGET_IMMUNE -4 /**< Single client is immune */ +#define COMMAND_TARGET_EMPTY_FILTER -5 /**< A multi-filter (such as @all) had no targets */ +#define COMMAND_TARGET_NOT_HUMAN -6 /**< Target was not human */ +#define COMMAND_TARGET_AMBIGUOUS -7 /**< Partial name had too many targets */ + +/** + * Processes a generic command target string, and resolves it to a list + * of clients or one client, based on filtering rules and a pattern. + * + * Note that you should use LoadTranslations("common.phrases") in OnPluginStart(), + * as that file is guaranteed to contain all of the translatable phrases that + * ProcessTargetString() will return. + * + * @param pattern Pattern to find clients against. + * @param admin Admin performing the action, or 0 if the server. + * @param targets Array to hold targets. + * @param max_targets Maximum size of the targets array. + * @param filter_flags Filter flags. + * @param target_name Buffer to store the target name. + * @param tn_maxlength Maximum length of the target name buffer. + * @param tn_is_ml OUTPUT: Will be true if the target name buffer is an ML phrase, + * false if it is a normal string. + * @return If a multi-target pattern was used, the number of clients found + * is returned. If a single-target pattern was used, 1 is returned + * if one valid client is found. Otherwise, a COMMAND_TARGET reason + * for failure is returned. + */ +native int ProcessTargetString(const char[] pattern, + int admin, + int[] targets, + int max_targets, + int filter_flags, + char[] target_name, + int tn_maxlength, + bool &tn_is_ml); + +/** + * Replies to a client with a given message describing a targetting + * failure reason. + * + * Note: The translation phrases are found in common.phrases.txt. + * + * @param client Client index, or 0 for server. + * @param reason COMMAND_TARGET reason. + */ +stock void ReplyToTargetError(int client, int reason) +{ + switch (reason) + { + case COMMAND_TARGET_NONE: + { + ReplyToCommand(client, "[SM] %t", "No matching client"); + } + case COMMAND_TARGET_NOT_ALIVE: + { + ReplyToCommand(client, "[SM] %t", "Target must be alive"); + } + case COMMAND_TARGET_NOT_DEAD: + { + ReplyToCommand(client, "[SM] %t", "Target must be dead"); + } + case COMMAND_TARGET_NOT_IN_GAME: + { + ReplyToCommand(client, "[SM] %t", "Target is not in game"); + } + case COMMAND_TARGET_IMMUNE: + { + ReplyToCommand(client, "[SM] %t", "Unable to target"); + } + case COMMAND_TARGET_EMPTY_FILTER: + { + ReplyToCommand(client, "[SM] %t", "No matching clients"); + } + case COMMAND_TARGET_NOT_HUMAN: + { + ReplyToCommand(client, "[SM] %t", "Cannot target bot"); + } + case COMMAND_TARGET_AMBIGUOUS: + { + ReplyToCommand(client, "[SM] %t", "More than one client matched"); + } + } +} + +/** + * Adds clients to a multi-target filter. + * + * @param pattern Pattern name. + * @param clients Array to fill with unique, valid client indexes. + * @return True if pattern was recognized, false otherwise. + */ +typedef MultiTargetFilter = function bool (const char[] pattern, Handle clients); + +/** + * Adds a multi-target filter function for ProcessTargetString(). + * + * @param pattern Pattern to match (case sensitive). + * @param filter Filter function. + * @param phrase Descriptive phrase to display on successful match. + * @param phraseIsML True if phrase is multi-lingual, false otherwise. + */ +native void AddMultiTargetFilter(const char[] pattern, MultiTargetFilter filter, + const char[] phrase, bool phraseIsML); + +/** + * Removes a multi-target filter function from ProcessTargetString(). + * + * @param pattern Pattern to match (case sensitive). + * @param filter Filter function. + */ +native void RemoveMultiTargetFilter(const char[] pattern, MultiTargetFilter filter); diff --git a/scripting/include/commandline.inc b/scripting/include/commandline.inc new file mode 100644 index 0000000..5ff7d22 --- /dev/null +++ b/scripting/include/commandline.inc @@ -0,0 +1,86 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _commandline_included_ + #endinput +#endif +#define _commandline_included_ + +/** + * Gets the full command line the server was launched with. + * + * @param commandLine Buffer to store the command line in. + * @param maxlen Maximum length of the command line buffer. + * @return True if the command line is valid; otherwise, false. + * @error No command line available, or no mod support. + */ +native bool GetCommandLine(char[] commandLine, int maxlen); + +/** + * Gets the value of a command line parameter the server was launched with. + * + * @param param The command line parameter to get the value of. + * @param value Buffer to store the parameter value in. + * @param maxlen Maximum length of the value buffer. + * @param defValue The default value to return if the parameter wasn't specified. + * @error No command line available, or no mod support. + */ +native void GetCommandLineParam(const char[] param, char[] value, int maxlen, const char[] defValue=""); + +/** + * Gets the value of a command line parameter the server was launched with. + * + * @param param The command line parameter to get the value of. + * @param defValue The default value to return if the parameter wasn't specified. + * @return The integer value of the command line parameter value. + * @error No command line available, or no mod support. + */ +native int GetCommandLineParamInt(const char[] param, int defValue=0); + +/** + * Gets the value of a command line parameter the server was launched with. + * + * @param param The command line parameter to get the value of. + * @param defValue The default value to return if the parameter wasn't specified. + * @return The floating point value of the command line parameter value. + * @error No command line available, or no mod support. + */ +native float GetCommandLineParamFloat(const char[] param, float defValue=0.0); + +/** + * Determines if a specific command line parameter is present. + * + * @param param The command line parameter to test. + * @return True if the command line parameter is specified; otherwise, false. + * @error No command line available, or no mod support. + */ +native bool FindCommandLineParam(const char[] param); diff --git a/scripting/include/console.inc b/scripting/include/console.inc new file mode 100644 index 0000000..2ea3b5f --- /dev/null +++ b/scripting/include/console.inc @@ -0,0 +1,668 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _console_included + #endinput +#endif +#define _console_included + +#define INVALID_FCVAR_FLAGS (-1) + +/** + * Console variable query helper values. + */ +enum QueryCookie +{ + QUERYCOOKIE_FAILED = 0, +}; + +/** + * Reply sources for commands. + */ +enum ReplySource +{ + SM_REPLY_TO_CONSOLE = 0, + SM_REPLY_TO_CHAT = 1, +}; + +/** + * @section Flags for console commands and console variables. The descriptions + * for each constant come directly from the Source SDK. + */ + +#pragma deprecated No logic using this flag ever existed in a released game. It only ever appeared in the first hl2sdk. +#define FCVAR_PLUGIN 0 // Actual value is same as FCVAR_SS_ADDED in Left 4 Dead and later. +#pragma deprecated Did you mean FCVAR_DEVELOPMENTONLY? (No logic using this flag ever existed in a released game. It only ever appeared in the first hl2sdk.) +#define FCVAR_LAUNCHER (1<<1) // Same value as FCVAR_DEVELOPMENTONLY, which is what most usages of this were intending to use. + + +#define FCVAR_NONE 0 // The default, no flags at all +#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc. +#define FCVAR_DEVELOPMENTONLY (1<<1) // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined. (OB+) +#define FCVAR_GAMEDLL (1<<2) // Defined by the game DLL. +#define FCVAR_CLIENTDLL (1<<3) // Defined by the client DLL. +#define FCVAR_MATERIAL_SYSTEM (1<<4) // Defined by the material system. (EP1-only) +#define FCVAR_HIDDEN (1<<4) // Hidden. Doesn't appear in find or autocomplete. Like DEVELOPMENTONLY, but can't be compiled out.1 (OB+) +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. + // Sends 1 if it's not bland/zero, 0 otherwise as value. +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_ARCHIVE (1<<7) // Set to cause it to be saved to vars.rc +#define FCVAR_NOTIFY (1<<8) // Notifies players when changed. +#define FCVAR_USERINFO (1<<9) // Changes the client's info string. +#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters (e.g., used for player name, etc.) +#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NEVER_AS_STRING (1<<12) // Never try to print that cvar. +#define FCVAR_REPLICATED (1<<13) // Server setting enforced on clients. +#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats +#define FCVAR_SS (1<<15) // causes varnameN where N 2 through max splitscreen slots for mod to be autogenerated (L4D+) +#define FCVAR_DEMO (1<<16) // Record this cvar when starting a demo file. +#define FCVAR_DONTRECORD (1<<17) // Don't record these command in demo files. +#define FCVAR_SS_ADDED (1<<18) // This is one of the "added" FCVAR_SS variables for the splitscreen players (L4D+) +#define FCVAR_RELEASE (1<<19) // Cvars tagged with this are the only cvars available to customers (L4D+) +#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload (OB+) +#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload (OB+) +#define FCVAR_NOT_CONNECTED (1<<22) // Cvar cannot be changed by a client that is connected to a server. +#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread (OB+) +#define FCVAR_ARCHIVE_XBOX (1<<24) // Cvar written to config.cfg on the Xbox. +#define FCVAR_ARCHIVE_GAMECONSOLE (1<<24) // Cvar written to config.cfg on the Xbox. +#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) // used as a debugging tool necessary to check material system thread convars (OB+) +#define FCVAR_SERVER_CAN_EXECUTE (1<<28) // the server is allowed to execute this command on clients via + // ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd. (OB+) +#define FCVAR_SERVER_CANNOT_QUERY (1<<29) // If this is set, then the server is not allowed to query this cvar's value (via + // IServerPluginHelpers::StartQueryCvarValue). +#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command. + // Note: IVEngineClient::ClientCmd_Unrestricted can run any client command. + +/** + * @endsection + */ + +/** + * Executes a server command as if it were on the server console (or RCON) + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +native void ServerCommand(const char[] format, any ...); + +/** + * Executes a server command as if it were on the server console (or RCON) + * and stores the printed text into buffer. + * + * Warning: This calls ServerExecute internally and may have issues if + * certain commands are in the buffer, only use when you really need + * the response. + * Also, on L4D2 this will not print the command output to the server console. + * + * @param buffer String to store command result into. + * @param maxlen Length of buffer. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +native void ServerCommandEx(char[] buffer, int maxlen, const char[] format, any ...); + +/** + * Inserts a server command at the beginning of the server command buffer. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +native void InsertServerCommand(const char[] format, any ...); + +/** + * Executes every command in the server's command buffer, rather than once per frame. + */ +native void ServerExecute(); + +/** + * Executes a client command. Note that this will not work on clients unless + * they have cl_restrict_server_commands set to 0. + * + * @param client Index of the client. + * @param fmt Format of the client command. + * @param ... Format parameters + * @error Invalid client index, or client not connected. + */ +native void ClientCommand(int client, const char[] fmt, any ...); + +/** + * Executes a client command on the server without being networked. + * + * FakeClientCommand() overwrites the command tokenization buffer. This can + * cause undesired effects because future calls to GetCmdArg* will return + * data from the FakeClientCommand(), not the parent command. If you are in + * a hook where this matters (for example, a "say" hook), you should use + * FakeClientCommandEx() instead. + * + * @param client Index of the client. + * @param fmt Format of the client command. + * @param ... Format parameters + * @error Invalid client index, or client not connected. + */ +native void FakeClientCommand(int client, const char[] fmt, any ...); + +/** + * Executes a client command on the server without being networked. The + * execution of the client command is delayed by one frame to prevent any + * re-entrancy issues that might surface with FakeClientCommand(). + * + * @param client Index of the client. + * @param fmt Format of the client command. + * @param ... Format parameters + * @error Invalid client index, or client not connected. + */ +native void FakeClientCommandEx(int client, const char[] fmt, any ...); + +/** + * Executes a KeyValues client command on the server without being networked. + * + * @param client Index of the client. + * @param kv KeyValues data to be sent. + * @error Invalid client index, client not connected, + * or unsupported on current game. + */ +native void FakeClientCommandKeyValues(int client, KeyValues kv); + +/** + * Sends a message to the server console. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +native void PrintToServer(const char[] format, any ...); + +/** + * Sends a message to a client's console. + * + * @param client Client index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error If the client is not connected an error will be thrown. + */ +native void PrintToConsole(int client, const char[] format, any ...); + + +/** + * Sends a message to every client's console. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +stock void PrintToConsoleAll(const char[] format, any ...) +{ + char buffer[254]; + + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i)) + { + SetGlobalTransTarget(i); + VFormat(buffer, sizeof(buffer), format, 2); + PrintToConsole(i, "%s", buffer); + } + } +} + +/** + * Reples to a message in a command. + * + * A client index of 0 will use PrintToServer(). + * If the command was from the console, PrintToConsole() is used. + * If the command was from chat, PrintToChat() is used. + * + * @param client Client index, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error If the client is not connected or invalid. + */ +native void ReplyToCommand(int client, const char[] format, any ...); + +/** + * Returns the current reply source of a command. + * + * @return ReplySource value. + */ +native ReplySource GetCmdReplySource(); + +/** + * Sets the current reply source of a command. + * + * Only use this if you know what you are doing. You should save the old value + * and restore it once you are done. + * + * @param source New ReplySource value. + * @return Old ReplySource value. + */ +native ReplySource SetCmdReplySource(ReplySource source); + +/** + * Returns whether the current say hook is a chat trigger. + * + * This function is only meaningful inside say or say_team hooks. + * + * @return True if a chat trigger, false otherwise. + */ +native bool IsChatTrigger(); + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. All users receive a message + * in their chat text, except for the originating client, who receives + * the message based on the current ReplySource. + * + * @param client Client index doing the action, or 0 for server. + * @param tag Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error + */ +native void ShowActivity2(int client, const char[] tag, const char[] format, any ...); + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * ShowActivity2() is slightly more useful. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error + */ +native void ShowActivity(int client, const char[] format, any ...); + +/** + * Same as ShowActivity(), except the tag parameter is used instead of + * "[SM] " (note that you must supply any spacing). + * + * @param client Client index doing the action, or 0 for server. + * @param tag Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error + */ +native void ShowActivityEx(int client, const char[] tag, const char[] format, any ...); + +/** + * Given an originating client and a target client, returns the string + * that describes the originating client according to the sm_show_activity cvar. + * + * For example, "ADMIN", "PLAYER", or a player's name could be placed in this buffer. + * + * @param client Originating client; may be 0 for server console. + * @param target Targeted client. + * @param namebuf Name buffer. + * @param maxlength Maximum size of the name buffer. + * @return True if activity should be shown. False otherwise. In either + * case, the name buffer is filled. The return value can be used + * to broadcast a "safe" name to all players regardless of the + * sm_show_activity filters. + * @error Invalid client index or client not connected. + */ +native bool FormatActivitySource(int client, int target, const char[] namebuf, int maxlength); + +/** + * Called when a server-only command is invoked. + * + * @param args Number of arguments that were in the argument string. + * @return An Action value. Not handling the command + * means that Source will report it as "not found." + */ +typedef SrvCmd = function Action (int args); + +/** + * Creates a server-only console command, or hooks an already existing one. + * + * Server commands are case sensitive. + * + * @param cmd Name of the command to hook or create. + * @param callback A function to use as a callback for when the command is invoked. + * @param description Optional description to use for command creation. + * @param flags Optional flags to use for command creation. + * @error Command name is the same as an existing convar. + */ +native void RegServerCmd(const char[] cmd, SrvCmd callback, const char[] description="", int flags=0); + +/** + * Called when a generic console command is invoked. + * + * @param client Index of the client, or 0 from the server. + * @param args Number of arguments that were in the argument string. + * @return An Action value. Not handling the command + * means that Source will report it as "not found." + */ +typedef ConCmd = function Action (int client, int args); + +/** + * Creates a console command, or hooks an already existing one. + * + * Console commands are case sensitive. However, if the command already exists in the game, + * a client may enter the command in any case. SourceMod corrects for this automatically, + * and you should only hook the "real" version of the command. + * + * @param cmd Name of the command to hook or create. + * @param callback A function to use as a callback for when the command is invoked. + * @param description Optional description to use for command creation. + * @param flags Optional flags to use for command creation. + * @error Command name is the same as an existing convar. + */ +native void RegConsoleCmd(const char[] cmd, ConCmd callback, const char[] description="", int flags=0); + +/** + * Creates a console command as an administrative command. If the command does not exist, + * it is created. When this command is invoked, the access rights of the player are + * automatically checked before allowing it to continue. + * + * Admin commands are case sensitive from both the client and server. + * + * @param cmd String containing command to register. + * @param callback A function to use as a callback for when the command is invoked. + * @param adminflags Administrative flags (bitstring) to use for permissions. + * @param description Optional description to use for help. + * @param group String containing the command group to use. If empty, + * the plugin's filename will be used instead. + * @param flags Optional console flags. + * @error Command name is the same as an existing convar. + */ +native void RegAdminCmd(const char[] cmd, + ConCmd callback, + int adminflags, + const char[] description="", + const char[] group="", + int flags=0); + +/** + * Returns the number of arguments from the current console or server command. + * @note Unlike the HL2 engine call, this does not include the command itself. + * + * @return Number of arguments to the current command. + */ +native int GetCmdArgs(); + +/** + * Retrieves a command argument given its index, from the current console or + * server command. + * @note Argument indexes start at 1; 0 retrieves the command name. + * + * @param argnum Argument number to retrieve. + * @param buffer Buffer to use for storing the string. + * @param maxlength Maximum length of the buffer. + * @return Length of string written to buffer. + */ +native int GetCmdArg(int argnum, char[] buffer, int maxlength); + +/** + * Retrieves the entire command argument string in one lump from the current + * console or server command. + * + * @param buffer Buffer to use for storing the string. + * @param maxlength Maximum length of the buffer. + * @return Length of string written to buffer. + */ +native int GetCmdArgString(char[] buffer, int maxlength); + +/** + * Gets a command iterator. Must be freed with CloseHandle(). + * + * @return A new command iterator. + */ +native Handle GetCommandIterator(); + +/** + * Reads a command iterator, then advances to the next command if any. + * Only SourceMod specific commands are returned. + * + * @param iter Command iterator Handle. + * @param name Name buffer. + * @param nameLen Name buffer size. + * @param eflags Effective default flags of a command. + * @param desc Command description buffer. + * @param descLen Command description buffer size. + * @return True on success, false if there are no more commands. + */ +native bool ReadCommandIterator(Handle iter, + char[] name, + int nameLen, + int &eflags=0, + char[] desc="", + int descLen=0); + +/** + * Returns whether a client has access to a given command string. The string + * can be any override string, as overrides can be independent of + * commands. This feature essentially allows you to create custom + * flags using the override system. + * + * @param client Client index. + * @param command Command name. If the command is not found, the default + * flags are used. + * @param flags Flag string to use as a default, if the command or override + * is not found. + * @param override_only If true, SourceMod will not attempt to find a matching + * command, and it will only use the default flags specified. + * Otherwise, SourceMod will ignore the default flags if + * there is a matching admin command. + * @return True if the client has access, false otherwise. + */ +native bool CheckCommandAccess(int client, + const char[] command, + int flags, + bool override_only=false); + +/** + * Returns whether an admin has access to a given command string. The string + * can be any override string, as overrides can be independent of + * commands. This feature essentially allows you to create custom flags + * using the override system. + * + * @param id AdminId of the admin. + * @param command Command name. If the command is not found, the default + * flags are used. + * @param flags Flag string to use as a default, if the command or override + * is not found. + * @param override_only If true, SourceMod will not attempt to find a matching + * command, and it will only use the default flags specified. + * Otherwise, SourceMod will ignore the default flags if + * there is a matching admin command. + * @return True if the admin has access, false otherwise. + */ +native bool CheckAccess(AdminId id, + const char[] command, + int flags, + bool override_only=false); + +/** + * Returns the bitstring of flags of a command. + * + * @param name Name of the command. + * @return A bitstring containing the FCVAR_* flags that are enabled + * or INVALID_FCVAR_FLAGS if command not found. + */ +native int GetCommandFlags(const char[] name); + +/** + * Sets the bitstring of flags of a command. + * + * @param name Name of the command. + * @param flags A bitstring containing the FCVAR_* flags to enable. + * @return True on success, otherwise false. + */ +native bool SetCommandFlags(const char[] name, int flags); + +/** + * Starts a ConCommandBase search, traversing the list of ConVars and + * ConCommands. If a Handle is returned, the next entry must be read + * via FindNextConCommand(). The order of the list is undefined. + * + * @param buffer Buffer to store entry name. + * @param max_size Maximum size of the buffer. + * @param isCommand Variable to store whether the entry is a command. + * If it is not a command, it is a ConVar. + * @param flags Variable to store entry flags. + * @param description Buffer to store the description, empty if no description present. + * @param descrmax_size Maximum size of the description buffer. + * @return On success, a ConCmdIter Handle is returned, which + * can be read via FindNextConCommand(), and must be + * closed via CloseHandle(). Additionally, the output + * parameters will be filled with information of the + * first ConCommandBase entry. + * On failure, INVALID_HANDLE is returned, and the + * contents of outputs is undefined. + */ +native Handle FindFirstConCommand(char[] buffer, int max_size, bool &isCommand, int &flags=0, char[] description="", int descrmax_size=0); + +/** + * Reads the next entry in a ConCommandBase iterator. + * + * @param search ConCmdIter Handle to search. + * @param buffer Buffer to store entry name. + * @param max_size Maximum size of the buffer. + * @param isCommand Variable to store whether the entry is a command. + * If it is not a command, it is a ConVar. + * @param flags Variable to store entry flags. + * @param description Buffer to store the description, empty if no description present. + * @param descrmax_size Maximum size of the description buffer. + * @return On success, the outputs are filled, the iterator is + * advanced to the next entry, and true is returned. + * If no more entries exist, false is returned, and the + * contents of outputs is undefined. + */ +native bool FindNextConCommand(Handle search, char[] buffer, int max_size, bool &isCommand, int &flags=0, char[] description="", int descrmax_size=0); + +/** + * Adds an informational string to the server's public "tags". + * This string should be a short, unique identifier. + * + * Note: Tags are automatically removed when a plugin unloads. + * Note: Currently, this function does nothing because of bugs in the Valve master. + * + * @param tag Tag string to append. + */ +native void AddServerTag(const char[] tag); + +/** + * Removes a tag previously added by the calling plugin. + * + * @param tag Tag string to remove. + */ +native void RemoveServerTag(const char[] tag); + +/** + * Callback for command listeners. This is invoked whenever any command + * reaches the server, from the server console itself or a player. + * + * Clients may be in the process of connecting when they are executing commands + * IsClientConnected(client) is not guaranteed to return true. Other functions + * such as GetClientIP() may not work at this point either. + * + * Returning Plugin_Handled or Plugin_Stop will prevent the original, + * baseline code from running. + * + * -- TEXT BELOW IS IMPLEMENTATION, AND NOT GUARANTEED -- + * Even if returning Plugin_Handled or Plugin_Stop, some callbacks will still + * trigger. These are: + * * C++ command dispatch hooks from Metamod:Source plugins + * * Reg*Cmd() hooks that did not create new commands. + * + * @param client Client, or 0 for server. + * Client may not be connected or in game. + * @param command Command name, lower case. To get name as typed, use + * GetCmdArg() and specify argument 0. + * @param argc Argument count. + * @return Action to take (see extended notes above). + */ +typedef CommandListener = function Action (int client, const char[] command, int argc); + +#define FEATURECAP_COMMANDLISTENER "command listener" + +/** + * Adds a callback that will fire when a command is sent to the server. + * + * Registering commands is designed to create a new command as part of the UI, + * whereas this is a lightweight hook on a command string, existing or not. + * Using Reg*Cmd to intercept is in poor practice, as it physically creates a + * new command and can slow down dispatch in general. + * + * To see if this feature is available, use FeatureType_Capability and + * FEATURECAP_COMMANDLISTENER. + * + * @param callback Callback. + * @param command Command, or if not specified, a global listener. + * The command is case insensitive. + * @return True if this feature is available on the current game, + * false otherwise. + */ +native bool AddCommandListener(CommandListener callback, const char[] command=""); + +/** + * Removes a previously added command listener, in reverse order of being added. + * + * @param callback Callback. + * @param command Command, or if not specified, a global listener. + * The command is case insensitive. + * @error Callback has no active listeners. + */ +native void RemoveCommandListener(CommandListener callback, const char[] command=""); + +/** + * Returns true if the supplied command exists. + * + * @param command Command to find. + * @return True if command is found, false otherwise. + */ +stock bool CommandExists(const char[] command) +{ + return (GetCommandFlags(command) != INVALID_FCVAR_FLAGS); +} +/** + * Global listener for the chat commands. + * + * @param client Client index. + * @param command Command name. + * @param sArgs Chat argument string. + * + * @return An Action value. Returning Plugin_Handled bypasses the game function call. + Returning Plugin_Stop bypasses the post hook as well as the game function. + */ +forward Action OnClientSayCommand(int client, const char[] command, const char[] sArgs); + +/** + * Global post listener for the chat commands. + * + * @param client Client index. + * @param command Command name. + * @param sArgs Chat argument string. + */ +forward void OnClientSayCommand_Post(int client, const char[] command, const char[] sArgs); diff --git a/scripting/include/convars.inc b/scripting/include/convars.inc new file mode 100644 index 0000000..6896ce1 --- /dev/null +++ b/scripting/include/convars.inc @@ -0,0 +1,498 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _convars_included + #endinput +#endif +#define _convars_included + +/** + * Console variable bound values used with Get/SetConVarBounds() + */ +enum ConVarBounds +{ + ConVarBound_Upper = 0, + ConVarBound_Lower +}; + +/** + * Console variable query result values. + */ +enum ConVarQueryResult +{ + ConVarQuery_Okay = 0, //< Retrieval of client convar value was successful. */ + ConVarQuery_NotFound, //< Client convar was not found. */ + ConVarQuery_NotValid, //< A console command with the same name was found, but there is no convar. */ + ConVarQuery_Protected //< Client convar was found, but it is protected. The server cannot retrieve its value. */ +}; + +// Called when a console variable's value is changed. +// +// @param convar Handle to the convar that was changed. +// @param oldValue String containing the value of the convar before it was changed. +// @param newValue String containing the new value of the convar. +typedef ConVarChanged = function void (ConVar convar, const char[] oldValue, const char[] newValue); + +// Creates a new console variable. +// +// @param name Name of new convar. +// @param defaultValue String containing the default value of new convar. +// @param description Optional description of the convar. +// @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details. +// @param hasMin Optional boolean that determines if the convar has a minimum value. +// @param min Minimum floating point value that the convar can have if hasMin is true. +// @param hasMax Optional boolean that determines if the convar has a maximum value. +// @param max Maximum floating point value that the convar can have if hasMax is true. +// @return A handle to the newly created convar. If the convar already exists, a handle to it will still be returned. +// @error Convar name is blank or is the same as an existing console command. +native ConVar CreateConVar( + const char[] name, + const char[] defaultValue, + const char[] description="", + int flags=0, + bool hasMin=false, float min=0.0, + bool hasMax=false, float max=0.0); + +// Searches for a console variable. +// +// @param name Name of convar to find. +// @return A ConVar object if found; null otherwise. +native ConVar FindConVar(const char[] name); + +// A ConVar is a configurable, named setting in the srcds console. +methodmap ConVar < Handle +{ + // Retrieves or sets a boolean value for the convar. + property bool BoolValue { + public native get(); + public native set(bool b); + } + + // Retrieves or sets an integer value for the convar. + property int IntValue { + public native get(); + public native set(int value); + } + + // Retrieves or sets a float value for the convar. + property float FloatValue { + public native get(); + public native set(float value); + } + + // Gets or sets the flag bits (FCVAR_*) on the convar. + property int Flags { + public native get(); + public native set(int flags); + } + + // Sets the boolean value of a console variable. + // + // Note: The replicate and notify params are only relevant for the + // original, Dark Messiah, and Episode 1 engines. Newer engines + // automatically do these things when the convar value is changed. + // + // @param value New boolean value. + // @param replicate If set to true, the new convar value will be set on all clients. + // This will only work if the convar has the FCVAR_REPLICATED flag + // and actually exists on clients. + // @param notify If set to true, clients will be notified that the convar has changed. + // This will only work if the convar has the FCVAR_NOTIFY flag. + public native void SetBool(bool value, bool replicate=false, bool notify=false); + + // Sets the integer value of a console variable. + // + // Note: The replicate and notify params are only relevant for the + // original, Dark Messiah, and Episode 1 engines. Newer engines + // automatically do these things when the convar value is changed. + // + // @param value New integer value. + // @param replicate If set to true, the new convar value will be set on all clients. + // This will only work if the convar has the FCVAR_REPLICATED flag + // and actually exists on clients. + // @param notify If set to true, clients will be notified that the convar has changed. + // This will only work if the convar has the FCVAR_NOTIFY flag. + public native void SetInt(int value, bool replicate=false, bool notify=false); + + // Sets the floating point value of a console variable. + // + // Note: The replicate and notify params are only relevant for the + // original, Dark Messiah, and Episode 1 engines. Newer engines + // automatically do these things when the convar value is changed. + // + // @param value New floating point value. + // @param replicate If set to true, the new convar value will be set on all clients. + // This will only work if the convar has the FCVAR_REPLICATED flag + // and actually exists on clients. + // @param notify If set to true, clients will be notified that the convar has changed. + // This will only work if the convar has the FCVAR_NOTIFY flag. + public native void SetFloat(float value, bool replicate=false, bool notify=false); + + // Retrieves the string value of a console variable. + // + // @param convar Handle to the convar. + // @param value Buffer to store the value of the convar. + // @param maxlength Maximum length of string buffer. + public native void GetString(char[] value, int maxlength); + + // Sets the string value of a console variable. + // + // Note: The replicate and notify params are only relevant for the + // original, Dark Messiah, and Episode 1 engines. Newer engines + // automatically do these things when the convar value is changed. + // + // @param value New string value. + // @param replicate If set to true, the new convar value will be set on all clients. + // This will only work if the convar has the FCVAR_REPLICATED flag + // and actually exists on clients. + // @param notify If set to true, clients will be notified that the convar has changed. + // This will only work if the convar has the FCVAR_NOTIFY flag. + public native void SetString(const char[] value, bool replicate=false, bool notify=false); + + // Resets the console variable to its default value. + // + // Note: The replicate and notify params are only relevant for the + // original, Dark Messiah, and Episode 1 engines. Newer engines + // automatically do these things when the convar value is changed. + // + // @param replicate If set to true, the new convar value will be set on all clients. + // This will only work if the convar has the FCVAR_REPLICATED flag + // and actually exists on clients. + // @param notify If set to true, clients will be notified that the convar has changed. + // This will only work if the convar has the FCVAR_NOTIFY flag. + public native void RestoreDefault(bool replicate=false, bool notify=false); + + // Retrieves the default string value of a console variable. + // + // @param value Buffer to store the default value of the convar. + // @param maxlength Maximum length of string buffer. + // @return Number of bytes written to the buffer (UTF-8 safe). + public native int GetDefault(char[] value, int maxlength); + + // Retrieves the specified bound of a console variable. + // + // @param type Type of bound to retrieve, ConVarBound_Lower or ConVarBound_Upper. + // @param value By-reference cell to store the specified floating point bound value. + // @return True if the convar has the specified bound set, false otherwise. + public native bool GetBounds(ConVarBounds type, float &value); + + // Sets the specified bound of a console variable. + // + // @param type Type of bound to set, ConVarBound_Lower or ConVarBound_Upper + // @param set If set to true, convar will use specified bound. If false, bound will be removed. + // @param value Floating point value to use as the specified bound. + public native void SetBounds(ConVarBounds type, bool set, float value=0.0); + + // Retrieves the name of a console variable. + // + // @param name Buffer to store the name of the convar. + // @param maxlength Maximum length of string buffer. + public native void GetName(char[] name, int maxlength); + + // Replicates a convar value to a specific client. This does not change the actual convar value. + // + // @param client Client index + // @param value String value to send + // @return True on success, false on failure + // @error Invalid client index, client not in game, or client is fake + public native bool ReplicateToClient(int client, const char[] value); + + // Creates a hook for when a console variable's value is changed. + // + // @param callback An OnConVarChanged function pointer. + public native void AddChangeHook(ConVarChanged callback); + + // Removes a hook for when a console variable's value is changed. + // + // @param convar Handle to the convar. + // @param callback An OnConVarChanged function pointer. + // @error No active hook on convar. + public native void RemoveChangeHook(ConVarChanged callback); +} + +/** + * Creates a hook for when a console variable's value is changed. + * + * @param convar Handle to the convar. + * @param callback An OnConVarChanged function pointer. + * @error Invalid or corrupt Handle or invalid callback function. + */ +native void HookConVarChange(Handle convar, ConVarChanged callback); + +/** + * Removes a hook for when a console variable's value is changed. + * + * @param convar Handle to the convar. + * @param callback An OnConVarChanged function pointer. + * @error Invalid or corrupt Handle, invalid callback function, or no active hook on convar. + */ +native void UnhookConVarChange(Handle convar, ConVarChanged callback); + +/** + * Returns the boolean value of a console variable. + * + * @param convar Handle to the convar. + * @return The boolean value of the convar. + * @error Invalid or corrupt Handle. + */ +native bool GetConVarBool(Handle convar); + +/** + * Sets the boolean value of a console variable. + * + * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and + * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. + * + * @param convar Handle to the convar. + * @param value New boolean value. + * @param replicate If set to true, the new convar value will be set on all clients. + * This will only work if the convar has the FCVAR_REPLICATED flag + * and actually exists on clients. + * @param notify If set to true, clients will be notified that the convar has changed. + * This will only work if the convar has the FCVAR_NOTIFY flag. + * @error Invalid or corrupt Handle. + */ +native void SetConVarBool(Handle convar, bool value, bool replicate=false, bool notify=false); + +/** + * Returns the integer value of a console variable. + * + * @param convar Handle to the convar. + * @return The integer value of the convar. + * @error Invalid or corrupt Handle. + */ +native int GetConVarInt(Handle convar); + +/** + * Sets the integer value of a console variable. + * + * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and + * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. + * + * @param convar Handle to the convar. + * @param value New integer value. + * @param replicate If set to true, the new convar value will be set on all clients. + * This will only work if the convar has the FCVAR_REPLICATED flag + * and actually exists on clients. + * @param notify If set to true, clients will be notified that the convar has changed. + * This will only work if the convar has the FCVAR_NOTIFY flag. + * @error Invalid or corrupt Handle. + */ +native void SetConVarInt(Handle convar, int value, bool replicate=false, bool notify=false); + +/** + * Returns the floating point value of a console variable. + * + * @param convar Handle to the convar. + * @return The floating point value of the convar. + * @error Invalid or corrupt Handle. + */ +native float GetConVarFloat(Handle convar); + +/** + * Sets the floating point value of a console variable. + * + * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and + * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. + * + * @param convar Handle to the convar. + * @param value New floating point value. + * @param replicate If set to true, the new convar value will be set on all clients. + * This will only work if the convar has the FCVAR_REPLICATED flag + * and actually exists on clients. + * @param notify If set to true, clients will be notified that the convar has changed. + * This will only work if the convar has the FCVAR_NOTIFY flag. + * @error Invalid or corrupt Handle. + */ +native void SetConVarFloat(Handle convar, float value, bool replicate=false, bool notify=false); + +/** + * Retrieves the string value of a console variable. + * + * @param convar Handle to the convar. + * @param value Buffer to store the value of the convar. + * @param maxlength Maximum length of string buffer. + * @error Invalid or corrupt Handle. + */ +native void GetConVarString(Handle convar, char[] value, int maxlength); + +/** + * Sets the string value of a console variable. + * + * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and + * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. + * + * @param convar Handle to the convar. + * @param value New string value. + * @param replicate If set to true, the new convar value will be set on all clients. + * This will only work if the convar has the FCVAR_REPLICATED flag + * and actually exists on clients. + * @param notify If set to true, clients will be notified that the convar has changed. + * This will only work if the convar has the FCVAR_NOTIFY flag. + * @error Invalid or corrupt Handle. + */ +native void SetConVarString(Handle convar, const char[] value, bool replicate=false, bool notify=false); + +/** + * Resets the console variable to its default value. + * + * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and + * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. + * + * @param convar Handle to the convar. + * @param replicate If set to true, the new convar value will be set on all clients. + * This will only work if the convar has the FCVAR_REPLICATED flag + * and actually exists on clients. + * @param notify If set to true, clients will be notified that the convar has changed. + * This will only work if the convar has the FCVAR_NOTIFY flag. + * @error Invalid or corrupt Handle. + */ +native void ResetConVar(Handle convar, bool replicate=false, bool notify=false); + +/** + * Retrieves the default string value of a console variable. + * + * @param convar Handle to the convar. + * @param value Buffer to store the default value of the convar. + * @param maxlength Maximum length of string buffer. + * @return Number of bytes written to the buffer (UTF-8 safe). + * @error Invalid or corrupt Handle. + */ +native int GetConVarDefault(Handle convar, char[] value, int maxlength); + +/** + * Returns the bitstring of flags on a console variable. + * + * @param convar Handle to the convar. + * @return A bitstring containing the FCVAR_* flags that are enabled. + * @error Invalid or corrupt Handle. + */ +native int GetConVarFlags(Handle convar); + +/** + * Sets the bitstring of flags on a console variable. + * + * @param convar Handle to the convar. + * @param flags A bitstring containing the FCVAR_* flags to enable. + * @error Invalid or corrupt Handle. + */ +native void SetConVarFlags(Handle convar, int flags); + +/** + * Retrieves the specified bound of a console variable. + * + * @param convar Handle to the convar. + * @param type Type of bound to retrieve, ConVarBound_Lower or ConVarBound_Upper. + * @param value By-reference cell to store the specified floating point bound value. + * @return True if the convar has the specified bound set, false otherwise. + * @error Invalid or corrupt Handle. + */ +native bool GetConVarBounds(Handle convar, ConVarBounds type, float &value); + +/** + * Sets the specified bound of a console variable. + * + * @param convar Handle to the convar. + * @param type Type of bound to set, ConVarBound_Lower or ConVarBound_Upper + * @param set If set to true, convar will use specified bound. If false, bound will be removed. + * @param value Floating point value to use as the specified bound. + * @error Invalid or corrupt Handle. + */ +native void SetConVarBounds(Handle convar, ConVarBounds type, bool set, float value=0.0); + +/** + * Retrieves the name of a console variable. + * + * @param convar Handle to the convar. + * @param name Buffer to store the name of the convar. + * @param maxlength Maximum length of string buffer. + * @error Invalid or corrupt Handle. + */ +native void GetConVarName(Handle convar, char[] name, int maxlength); + +/** + * Replicates a convar value to a specific client. This does not change the actual convar value. + * + * @param client Client index + * @param convar ConVar handle + * @param value String value to send + * @return True on success, false on failure + * @error Invalid client index, client not in game, or client is fake + */ +native bool SendConVarValue(int client, Handle convar, const char[] value); + +typeset ConVarQueryFinished +{ + // Called when a query to retrieve a client's console variable has finished. + // + // @param cookie Unique identifier of query. + // @param client Player index. + // @param result Result of query that tells one whether or not query was successful. + // See ConVarQueryResult enum for more details. + // @param convarName Name of client convar that was queried. + // @param convarValue Value of client convar that was queried if successful. This will be "" if it was not. + // @param value Value that was passed when query was started. + function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value); + + // Called when a query to retrieve a client's console variable has finished. + // + // @param cookie Unique identifier of query. + // @param client Player index. + // @param result Result of query that tells one whether or not query was successful. + // See ConVarQueryResult enum for more details. + // @param convarName Name of client convar that was queried. + // @param convarValue Value of client convar that was queried if successful. This will be "" if it was not. + function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue); +}; + +/** + * Starts a query to retrieve the value of a client's console variable. + * + * @param client Player index. + * @param cvarName Name of client convar to query. + * @param callback A function to use as a callback when the query has finished. + * @param value Optional value to pass to the callback function. + * @return A cookie that uniquely identifies the query. + * Returns QUERYCOOKIE_FAILED on failure, such as when used on a bot. + */ +native QueryCookie QueryClientConVar(int client, const char[] cvarName, ConVarQueryFinished callback, any value=0); + +/** + * Returns true if the supplied character is valid in a ConVar name. + * + * @param c Character to validate. + * @return True is valid for ConVars, false otherwise + */ +stock bool IsValidConVarChar(int c) +{ + return (c == '_' || IsCharAlpha(c) || IsCharNumeric(c)); +} diff --git a/scripting/include/core.inc b/scripting/include/core.inc new file mode 100644 index 0000000..47f05e1 --- /dev/null +++ b/scripting/include/core.inc @@ -0,0 +1,317 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet: + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _core_included + #endinput +#endif +#define _core_included + +#include + +/** If this gets changed, you need to update Core's check. */ +#define SOURCEMOD_PLUGINAPI_VERSION 5 + +struct PlVers +{ + public int version; + public const char[] filevers; + public const char[] date; + public const char[] time; +}; + +/** + * Specifies what to do after a hook completes. + */ +enum Action +{ + Plugin_Continue = 0, /**< Continue with the original action */ + Plugin_Changed = 1, /**< Inputs or outputs have been overridden with new values */ + Plugin_Handled = 3, /**< Handle the action at the end (don't call it) */ + Plugin_Stop = 4, /**< Immediately stop the hook chain and handle the original */ +}; + +/** + * Specifies identity types. + */ +enum Identity +{ + Identity_Core = 0, + Identity_Extension = 1, + Identity_Plugin = 2 +}; + +public PlVers __version = +{ + version = SOURCEMOD_PLUGINAPI_VERSION, + filevers = SOURCEMOD_VERSION, + date = __DATE__, + time = __TIME__ +}; + +/** + * Plugin status values. + */ +enum PluginStatus +{ + Plugin_Running=0, /**< Plugin is running */ + /* All states below are "temporarily" unexecutable */ + Plugin_Paused, /**< Plugin is loaded but paused */ + Plugin_Error, /**< Plugin is loaded but errored/locked */ + /* All states below do not have all natives */ + Plugin_Loaded, /**< Plugin has passed loading and can be finalized */ + Plugin_Failed, /**< Plugin has a fatal failure */ + Plugin_Created, /**< Plugin is created but not initialized */ + Plugin_Uncompiled, /**< Plugin is not yet compiled by the JIT */ + Plugin_BadLoad, /**< Plugin failed to load */ + Plugin_Evicted /**< Plugin was unloaded due to an error */ +}; + +/** + * Plugin information properties. Plugins can declare a global variable with + * their info. Example, + * + * public Plugin myinfo = { + * name = "Admin Help", + * author = "AlliedModders LLC", + * description = "Display command information", + * version = "1.0", + * url = "http://www.sourcemod.net/" + * }; + * + * SourceMod will display this information when a user inspects plugins in the + * console. + */ +enum PluginInfo +{ + PlInfo_Name, /**< Plugin name */ + PlInfo_Author, /**< Plugin author */ + PlInfo_Description, /**< Plugin description */ + PlInfo_Version, /**< Plugin version */ + PlInfo_URL, /**< Plugin URL */ +}; + +/** + * Defines how an extension must expose itself for autoloading. + */ +struct Extension +{ + public const char[] name; /**< Short name */ + public const char[] file; /**< Default file name */ + public bool autoload; /**< Whether or not to auto-load */ + public bool required; /**< Whether or not to require */ +}; + +/** + * Defines how a plugin must expose itself for native requiring. + */ +struct SharedPlugin +{ + public const char[] name; /**< Short name */ + public const char[] file; /**< File name */ + public bool required; /**< Whether or not to require */ +}; + +public float NULL_VECTOR[3]; /**< Pass this into certain functions to act as a C++ NULL */ +public const char NULL_STRING[1]; /**< pass this into certain functions to act as a C++ NULL */ + +/** + * Check if the given vector is the NULL_VECTOR. + * + * @param vec The vector to test. + * @return True if NULL_VECTOR, false otherwise. + */ +native bool IsNullVector(const float vec[3]); + +/** + * Check if the given string is the NULL_STRING. + * + * @param str The string to test. + * @return True if NULL_STRING, false otherwise. + */ +native bool IsNullString(const char[] str); + +/** + * Horrible compatibility shim. + */ +public Extension __ext_core = +{ + name = "Core", + file = "core", + autoload = 0, + required = 0, +}; + +native int VerifyCoreVersion(); + +/** + * Sets a native as optional, such that if it is unloaded, removed, + * or otherwise non-existent, the plugin will still work. Calling + * removed natives results in a run-time error. + * + * @param name Native name. + */ +native void MarkNativeAsOptional(const char[] name); + +public void __ext_core_SetNTVOptional() +{ + MarkNativeAsOptional("GetFeatureStatus"); + MarkNativeAsOptional("RequireFeature"); + MarkNativeAsOptional("AddCommandListener"); + MarkNativeAsOptional("RemoveCommandListener"); + + MarkNativeAsOptional("BfWriteBool"); + MarkNativeAsOptional("BfWriteByte"); + MarkNativeAsOptional("BfWriteChar"); + MarkNativeAsOptional("BfWriteShort"); + MarkNativeAsOptional("BfWriteWord"); + MarkNativeAsOptional("BfWriteNum"); + MarkNativeAsOptional("BfWriteFloat"); + MarkNativeAsOptional("BfWriteString"); + MarkNativeAsOptional("BfWriteEntity"); + MarkNativeAsOptional("BfWriteAngle"); + MarkNativeAsOptional("BfWriteCoord"); + MarkNativeAsOptional("BfWriteVecCoord"); + MarkNativeAsOptional("BfWriteVecNormal"); + MarkNativeAsOptional("BfWriteAngles"); + MarkNativeAsOptional("BfReadBool"); + MarkNativeAsOptional("BfReadByte"); + MarkNativeAsOptional("BfReadChar"); + MarkNativeAsOptional("BfReadShort"); + MarkNativeAsOptional("BfReadWord"); + MarkNativeAsOptional("BfReadNum"); + MarkNativeAsOptional("BfReadFloat"); + MarkNativeAsOptional("BfReadString"); + MarkNativeAsOptional("BfReadEntity"); + MarkNativeAsOptional("BfReadAngle"); + MarkNativeAsOptional("BfReadCoord"); + MarkNativeAsOptional("BfReadVecCoord"); + MarkNativeAsOptional("BfReadVecNormal"); + MarkNativeAsOptional("BfReadAngles"); + MarkNativeAsOptional("BfGetNumBytesLeft"); + + MarkNativeAsOptional("BfWrite.WriteBool"); + MarkNativeAsOptional("BfWrite.WriteByte"); + MarkNativeAsOptional("BfWrite.WriteChar"); + MarkNativeAsOptional("BfWrite.WriteShort"); + MarkNativeAsOptional("BfWrite.WriteWord"); + MarkNativeAsOptional("BfWrite.WriteNum"); + MarkNativeAsOptional("BfWrite.WriteFloat"); + MarkNativeAsOptional("BfWrite.WriteString"); + MarkNativeAsOptional("BfWrite.WriteEntity"); + MarkNativeAsOptional("BfWrite.WriteAngle"); + MarkNativeAsOptional("BfWrite.WriteCoord"); + MarkNativeAsOptional("BfWrite.WriteVecCoord"); + MarkNativeAsOptional("BfWrite.WriteVecNormal"); + MarkNativeAsOptional("BfWrite.WriteAngles"); + MarkNativeAsOptional("BfRead.ReadBool"); + MarkNativeAsOptional("BfRead.ReadByte"); + MarkNativeAsOptional("BfRead.ReadChar"); + MarkNativeAsOptional("BfRead.ReadShort"); + MarkNativeAsOptional("BfRead.ReadWord"); + MarkNativeAsOptional("BfRead.ReadNum"); + MarkNativeAsOptional("BfRead.ReadFloat"); + MarkNativeAsOptional("BfRead.ReadString"); + MarkNativeAsOptional("BfRead.ReadEntity"); + MarkNativeAsOptional("BfRead.ReadAngle"); + MarkNativeAsOptional("BfRead.ReadCoord"); + MarkNativeAsOptional("BfRead.ReadVecCoord"); + MarkNativeAsOptional("BfRead.ReadVecNormal"); + MarkNativeAsOptional("BfRead.ReadAngles"); + MarkNativeAsOptional("BfRead.GetNumBytesLeft"); + + MarkNativeAsOptional("PbReadInt"); + MarkNativeAsOptional("PbReadFloat"); + MarkNativeAsOptional("PbReadBool"); + MarkNativeAsOptional("PbReadString"); + MarkNativeAsOptional("PbReadColor"); + MarkNativeAsOptional("PbReadAngle"); + MarkNativeAsOptional("PbReadVector"); + MarkNativeAsOptional("PbReadVector2D"); + MarkNativeAsOptional("PbGetRepeatedFieldCount"); + MarkNativeAsOptional("PbSetInt"); + MarkNativeAsOptional("PbSetFloat"); + MarkNativeAsOptional("PbSetBool"); + MarkNativeAsOptional("PbSetString"); + MarkNativeAsOptional("PbSetColor"); + MarkNativeAsOptional("PbSetAngle"); + MarkNativeAsOptional("PbSetVector"); + MarkNativeAsOptional("PbSetVector2D"); + MarkNativeAsOptional("PbAddInt"); + MarkNativeAsOptional("PbAddFloat"); + MarkNativeAsOptional("PbAddBool"); + MarkNativeAsOptional("PbAddString"); + MarkNativeAsOptional("PbAddColor"); + MarkNativeAsOptional("PbAddAngle"); + MarkNativeAsOptional("PbAddVector"); + MarkNativeAsOptional("PbAddVector2D"); + MarkNativeAsOptional("PbRemoveRepeatedFieldValue"); + MarkNativeAsOptional("PbReadMessage"); + MarkNativeAsOptional("PbReadRepeatedMessage"); + MarkNativeAsOptional("PbAddMessage"); + + MarkNativeAsOptional("Protobuf.ReadInt"); + MarkNativeAsOptional("Protobuf.ReadFloat"); + MarkNativeAsOptional("Protobuf.ReadBool"); + MarkNativeAsOptional("Protobuf.ReadString"); + MarkNativeAsOptional("Protobuf.ReadColor"); + MarkNativeAsOptional("Protobuf.ReadAngle"); + MarkNativeAsOptional("Protobuf.ReadVector"); + MarkNativeAsOptional("Protobuf.ReadVector2D"); + MarkNativeAsOptional("Protobuf.GetRepeatedFieldCount"); + MarkNativeAsOptional("Protobuf.SetInt"); + MarkNativeAsOptional("Protobuf.SetFloat"); + MarkNativeAsOptional("Protobuf.SetBool"); + MarkNativeAsOptional("Protobuf.SetString"); + MarkNativeAsOptional("Protobuf.SetColor"); + MarkNativeAsOptional("Protobuf.SetAngle"); + MarkNativeAsOptional("Protobuf.SetVector"); + MarkNativeAsOptional("Protobuf.SetVector2D"); + MarkNativeAsOptional("Protobuf.AddInt"); + MarkNativeAsOptional("Protobuf.AddFloat"); + MarkNativeAsOptional("Protobuf.AddBool"); + MarkNativeAsOptional("Protobuf.AddString"); + MarkNativeAsOptional("Protobuf.AddColor"); + MarkNativeAsOptional("Protobuf.AddAngle"); + MarkNativeAsOptional("Protobuf.AddVector"); + MarkNativeAsOptional("Protobuf.AddVector2D"); + MarkNativeAsOptional("Protobuf.RemoveRepeatedFieldValue"); + MarkNativeAsOptional("Protobuf.ReadMessage"); + MarkNativeAsOptional("Protobuf.ReadRepeatedMessage"); + MarkNativeAsOptional("Protobuf.AddMessage"); + + VerifyCoreVersion(); +} + + +#define AUTOLOAD_EXTENSIONS +#define REQUIRE_EXTENSIONS +#define REQUIRE_PLUGIN diff --git a/scripting/include/cstrike.inc b/scripting/include/cstrike.inc new file mode 100644 index 0000000..49e0aec --- /dev/null +++ b/scripting/include/cstrike.inc @@ -0,0 +1,458 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _cstrike_included + #endinput +#endif +#define _cstrike_included + +#define CS_TEAM_NONE 0 /**< No team yet. */ +#define CS_TEAM_SPECTATOR 1 /**< Spectators. */ +#define CS_TEAM_T 2 /**< Terrorists. */ +#define CS_TEAM_CT 3 /**< Counter-Terrorists. */ + +#define CS_SLOT_PRIMARY 0 /**< Primary weapon slot. */ +#define CS_SLOT_SECONDARY 1 /**< Secondary weapon slot. */ +#define CS_SLOT_KNIFE 2 /**< Knife slot. */ +#define CS_SLOT_GRENADE 3 /**< Grenade slot (will only return one grenade). */ +#define CS_SLOT_C4 4 /**< C4 slot. */ + +#define CS_DMG_HEADSHOT (1 << 30) /**< Headshot */ + +enum CSRoundEndReason +{ + CSRoundEnd_TargetBombed = 0, /**< Target Successfully Bombed! */ + CSRoundEnd_VIPEscaped, /**< The VIP has escaped! - Doesn't exist on CS:GO */ + CSRoundEnd_VIPKilled, /**< VIP has been assassinated! - Doesn't exist on CS:GO */ + CSRoundEnd_TerroristsEscaped, /**< The terrorists have escaped! */ + CSRoundEnd_CTStoppedEscape, /**< The CTs have prevented most of the terrorists from escaping! */ + CSRoundEnd_TerroristsStopped, /**< Escaping terrorists have all been neutralized! */ + CSRoundEnd_BombDefused, /**< The bomb has been defused! */ + CSRoundEnd_CTWin, /**< Counter-Terrorists Win! */ + CSRoundEnd_TerroristWin, /**< Terrorists Win! */ + CSRoundEnd_Draw, /**< Round Draw! */ + CSRoundEnd_HostagesRescued, /**< All Hostages have been rescued! */ + CSRoundEnd_TargetSaved, /**< Target has been saved! */ + CSRoundEnd_HostagesNotRescued, /**< Hostages have not been rescued! */ + CSRoundEnd_TerroristsNotEscaped, /**< Terrorists have not escaped! */ + CSRoundEnd_VIPNotEscaped, /**< VIP has not escaped! - Doesn't exist on CS:GO */ + CSRoundEnd_GameStart, /**< Game Commencing! */ + + // The below only exist on CS:GO + CSRoundEnd_TerroristsSurrender, /**< Terrorists Surrender */ + CSRoundEnd_CTSurrender, /**< CTs Surrender */ + CSRoundEnd_TerroristsPlanted, /**< Terrorists Planted the bomb */ + CSRoundEnd_CTsReachedHostage, /**< CTs Reached the hostage */ +}; + +enum CSWeaponID +{ + CSWeapon_NONE = 0, + CSWeapon_P228, + CSWeapon_GLOCK, + CSWeapon_SCOUT, + CSWeapon_HEGRENADE, + CSWeapon_XM1014, + CSWeapon_C4, + CSWeapon_MAC10, + CSWeapon_AUG, + CSWeapon_SMOKEGRENADE, + CSWeapon_ELITE, + CSWeapon_FIVESEVEN, + CSWeapon_UMP45, + CSWeapon_SG550, + CSWeapon_GALIL, + CSWeapon_FAMAS, + CSWeapon_USP, + CSWeapon_AWP, + CSWeapon_MP5NAVY, + CSWeapon_M249, + CSWeapon_M3, + CSWeapon_M4A1, + CSWeapon_TMP, + CSWeapon_G3SG1, + CSWeapon_FLASHBANG, + CSWeapon_DEAGLE, + CSWeapon_SG552, + CSWeapon_AK47, + CSWeapon_KNIFE, + CSWeapon_P90, + CSWeapon_SHIELD, + CSWeapon_KEVLAR, + CSWeapon_ASSAULTSUIT, + CSWeapon_NIGHTVISION, //Anything below is CS:GO ONLY + CSWeapon_GALILAR, + CSWeapon_BIZON, + CSWeapon_MAG7, + CSWeapon_NEGEV, + CSWeapon_SAWEDOFF, + CSWeapon_TEC9, + CSWeapon_TASER, + CSWeapon_HKP2000, + CSWeapon_MP7, + CSWeapon_MP9, + CSWeapon_NOVA, + CSWeapon_P250, + CSWeapon_SCAR17, + CSWeapon_SCAR20, + CSWeapon_SG556, + CSWeapon_SSG08, + CSWeapon_KNIFE_GG, + CSWeapon_MOLOTOV, + CSWeapon_DECOY, + CSWeapon_INCGRENADE, + CSWeapon_DEFUSER, + CSWeapon_HEAVYASSAULTSUIT, + //The rest are actual item definition indexes for CS:GO + CSWeapon_CUTTERS = 56, + CSWeapon_HEALTHSHOT = 57, + CSWeapon_KNIFE_T = 59, + CSWeapon_M4A1_SILENCER = 60, + CSWeapon_USP_SILENCER = 61, + CSWeapon_CZ75A = 63, + CSWeapon_REVOLVER = 64, + CSWeapon_TAGGRENADE = 68, + CSWeapon_MAX_WEAPONS_NO_KNIFES, // Max without the knife item defs, useful when treating all knives as a regular knife. + CSWeapon_BAYONET = 500, + CSWeapon_KNIFE_FLIP = 505, + CSWeapon_KNIFE_GUT = 506, + CSWeapon_KNIFE_KARAMBIT = 507, + CSWeapon_KNIFE_M9_BAYONET = 508, + CSWeapon_KNIFE_TATICAL = 509, + CSWeapon_KNIFE_FALCHION = 512, + CSWeapon_KNIFE_SURVIVAL_BOWIE = 514, + CSWeapon_KNIFE_BUTTERFLY = 515, + CSWeapon_KNIFE_PUSH = 516, + CSWeapon_MAX_WEAPONS //THIS MUST BE LAST, EASY WAY TO CREATE LOOPS. When looping, do CS_IsValidWeaponID(i), to check. +}; + +/** + * Called when a player attempts to purchase an item. + * Return Plugin_Continue to allow the purchase or return a + * higher action to deny. + * + * @param client Client index + * @param weapon User input for weapon name + */ +forward Action CS_OnBuyCommand(int client, const char[] weapon); + +/** + * Called when CSWeaponDrop is called + * Return Plugin_Continue to allow the call or return a + * higher action to block. + * + * @param client Client index + * @param weaponIndex Weapon index + */ +forward Action CS_OnCSWeaponDrop(int client, int weaponIndex); + +/** + * Called when game retrieves a weapon's price for a player. + * Return Plugin_Continue to use default value or return a higher + * action to use a newly-set price. + * + * @note This can be called multiple times per weapon purchase + * + * @param client Client index + * @param weapon Weapon classname + * @param price Buffer param for the price of the weapon + * + * @note Not all "weapons" call GetWeaponPrice. Example: c4, knife, vest, vest helmet, night vision. + */ +forward Action CS_OnGetWeaponPrice(int client, const char[] weapon, int &price); + +/** + * Called when TerminateRound is called. + * Return Plugin_Continue to ignore, return Plugin_Changed to continue, + * using the given delay and reason, or return Plugin_Handled or a higher + * action to block TerminateRound from firing. + * + * @param delay Time (in seconds) until new round starts + * @param reason Reason for round end + */ +forward Action CS_OnTerminateRound(float &delay, CSRoundEndReason &reason); + +/** + * Respawns a player. + * + * @param client Player's index. + * @error Invalid client index, client not in game. + */ +native void CS_RespawnPlayer(int client); + +/** + * Switches the player's team. + * + * @param client Player's index. + * @param team Team index. + * @error Invalid client index, client not in game. + */ +native void CS_SwitchTeam(int client, int team); + +/** + * Forces a player to drop or toss their weapon + * + * @param client Player's index. + * @param weaponIndex Index of weapon to drop. + * @param toss True to toss weapon (with velocity) or false to just drop weapon + * @param blockhook Set to true to stop the corresponding CS_OnCSWeaponDrop + * + * @error Invalid client index, client not in game, or invalid weapon index. + */ +native void CS_DropWeapon(int client, int weaponIndex, bool toss, bool blockhook = false); + +/** + * Forces round to end with a reason + * + * @param delay Time (in seconds) to delay before new round starts + * @param reason Reason for the round ending + * @param blockhook Set to true to stop the corresponding CS_OnTerminateRound + * forward from being called. + */ +native void CS_TerminateRound(float delay, CSRoundEndReason reason, bool blockhook = false); + +/** + * Gets a weapon name from a weapon alias + * + * @param alias Weapons alias to get weapon name for. + * @param weapon Buffer to store weapons name + * @param size Size of buffer to store the weapons name. + * + * @note Will set the buffer to the original alias if it is not an alias to a weapon. + */ +native void CS_GetTranslatedWeaponAlias(const char[] alias, char[] weapon, int size); + +/** + * Gets a weapon's price + * + * @param client Client to check weapon price for. + * @param id Weapon id for the weapon to check + * @param defaultprice Set to true to get defaultprice. + * @return Returns price of the weapon (even if modified) + * + * @error Invalid client, failing to get weapon info, or failing to get price offset. + * @note c4, knife and shield will always return 0. vest, vest helmet and night vision will always return default price. + */ +native int CS_GetWeaponPrice(int client, CSWeaponID id, bool defaultprice = false); + +/** + * Gets a clients clan tag + * @param client Client index to get clan tag for. + * @param buffer Buffer to store clients clan tag in. + * @param size Size of the buffer. + * @return Number of non-null bytes written. + * + * @error Invalid client. + */ +native int CS_GetClientClanTag(int client, char[] buffer, int size); + +/** + * Sets a clients clan tag + * @param client Client index to set clan tag for. + * @param tag Tag to set clients clan tag as. + * + * @error Invalid client. + */ +native void CS_SetClientClanTag(int client, const char[] tag); + +/** + * Gets a team's score + * @param team Team index to get score for. + * @return Returns the internal team score. + * + * @error Invalid team index. + */ +native int CS_GetTeamScore(int team); + +/** + * Sets a team's score + * @param team Team index to set score for. + * @param value Value to set teams score as. + * + * @error Invalid team index. + * @note This will update the scoreboard only after the scoreboard update function is called. Use SetTeamScore plus this to update the scoreboard instantly and save values correctly. + */ +native void CS_SetTeamScore(int team, int value); + +/** + * Gets a client's mvp count + * @param client Client index to get mvp count of. + * @return Returns the client's internal MVP count. + * + * @error Invalid client. + */ +native int CS_GetMVPCount(int client); + +/** + * Sets a client's mvp count + * @param client Client index to set mvp count for. + * @param value Value to set client's mvp count as. + * + * @error Invalid client. + */ +native void CS_SetMVPCount(int client, int value); + +/** + * Gets a client's contribution score (CS:GO only) + * @param client Client index to get score of. + * @return Returns the client's score. + * + * @error Invalid client. + */ +native int CS_GetClientContributionScore(int client); + +/** + * Sets a client's contribution score (CS:GO only) + * @param client Client index to set score for. + * @param value Value to set client's score as. + * + * @error Invalid client. + */ +native void CS_SetClientContributionScore(int client, int value); + +/** + * Gets a client's assists (CS:GO only) + * @param client Client index to get assists of. + * @return Returns the client's assists. + * + * @error Invalid client. + */ +native int CS_GetClientAssists(int client); + +/** + * Sets a client's assists (CS:GO only) + * @param client Client index to set assists for. + * @param value Value to set client's assists as. + * + * @error Invalid client. + */ +native void CS_SetClientAssists(int client, int value); + +/** + * Gets a weaponID from a alias + * @param alias Weapon alias to attempt to get an id for. + * @return Returns a weapon id or 0 if failed to find a match. + * + * @note For best results use CS_GetTranslatedWeaponAlias on the weapon name before passing it. + */ +native CSWeaponID CS_AliasToWeaponID(const char[] alias); + +/** + * Gets a alias from a weaponID + * @param weaponID WeaponID to get alias for. + * @param destination Destination string to hold the weapon alias. + * @param len Length of the destination array. + * @return Returns number of cells written. + */ +native int CS_WeaponIDToAlias(CSWeaponID weaponID, char[] destination, int len); + +/** + * Returns weather a WeaponID is valid on the current mod (css or csgo) + * @param weaponID WeaponID to check + * @return Returns true if its a valid WeaponID false otherwise. + * + * @note This will return false always for CSWeapon_NONE. Should only be called after OnMapStart since weapon info isnt intialized before. + */ +native bool CS_IsValidWeaponID(CSWeaponID id); + +/** + * Sets a player's model based on their current class + * + * @param client Player's index. + * @error Invalid client index, client not in game. + */ +native void CS_UpdateClientModel(int client); + +/** + * Returns a CSWeaponID equivalent based on the item definition index. + * + * @param iDefIndex Definition index to get the CSWeaponID value for. + * @return Returns CSWeaponID value for the definition index. + * + * @error Invalid definition index. + * @note In most cases the id will be the item definition index. Works for CS:GO ONLY. + */ +native CSWeaponID CS_ItemDefIndexToID(int iDefIndex); + +/** + * Returns a item definition index equivalent based on the CSWeaponID. + * + * @param id CSWeaponID to get the item definition for. + * @return Returns item definition index value for the weapon id. + * + * @error Invalid weapon id. + * @note In most cases the item deinition index will be the id. Works for CS:GO ONLY. + */ +native int CS_WeaponIDToItemDefIndex(CSWeaponID id); + +/** + * Do not edit below this line! + */ +public Extension __ext_cstrike = +{ + name = "cstrike", + file = "games/game.cstrike.ext", + autoload = 0, +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public void __ext_cstrike_SetNTVOptional() +{ + MarkNativeAsOptional("CS_RespawnPlayer"); + MarkNativeAsOptional("CS_SwitchTeam"); + MarkNativeAsOptional("CS_DropWeapon"); + MarkNativeAsOptional("CS_TerminateRound"); + MarkNativeAsOptional("CS_GetTranslatedWeaponAlias"); + MarkNativeAsOptional("CS_GetWeaponPrice"); + MarkNativeAsOptional("CS_GetClientClanTag"); + MarkNativeAsOptional("CS_SetClientClanTag"); + MarkNativeAsOptional("CS_GetTeamScore"); + MarkNativeAsOptional("CS_SetTeamScore"); + MarkNativeAsOptional("CS_GetMVPCount"); + MarkNativeAsOptional("CS_SetMVPCount"); + MarkNativeAsOptional("CS_GetClientContributionScore"); + MarkNativeAsOptional("CS_SetClientContributionScore"); + MarkNativeAsOptional("CS_GetClientAssists"); + MarkNativeAsOptional("CS_SetClientAssists"); + MarkNativeAsOptional("CS_AliasToWeaponID"); + MarkNativeAsOptional("CS_WeaponIDToAlias"); + MarkNativeAsOptional("CS_IsValidWeaponID"); + MarkNativeAsOptional("CS_UpdateClientModel"); + MarkNativeAsOptional("CS_ItemDefIndexToID"); + MarkNativeAsOptional("CS_WeaponIDToItemDefIndex"); +} +#endif diff --git a/scripting/include/customkeyvalues.inc b/scripting/include/customkeyvalues.inc new file mode 100644 index 0000000..816f3af --- /dev/null +++ b/scripting/include/customkeyvalues.inc @@ -0,0 +1,26 @@ +#if !defined _CUSTOMKEYVALUES_INC_ +#define _CUSTOMKEYVALUES_INC_ + +native bool GetCustomKeyValue( int entity, const char[] key, char[] value, int maxlen ); +native bool SetCustomKeyValue( int entity, const char[] key, const char[] value, bool replace ); + +#if !defined REQUIRE_PLUGIN +public __pl_customkeyvalues_SetNTVOptional() +{ + MarkNativeAsOptional("GetCustomKeyValue"); + MarkNativeAsOptional("SetCustomKeyValue"); +} +#endif + +public SharedPlugin __pl_customkeyvalues = +{ + name = "CustomKeyValues", + file = "customkeyvalues.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#endif \ No newline at end of file diff --git a/scripting/include/datapack.inc b/scripting/include/datapack.inc new file mode 100644 index 0000000..12b7a3b --- /dev/null +++ b/scripting/include/datapack.inc @@ -0,0 +1,225 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _datapack_included + #endinput +#endif +#define _datapack_included + + +/** + * Opaque handle to a datapack position. + */ + enum DataPackPos: {}; + +// A DataPack allows serializing multiple variables into a single stream. +methodmap DataPack < Handle +{ + // Creates a new data pack. + public native DataPack(); + + // Packs a normal cell into a data pack. + // + // @param cell Cell to add. + public native void WriteCell(any cell); + + // Packs a float into a data pack. + // + // @param val Float to add. + public native void WriteFloat(float val); + + // Packs a string into a data pack. + // + // @param str String to add. + public native void WriteString(const char[] str); + + // Packs a function pointer into a data pack. + // + // @param fktptr Function pointer to add. + public native void WriteFunction(Function fktptr); + + // Reads a cell from a data pack. + // + // @param pack Handle to the data pack. + public native any ReadCell(); + + // Reads a float from a data pack. + // + // @param pack Handle to the data pack. + public native float ReadFloat(); + + // Reads a string from a data pack. + // + // @param buffer Destination string buffer. + // @param maxlen Maximum length of output string buffer. + public native void ReadString(char[] buffer, int maxlen); + + // Reads a function pointer from a data pack. + // + // @return Function pointer. + public native Function ReadFunction(); + + // Resets the position in a data pack. + // + // @param clear If true, clears the contained data. + public native void Reset(bool clear=false); + + // Returns whether or not a specified number of bytes from the data pack + // position to the end can be read. + // + // @param bytes Number of bytes to simulate reading. + public native bool IsReadable(int bytes); + + // The read or write position in a data pack. + property DataPackPos Position { + public native get(); + public native set(DataPackPos pos); + } +}; + +/** + * Creates a new data pack. + * + * @return A Handle to the data pack. Must be closed with CloseHandle(). + */ +native DataPack CreateDataPack(); + +/** + * Packs a normal cell into a data pack. + * + * @param pack Handle to the data pack. + * @param cell Cell to add. + * @error Invalid handle. + */ +native void WritePackCell(Handle pack, any cell); + +/** + * Packs a float into a data pack. + * + * @param pack Handle to the data pack. + * @param val Float to add. + * @error Invalid handle. + */ +native void WritePackFloat(Handle pack, float val); + +/** + * Packs a string into a data pack. + * + * @param pack Handle to the data pack. + * @param str String to add. + * @error Invalid handle. + */ +native void WritePackString(Handle pack, const char[] str); + +/** + * Packs a function pointer into a data pack. + * + * @param pack Handle to the data pack. + * @param fktptr Function pointer to add. + * @error Invalid handle. + */ +native void WritePackFunction(Handle pack, Function fktptr); + +/** + * Reads a cell from a data pack. + * + * @param pack Handle to the data pack. + * @return Cell value. + * @error Invalid handle, or bounds error. + */ +native any ReadPackCell(Handle pack); + +/** + * Reads a float from a data pack. + * + * @param pack Handle to the data pack. + * @return Float value. + * @error Invalid handle, or bounds error. + */ +native float ReadPackFloat(Handle pack); + +/** + * Reads a string from a data pack. + * + * @param pack Handle to the data pack. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @error Invalid handle, or bounds error. + */ +native void ReadPackString(Handle pack, char[] buffer, int maxlen); + +/** + * Reads a function pointer from a data pack. + * + * @param pack Handle to the data pack. + * @return Function pointer. + * @error Invalid handle, or bounds error. + */ +native Function ReadPackFunction(Handle pack); + +/** + * Resets the position in a data pack. + * + * @param pack Handle to the data pack. + * @param clear If true, clears the contained data. + * @error Invalid handle. + */ +native void ResetPack(Handle pack, bool clear=false); + +/** + * Returns the read or write position in a data pack. + * + * @param pack Handle to the data pack. + * @return Position in the data pack, only usable with calls to SetPackPosition. + * @error Invalid handle. + */ +native DataPackPos GetPackPosition(Handle pack); + +/** + * Sets the read/write position in a data pack. + * + * @param pack Handle to the data pack. + * @param position New position to set. Must have been previously retrieved from a call to GetPackPosition. + * @error Invalid handle, or position is beyond the pack bounds. + */ +native void SetPackPosition(Handle pack, DataPackPos position); + +/** + * Returns whether or not a specified number of bytes from the data pack + * position to the end can be read. + * + * @param pack Handle to the data pack. + * @param bytes Number of bytes to simulate reading. + * @return True if can be read, false otherwise. + * @error Invalid handle. + */ +native bool IsPackReadable(Handle pack, int bytes); diff --git a/scripting/include/datetime.inc b/scripting/include/datetime.inc new file mode 100644 index 0000000..a0447d6 --- /dev/null +++ b/scripting/include/datetime.inc @@ -0,0 +1,274 @@ +/* + Unix Time Conversion + by bugsy, + v0.3 + + http://forums.alliedmods.net/showthread.php?t=91915 + TimeZone data: http://www.epochconverter.com/epoch/timezones.php + + Ported to Source Mod by Milutinke (ByM), modded by TheXeon +*/ + +#if defined _file_unixtime_sourcemod_included + #endinput +#endif +#define _file_unixtime_sourcemod_included + +//============================================================================================ +// Macros +//============================================================================================ + +// Enumerator causes index out of bounds exception for some strange reason, so I had to change everything to define preprocessor +// Change if you must xD +#define UT_TIMEZONE_SERVER 0 +#define UT_TIMEZONE_MIT 1 +#define UT_TIMEZONE_HAST 2 +#define UT_TIMEZONE_AKST 3 +#define UT_TIMEZONE_AKDT 4 +#define UT_TIMEZONE_PST 5 +#define UT_TIMEZONE_PDT 6 +#define UT_TIMEZONE_MST 7 +#define UT_TIMEZONE_MDT 8 +#define UT_TIMEZONE_CST 9 +#define UT_TIMEZONE_CDT 10 +#define UT_TIMEZONE_EST 11 +#define UT_TIMEZONE_EDT 12 +#define UT_TIMEZONE_PRT 13 +#define UT_TIMEZONE_CNT 14 +#define UT_TIMEZONE_AGT 15 +#define UT_TIMEZONE_BET 16 +#define UT_TIMEZONE_CAT 17 +#define UT_TIMEZONE_UTC 18 +#define UT_TIMEZONE_WET 19 +#define UT_TIMEZONE_WEST 20 +#define UT_TIMEZONE_CET 21 +#define UT_TIMEZONE_CEST 22 +#define UT_TIMEZONE_EET 23 +#define UT_TIMEZONE_EEST 24 +#define UT_TIMEZONE_ART 25 +#define UT_TIMEZONE_EAT 26 +#define UT_TIMEZONE_MET 27 +#define UT_TIMEZONE_NET 28 +#define UT_TIMEZONE_PLT 29 +#define UT_TIMEZONE_IST 30 +#define UT_TIMEZONE_BST 31 +#define UT_TIMEZONE_ICT 32 +#define UT_TIMEZONE_CTT 33 +#define UT_TIMEZONE_AWST 34 +#define UT_TIMEZONE_JST 35 +#define UT_TIMEZONE_ACST 36 +#define UT_TIMEZONE_AEST 37 +#define UT_TIMEZONE_SST 38 +#define UT_TIMEZONE_NZST 39 +#define UT_TIMEZONE_NZD 40 + +//============================================================================================ +// Variables +//============================================================================================ +stock const int g_iYearSeconds[ 2 ] = { + 31536000, // Normal year + 31622400 // Leap year +}; + +stock const int g_iMonthSeconds[ 12 ] = { + 2678400, // January 31 + 2419200, // February 28 + 2678400, // March 31 + 2592000, // April 30 + 2678400, // May 31 + 2592000, // June 30 + 2678400, // July 31 + 2678400, // August 31 + 2592000, // September 30 + 2678400, // October 31 + 2592000, // November 30 + 2678400 // December 31 +}; + +stock const int g_iTimeZoneOffset[ ] = { + -1, + -39600, + -36000, + -32400, + -28800, + -28800, + -25200, + -25200, + -21600, + -21600, + -18000, + -18000, + -14400, + -14400, + -12600, + -10800, + -10800, + -3600, + 0, + 0, + 3600, + 3600, + 7200, + 7200, + 10800, + 7200, + 10800, + 12600, + 14400, + 18000, + 19800, + 21600, + 25200, + 28800, + 28800, + 32400, + 34200, + 36000, + 39600, + 43200, + 46800 +}; + +stock int g_iTimeZone; +stock const int g_iDaySeconds = 86400; +stock const int g_iHourSeconds = 3600; +stock const int g_iMinuteSeconds = 60; + +//============================================================================================ +// Stocks +//============================================================================================ +stock void UnixToTime( int iTimeStamp_, int &iYear, int &iMonth, int &iDay, int &iHour, int &iMinute, int &iSecond, int iTimeZone_ = UT_TIMEZONE_UTC ) { + int iTemp; + + iYear = 1970; + iMonth = 1; + iDay = 1; + iHour = 0; + + if ( iTimeZone_ == UT_TIMEZONE_SERVER ) + iTimeZone_ = GetTimeZone( ); + + iTimeStamp_ += g_iTimeZoneOffset[ iTimeZone_ ]; + + while( iTimeStamp_ > 0 ) { + iTemp = IsLeapYear( iYear ); + + if ( ( iTimeStamp_ - g_iYearSeconds[ iTemp ] ) >= 0 ) { + iTimeStamp_ -= g_iYearSeconds[ iTemp ]; + iYear ++; + } else { + break; + } + } + + while( iTimeStamp_ > 0 ) { + iTemp = SecondsInMonth( iYear, iMonth ); + + if( ( iTimeStamp_ - iTemp ) >= 0 ) { + iTimeStamp_ -= iTemp; + iMonth ++; + } else { + break; + } + } + + while( iTimeStamp_ > 0 ) { + if ( ( iTimeStamp_ - g_iDaySeconds ) >= 0 ) { + iTimeStamp_ -= g_iDaySeconds; + iDay ++; + } else { + break; + } + } + + while( iTimeStamp_ > 0 ) { + if( ( iTimeStamp_ - g_iHourSeconds ) >= 0 ) { + iTimeStamp_ -= g_iHourSeconds; + iHour ++; + } else { + break; + } + } + + iMinute = ( iTimeStamp_ / 60 ); + iSecond = ( iTimeStamp_ % 60 ); +} + +stock int TimeToUnix( const int iYear, const int iMonth, const int iDay, const int iHour, const int iMinute, const int iSecond, int iTimeZone = UT_TIMEZONE_UTC ) { + int iIterator, iTimeStamp; + + for( iIterator = 1970; iIterator < iYear ; iIterator ++ ) + iTimeStamp += g_iYearSeconds[ IsLeapYear( iIterator ) ]; + + for( iIterator = 1 ; iIterator < iMonth; iIterator ++ ) + iTimeStamp += SecondsInMonth( iYear , iIterator ); + + iTimeStamp += ( ( iDay - 1 ) * g_iDaySeconds ); + iTimeStamp += ( iHour * g_iHourSeconds ); + iTimeStamp += ( iMinute * g_iMinuteSeconds ); + iTimeStamp += iSecond; + + if( iTimeZone == UT_TIMEZONE_SERVER ) + iTimeZone = GetTimeZone( ); + + return ( iTimeStamp + g_iTimeZoneOffset[ iTimeZone ] ); +} + +stock int GetTimeZone( ) { + if( g_iTimeZone ) + return g_iTimeZone; + + int iZone, iOffset, iTime, iYear, iMonth, iDay, iHour, iMinute, iSecond; + + char szTime[ 64 ]; + FormatTime( szTime, sizeof( szTime ), "%m~%d~%y~%H~%M~%S", GetTime( ) ); + + char szTimeParts[ 6 ][ 4 ]; + ExplodeString( szTime, "~", szTimeParts, sizeof( szTimeParts ), sizeof( szTimeParts[ ] ) ); + + iYear = StringToInt( szTimeParts[ 2 ] ); + iMonth = StringToInt( szTimeParts[ 0 ] ); + iDay = StringToInt( szTimeParts[ 1 ] ); + + iHour = StringToInt( szTimeParts[ 3 ] ); + iMinute = StringToInt( szTimeParts[ 4 ] ); + iSecond = StringToInt( szTimeParts[ 5 ] ); + + iTime = TimeToUnix( iYear, iMonth, iDay, iHour, iMinute, iSecond, UT_TIMEZONE_UTC ); + iOffset = iTime - GetTime( ); + + for( iZone = 0 ; iZone < 40; iZone ++ ) { + if( iOffset == g_iTimeZoneOffset[ iZone ] ) + break; + } + + return ( g_iTimeZone = iZone ); +} + +stock int SecondsInMonth( const int iYear, const int iMonth ) { + return ( ( IsLeapYear( iYear ) && ( iMonth == 2 ) ) ? ( g_iMonthSeconds[ iMonth - 1 ] + g_iDaySeconds ) : g_iMonthSeconds[ iMonth - 1 ] ); +} + +stock int IsLeapYear( const int iYear ) { + return ( ( ( iYear % 4 ) == 0 ) && ( ( ( iYear % 100 ) != 0) || ( ( iYear % 400 ) == 0 ) ) ); +} + +methodmap Date < StringMap +{ + public Date() + { + StringMap map = new StringMap(); + int currentTime = GetTime(); + map.SetValue("time", currentTime); + int year, month, day, hour, minute, second; + UnixToTime(currentTime, year, month, day, hour, minute, second, UT_TIMEZONE_UTC); + map.SetValue("year", year); + map.SetValue("month", month); + map.SetValue("day", day); + map.SetValue("hour", hour); + map.SetValue("minute", minute); + map.SetValue("second", second); + map.SetValue("timezone", UT_TIMEZONE_UTC); + return view_as(map); + } +} \ No newline at end of file diff --git a/scripting/include/dbi.inc b/scripting/include/dbi.inc new file mode 100644 index 0000000..55bc695 --- /dev/null +++ b/scripting/include/dbi.inc @@ -0,0 +1,1066 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _dbi_included + #endinput +#endif +#define _dbi_included + +/** + * Describes a database field fetch status. + */ +enum DBResult +{ + DBVal_Error = 0, /**< Column number/field is invalid. */ + DBVal_TypeMismatch = 1, /**< You cannot retrieve this data with this type. */ + DBVal_Null = 2, /**< Field has no data (NULL) */ + DBVal_Data = 3, /**< Field has data */ +}; + +/** + * Describes binding types. + */ +enum DBBindType +{ + DBBind_Int = 0, /**< Bind an integer. */ + DBBind_Float = 1, /**< Bind a float. */ + DBBind_String = 2, /**< Bind a string. */ +}; + +/** + * Threading priority level. + */ +enum DBPriority +{ + DBPrio_High = 0, /**< High priority. */ + DBPrio_Normal = 1, /**< Normal priority. */ + DBPrio_Low = 2, /**< Low priority. */ +}; + +// A Driver represents a database backend, currently MySQL or SQLite. +// +// Driver handles cannot be closed. +methodmap DBDriver < Handle +{ + // Finds the driver associated with a name. + // + // Supported driver strings: + // mysql + // sqlite + // + // @param name Driver identification string, or an empty string + // to return the default driver. + // @return Driver handle, or null on failure. + public static native DBDriver Find(const char[] name = ""); + + // Retrieves a driver's identification string. + // + // Example: "mysql", "sqlite" + // + // @param ident Identification string buffer. + // @param maxlength Maximum length of the buffer. + public native void GetIdentifier(char[] ident, int maxlength); + + // Retrieves a driver's product string. + // + // Example: "MySQL", "SQLite" + // + // @param product Product string buffer. + // @param maxlength Maximum length of the buffer. + public native void GetProduct(char[] product, int maxlength); +}; + +// Represents a set of results returned from executing a query. +methodmap DBResultSet < Handle +{ + // Advances to the next set of results. + // + // In some SQL implementations, multiple result sets can exist on one query. + // This is possible in MySQL with simple queries when executing a CALL + // query. If this is the case, all result sets must be processed before + // another query is made. + // + // @return True if there was another result set, false otherwise. + public native bool FetchMoreResults(); + + // Returns whether or not a result set exists. This will + // return true even if 0 results were returned, but false + // on queries like UPDATE, INSERT, or DELETE. + property bool HasResults { + public native get(); + } + + // Retrieves the number of rows in the last result set. + // + // @param query A query (or statement) Handle. + // @return Number of rows in the current result set. + property int RowCount { + public native get(); + } + + // Retrieves the number of fields in the last result set. + property int FieldCount { + public native get(); + } + + // Returns the number of affected rows from the query that generated this + // result set. + property int AffectedRows { + public native get(); + } + + // Returns the insert id from the query that generated this result set. + property int InsertId { + public native get(); + } + + // Retrieves the name of a field by index. + // + // @param field Field number (starting from 0). + // @param name Name buffer. + // @param maxlength Maximum length of the name buffer. + // @error Invalid field index, or no current result set. + public native void FieldNumToName(int field, char[] name, int maxlength); + + // Retrieves a field index by name. + // + // @param name Name of the field (case sensitive). + // @param field Variable to store field index in. + // @return True if found, false if not found. + // @error No current result set. + public native bool FieldNameToNum(const char[] name, int &field); + + // Fetches a row from the current result set. This must be + // successfully called before any results are fetched. + // + // If this function fails, _MoreResults can be used to + // tell if there was an error or the result set is finished. + // + // @return True if a row was fetched, false otherwise. + public native bool FetchRow(); + + // Returns if there are more rows. + // + // @return True if there are more rows, false otherwise. + property bool MoreRows { + public native get(); + } + + // Rewinds a result set back to the first result. + // + // @return True on success, false otherwise. + // @error No current result set. + public native bool Rewind(); + + // Fetches a string from a field in the current row of a result set. + // If the result is NULL, an empty string will be returned. A NULL + // check can be done with the result parameter, or SQL_IsFieldNull(). + // + // @param field The field index (starting from 0). + // @param buffer String buffer. + // @param maxlength Maximum size of the string buffer. + // @param result Optional variable to store the status of the return value. + // @return Number of bytes written. + // @error Invalid field index, invalid type conversion requested + // from the database, or no current result set. + public native int FetchString(int field, char[] buffer, int maxlength, + DBResult &result=DBVal_Error); + + // Fetches a float from a field in the current row of a result set. + // If the result is NULL, a value of 0.0 will be returned. A NULL + // check can be done with the result parameter, or SQL_IsFieldNull(). + // + // @param field The field index (starting from 0). + // @param result Optional variable to store the status of the return value. + // @return A float value. + // @error Invalid field index, invalid type conversion requested + // from the database, or no current result set. + public native float FetchFloat(int field, DBResult &result=DBVal_Error); + + // Fetches an integer from a field in the current row of a result set. + // If the result is NULL, a value of 0 will be returned. A NULL + // check can be done with the result parameter, or SQL_IsFieldNull(). + // + // @param field The field index (starting from 0). + // @param result Optional variable to store the status of the return value. + // @return An integer value. + // @error Invalid field index, invalid type conversion requested + // from the database, or no current result set. + public native int FetchInt(int field, DBResult &result=DBVal_Error); + + // Returns whether a field's data in the current row of a result set is + // NULL or not. NULL is an SQL type which means "no data." + // + // @param field The field index (starting from 0). + // @return True if data is NULL, false otherwise. + // @error Invalid field index, or no current result set. + public native bool IsFieldNull(int field); + + // Returns the length of a field's data in the current row of a result + // set. This only needs to be called for strings to determine how many + // bytes to use. Note that the return value does not include the null + // terminator. + // + // @param field The field index (starting from 0). + // @return Number of bytes for the field's data size. + // @error Invalid field index or no current result set. + public native int FetchSize(int field); +}; + +typeset SQLTxnSuccess +{ + // Callback for a successful transaction. + // + // @param db Database handle. + // @param data Data value passed to SQL_ExecuteTransaction(). + // @param numQueries Number of queries executed in the transaction. + // @param results An array of Query handle results, one for each of numQueries. They are closed automatically. + // @param queryData An array of each data value passed to SQL_AddQuery(). + function void (Database db, any data, int numQueries, Handle[] results, any[] queryData); + + // Callback for a successful transaction. + // + // @param db Database handle. + // @param data Data value passed to SQL_ExecuteTransaction(). + // @param numQueries Number of queries executed in the transaction. + // @param results An array of DBResultSet results, one for each of numQueries. They are closed automatically. + // @param queryData An array of each data value passed to SQL_AddQuery(). + function void (Database db, any data, int numQueries, DBResultSet[] results, any[] queryData); +} + +// Callback for a failed transaction. +// +// @param db Database handle. +// @param data Data value passed to SQL_ExecuteTransaction(). +// @param numQueries Number of queries executed in the transaction. +// @param error Error message. +// @param failIndex Index of the query that failed, or -1 if something else. +// @param queryData An array of each data value passed to SQL_AddQuery(). +typedef SQLTxnFailure = function void (Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData); + +// A Transaction is a collection of SQL statements that must all execute +// successfully or not at all. +methodmap Transaction < Handle +{ + // Create a new transaction. + public native Transaction(); + + // Adds a query to the transaction. + // + // @param query Query string. + // @param data Extra data value to pass to the final callback. + // @return The index of the query in the transaction's query list. + public native int AddQuery(const char[] query, any data=0); +}; + +// A DBStatement is a pre-compiled SQL query that may be executed multiple +// times with different parameters. A DBStatement holds a reference to the +// Database that prepared it. +methodmap DBStatement < Handle +{ + // Binds a parameter in a prepared statement to a given integer value. + // + // @param param The parameter index (starting from 0). + // @param number The number to bind. + // @param signed True to bind the number as signed, false to + // bind it as unsigned. + // @error Invalid parameter index, or SQL error. + public native void BindInt(int param, int number, bool signed=true); + + // Binds a parameter in a prepared statement to a given float value. + // + // @param param The parameter index (starting from 0). + // @param value The float number to bind. + // @error Invalid parameter index, or SQL error. + public native void BindFloat(int param, float value); + + // Binds a parameter in a prepared statement to a given string value. + // + // @param param The parameter index (starting from 0). + // @param value The string to bind. + // @param copy Whether or not SourceMod should copy the value + // locally if necessary. If the string contents + // won't change before calling SQL_Execute(), this + // can be set to false for optimization. + // @error Invalid parameter index, or SQL error. + public native void BindString(int param, const char[] value, bool copy); +}; + +// Callback for receiving asynchronous database connections. +// +// @param db Handle to the database connection. +// @param error Error string if there was an error. The error could be +// empty even if an error condition exists, so it is important +// to check the actual Handle value instead. +// @param data Data passed in via the original threaded invocation. +typedef SQLConnectCallback = function void (Database db, const char[] error, any data); + +// Callback for receiving asynchronous database query results. +// +// @param db Cloned handle to the database connection. +// @param results Result object, or null on failure. +// @param error Error string if there was an error. The error could be +// empty even if an error condition exists, so it is important +// to check the actual results value instead. +// @param data Data passed in via the original threaded invocation. +typedef SQLQueryCallback = function void (Database db, DBResultSet results, const char[] error, any data); + +// A Database represents a live connection to a database, either over the +// wire, through a unix domain socket, or over an open file. +methodmap Database < Handle +{ + // Connects to a database asynchronously, so the game thread is not blocked. + // + // @param callback Callback. If no driver was found, the owner is null. + // @param name Database configuration name. + // @param data Extra data value to pass to the callback. + public static native void Connect(SQLConnectCallback callback, const char[] name="default", any data=0); + + // Returns the driver for this database connection. + property DBDriver Driver { + public native get(); + } + + // Sets the character set of the connection. + // Like SET NAMES .. in mysql, but stays after connection problems. + // + // Example: "utf8", "latin1" + // + // @param characterset The character set string to change to. + // @return True, if character set was changed, false otherwise. + public native bool SetCharset(const char[] charset); + + // Escapes a database string for literal insertion. This is not needed + // for binding strings in prepared statements. + // + // Generally, database strings are inserted into queries enclosed in + // single quotes ('). If user input has a single quote in it, the + // quote needs to be escaped. This function ensures that any unsafe + // characters are safely escaped according to the database engine and + // the database's character set. + // + // NOTE: SourceMod only guarantees properly escaped strings when the query + // encloses the string in ''. While drivers tend to allow " instead, the string + // may be not be escaped (for example, on SQLite)! + // + // @param string String to quote. + // @param buffer Buffer to store quoted string in. + // @param maxlength Maximum length of the buffer. + // @param written Optionally returns the number of bytes written. + // @return True on success, false if buffer is not big enough. + // The buffer must be at least 2*strlen(string)+1. + public native bool Escape(const char[] string, char[] buffer, int maxlength, int &written=0); + + // Formats a string according to the SourceMod format rules (see documentation). + // All format specifiers are escaped (see SQL_EscapeString) unless the '!' flag is used. + // + // @param buffer Destination string buffer. + // @param maxlength Maximum length of output string buffer. + // @param format Formatting rules. + // @param ... Variable number of format parameters. + // @return Number of cells written. + public native int Format(const char[] buffer, int maxlength, const char[] format, any ...); + + // Returns whether a database is the same connection as another database. + public native bool IsSameConnection(Database other); + + // Executes a query via a thread. The result handle is passed through the + // callback. + // + // The database handle returned through the callback is always a new Handle, + // and if necessary, IsSameConnection() should be used to test against other + // connections. + // + // The result handle returned through the callback is temporary and destroyed + // at the end of the callback. + // + // @param callback Callback. + // @param query Query string. + // @param data Extra data value to pass to the callback. + // @param prio Priority queue to use. + public native void Query(SQLQueryCallback callback, const char[] query, + any data = 0, + DBPriority prio = DBPrio_Normal); + + // Sends a transaction to the database thread. The transaction handle is + // automatically closed. When the transaction completes, the optional + // callback is invoked. + // + // @param txn A transaction handle. + // @param onSuccess An optional callback to receive a successful transaction. + // @param onError An optional callback to receive an error message. + // @param data An optional value to pass to callbacks. + // @param prio Priority queue to use. + public native void Execute(Transaction txn, + SQLTxnSuccess onSuccess = INVALID_FUNCTION, + SQLTxnFailure onError = INVALID_FUNCTION, + any data = 0, + DBPriority priority = DBPrio_Normal); +}; + +/** + * Creates an SQL connection from a named configuration. + * + * @param confname Named configuration. + * @param persistent True to re-use a previous persistent connection if + * possible, false otherwise. + * @param error Error buffer. + * @param maxlength Maximum length of the error buffer. + * @return A database connection Handle, or INVALID_HANDLE on failure. + */ +native Database SQL_Connect(const char[] confname, bool persistent, char[] error, int maxlength); + +/** + * Creates a default SQL connection. + * + * @param error Error buffer. + * @param maxlength Maximum length of the error buffer. + * @param persistent True to re-use a previous persistent connection + * if possible, false otherwise. + * @return A database connection Handle, or INVALID_HANDLE on failure. + * On failure the error buffer will be filled with a message. + */ +stock Database SQL_DefConnect(char[] error, int maxlength, bool persistent=true) +{ + return SQL_Connect("default", persistent, error, maxlength); +} + +/** + * Connects to a database using key value pairs containing the database info. + * The key/value pairs should match what would be in databases.cfg. + * + * I.e. "driver" should be "default" or a driver name (or omitted for + * the default). For SQLite, only the "database" parameter is needed in addition. + * For drivers which require external connections, more of the parameters may be + * needed. + * + * In general it is discouraged to use this function. Connections should go through + * databases.cfg for greatest flexibility on behalf of users. + * + * @param keyvalues Key/value pairs from a KeyValues handle, describing the connection. + * @param error Error buffer. + * @param maxlength Maximum length of the error buffer. + * @param persistent True to re-use a previous persistent connection if + * possible, false otherwise. + * @return A database connection Handle, or INVALID_HANDLE on failure. + * On failure the error buffer will be filled with a message. + * @error Invalid KeyValues handle. + */ +native Database SQL_ConnectCustom(Handle keyvalues, + char[] error, + int maxlength, + bool persistent); + +/** + * Grabs a handle to an SQLite database, creating one if it does not exist. + * + * Unless there are extenuating circumstances, you should consider using "sourcemod-local" as the + * database name. This provides some unification between plugins on behalf of users. + * + * As a precaution, you should always create some sort of unique prefix to your table names so + * there are no conflicts, and you should never drop or modify tables that you do not own. + * + * @param database Database name. + * @param error Error buffer. + * @param maxlength Maximum length of the error buffer. + * @return A database connection Handle, or INVALID_HANDLE on failure. + * On failure the error buffer will be filled with a message. + */ +stock Database SQLite_UseDatabase(const char[] database, + char[] error, + int maxlength) +{ + KeyValues kv = new KeyValues(""); + kv.SetString("driver", "sqlite"); + kv.SetString("database", database); + + Database db = SQL_ConnectCustom(kv, error, maxlength, false); + + delete kv; + + return db; +} + +/** + * This function is deprecated. Use SQL_ConnectCustom or SQLite_UseDatabase instead. + */ +#pragma deprecated Use SQL_ConnectCustom instead. +native Handle SQL_ConnectEx(Handle driver, + const char[] host, + const char[] user, + const char[] pass, + const char[] database, + char[] error, + int maxlength, + bool persistent=true, + int port=0, + int maxTimeout=0); + +/** + * Returns if a named configuration is present in databases.cfg. + * + * @param name Configuration name. + * @return True if it exists, false otherwise. + */ +native bool SQL_CheckConfig(const char[] name); + +/** + * Returns a driver Handle from a name string. + * + * If the driver is not found, SourceMod will attempt + * to load an extension named dbi..ext.[dll|so]. + * + * @param name Driver identification string, or an empty + * string to return the default driver. + * @return Driver Handle, or INVALID_HANDLE on failure. + */ +native Handle SQL_GetDriver(const char[] name=""); + +/** + * Reads the driver of an opened database. + * + * @param database Database Handle. + * @param ident Option buffer to store the identification string. + * @param ident_length Maximum length of the buffer. + * @return Driver Handle. + */ +native Handle SQL_ReadDriver(Handle database, char[] ident="", int ident_length=0); + +/** + * Retrieves a driver's identification string. + * + * Example: "mysql", "sqlite" + * + * @param driver Driver Handle, or INVALID_HANDLE for the default driver. + * @param ident Identification string buffer. + * @param maxlength Maximum length of the buffer. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native void SQL_GetDriverIdent(Handle driver, char[] ident, int maxlength); + +/** + * Retrieves a driver's product string. + * + * Example: "MySQL", "SQLite" + * + * @param driver Driver Handle, or INVALID_HANDLE for the default driver. + * @param product Product string buffer. + * @param maxlength Maximum length of the buffer. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native void SQL_GetDriverProduct(Handle driver, char[] product, int maxlength); + +/** + * Sets the character set of the current connection. + * Like SET NAMES .. in mysql, but stays after connection problems. + * + * Example: "utf8", "latin1" + * + * @param database Database Handle. + * @param characterset The character set string to change to. + * @return True, if character set was changed, false otherwise. + */ +native bool SQL_SetCharset(Handle database, const char[] charset); + +/** + * Returns the number of affected rows from the last query. + * + * @param hndl A database OR statement Handle. + * @return Number of rows affected by the last query. + * @error Invalid database or statement Handle. + */ +native int SQL_GetAffectedRows(Handle hndl); + +/** + * Returns the last query's insertion id. + * + * @param hndl A database, query, OR statement Handle. + * @return Last query's insertion id. + * @error Invalid database, query, or statement Handle. + */ +native int SQL_GetInsertId(Handle hndl); + +/** + * Returns the error reported by the last query. + * + * @param hndl A database, query, OR statement Handle. + * @param error Error buffer. + * @param maxlength Maximum length of the buffer. + * @return True if there was an error, false otherwise. + * @error Invalid database, query, or statement Handle. + */ +native bool SQL_GetError(Handle hndl, char[] error, int maxlength); + +/** + * Escapes a database string for literal insertion. This is not needed + * for binding strings in prepared statements. + * + * Generally, database strings are inserted into queries enclosed in + * single quotes ('). If user input has a single quote in it, the + * quote needs to be escaped. This function ensures that any unsafe + * characters are safely escaped according to the database engine and + * the database's character set. + * + * NOTE: SourceMod only guarantees properly escaped strings when the query + * encloses the string in ''. While drivers tend to allow " instead, the string + * may be not be escaped (for example, on SQLite)! + * + * @param database A database Handle. + * @param string String to quote. + * @param buffer Buffer to store quoted string in. + * @param maxlength Maximum length of the buffer. + * @param written Optionally returns the number of bytes written. + * @return True on success, false if buffer is not big enough. + * The buffer must be at least 2*strlen(string)+1. + * @error Invalid database or statement Handle. + */ +native bool SQL_EscapeString(Handle database, + const char[] string, + char[] buffer, + int maxlength, + int &written=0); + +/** + * Formats a string according to the SourceMod format rules (see documentation). + * All format specifiers are escaped (see SQL_EscapeString) unless the '!' flag is used. + * + * @param database A database Handle. + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @return Number of cells written. + */ +native int SQL_FormatQuery(Handle database, const char[] buffer, int maxlength, const char[] format, any ...); + +/** + * This is a backwards compatibility stock. You should use SQL_EscapeString() + * instead, as this function will probably be deprecated in SourceMod 1.1. + */ +stock bool SQL_QuoteString(Handle database, + const char[] string, + char[] buffer, + int maxlength, + int &written=0) +{ + return SQL_EscapeString(database, string, buffer, maxlength, written); +} + +/** + * Executes a query and ignores the result set. + * + * @param database A database Handle. + * @param query Query string. + * @param len Optional parameter to specify the query length, in + * bytes. This can be used to send binary queries that + * have a premature terminator. + * @return True if query succeeded, false otherwise. Use + * SQL_GetError to find the last error. + * @error Invalid database Handle. + */ +native bool SQL_FastQuery(Handle database, const char[] query, int len=-1); + +/** + * Executes a simple query and returns a new query Handle for + * receiving the results. + * + * @param database A database Handle. + * @param query Query string. + * @param len Optional parameter to specify the query length, in + * bytes. This can be used to send binary queries that + * have a premature terminator. + * @return A new Query Handle on success, INVALID_HANDLE + * otherwise. The Handle must be freed with CloseHandle(). + * @error Invalid database Handle. + */ +native DBResultSet SQL_Query(Handle database, const char[] query, int len=-1); + +/** + * Creates a new prepared statement query. Prepared statements can + * be executed any number of times. They can also have placeholder + * parameters, similar to variables, which can be bound safely and + * securely (for example, you do not need to quote bound strings). + * + * Statement handles will work in any function that accepts a Query handle. + * + * @param database A database Handle. + * @param query Query string. + * @param error Error buffer. + * @param maxlength Maximum size of the error buffer. + * @return A new statement Handle on success, INVALID_HANDLE + * otherwise. The Handle must be freed with CloseHandle(). + * @error Invalid database Handle. + */ +native DBStatement SQL_PrepareQuery(Handle database, const char[] query, char[] error, int maxlength); + +/** + * Advances to the next set of results. + * + * In some SQL implementations, multiple result sets can exist on one query. + * This is possible in MySQL with simple queries when executing a CALL + * query. If this is the case, all result sets must be processed before + * another query is made. + * + * @param query A query Handle. + * @return True if there was another result set, false otherwise. + * @error Invalid query Handle. + */ +native bool SQL_FetchMoreResults(Handle query); + +/** + * Returns whether or not a result set exists. This will + * return true even if 0 results were returned, but false + * on queries like UPDATE, INSERT, or DELETE. + * + * @param query A query (or statement) Handle. + * @return True if there is a result set, false otherwise. + * @error Invalid query Handle. + */ +native bool SQL_HasResultSet(Handle query); + +/** + * Retrieves the number of rows in the last result set. + * + * @param query A query (or statement) Handle. + * @return Number of rows in the current result set. + * @error Invalid query Handle. + */ +native int SQL_GetRowCount(Handle query); + +/** + * Retrieves the number of fields in the last result set. + * + * @param query A query (or statement) Handle. + * @return Number of fields in the current result set. + * @error Invalid query Handle. + */ +native int SQL_GetFieldCount(Handle query); + +/** + * Retrieves the name of a field by index. + * + * @param query A query (or statement) Handle. + * @param field Field number (starting from 0). + * @param name Name buffer. + * @param maxlength Maximum length of the name buffer. + * @error Invalid query Handle, invalid field index, or + * no current result set. + */ +native void SQL_FieldNumToName(Handle query, int field, char[] name, int maxlength); + +/** + * Retrieves a field index by name. + * + * @param query A query (or statement) Handle. + * @param name Name of the field (case sensitive). + * @param field Variable to store field index in. + * @return True if found, false if not found. + * @error Invalid query Handle or no current result set. + */ +native bool SQL_FieldNameToNum(Handle query, const char[] name, int &field); + +/** + * Fetches a row from the current result set. This must be + * successfully called before any results are fetched. + * + * If this function fails, SQL_MoreResults() can be used to + * tell if there was an error or the result set is finished. + * + * @param query A query (or statement) Handle. + * @return True if a row was fetched, false otherwise. + * @error Invalid query Handle. + */ +native bool SQL_FetchRow(Handle query); + +/** + * Returns if there are more rows. + * + * @param query A query (or statement) Handle. + * @return True if there are more rows, false otherwise. + * @error Invalid query Handle. + */ +native bool SQL_MoreRows(Handle query); + +/** + * Rewinds a result set back to the first result. + * + * @param query A query (or statement) Handle. + * @return True on success, false otherwise. + * @error Invalid query Handle or no current result set. + */ +native bool SQL_Rewind(Handle query); + +/** + * Fetches a string from a field in the current row of a result set. + * If the result is NULL, an empty string will be returned. A NULL + * check can be done with the result parameter, or SQL_IsFieldNull(). + * + * @param query A query (or statement) Handle. + * @param field The field index (starting from 0). + * @param buffer String buffer. + * @param maxlength Maximum size of the string buffer. + * @param result Optional variable to store the status of the return value. + * @return Number of bytes written. + * @error Invalid query Handle or field index, invalid + * type conversion requested from the database, + * or no current result set. + */ +native int SQL_FetchString(Handle query, int field, char[] buffer, int maxlength, DBResult &result=DBVal_Error); + +/** + * Fetches a float from a field in the current row of a result set. + * If the result is NULL, a value of 0.0 will be returned. A NULL + * check can be done with the result parameter, or SQL_IsFieldNull(). + * + * @param query A query (or statement) Handle. + * @param field The field index (starting from 0). + * @param result Optional variable to store the status of the return value. + * @return A float value. + * @error Invalid query Handle or field index, invalid + * type conversion requested from the database, + * or no current result set. + */ +native float SQL_FetchFloat(Handle query, int field, DBResult &result=DBVal_Error); + +/** + * Fetches an integer from a field in the current row of a result set. + * If the result is NULL, a value of 0 will be returned. A NULL + * check can be done with the result parameter, or SQL_IsFieldNull(). + * + * @param query A query (or statement) Handle. + * @param field The field index (starting from 0). + * @param result Optional variable to store the status of the return value. + * @return An integer value. + * @error Invalid query Handle or field index, invalid + * type conversion requested from the database, + * or no current result set. + */ +native int SQL_FetchInt(Handle query, int field, DBResult &result=DBVal_Error); + +/** + * Returns whether a field's data in the current row of a result set is + * NULL or not. NULL is an SQL type which means "no data." + * + * @param query A query (or statement) Handle. + * @param field The field index (starting from 0). + * @return True if data is NULL, false otherwise. + * @error Invalid query Handle or field index, or no + * current result set. + */ +native bool SQL_IsFieldNull(Handle query, int field); + +/** + * Returns the length of a field's data in the current row of a result + * set. This only needs to be called for strings to determine how many + * bytes to use. Note that the return value does not include the null + * terminator. + * + * @param query A query (or statement) Handle. + * @param field The field index (starting from 0). + * @return Number of bytes for the field's data size. + * @error Invalid query Handle or field index or no + * current result set. + */ +native int SQL_FetchSize(Handle query, int field); + +/** + * Binds a parameter in a prepared statement to a given integer value. + * + * @param statement A statement (prepared query) Handle. + * @param param The parameter index (starting from 0). + * @param number The number to bind. + * @param signed True to bind the number as signed, false to + * bind it as unsigned. + * @error Invalid statement Handle or parameter index, or + * SQL error. + */ +native void SQL_BindParamInt(Handle statement, int param, int number, bool signed=true); + +/** + * Binds a parameter in a prepared statement to a given float value. + * + * @param statement A statement (prepared query) Handle. + * @param param The parameter index (starting from 0). + * @param value The float number to bind. + * @error Invalid statement Handle or parameter index, or + * SQL error. + */ +native void SQL_BindParamFloat(Handle statement, int param, float value); + +/** + * Binds a parameter in a prepared statement to a given string value. + * + * @param statement A statement (prepared query) Handle. + * @param param The parameter index (starting from 0). + * @param value The string to bind. + * @param copy Whether or not SourceMod should copy the value + * locally if necessary. If the string contents + * won't change before calling SQL_Execute(), this + * can be set to false for optimization. + * @error Invalid statement Handle or parameter index, or + * SQL error. + */ +native void SQL_BindParamString(Handle statement, int param, const char[] value, bool copy); + +/** + * Executes a prepared statement. All parameters must be bound beforehand. + * + * @param statement A statement (prepared query) Handle. + * @return True on success, false on failure. + * @error Invalid statement Handle. + */ +native bool SQL_Execute(Handle statement); + +/** + * Locks a database so threading operations will not interrupt. + * + * If you are using a database Handle for both threading and non-threading, + * this MUST be called before doing any set of non-threading DB operations. + * Otherwise you risk corrupting the database driver's memory or network + * connection. + * + * Leaving a lock on a database and then executing a threaded query results + * in a dead lock! Make sure to call SQL_UnlockDatabase()! + * + * If the lock cannot be acquired, the main thread will pause until the + * threaded operation has concluded. + * + * @param database A database Handle. + * @error Invalid database Handle. + */ +native void SQL_LockDatabase(Handle database); + +/** + * Unlocks a database so threading operations may continue. + * + * @param database A database Handle. + * @error Invalid database Handle. + */ +native void SQL_UnlockDatabase(Handle database); + +// General callback for threaded SQL stuff. +// +// @param owner Parent object of the Handle (or INVALID_HANDLE if none). +// @param hndl Handle to the child object (or INVALID_HANDLE if none). +// @param error Error string if there was an error. The error could be +// empty even if an error condition exists, so it is important +// to check the actual Handle value instead. +// @param data Data passed in via the original threaded invocation. +typedef SQLTCallback = function void (Handle owner, Handle hndl, const char[] error, any data); + +/** + * Tells whether two database handles both point to the same database + * connection. + * + * @param hndl1 First database Handle. + * @param hndl2 Second database Handle. + * @return True if the Handles point to the same + * connection, false otherwise. + * @error Invalid Handle. + */ +native bool SQL_IsSameConnection(Handle hndl1, Handle hndl2); + +/** + * Connects to a database via a thread. This can be used instead of + * SQL_Connect() if you wish for non-blocking functionality. + * + * It is not necessary to use this to use threaded queries. However, if you + * don't (or you mix threaded/non-threaded queries), you should see + * SQL_LockDatabase(). + * + * @param callback Callback; new Handle will be in hndl, owner is the driver. + * If no driver was found, the owner is INVALID_HANDLE. + * @param name Database name. + * @param data Extra data value to pass to the callback. + */ +native void SQL_TConnect(SQLTCallback callback, const char[] name="default", any data=0); + +/** + * Executes a simple query via a thread. The query Handle is passed through + * the callback. + * + * The database Handle returned through the callback is always a new Handle, + * and if necessary, SQL_IsSameConnection() should be used to test against + * other connections. + * + * The query Handle returned through the callback is temporary and destroyed + * at the end of the callback. If you need to hold onto it, use CloneHandle(). + * + * @param database A database Handle. + * @param callback Callback; database is in "owner" and the query Handle + * is passed in "hndl". + * @param query Query string. + * @param data Extra data value to pass to the callback. + * @param prio Priority queue to use. + * @error Invalid database Handle. + */ +native void SQL_TQuery(Handle database, SQLTCallback callback, const char[] query, any data=0, DBPriority prio=DBPrio_Normal); + +/** + * Creates a new transaction object. A transaction object is a list of queries + * that can be sent to the database thread and executed as a single transaction. + * + * @return A transaction handle. + */ +native Transaction SQL_CreateTransaction(); + +/** + * Adds a query to a transaction object. + * + * @param txn A transaction handle. + * @param query Query string. + * @param data Extra data value to pass to the final callback. + * @return The index of the query in the transaction's query list. + * @error Invalid transaction handle. + */ +native int SQL_AddQuery(Transaction txn, const char[] query, any data=0); + +/** + * Sends a transaction to the database thread. The transaction handle is + * automatically closed. When the transaction completes, the optional + * callback is invoked. + * + * @param db A database handle. + * @param txn A transaction handle. + * @param onSuccess An optional callback to receive a successful transaction. + * @param onError An optional callback to receive an error message. + * @param data An optional value to pass to callbacks. + * @param prio Priority queue to use. + * @error An invalid handle. + */ +native void SQL_ExecuteTransaction( + Handle db, + Transaction txn, + SQLTxnSuccess onSuccess = INVALID_FUNCTION, + SQLTxnFailure onError = INVALID_FUNCTION, + any data=0, + DBPriority priority=DBPrio_Normal); diff --git a/scripting/include/entity.inc b/scripting/include/entity.inc new file mode 100644 index 0000000..fba1e80 --- /dev/null +++ b/scripting/include/entity.inc @@ -0,0 +1,759 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _entity_included + #endinput +#endif +#define _entity_included + +/** + * Property types for entities. + */ +enum PropType +{ + Prop_Send = 0, /**< This property is networked. */ + Prop_Data = 1, /**< This property is for save game data fields. */ +}; + +/** + * @section For more information on these, see the HL2SDK (public/edict.h) + */ +#define FL_EDICT_CHANGED (1<<0) /**< Game DLL sets this when the entity state changes + Mutually exclusive with FL_EDICT_PARTIAL_CHANGE. */ +#define FL_EDICT_FREE (1<<1) /**< this edict if free for reuse */ +#define FL_EDICT_FULL (1<<2) /**< this is a full server entity */ +#define FL_EDICT_FULLCHECK (0<<0) /**< call ShouldTransmit() each time, this is a fake flag */ +#define FL_EDICT_ALWAYS (1<<3) /**< always transmit this entity */ +#define FL_EDICT_DONTSEND (1<<4) /**< don't transmit this entity */ +#define FL_EDICT_PVSCHECK (1<<5) /**< always transmit entity, but cull against PVS */ +#define FL_EDICT_PENDING_DORMANT_CHECK (1<<6) +#define FL_EDICT_DIRTY_PVS_INFORMATION (1<<7) +#define FL_FULL_EDICT_CHANGED (1<<8) + +enum PropFieldType +{ + PropField_Unsupported, /**< The type is unsupported. */ + PropField_Integer, /**< Valid for SendProp and Data fields */ + PropField_Float, /**< Valid for SendProp and Data fields */ + PropField_Entity, /**< Valid for Data fields only (SendProp shows as int) */ + PropField_Vector, /**< Valid for SendProp and Data fields */ + PropField_String, /**< Valid for SendProp and Data fields */ + PropField_String_T, /**< Valid for Data fields. Read only. + Note that the size of a string_t is dynamic, and + thus FindDataMapOffs() will return the constant size + of the string_t container (which is 32 bits right now). + */ + PropField_Variant, /**< Valid for Data fields only Type is not known at the field level, + (for this call), but dependent on current field value. */ +}; + +/** + * @endsection + */ + +/** + * Returns the maximum number of networked entities. + * + * Note: For legacy reasons, this only returns the maximum + * networked entities (maximum edicts), rather than total + * maximum entities. + * + * @return Maximum number of networked entities. + */ +native int GetMaxEntities(); + +/** + * Returns the number of networked entities in the server. + * + * Note: For legacy reasons, this only returns the current count + * of networked entities (current edicts), rather than total + * count of current entities. + * + * @return Number of entities in the server. + */ +native int GetEntityCount(); + +/** + * Returns whether or not an entity is valid. Returns false + * if there is no matching CBaseEntity for this entity index. + * + * @param entity Index of the entity. + * @return True if valid, false otherwise. + */ +native bool IsValidEntity(int entity); + +/** + * Returns whether or not an edict index is valid. + * + * @param edict Index of the edict. + * @return True if valid, false otherwise. + */ +native bool IsValidEdict(int edict); + +/** + * Returns whether or not an entity has a valid networkable edict. + * + * @param edict Index of the entity. + * @return True if networkable, false if invalid or not networkable. + */ +native bool IsEntNetworkable(int entiy); + +/** + * Creates a new edict (the basis of a networkable entity) + * + * @return Index of the edict, 0 on failure. + */ +native int CreateEdict(); + +/** + * Removes an edict from the world. + * + * @param edict Index of the edict. + * @error Invalid edict index. + */ +native void RemoveEdict(int edict); + +/** + * Marks an entity for deletion. + * + * @param entity Index of the entity. + * @error Invalid entity index. + */ +native void RemoveEntity(int entity); + +/** + * Returns the flags on an edict. These are not the same as entity flags. + * + * @param edict Index of the entity. + * @return Edict flags. + * @error Invalid edict index. + */ +native int GetEdictFlags(int edict); + +/** + * Sets the flags on an edict. These are not the same as entity flags. + * + * @param edict Index of the entity. + * @param flags Flags to set. + * @error Invalid edict index. + */ +native void SetEdictFlags(int edict, int flags); + +/** + * Retrieves an edict classname. + * + * @param edict Index of the entity. + * @param clsname Buffer to store the classname. + * @param maxlength Maximum length of the buffer. + * @return True on success, false if there is no classname set. + */ +native bool GetEdictClassname(int edict, char[] clsname, int maxlength); + +/** + * Retrieves an entity's networkable serverclass name. + * This is not the same as the classname and is used for networkable state changes. + * + * @param edict Index of the entity. + * @param clsname Buffer to store the serverclass name. + * @param maxlength Maximum length of the buffer. + * @return True on success, false if the edict is not networkable. + * @error Invalid edict index. + */ +native bool GetEntityNetClass(int edict, char[] clsname, int maxlength); + +/** + * @section Entity offset functions + * + * Offsets should be specified in byte distance from the CBaseEntity + * structure, not short (double byte) or integer (four byte) multiples. + * It is somewhat common practice to use offsets aligned to their final + * type, and thus make sure you are not falling to this error in SourceMod. + * For example, if your "integer-aligned" offset was 119, your byte-aligned + * offset is 119*4, or 476. + + * Specifying incorrect offsets or the incorrect data type for an offset + * can have fatal consequences. If you are hardcoding offsets, and the + * layout of CBaseEntity does not match, you can easily crash the server. + * + * The reasonable bounds for offsets is greater than or equal to 0 and + * below 32768. Offsets out of these bounds will throw an error. However, + * this does not represent any real range, it is simply a sanity check for + * illegal values. Any range outside of the CBaseEntity structure's private + * size will cause undefined behavior or even crash. + */ + +/** + * Marks an entity as state changed. This can be useful if you set an offset + * and wish for it to be immediately changed over the network. By default this + * is not done for offset setting functions. + * + * @param edict Index to the edict. + * @param offset Offset to mark as changed. If 0, + * the entire edict is marked as changed. + * @error Invalid entity or offset out of bounds. + */ +native void ChangeEdictState(int edict, int offset = 0); + +/** + * Peeks into an entity's object data and retrieves the integer value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param size Number of bytes to read (valid values are 1, 2, or 4). + * @return Value at the given memory location. + * @error Invalid entity or offset out of reasonable bounds. + */ +native int GetEntData(int entity, int offset, int size=4); + +/** + * Peeks into an entity's object data and sets the integer value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param value Value to set. + * @param size Number of bytes to write (valid values are 1, 2, or 4). + * @param changeState If true, change will be sent over the network. + * @error Invalid entity or offset out of reasonable bounds. + */ +native void SetEntData(int entity, int offset, any value, int size=4, bool changeState=false); + +/** + * Peeks into an entity's object data and retrieves the float value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @return Value at the given memory location. + * @error Invalid entity or offset out of reasonable bounds. + */ +native float GetEntDataFloat(int entity, int offset); + +/** + * Peeks into an entity's object data and sets the float value at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param value Value to set. + * @param changeState If true, change will be sent over the network. + * @error Invalid entity or offset out of reasonable bounds. + */ +native void SetEntDataFloat(int entity, int offset, float value, bool changeState=false); + +/** + * This function is deprecated. Use GetEntDataEnt2 instead, for + * reasons explained in the notes. + * + * Note: This function returns 0 on failure, which may be misleading, + * as the number 0 is also used for the world entity index. + * + * Note: This function makes no attempt to validate the returned + * entity, and in fact, it could be garbage or completely unexpected. + * + * @param entity Edict index. + * @param offset Offset to use. + * @return Entity index at the given location, or 0 if none. + * @error Invalid entity or offset out of reasonable bounds. + */ +#pragma deprecated Use GetEntDataEnt2() instead. +native int GetEntDataEnt(int entity, int offset); + +/** + * This function is deprecated. Use SetEntDataEnt2 instead, for + * reasons explained in the notes. + * + * Note: This function uses 0 as an indicator to unset data, but + * 0 is also the world entity index. Thus, a property cannot + * be set to the world entity using this native. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param other Entity index to set, or 0 to clear. + * @param changeState If true, change will be sent over the network. + * @error Invalid entity or offset out of reasonable bounds. + */ +#pragma deprecated Use SetEntDataEnt2() instead. +native void SetEntDataEnt(int entity, int offset, int other, bool changeState=false); + +/** + * Peeks into an entity's object data and retrieves the entity index + * at the given offset. + * + * Note: This will only work on offsets that are stored as "entity + * handles" (which usually looks like m_h* in properties). These + * are not SourceMod Handles, but internal Source structures. + * + * @param entity Edict index. + * @param offset Offset to use. + * @return Entity index at the given location. If there is no entity, + * or the stored entity is invalid, then -1 is returned. + * @error Invalid input entity, or offset out of reasonable bounds. + */ +native int GetEntDataEnt2(int entity, int offset); + +/** + * Peeks into an entity's object data and sets the entity index at the + * given offset. + * + * Note: This will only work on offsets that are stored as "entity + * handles" (which usually looks like m_h* in properties). These + * are not SourceMod Handles, but internal Source structures. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param other Entity index to set, or -1 to clear. + * @param changeState If true, change will be sent over the network. + * @error Invalid input entity, or offset out of reasonable bounds. + */ +native void SetEntDataEnt2(int entity, int offset, int other, bool changeState=false); + +/** + * Peeks into an entity's object data and retrieves the vector at the + * given offset. + * @note Both a Vector and a QAngle are three floats. This is a + * convenience function and will work with both types. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param vec Vector buffer to store data in. + * @error Invalid entity or offset out of reasonable bounds. + */ +native void GetEntDataVector(int entity, int offset, float vec[3]); + +/** + * Peeks into an entity's object data and sets the vector at the given + * offset. + * @note Both a Vector and a QAngle are three floats. This is a + * convenience function and will work with both types. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param vec Vector to set. + * @param changeState If true, change will be sent over the network. + * @error Invalid entity or offset out of reasonable bounds. + */ +native void SetEntDataVector(int entity, int offset, const float vec[3], bool changeState=false); + +/** + * Peeks into an entity's object data and retrieves the string at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @return Number of non-null bytes written. + * @error Invalid entity or offset out of reasonable bounds. + */ +native int GetEntDataString(int entity, int offset, char[] buffer, int maxlen); + +/** + * Peeks into an entity's object data and sets the string at + * the given offset. + * + * @param entity Edict index. + * @param offset Offset to use. + * @param buffer String to set. + * @param maxlen Maximum length of bytes to write. + * @param changeState If true, change will be sent over the network. + * @return Number of non-null bytes written. + * @error Invalid entity or offset out of reasonable bounds. + */ +native int SetEntDataString(int entity, int offset, const char[] buffer, int maxlen, bool changeState=false); + +/** + * @endsection + */ + +/** + * Given a ServerClass name, finds a networkable send property offset. + * This information is cached for future calls. + * + * Note, this function may return offsets that do not work! + * If a property is nested beneath a parent object, the resulting offset + * will be invalid for direct use with data functions. Therefore, you + * should use FindSendPropInfo() instead. An example of such a property is + * CTFPlayer::DT_LocalPlayer.m_nDisguiseClass on Team Fortress. + * + * @param cls Classname. + * @param prop Property name. + * @return An offset, or -1 on failure. + */ +#pragma deprecated Use FindSendPropInfo instead, or HasEntProp if you just want to check for existence. +native int FindSendPropOffs(const char[] cls, const char[] prop); + +/** + * Given a ServerClass name, finds a networkable send property offset. + * This information is cached for future calls. + * + * @param cls Classname. + * @param prop Property name. + * @param type Optional parameter to store the type. + * @param num_bits Optional parameter to store the number of bits the field + * uses, if applicable (otherwise 0 is stored). The number + * of bits varies for integers and floats, and is always 0 + * for strings. + * @param local_offset Optional parameter to store the local offset, as + * FindSendPropOffs() would return. + * @return On success, returns an absolutely computed offset. + * If no offset is available, 0 is returned. + * If the property is not found, -1 is returned. + */ +native int FindSendPropInfo(const char[] cls, + const char[] prop, + PropFieldType &type=view_as(0), + int &num_bits=0, + int &local_offset=0); + +/** + * Given an entity, finds a datamap property offset. + * This information is cached for future calls. + * + * @param entity Entity index. + * @param prop Property name. + * @param type Optional parameter to store the type. + * @param num_bits Optional parameter to store the number of bits the field + * uses. The bit count will either be 1 (for boolean) or + * divisible by 8 (including 0 if unknown). + * @return An offset, or -1 on failure. + */ +#pragma deprecated Use FindDataMapInfo instead, or HasEntProp if you just want to check for existence. +native int FindDataMapOffs(int entity, + const char[] prop, + PropFieldType &type=view_as(0), + int &num_bits=0); + +/** + * Given an entity, finds a nested datamap property offset. + * This information is cached for future calls. + * + * @param entity Entity index. + * @param prop Property name. + * @param type Optional parameter to store the type. + * @param num_bits Optional parameter to store the number of bits the field + * uses. The bit count will either be 1 (for boolean) or + * divisible by 8 (including 0 if unknown). + * @param local_offset Optional parameter to store the local offset, as + * FindDataMapOffs() would return. + * @return An offset, or -1 on failure. + */ +native int FindDataMapInfo(int entity, + const char[] prop, + PropFieldType &type=view_as(0), + int &num_bits=0, + int &local_offset=0); + +/** + * Wrapper function for finding a send property for a particular entity. + * + * @param ent Entity index. + * @param prop Property name. + * @param actual Defaults to false for backwards compatibility. + * If true, the newer FindSendPropInfo() function + * is used instead. + * @return An offset, or -1 on failure. + */ +stock int GetEntSendPropOffs(int ent, const char[] prop, bool actual=false) +{ + char cls[64]; + + if (!GetEntityNetClass(ent, cls, sizeof(cls))) + { + return -1; + } + + int local = -1; + int offset = FindSendPropInfo(cls, prop, _, _, local); + + if (actual) + { + return offset; + } else { + return local; + } +} + +/** + * Checks if an entity property exists on an entity. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @return Whether the property exists on the entity. + * @error Invalid entity. + */ +stock bool HasEntProp(int entity, PropType type, const char[] prop) +{ + if (type == Prop_Data) { + return (FindDataMapInfo(entity, prop) != -1); + } + + if (type != Prop_Send) { + return false; + } + + char cls[64]; + if (!GetEntityNetClass(entity, cls, sizeof(cls))) { + return false; + } + + return (FindSendPropInfo(cls, prop) != -1); +} + +/** + * Retrieves an integer value from an entity's property. + * + * This function is considered safer and more robust over GetEntData, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param size Number of bytes to write (valid values are 1, 2, or 4). + * This value is auto-detected, and the size parameter is + * only used as a fallback in case detection fails. + * @param element Element # (starting from 0) if property is an array. + * @return Value at the given property offset. + * @error Invalid entity or property not found. + */ +native int GetEntProp(int entity, PropType type, const char[] prop, int size=4, int element=0); + +/** + * Sets an integer value in an entity's property. + * + * This function is considered safer and more robust over SetEntData, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param value Value to set. + * @param size Number of bytes to write (valid values are 1, 2, or 4). + * This value is auto-detected, and the size parameter is + * only used as a fallback in case detection fails. + * @param element Element # (starting from 0) if property is an array. + * @error Invalid entity or offset out of reasonable bounds. + */ +native void SetEntProp(int entity, PropType type, const char[] prop, any value, int size=4, int element=0); + +/** + * Retrieves a float value from an entity's property. + * + * This function is considered safer and more robust over GetEntDataFloat, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param element Element # (starting from 0) if property is an array. + * @return Value at the given property offset. + * @error Invalid entity or offset out of reasonable bounds. + */ +native float GetEntPropFloat(int entity, PropType type, const char[] prop, int element=0); + +/** + * Sets a float value in an entity's property. + * + * This function is considered safer and more robust over SetEntDataFloat, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param value Value to set. + * @param element Element # (starting from 0) if property is an array. + * @error Invalid entity or offset out of reasonable bounds. + */ +native void SetEntPropFloat(int entity, PropType type, const char[] prop, float value, int element=0); + +/** + * Retrieves an entity index from an entity's property. + * + * This function is considered safer and more robust over GetEntDataEnt*, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param element Element # (starting from 0) if property is an array. + * @return Entity index at the given property. + * If there is no entity, or the entity is not valid, + * then -1 is returned. + * @error Invalid entity or offset out of reasonable bounds. + */ +native int GetEntPropEnt(int entity, PropType type, const char[] prop, int element=0); + +/** + * Sets an entity index in an entity's property. + * + * This function is considered safer and more robust over SetEntDataEnt*, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param other Entity index to set, or -1 to unset. + * @param element Element # (starting from 0) if property is an array. + * @error Invalid entity or offset out of reasonable bounds. + */ +native void SetEntPropEnt(int entity, PropType type, const char[] prop, int other, int element=0); + +/** + * Retrieves a vector of floats from an entity, given a named network property. + * + * This function is considered safer and more robust over GetEntDataVector, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param vec Vector buffer to store data in. + * @param element Element # (starting from 0) if property is an array. + * @error Invalid entity, property not found, or property not + * actually a vector data type. + */ +native void GetEntPropVector(int entity, PropType type, const char[] prop, float vec[3], int element=0); + +/** + * Sets a vector of floats in an entity, given a named network property. + * + * This function is considered safer and more robust over SetEntDataVector, + * because it performs strict offset checking and typing rules. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @param vec Vector to set. + * @param element Element # (starting from 0) if property is an array. + * @error Invalid entity, property not found, or property not + * actually a vector data type. + */ +native void SetEntPropVector(int entity, PropType type, const char[] prop, const float vec[3], int element=0); + +/** + * Gets a network property as a string. + * + * @param entity Edict index. + * @param type Property type. + * @param prop Property to use. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @param element Element # (starting from 0) if property is an array. + * @return Number of non-null bytes written. + * @error Invalid entity, offset out of reasonable bounds, or property is not a valid string. + */ +native int GetEntPropString(int entity, PropType type, const char[] prop, char[] buffer, int maxlen, int element=0); + +/** + * Sets a network property as a string. + * + * @param entity Edict index. + * @param type Property type. + * @param prop Property to use. + * @param buffer String to set. + * @param element Element # (starting from 0) if property is an array. + * @return Number of non-null bytes written. + * @error Invalid entity, offset out of reasonable bounds, or property is not a valid string. + */ +native int SetEntPropString(int entity, PropType type, const char[] prop, const char[] buffer, int element=0); + +/** + * Retrieves the count of values that an entity property's array can store. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @return Size of array (in elements) or 1 if property is not an array. + * @error Invalid entity or property not found. + */ +native int GetEntPropArraySize(int entity, PropType type, const char[] prop); + +/** + * Copies an array of cells from an entity at a given offset. + * + * @param entity Entity index. + * @param offset Offset to use. + * @param array Array to read into. + * @param arraySize Number of values to read. + * @param dataSize Size of each value in bytes (1, 2, or 4). + * @error Invalid entity or offset out of reasonable bounds. + */ +stock void GetEntDataArray(int entity, int offset, int[] array, int arraySize, int dataSize=4) +{ + for (int i=0; i. + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _entity_prop_stocks_included + #endinput +#endif +#define _entity_prop_stocks_included + +enum MoveType +{ + MOVETYPE_NONE = 0, /**< never moves */ + MOVETYPE_ISOMETRIC, /**< For players */ + MOVETYPE_WALK, /**< Player only - moving on the ground */ + MOVETYPE_STEP, /**< gravity, special edge handling -- monsters use this */ + MOVETYPE_FLY, /**< No gravity, but still collides with stuff */ + MOVETYPE_FLYGRAVITY, /**< flies through the air + is affected by gravity */ + MOVETYPE_VPHYSICS, /**< uses VPHYSICS for simulation */ + MOVETYPE_PUSH, /**< no clip to world, push and crush */ + MOVETYPE_NOCLIP, /**< No gravity, no collisions, still do velocity/avelocity */ + MOVETYPE_LADDER, /**< Used by players only when going onto a ladder */ + MOVETYPE_OBSERVER, /**< Observer movement, depends on player's observer mode */ + MOVETYPE_CUSTOM, /**< Allows the entity to describe its own physics */ +}; + +enum RenderMode +{ + RENDER_NORMAL, /**< src */ + RENDER_TRANSCOLOR, /**< c*a+dest*(1-a) */ + RENDER_TRANSTEXTURE, /**< src*a+dest*(1-a) */ + RENDER_GLOW, /**< src*a+dest -- No Z buffer checks -- Fixed size in screen space */ + RENDER_TRANSALPHA, /**< src*srca+dest*(1-srca) */ + RENDER_TRANSADD, /**< src*a+dest */ + RENDER_ENVIRONMENTAL, /**< not drawn, used for environmental effects */ + RENDER_TRANSADDFRAMEBLEND, /**< use a fractional frame value to blend between animation frames */ + RENDER_TRANSALPHAADD, /**< src + dest*(1-a) */ + RENDER_WORLDGLOW, /**< Same as kRenderGlow but not fixed size in screen space */ + RENDER_NONE, /**< Don't render. */ +}; + +enum RenderFx +{ + RENDERFX_NONE = 0, + RENDERFX_PULSE_SLOW, + RENDERFX_PULSE_FAST, + RENDERFX_PULSE_SLOW_WIDE, + RENDERFX_PULSE_FAST_WIDE, + RENDERFX_FADE_SLOW, + RENDERFX_FADE_FAST, + RENDERFX_SOLID_SLOW, + RENDERFX_SOLID_FAST, + RENDERFX_STROBE_SLOW, + RENDERFX_STROBE_FAST, + RENDERFX_STROBE_FASTER, + RENDERFX_FLICKER_SLOW, + RENDERFX_FLICKER_FAST, + RENDERFX_NO_DISSIPATION, + RENDERFX_DISTORT, /**< Distort/scale/translate flicker */ + RENDERFX_HOLOGRAM, /**< kRenderFxDistort + distance fade */ + RENDERFX_EXPLODE, /**< Scale up really big! */ + RENDERFX_GLOWSHELL, /**< Glowing Shell */ + RENDERFX_CLAMP_MIN_SCALE, /**< Keep this sprite from getting very small (SPRITES only!) */ + RENDERFX_ENV_RAIN, /**< for environmental rendermode, make rain */ + RENDERFX_ENV_SNOW, /**< " " " , make snow */ + RENDERFX_SPOTLIGHT, /**< TEST CODE for experimental spotlight */ + RENDERFX_RAGDOLL, /**< HACKHACK: TEST CODE for signalling death of a ragdoll character */ + RENDERFX_PULSE_FAST_WIDER, + RENDERFX_MAX +}; + +// These defines are for client button presses. +#define IN_ATTACK (1 << 0) +#define IN_JUMP (1 << 1) +#define IN_DUCK (1 << 2) +#define IN_FORWARD (1 << 3) +#define IN_BACK (1 << 4) +#define IN_USE (1 << 5) +#define IN_CANCEL (1 << 6) +#define IN_LEFT (1 << 7) +#define IN_RIGHT (1 << 8) +#define IN_MOVELEFT (1 << 9) +#define IN_MOVERIGHT (1 << 10) +#define IN_ATTACK2 (1 << 11) +#define IN_RUN (1 << 12) +#define IN_RELOAD (1 << 13) +#define IN_ALT1 (1 << 14) +#define IN_ALT2 (1 << 15) +#define IN_SCORE (1 << 16) /**< Used by client.dll for when scoreboard is held down */ +#define IN_SPEED (1 << 17) /**< Player is holding the speed key */ +#define IN_WALK (1 << 18) /**< Player holding walk key */ +#define IN_ZOOM (1 << 19) /**< Zoom key for HUD zoom */ +#define IN_WEAPON1 (1 << 20) /**< weapon defines these bits */ +#define IN_WEAPON2 (1 << 21) /**< weapon defines these bits */ +#define IN_BULLRUSH (1 << 22) +#define IN_GRENADE1 (1 << 23) /**< grenade 1 */ +#define IN_GRENADE2 (1 << 24) /**< grenade 2 */ +#define IN_ATTACK3 (1 << 25) + +// Note: these are only for use with GetEntityFlags and SetEntityFlags +// and may not match the game's actual, internal m_fFlags values. +// PLAYER SPECIFIC FLAGS FIRST BECAUSE WE USE ONLY A FEW BITS OF NETWORK PRECISION +#define FL_ONGROUND (1 << 0) /**< At rest / on the ground */ +#define FL_DUCKING (1 << 1) /**< Player flag -- Player is fully crouched */ +#define FL_WATERJUMP (1 << 2) /**< player jumping out of water */ +#define FL_ONTRAIN (1 << 3) /**< Player is _controlling_ a train, so movement commands should be ignored on client during prediction. */ +#define FL_INRAIN (1 << 4) /**< Indicates the entity is standing in rain */ +#define FL_FROZEN (1 << 5) /**< Player is frozen for 3rd person camera */ +#define FL_ATCONTROLS (1 << 6) /**< Player can't move, but keeps key inputs for controlling another entity */ +#define FL_CLIENT (1 << 7) /**< Is a player */ +#define FL_FAKECLIENT (1 << 8) /**< Fake client, simulated server side; don't send network messages to them */ +// NOTE if you move things up, make sure to change this value +#define PLAYER_FLAG_BITS 9 +// NON-PLAYER SPECIFIC (i.e., not used by GameMovement or the client .dll ) -- Can still be applied to players, though +#define FL_INWATER (1 << 9) /**< In water */ +#define FL_FLY (1 << 10) /**< Changes the SV_Movestep() behavior to not need to be on ground */ +#define FL_SWIM (1 << 11) /**< Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) */ +#define FL_CONVEYOR (1 << 12) +#define FL_NPC (1 << 13) +#define FL_GODMODE (1 << 14) +#define FL_NOTARGET (1 << 15) +#define FL_AIMTARGET (1 << 16) /**< set if the crosshair needs to aim onto the entity */ +#define FL_PARTIALGROUND (1 << 17) /**< not all corners are valid */ +#define FL_STATICPROP (1 << 18) /**< Eetsa static prop! */ +#define FL_GRAPHED (1 << 19) /**< worldgraph has this ent listed as something that blocks a connection */ +#define FL_GRENADE (1 << 20) +#define FL_STEPMOVEMENT (1 << 21) /**< Changes the SV_Movestep() behavior to not do any processing */ +#define FL_DONTTOUCH (1 << 22) /**< Doesn't generate touch functions, generates Untouch() for anything it was touching when this flag was set */ +#define FL_BASEVELOCITY (1 << 23) /**< Base velocity has been applied this frame (used to convert base velocity into momentum) */ +#define FL_WORLDBRUSH (1 << 24) /**< Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) */ +#define FL_OBJECT (1 << 25) /**< Terrible name. This is an object that NPCs should see. Missiles, for example. */ +#define FL_KILLME (1 << 26) /**< This entity is marked for death -- will be freed by game DLL */ +#define FL_ONFIRE (1 << 27) /**< You know... */ +#define FL_DISSOLVING (1 << 28) /**< We're dissolving! */ +#define FL_TRANSRAGDOLL (1 << 29) /**< In the process of turning into a client side ragdoll. */ +#define FL_UNBLOCKABLE_BY_PLAYER (1 << 30) /**< pusher that can't be blocked by the player */ +#define FL_FREEZING (1 << 31) /**< We're becoming frozen! */ +#define FL_EP2V_UNKNOWN1 (1 << 31) /**< Unknown */ +// END entity flag #defines + +/** + * Get an entity's flags. + * + * @note The game's actual flags are internally translated by SM + * to match the entity flags defined above as the actual values + * can differ per engine. + * + * @param entity Entity index. + * @return Entity's flags, see entity flag defines above. + * @error Invalid entity index, or lack of mod compliance. + */ +native int GetEntityFlags(int entity); + +/** + * Sets an entity's flags. + * + * @note The entity flags as defined above are internally translated by SM + * to match the current game's expected value for the flags as + * the actual values can differ per engine. + * + * @param entity Entity index. + * @param flags Entity flags, see entity flag defines above. + * @error Invalid entity index, or lack of mod compliance. + */ +native void SetEntityFlags(int entity, int flags); + + +/** + * Gets an entity's movetype. + * + * @param entity Entity index. + * @return Movetype, see enum above. + * @error Invalid entity index, or lack of mod compliance. + */ +stock MoveType GetEntityMoveType(int entity) +{ + static bool gotconfig = false; + static char datamap[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_MoveType", datamap, sizeof(datamap)); + CloseHandle(gc); + + if (!exists) + { + strcopy(datamap, sizeof(datamap), "m_MoveType"); + } + + gotconfig = true; + } + + return view_as(GetEntProp(entity, Prop_Data, datamap)); +} + +/** + * Sets an entity's movetype. + * + * @param entity Entity index. + * @param mt Movetype, see enum above. + * @error Invalid entity index, or lack of mod compliance. + */ +stock void SetEntityMoveType(int entity, MoveType mt) +{ + static bool gotconfig = false; + static char datamap[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_MoveType", datamap, sizeof(datamap)); + CloseHandle(gc); + + if (!exists) + { + strcopy(datamap, sizeof(datamap), "m_MoveType"); + } + + gotconfig = true; + } + + SetEntProp(entity, Prop_Data, datamap, mt); +} + +/** + * Gets an entity's render mode. + * + * @param entity Entity index. + * @return RenderMode value. + * @error Invalid entity index, or lack of mod compliance. + */ +stock RenderMode GetEntityRenderMode(int entity) +{ + static bool gotconfig = false; + static char prop[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_nRenderMode", prop, sizeof(prop)); + CloseHandle(gc); + + if (!exists) + { + strcopy(prop, sizeof(prop), "m_nRenderMode"); + } + + gotconfig = true; + } + + return view_as(GetEntProp(entity, Prop_Send, prop, 1)); +} + +/** + * Sets an entity's render mode. + * + * @param entity Entity index. + * @param mode RenderMode value. + * @error Invalid entity index, or lack of mod compliance. + */ +stock void SetEntityRenderMode(int entity, RenderMode mode) +{ + static bool gotconfig = false; + static char prop[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_nRenderMode", prop, sizeof(prop)); + CloseHandle(gc); + + if (!exists) + { + strcopy(prop, sizeof(prop), "m_nRenderMode"); + } + + gotconfig = true; + } + + SetEntProp(entity, Prop_Send, prop, mode, 1); +} + +/** + * Gets an entity's render Fx. + * + * @param entity Entity index. + * @return RenderFx value. + * @error Invalid entity index, or lack of mod compliance. + */ +stock RenderFx GetEntityRenderFx(int entity) +{ + static bool gotconfig = false; + static char prop[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_nRenderFX", prop, sizeof(prop)); + CloseHandle(gc); + + if (!exists) + { + strcopy(prop, sizeof(prop), "m_nRenderFX"); + } + + gotconfig = true; + } + + return view_as(GetEntProp(entity, Prop_Send, prop, 1)); +} + +/** + * Sets an entity's render Fx. + * + * @param entity Entity index. + * @param fx RenderFx value. + * @error Invalid entity index, or lack of mod compliance. + */ +stock void SetEntityRenderFx(int entity, RenderFx fx) +{ + static bool gotconfig = false; + static char prop[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_nRenderFX", prop, sizeof(prop)); + CloseHandle(gc); + + if (!exists) + { + strcopy(prop, sizeof(prop), "m_nRenderFX"); + } + + gotconfig = true; + } + + SetEntProp(entity, Prop_Send, prop, fx, 1); +} + +/** + * Gets an entity's color. + * + * @param entity Entity index. + * @param r Amount of red (0-255) + * @param g Amount of green (0-255) + * @param b Amount of blue (0-255) + * @param a Amount of alpha (0-255) + * @error Invalid entity index, or lack of mod compliance. + */ +stock void GetEntityRenderColor(int entity, int &r, int &g, int &b, int &a) +{ + static bool gotconfig = false; + static char prop[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_clrRender", prop, sizeof(prop)); + CloseHandle(gc); + + if (!exists) + { + strcopy(prop, sizeof(prop), "m_clrRender"); + } + + gotconfig = true; + } + + int offset = GetEntSendPropOffs(entity, prop); + + if (offset <= 0) + { + ThrowError("GetEntityRenderColor not supported by this mod"); + } + + r = GetEntData(entity, offset, 1); + g = GetEntData(entity, offset + 1, 1); + b = GetEntData(entity, offset + 2, 1); + a = GetEntData(entity, offset + 3, 1); +} + +/** + * Sets an entity's color. + * + * @param entity Entity index + * @param r Amount of red (0-255) + * @param g Amount of green (0-255) + * @param b Amount of blue (0-255) + * @param a Amount of alpha (0-255) + * @error Invalid entity index, or lack of mod compliance. + */ +stock void SetEntityRenderColor(int entity, int r=255, int g=255, int b=255, int a=255) +{ + static bool gotconfig = false; + static char prop[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_clrRender", prop, sizeof(prop)); + CloseHandle(gc); + + if (!exists) + { + strcopy(prop, sizeof(prop), "m_clrRender"); + } + + gotconfig = true; + } + + int offset = GetEntSendPropOffs(entity, prop); + + if (offset <= 0) + { + ThrowError("SetEntityRenderColor not supported by this mod"); + } + + SetEntData(entity, offset, r, 1, true); + SetEntData(entity, offset + 1, g, 1, true); + SetEntData(entity, offset + 2, b, 1, true); + SetEntData(entity, offset + 3, a, 1, true); +} + +/** + * Gets an entity's gravity. + * + * @param entity Entity index. + * @return Entity's m_flGravity value. + * @error Invalid entity index, or lack of mod compliance. + */ +stock float GetEntityGravity(int entity) +{ + static bool gotconfig = false; + static char datamap[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_flGravity", datamap, sizeof(datamap)); + CloseHandle(gc); + + if (!exists) + { + strcopy(datamap, sizeof(datamap), "m_flGravity"); + } + + gotconfig = true; + } + + return GetEntPropFloat(entity, Prop_Data, datamap); +} + +/** + * Sets an entity's gravity. + * + * @param entity Entity index. + * @param amount Gravity to set (default = 1.0, half = 0.5, double = 2.0). + * @error Invalid entity index, or lack of mod compliance. + */ +stock void SetEntityGravity(int entity, float amount) +{ + static bool gotconfig = false; + static char datamap[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_flGravity", datamap, sizeof(datamap)); + CloseHandle(gc); + + if (!exists) + { + strcopy(datamap, sizeof(datamap), "m_flGravity"); + } + + gotconfig = true; + } + + SetEntPropFloat(entity, Prop_Data, datamap, amount); +} + +/** + * Sets an entity's health + * + * @param entity Entity index. + * @param amount Health amount. + * @error Invalid entity index, or lack of mod compliance. + */ +stock void SetEntityHealth(int entity, int amount) +{ + static bool gotconfig = false; + static char prop[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_iHealth", prop, sizeof(prop)); + CloseHandle(gc); + + if (!exists) + { + strcopy(prop, sizeof(prop), "m_iHealth"); + } + + gotconfig = true; + } + + char cls[64]; + PropFieldType type; + int offset; + + if (!GetEntityNetClass(entity, cls, sizeof(cls))) + { + ThrowError("SetEntityHealth not supported by this mod: Could not get serverclass name"); + return; + } + + offset = FindSendPropInfo(cls, prop, type); + + if (offset <= 0) + { + ThrowError("SetEntityHealth not supported by this mod"); + return; + } + + /* Dark Messiah uses a float for the health instead an integer */ + if (type == PropField_Float) + { + SetEntDataFloat(entity, offset, float(amount)); + } + else + { + SetEntProp(entity, Prop_Send, prop, amount); + } +} + +/** + * Get's a users current pressed buttons + * + * @param client Client index + * @return Bitsum of buttons + * @error Invalid client index, client not in game, + * or lack of mod compliance. + */ +stock int GetClientButtons(int client) +{ + static bool gotconfig = false; + static char datamap[32]; + + if (!gotconfig) + { + Handle gc = LoadGameConfigFile("core.games"); + bool exists = GameConfGetKeyValue(gc, "m_nButtons", datamap, sizeof(datamap)); + CloseHandle(gc); + + if (!exists) + { + strcopy(datamap, sizeof(datamap), "m_nButtons"); + } + + gotconfig = true; + } + + return GetEntProp(client, Prop_Data, datamap); +} diff --git a/scripting/include/events.inc b/scripting/include/events.inc new file mode 100644 index 0000000..d7d799a --- /dev/null +++ b/scripting/include/events.inc @@ -0,0 +1,340 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _events_included + #endinput +#endif +#define _events_included + +/** + * Event hook modes determining how hooking should be handled + */ +enum EventHookMode +{ + EventHookMode_Pre, //< Hook callback fired before event is fired */ + EventHookMode_Post, //< Hook callback fired after event is fired */ + EventHookMode_PostNoCopy //< Hook callback fired after event is fired, but event data won't be copied */ +}; + +/** + * Hook function types for events. + */ +typeset EventHook +{ + // Called when a game event is fired. + // + // @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking + // this event has set the hook mode EventHookMode_PostNoCopy. + // @param name String containing the name of the event. + // @param dontBroadcast True if event was not broadcast to clients, false otherwise. + // @return Ignored for post hooks. Plugin_Handled will block event if hooked as pre. + /// + function Action (Event event, const char[] name, bool dontBroadcast); + // + // Called when a game event is fired. + // + // @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking + // this event has set the hook mode EventHookMode_PostNoCopy. + // @param name String containing the name of the event. + // @param dontBroadcast True if event was not broadcast to clients, false otherwise. + /// + function void (Event event, const char[] name, bool dontBroadcast); +}; + +methodmap Event < Handle +{ + // Fires a game event. + // + // This function closes the event Handle after completing. + // + // @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. + public native void Fire(bool dontBroadcast=false); + + // Fires a game event to only the specified client. + // + // Unlike Fire, this function DOES NOT close the event Handle. + // + // @param client Index of client to receive the event.. + public native void FireToClient(int client); + + // Cancels a previously created game event that has not been fired. This + // is necessary to avoid leaking memory when an event isn't fired. + public native void Cancel(); + + // Returns the boolean value of a game event's key. + // + // @param key Name of event key. + // @param defValue Optional default value to use if the key is not found. + // @return The boolean value of the specified event key. + public native bool GetBool(const char[] key, bool defValue=false); + + // Sets the boolean value of a game event's key. + // + // @param key Name of event key. + // @param value New boolean value. + public native void SetBool(const char[] key, bool value); + + // Returns the integer value of a game event's key. + // + // @param key Name of event key. + // @param defValue Optional default value to use if the key is not found. + // @return The integer value of the specified event key. + public native int GetInt(const char[] key, int defValue=0); + + // Sets the integer value of a game event's key. + // + // Integer value refers to anything that can be reduced to an integer. + // The various size specifiers, such as "byte" and "short" are still + // integers, and only refer to how much data will actually be sent + // over the network (if applicable). + // + // @param key Name of event key. + // @param value New integer value. + public native void SetInt(const char[] key, int value); + + // Returns the floating point value of a game event's key. + // + // @param key Name of event key. + // @param defValue Optional default value to use if the key is not found. + // @return The floating point value of the specified event key. + public native float GetFloat(const char[] key, float defValue=0.0); + + // Sets the floating point value of a game event's key. + // + // @param key Name of event key. + // @param value New floating point value. + public native void SetFloat(const char[] key, float value); + + // Retrieves the string value of a game event's key. + // + // @param key Name of event key. + // @param value Buffer to store the value of the specified event key. + // @param maxlength Maximum length of string buffer. + // @param defValue Optional default value to use if the key is not found. + public native void GetString(const char[] key, char[] value, int maxlength, const char[] defvalue=""); + + // Sets the string value of a game event's key. + // + // @param key Name of event key. + // @param value New string value. + public native void SetString(const char[] key, const char[] value); + + // Retrieves the name of a game event. + // + // @param name Buffer to store the name of the event. + // @param maxlength Maximum length of string buffer. + public native void GetName(char[] name, int maxlength); + + // Sets whether an event's broadcasting will be disabled or not. + // + // This has no effect on events Handles that are not from HookEvent + // or HookEventEx callbacks. + property bool BroadcastDisabled { + public native set(bool dontBroadcast); + } +} + +/** + * Creates a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @error Invalid event name or invalid callback function. + */ +native void HookEvent(const char[] name, EventHook callback, EventHookMode mode=EventHookMode_Post); + +/** + * Creates a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @return True if event exists and was hooked successfully, false otherwise. + * @error Invalid callback function. + */ +native bool HookEventEx(const char[] name, EventHook callback, EventHookMode mode=EventHookMode_Post); + +/** + * Removes a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @error Invalid callback function or no active hook for specified event. + */ +native void UnhookEvent(const char[] name, EventHook callback, EventHookMode mode=EventHookMode_Post); + +/** + * Creates a game event to be fired later. + * + * The Handle should not be closed via CloseHandle(). It must be closed via + * event.Fire() or event.Cancel(). + * + * @param name Name of event. + * @param force If set to true, this forces the event to be created even if it's not being hooked. + * Note that this will not force it if the event doesn't exist at all. + * @return Handle to event. INVALID_HANDLE is returned if the event doesn't exist or isn't + being hooked (unless force is true). + */ +native Event CreateEvent(const char[] name, bool force=false); + +/** + * Fires a game event. + * + * This function closes the event Handle after completing. + * + * @param event Handle to the event. + * @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. + * @error Invalid or corrupt Handle. + */ +native void FireEvent(Handle event, bool dontBroadcast=false); + +/** + * Cancels a previously created game event that has not been fired. + * + * @param event Handled to the event. + * @error Invalid or corrupt Handle. + */ +native void CancelCreatedEvent(Handle event); + +/** + * Returns the boolean value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param defValue Optional default value to use if the key is not found. + * @return The boolean value of the specified event key. + * @error Invalid or corrupt Handle. + */ +native bool GetEventBool(Handle event, const char[] key, bool defValue=false); + +/** + * Sets the boolean value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New boolean value. + * @error Invalid or corrupt Handle. + */ +native void SetEventBool(Handle event, const char[] key, bool value); + +/** + * Returns the integer value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param defValue Optional default value to use if the key is not found. + * @return The integer value of the specified event key. + * @error Invalid or corrupt Handle. + */ +native int GetEventInt(Handle event, const char[] key, int defValue=0); + +/** + * Sets the integer value of a game event's key. + * + * Integer value refers to anything that can be reduced to an integer. + * The various size specifiers, such as "byte" and "short" are still + * integers, and only refer to how much data will actually be sent + * over the network (if applicable). + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New integer value. + * @error Invalid or corrupt Handle. + */ +native void SetEventInt(Handle event, const char[] key, int value); + +/** + * Returns the floating point value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param defValue Optional default value to use if the key is not found. + * @return The floating point value of the specified event key. + * @error Invalid or corrupt Handle. + */ +native float GetEventFloat(Handle event, const char[] key, float defValue=0.0); + +/** + * Sets the floating point value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New floating point value. + * @error Invalid or corrupt Handle. + */ +native void SetEventFloat(Handle event, const char[] key, float value); + +/** + * Retrieves the string value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value Buffer to store the value of the specified event key. + * @param maxlength Maximum length of string buffer. + * @param defValue Optional default value to use if the key is not found. + * @error Invalid or corrupt Handle. + */ +native void GetEventString(Handle event, const char[] key, char[] value, int maxlength, const char[] defvalue=""); + +/** + * Sets the string value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New string value. + * @error Invalid or corrupt Handle. + */ +native void SetEventString(Handle event, const char[] key, const char[] value); + +/** + * Retrieves the name of a game event. + * + * @param event Handle to the event. + * @param name Buffer to store the name of the event. + * @param maxlength Maximum length of string buffer. + * @error Invalid or corrupt Handle. + */ +native void GetEventName(Handle event, char[] name, int maxlength); + +/** + * Sets whether an event's broadcasting will be disabled or not. + * + * This has no effect on events Handles that are not from HookEvent + * or HookEventEx callbacks. + * + * @param event Handle to an event from an event hook. + * @param dontBroadcast True to disable broadcasting, false otherwise. + * @error Invalid Handle. + */ +native void SetEventBroadcast(Handle event, bool dontBroadcast); diff --git a/scripting/include/files.inc b/scripting/include/files.inc new file mode 100644 index 0000000..cae2088 --- /dev/null +++ b/scripting/include/files.inc @@ -0,0 +1,618 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _files_included + #endinput +#endif +#define _files_included + +/** + * @global All paths in SourceMod natives are relative to the mod folder + * unless otherwise noted. + * + * Most functions in SourceMod (at least, ones that deal with direct + * file manipulation) will support an alternate path specification. + * + * If the path starts with the string "file://" and the PathType is + * not relative, then the "file://" portion is stripped off, and the + * rest of the path is used without any modification (except for + * correcting slashes). This can be used to override the path + * builder to supply alternate absolute paths. Examples: + * + * file://C:/Temp/file.txt + * file:///tmp/file.txt + */ + +/** + * File inode types. + */ +enum FileType +{ + FileType_Unknown = 0, /* Unknown file type (device/socket) */ + FileType_Directory = 1, /* File is a directory */ + FileType_File = 2, /* File is a file */ +}; + +/** + * File time modes. + */ +enum FileTimeMode +{ + FileTime_LastAccess = 0, /* Last access (does not work on FAT) */ + FileTime_Created = 1, /* Creation (does not work on FAT) */ + FileTime_LastChange = 2, /* Last modification */ +}; + +#define PLATFORM_MAX_PATH 256 /**< Maximum path length. */ + +#define SEEK_SET 0 /**< Seek from start. */ +#define SEEK_CUR 1 /**< Seek from current position. */ +#define SEEK_END 2 /**< Seek from end position. */ + +/** + * Path types. + */ +enum PathType +{ + Path_SM, /**< SourceMod root folder */ +}; + +// A DirectoryListing iterates over the contents of a directory. To obtain a +// DirectoryListing handle, call OpenDirectory(). +methodmap DirectoryListing < Handle +{ + // Reads the current directory entry as a local filename, then moves to the + // next file. + // + // Note: Both the '.' and '..' automatic directory entries will be retrieved. + // + // @param buffer String buffer to hold directory name. + // @param maxlength Maximum size of string buffer. + // @param type Optional variable to store the file type. + // @return True on success, false if there are no more files to read. + public native bool GetNext(char[] buffer, int maxlength, FileType &type=FileType_Unknown); +}; + +// A File object can be obtained by calling OpenFile(). File objects should be +// closed with delete or Close(). Note that, "delete file" does not +// actually a file, it just closes it. +methodmap File < Handle +{ + // Close the file handle. This is the same as using CloseHandle() or delete. + public void Close() { + CloseHandle(this); + } + + // Reads a line of text from a file. + // + // @param buffer String buffer to hold the line. + // @param maxlength Maximum size of string buffer. + // @return True on success, false otherwise. + public native bool ReadLine(char[] buffer, int maxlength); + + // Reads binary data from a file. + // + // @param items Array to store each item read. + // @param num_items Number of items to read into the array. + // @param size Size of each element, in bytes, to be read. + // Valid sizes are 1, 2, or 4. + // @return Number of elements read, or -1 on error. + public native int Read(int[] items, int num_items, int size); + + // Reads a UTF8 or ANSI string from a file. + // + // @param buffer Buffer to store the string. + // @param max_size Maximum size of the string buffer. + // @param read_count If -1, reads until a null terminator is encountered in + // the file. Otherwise, read_count bytes are read + // into the buffer provided. In this case the buffer + // is not explicitly null terminated, and the buffer + // will contain any null terminators read from the file. + // @return Number of characters written to the buffer, or -1 + // if an error was encountered. + // @error read_count > max_size. + public native int ReadString(char[] buffer, int max_size, int read_count=-1); + + // Writes binary data to a file. + // + // @param items Array of items to write. The data is read directly. + // That is, in 1 or 2-byte mode, the lower byte(s) in + // each cell are used directly, rather than performing + // any casts from a 4-byte number to a smaller number. + // @param num_items Number of items in the array. + // @param size Size of each item in the array in bytes. + // Valid sizes are 1, 2, or 4. + // @return True on success, false on error. + public native bool Write(const int[] items, int num_items, int size); + + // Writes a binary string to a file. + // + // @param buffer String to write. + // @param term True to append NUL terminator, false otherwise. + // @return True on success, false on error. + public native bool WriteString(const char[] buffer, bool term); + + // Writes a line of text to a text file. A newline is automatically appended. + // + // @param hndl Handle to the file. + // @param format Formatting rules. + // @param ... Variable number of format parameters. + // @return True on success, false otherwise. + public native bool WriteLine(const char[] format, any ...); + + // Reads a single int8 (byte) from a file. The returned value is sign- + // extended to an int32. + // + // @param data Variable to store the data read. + // @return True on success, false on failure. + public native bool ReadInt8(int &data); + + // Reads a single uint8 (unsigned byte) from a file. The returned value is + // zero-extended to an int32. + // + // @param data Variable to store the data read. + // @return True on success, false on failure. + public native bool ReadUint8(int &data); + + // Reads a single int16 (short) from a file. The value is sign-extended to + // an int32. + // + // @param data Variable to store the data read. + // @return True on success, false on failure. + public native bool ReadInt16(int &data); + + // Reads a single unt16 (unsigned short) from a file. The value is zero- + // extended to an int32. + // + // @param data Variable to store the data read. + // @return True on success, false on failure. + public native bool ReadUint16(int &data); + + // Reads a single int32 (int/cell) from a file. + // + // @param data Variable to store the data read. + // @return True on success, false on failure. + public native bool ReadInt32(int &data); + + // Writes a single int8 (byte) to a file. + // + // @param data Data to write (truncated to an int8). + // @return True on success, false on failure. + public native bool WriteInt8(int data); + + // Writes a single int16 (short) to a file. + // + // @param data Data to write (truncated to an int16). + // @return True on success, false on failure. + public native bool WriteInt16(int data); + + // Writes a single int32 (int/cell) to a file. + // + // @param data Data to write. + // @return True on success, false on failure. + public native bool WriteInt32(int data); + + // Tests if the end of file has been reached. + // + // @return True if end of file has been reached, false otherwise. + public native bool EndOfFile(); + + // Sets the file position indicator. + // + // @param position Position relative to what is specified in whence. + // @param where SEEK_ constant value of where to see from. + // @return True on success, false otherwise. + public native bool Seek(int position, int where); + + // Get the current position in the file; returns -1 on failure. + property int Position { + public native get(); + } +} + +/** + * Builds a path relative to the SourceMod folder. This should be used instead of + * directly referencing addons/sourcemod, in case users change the name of their + * folder layout. + * + * @param type Type of path to build as the base. + * @param buffer Buffer to store the path. + * @param maxlength Maximum length of buffer. + * @param fmt Format string. + * @param ... Format arguments. + * @return Number of bytes written to buffer (not including null terminator). + */ +native int BuildPath(PathType type, char[] buffer, int maxlength, const char[] fmt, any ...); + +/** + * Opens a directory/folder for contents enumeration. + * + * @note Directories are closed with CloseHandle() or delete. + * @note Directories Handles can be cloned. + * @note OpenDirectory() supports the "file://" notation. + * + * @param path Path to open. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. + * @return A Handle to the directory, null on error. + */ +native DirectoryListing OpenDirectory(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); + +/** + * Reads the current directory entry as a local filename, then moves to the next file. + * + * @note Contents of buffers are undefined when returning false. + * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux. + * + * @param dir Handle to a directory. + * @param buffer String buffer to hold directory name. + * @param maxlength Maximum size of string buffer. + * @param type Optional variable to store the file type. + * @return True on success, false if there are no more files to read. + * @error Invalid or corrupt Handle. + */ +native bool ReadDirEntry(Handle dir, char[] buffer, int maxlength, FileType &type=FileType_Unknown); + +/** + * Opens or creates a file, returning a File handle on success. File handles + * should be closed with delete or CloseHandle(). + * + * The open mode may be one of the following strings: + * "r": Open an existing file for reading. + * "w": Create a file for writing, or truncate (delete the contents of) an + * existing file and then open it for writing. + * "a": Create a file for writing, or open an existing file such that writes + * will be appended to the end. + * "r+": Open an existing file for both reading and writing. + * "w+": Create a file for reading and writing, or truncate an existing file + * and then open it for reading and writing. + * "a+": Create a file for both reading and writing, or open an existing file + * such that writes will be appended to the end. + * + * The open mode may also contain an additional character after "r", "w", or "a", + * but before any "+" sign. This character may be "b" (indicating binary mode) or + * "t" (indicating text mode). By default, "text" mode is implied. On Linux and + * Mac, this has no distinction from binary mode. On Windows, it causes the '\n' + * character (0xA) to be written as "\r\n" (0xD, 0xA). + * + * Example: "rb" opens a binary file for writing; "at" opens a text file for + * appending. + * + * @param file File to open. + * @param mode Open mode. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in valve + * search paths, rather than solely files existing directly + * in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. + * @return A File handle, or null if the file could not be opened. + */ +native File OpenFile(const char[] file, const char[] mode, bool use_valve_fs=false, const char[] valve_path_id="GAME"); + +/** + * Deletes a file. + * + * @param path Path of the file to delete. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to delete files existing in the Valve + * search path, rather than solely files existing directly + * in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. + * @return True on success, false on failure or if file not immediately removed. + */ +native bool DeleteFile(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="DEFAULT_WRITE_PATH"); + +/** + * Reads a line from a text file. + * + * @param hndl Handle to the file. + * @param buffer String buffer to hold the line. + * @param maxlength Maximum size of string buffer. + * @return True on success, false otherwise. + */ +native bool ReadFileLine(Handle hndl, char[] buffer, int maxlength); + +/** + * Reads binary data from a file. + * + * @param hndl Handle to the file. + * @param items Array to store each item read. + * @param num_items Number of items to read into the array. + * @param size Size of each element, in bytes, to be read. + * Valid sizes are 1, 2, or 4. + * @return Number of elements read, or -1 on error. + */ +native int ReadFile(Handle hndl, int[] items, int num_items, int size); + +/** + * Reads a UTF8 or ANSI string from a file. + * + * @param hndl Handle to the file. + * @param buffer Buffer to store the string. + * @param max_size Maximum size of the string buffer. + * @param read_count If -1, reads until a null terminator is encountered in + * the file. Otherwise, read_count bytes are read + * into the buffer provided. In this case the buffer + * is not explicitly null terminated, and the buffer + * will contain any null terminators read from the file. + * @return Number of characters written to the buffer, or -1 + * if an error was encountered. + * @error Invalid Handle, or read_count > max_size. + */ +native int ReadFileString(Handle hndl, char[] buffer, int max_size, int read_count=-1); + +/** + * Writes binary data to a file. + * + * @param hndl Handle to the file. + * @param items Array of items to write. The data is read directly. + * That is, in 1 or 2-byte mode, the lower byte(s) in + * each cell are used directly, rather than performing + * any casts from a 4-byte number to a smaller number. + * @param num_items Number of items in the array. + * @param size Size of each item in the array in bytes. + * Valid sizes are 1, 2, or 4. + * @return True on success, false on error. + * @error Invalid Handle. + */ +native bool WriteFile(Handle hndl, const int[] items, int num_items, int size); + +/** + * Writes a binary string to a file. + * + * @param hndl Handle to the file. + * @param buffer String to write. + * @param term True to append NUL terminator, false otherwise. + * @return True on success, false on error. + * @error Invalid Handle. + */ +native bool WriteFileString(Handle hndl, const char[] buffer, bool term); + +/** + * Writes a line of text to a text file. A newline is automatically appended. + * + * @param hndl Handle to the file. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool WriteFileLine(Handle hndl, const char[] format, any ...); + +/** + * Reads a single binary cell from a file. + * + * @param hndl Handle to the file. + * @param data Variable to store the data read. + * @param size Size of the data to read in bytes. Valid + * sizes are 1, 2, or 4 bytes. + * @return Number of elements read (max 1), or -1 on error. + * @error Invalid Handle. + */ +stock int ReadFileCell(Handle hndl, int &data, int size) +{ + int ret; + int array[1]; + + if ((ret = ReadFile(hndl, array, 1, size)) == 1) + data = array[0]; + + return ret; +} + +/** + * Writes a single binary cell to a file. + * + * @param hndl Handle to the file. + * @param data Cell to write to the file. + * @param size Size of the data to read in bytes. Valid + * sizes are 1, 2, or 4 bytes. If the size + * is less than 4 bytes, the data is truncated + * rather than casted. That is, only the lower + * bits will be read. + * @return True on success, false on error. + * @error Invalid Handle. + */ +stock bool WriteFileCell(Handle hndl, int data, int size) +{ + int array[1]; + + array[0] = data; + return WriteFile(hndl, array, 1, size); +} + +/** + * Tests if the end of file has been reached. + * + * @param file Handle to the file. + * @return True if end of file has been reached, false otherwise. + * @error Invalid Handle. + */ +native bool IsEndOfFile(Handle file); + +/** + * Sets the file position indicator. + * + * @param file Handle to the file. + * @param position Position relative to what is specified in whence. + * @param where SEEK_ constant value of where to see from. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool FileSeek(Handle file, int position, int where); + +/** + * Get current position in the file. + * + * @param file Handle to the file. + * @return Value for the file position indicator. + * @error Invalid Handle. + */ +native int FilePosition(Handle file); + +/** + * Checks if a file exists. + * + * @param path Path to the file. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. + * @return True if the file exists, false otherwise. + */ +native bool FileExists(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); + +/** + * Renames a file. + * + * @param newpath New path to the file. + * @param oldpath Path to the existing file. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to rename files in the game's + * Valve search paths, rather than directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. + * @return True on success or use_valve_fs specified, false otherwise. + */ +native bool RenameFile(const char[] newpath, const char[] oldpath, bool use_valve_fs=false, const char[] valve_path_id="DEFAULT_WRITE_PATH"); + +/** + * Checks if a directory exists. + * + * @param path Path to the directory. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. + * @return True if the directory exists, false otherwise. + */ +native bool DirExists(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); + +/** + * Get the file size in bytes. + * + * @param path Path to the file. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to find files existing in any of + * the Valve search paths, rather than solely files + * existing directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. + * @return File size in bytes, -1 if file not found. + */ +native int FileSize(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); + +/** + * Flushes a file's buffered output; any buffered output + * is immediately written to the file. + * + * @param file Handle to the file. + * @return True on success or use_valve_fs specified with OpenFile, + * otherwise false on failure. + */ +native bool FlushFile(Handle file); + +/** + * Removes a directory. + * @note On most Operating Systems you cannot remove a directory which has files inside it. + * + * @param path Path to the directory. + * @return True on success, false otherwise. + */ +native bool RemoveDir(const char[] path); + +#define FPERM_U_READ 0x0100 /* User can read. */ +#define FPERM_U_WRITE 0x0080 /* User can write. */ +#define FPERM_U_EXEC 0x0040 /* User can exec. */ +#define FPERM_G_READ 0x0020 /* Group can read. */ +#define FPERM_G_WRITE 0x0010 /* Group can write. */ +#define FPERM_G_EXEC 0x0008 /* Group can exec. */ +#define FPERM_O_READ 0x0004 /* Anyone can read. */ +#define FPERM_O_WRITE 0x0002 /* Anyone can write. */ +#define FPERM_O_EXEC 0x0001 /* Anyone can exec. */ + +/** + * Creates a directory. + * + * @param path Path to create. + * @param mode Permissions (default is o=rx,g=rx,u=rwx). Note that folders must have + * the execute bit set on Linux. On Windows, the mode is ignored. + * @param use_valve_fs If true, the Valve file system will be used instead. + * This can be used to create folders in the game's + * Valve search paths, rather than directly in the gamedir. + * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for default. + * In this case, mode is ignored. + */ +native bool CreateDirectory(const char[] path, int mode, bool use_valve_fs=false, const char[] valve_path_id="DEFAULT_WRITE_PATH"); + +/** + * Changes a file or directories permissions. + * + * @param path Path to the file. + * @param mode Permissions to set. + * @return True on success, false otherwise. + */ +native bool SetFilePermissions(const char[] path, int mode); + +/** + * Returns a file timestamp as a unix timestamp. + * + * @param file File name. + * @param tmode Time mode. + * @return Time value, or -1 on failure. + */ +native int GetFileTime(const char[] file, FileTimeMode tmode); + +/** + * Same as LogToFile(), except uses an open file Handle. The file must + * be opened in text appending mode. + * + * @param hndl Handle to the file. + * @param message Message format. + * @param ... Message format parameters. + * @error Invalid Handle. + */ +native void LogToOpenFile(Handle hndl, const char[] message, any ...); + +/** + * Same as LogToFileEx(), except uses an open file Handle. The file must + * be opened in text appending mode. + * + * @param hndl Handle to the file. + * @param message Message format. + * @param ... Message format parameters. + * @error Invalid Handle. + */ +native void LogToOpenFileEx(Handle hndl, const char[] message, any ...); diff --git a/scripting/include/float.inc b/scripting/include/float.inc new file mode 100644 index 0000000..99d90f6 --- /dev/null +++ b/scripting/include/float.inc @@ -0,0 +1,436 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _float_included + #endinput +#endif +#define _float_included + +#if !defined __sourcepawn2__ +/** + * Converts an integer into a floating point value. + * + * @param value Integer to convert. + * @return Floating point value. + */ +native float float(int value); +#endif + +/** + * Multiplies two floats together. + * + * @param oper1 First value. + * @param oper2 Second value. + * @return oper1*oper2. + */ +native float FloatMul(float oper1, float oper2); + +/** + * Divides the dividend by the divisor. + * + * @param dividend First value. + * @param divisor Second value. + * @return dividend/divisor. + */ +native float FloatDiv(float dividend, float divisor); + +/** + * Adds two floats together. + * + * @param oper1 First value. + * @param oper2 Second value. + * @return oper1+oper2. + */ +native float FloatAdd(float oper1, float oper2); + +/** + * Subtracts oper2 from oper1. + * + * @param oper1 First value. + * @param oper2 Second value. + * @return oper1-oper2. + */ +native float FloatSub(float oper1, float oper2); + +/** + * Returns the decimal part of a float. + * + * @param value Input value. + * @return Decimal part. + */ +native float FloatFraction(float value); + +/** + * Rounds a float to the closest integer to zero. + * + * @param value Input value to be rounded. + * @return Rounded value. + */ +native int RoundToZero(float value); + +/** + * Rounds a float to the next highest integer value. + * + * @param value Input value to be rounded. + * @return Rounded value. + */ +native int RoundToCeil(float value); + +/** + * Rounds a float to the next lowest integer value. + * + * @param value Input value to be rounded. + * @return Rounded value. + */ +native int RoundToFloor(float value); + +/** + * Standard IEEE rounding. + * + * @param value Input value to be rounded. + * @return Rounded value. + */ +native int RoundToNearest(float value); + +/** + * Compares two floats. + * + * @param fOne First value. + * @param fTwo Second value. + * @return Returns 1 if the first argument is greater than the second argument. + * Returns -1 if the first argument is smaller than the second argument. + * Returns 0 if both arguments are equal. + */ +native int FloatCompare(float fOne, float fTwo); + +/** + * Returns the square root of the input value, equivalent to floatpower(value, 0.5). + * + * @param value Input value. + * @return Square root of the value. + */ +native float SquareRoot(float value); + +/** + * Returns the value raised to the power of the exponent. + * + * @param value Value to be raised. + * @param exponent Value to raise the base. + * @return value^exponent. + */ +native float Pow(float value, float exponent); + +/** + * Returns the value of raising the input by e. + * + * @param value Input value. + * @return exp(value). + */ +native float Exponential(float value); + +/** + * Returns the logarithm of any base specified. + * + * @param value Input value. + * @param base Logarithm base to use, default is 10. + * @return log(value)/log(base). + */ +native float Logarithm(float value, float base=10.0); + +/** + * Returns the sine of the argument. + * + * @param value Input value in radians. + * @return sin(value). + */ +native float Sine(float value); + +/** + * Returns the cosine of the argument. + * + * @param value Input value in radians. + * @return cos(value). + */ +native float Cosine(float value); + +/** + * Returns the tangent of the argument. + * + * @param value Input value in radians. + * @return tan(value). + */ +native float Tangent(float value); + +/** + * Returns an absolute value. + * + * @param value Input value. + * @return Absolute value of the input. + */ +native float FloatAbs(float value); + +/** + * Returns the arctangent of the input value. + * + * @param angle Input value. + * @return atan(value) in radians. + */ +native float ArcTangent(float angle); + +/** + * Returns the arccosine of the input value. + * + * @param angle Input value. + * @return acos(value) in radians. + */ +native float ArcCosine(float angle); + +/** + * Returns the arcsine of the input value. + * + * @param angle Input value. + * @return asin(value) in radians. + */ +native float ArcSine(float angle); + +/** + * Returns the arctangent2 of the input values. + * + * @param x Horizontal value. + * @param y Vertical value. + * @return atan2(value) in radians. + */ +native float ArcTangent2(float x, float y); + +/** + * Rounds a floating point number using the "round to nearest" algorithm. + * + * @param value Floating point value to round. + * @return The value rounded to the nearest integer. + */ +stock int RoundFloat(float value) +{ + return RoundToNearest(value); +} + +/** + * User defined operators. + */ +#if !defined __sourcepawn2__ +#pragma rational Float + +native bool __FLOAT_GT__(float a, float b); +native bool __FLOAT_GE__(float a, float b); +native bool __FLOAT_LT__(float a, float b); +native bool __FLOAT_LE__(float a, float b); +native bool __FLOAT_EQ__(float a, float b); +native bool __FLOAT_NE__(float a, float b); +native bool __FLOAT_NOT__(float a); + +native float operator*(float oper1, float oper2) = FloatMul; +native float operator/(float oper1, float oper2) = FloatDiv; +native float operator+(float oper1, float oper2) = FloatAdd; +native float operator-(float oper1, float oper2) = FloatSub; +native bool operator!(float oper1) = __FLOAT_NOT__; +native bool operator>(float oper1, float oper2) = __FLOAT_GT__; +native bool operator>=(float oper1, float oper2) = __FLOAT_GE__; +native bool operator<(float oper1, float oper2) = __FLOAT_LT__; +native bool operator<=(float oper1, float oper2) = __FLOAT_LE__; +native bool operator!=(float oper1, float oper2) = __FLOAT_NE__; +native bool operator==(float oper1, float oper2) = __FLOAT_EQ__; + +stock float operator++(float oper) +{ + return oper+1.0; +} + +stock float operator--(float oper) +{ + return oper-1.0; +} + +stock float operator-(float oper) +{ + return oper^view_as(cellmin); /* IEEE values are sign/magnitude */ +} + +stock float operator*(float oper1, int oper2) +{ + return FloatMul(oper1, float(oper2)); /* "*" is commutative */ +} + +stock float operator/(float oper1, int oper2) +{ + return FloatDiv(oper1, float(oper2)); +} + +stock float operator/(int oper1, float oper2) +{ + return FloatDiv(float(oper1), oper2); +} + +stock float operator+(float oper1, int oper2) +{ + return FloatAdd(oper1, float(oper2)); /* "+" is commutative */ +} + +stock float operator-(float oper1, int oper2) +{ + return FloatSub(oper1, float(oper2)); +} + +stock float operator-(int oper1, float oper2) +{ + return FloatSub(float(oper1), oper2); +} + +stock bool operator==(float oper1, int oper2) +{ + return __FLOAT_EQ__(oper1, float(oper2)); +} + +stock bool operator!=(float oper1, int oper2) +{ + return __FLOAT_NE__(oper1, float(oper2)); +} + +stock bool operator>(float oper1, int oper2) +{ + return __FLOAT_GT__(oper1, float(oper2)); +} + +stock bool operator>(int oper1, float oper2) +{ + return __FLOAT_GT__(float(oper1), oper2); +} + +stock bool operator>=(float oper1, int oper2) +{ + return __FLOAT_GE__(oper1, float(oper2)); +} + +stock bool operator>=(int oper1, float oper2) +{ + return __FLOAT_GE__(float(oper1), oper2); +} + +stock bool operator<(float oper1, int oper2) +{ + return __FLOAT_LT__(oper1, float(oper2)); +} + +stock bool operator<(int oper1, float oper2) +{ + return __FLOAT_LT__(float(oper1), oper2); +} + +stock bool operator<=(float oper1, int oper2) +{ + return __FLOAT_LE__(oper1, float(oper2)); +} + +stock bool operator<=(int oper1, float oper2) +{ + return __FLOAT_LE__(float(oper1), oper2); +} + +/** + * Forbidden operators. + */ +forward operator%(float oper1, float oper2); +forward operator%(float oper1, int oper2); +forward operator%(int oper1, float oper2); +#endif // __sourcepawn2__ + +#define FLOAT_PI 3.1415926535897932384626433832795 + +/** + * Converts degrees to radians. + * + * @param angle Degrees. + * @return Radians. + */ +stock float DegToRad(float angle) +{ + return (angle*FLOAT_PI)/180; +} + +/** + * Converts radians to degrees. + * + * @param angle Radians. + * @return Degrees. + */ +stock float RadToDeg(float angle) +{ + return (angle*180)/FLOAT_PI; +} + +/** + * Returns a random integer in the range [0, 2^31-1]. + * + * Note: Uniform random number streams are seeded automatically per-plugin. + * + * @return Random integer. + */ +native int GetURandomInt(); + +/** + * Returns a uniform random float in the range [0, 1). + * + * Note: Uniform random number streams are seeded automatically per-plugin. + * + * @return Uniform random floating-point number. + */ +native float GetURandomFloat(); + +/** + * Seeds a plugin's uniform random number stream. This is done automatically, + * so normally it is totally unnecessary to call this. + * + * @param seeds Array of numbers to use as seeding data. + * @param numSeeds Number of seeds in the seeds array. + */ +native void SetURandomSeed(const int[] seeds, int numSeeds); + +/** + * Seeds a plugin's uniform random number stream. This is done automatically, + * so normally it is totally unnecessary to call this. + * + * @param seed Single seed value. + */ +stock void SetURandomSeedSimple(int seed) +{ + int seeds[1]; + seeds[0] = seed; + SetURandomSeed(seeds, 1); +} diff --git a/scripting/include/functions.inc b/scripting/include/functions.inc new file mode 100644 index 0000000..b9bd2f9 --- /dev/null +++ b/scripting/include/functions.inc @@ -0,0 +1,541 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _functions_included + #endinput +#endif +#define _functions_included + +#define SP_PARAMFLAG_BYREF (1<<0) /**< Internal use only. */ + +/** + * Describes the various ways to pass parameters to functions or forwards. + */ +enum ParamType +{ + Param_Any = 0, /**< Any data type can be pushed */ + Param_Cell = (1<<1), /**< Only basic cells can be pushed */ + Param_Float = (2<<1), /**< Only floats can be pushed */ + Param_String = (3<<1)|SP_PARAMFLAG_BYREF, /**< Only strings can be pushed */ + Param_Array = (4<<1)|SP_PARAMFLAG_BYREF, /**< Only arrays can be pushed */ + Param_VarArgs = (5<<1), /**< Same as "..." in plugins, anything can be pushed, but it will always be byref */ + Param_CellByRef = (1<<1)|SP_PARAMFLAG_BYREF, /**< Only a cell by reference can be pushed */ + Param_FloatByRef = (2<<1)|SP_PARAMFLAG_BYREF /**< Only a float by reference can be pushed */ +}; + +/** + * Defines how a forward iterates through plugin functions. + */ +enum ExecType +{ + ET_Ignore = 0, /**< Ignore all return values, return 0 */ + ET_Single = 1, /**< Only return the last exec, ignore all others */ + ET_Event = 2, /**< Acts as an event with the Actions defined in core.inc, no mid-Stops allowed, returns highest */ + ET_Hook = 3 /**< Acts as a hook with the Actions defined in core.inc, mid-Stops allowed, returns highest */ +}; + +/** + * @section Flags that are used with Call_PushArrayEx() and Call_PushStringEx() + */ + +#define SM_PARAM_COPYBACK (1<<0) /**< Copy an array/reference back after call */ + +#define SM_PARAM_STRING_UTF8 (1<<0) /**< String should be UTF-8 handled */ +#define SM_PARAM_STRING_COPY (1<<1) /**< String should be copied into the plugin */ +#define SM_PARAM_STRING_BINARY (1<<2) /**< Treat the string as a binary string */ + +/** + * @endsection + */ + +/** + * @section Error codes + */ +#define SP_ERROR_NONE 0 /**< No error occurred */ +#define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */ +#define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */ +#define SP_ERROR_HEAPLOW 3 /**< Not enough space left on the heap */ +#define SP_ERROR_PARAM 4 /**< Invalid parameter or parameter type */ +#define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */ +#define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */ +#define SP_ERROR_INDEX 7 /**< Invalid index parameter */ +#define SP_ERROR_STACKLOW 8 /**< Not enough space left on the stack */ +#define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */ +#define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */ +#define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */ +#define SP_ERROR_STACKMIN 12 /**< Stack went beyond its minimum value */ +#define SP_ERROR_HEAPMIN 13 /**< Heap went beyond its minimum value */ +#define SP_ERROR_DIVIDE_BY_ZERO 14 /**< Division by zero */ +#define SP_ERROR_ARRAY_BOUNDS 15 /**< Array index is out of bounds */ +#define SP_ERROR_INSTRUCTION_PARAM 16 /**< Instruction had an invalid parameter */ +#define SP_ERROR_STACKLEAK 17 /**< A native leaked an item on the stack */ +#define SP_ERROR_HEAPLEAK 18 /**< A native leaked an item on the heap */ +#define SP_ERROR_ARRAY_TOO_BIG 19 /**< A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 20 /**< Tracker stack is out of bounds */ +#define SP_ERROR_INVALID_NATIVE 21 /**< Native was pending or invalid */ +#define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */ +#define SP_ERROR_NATIVE 23 /**< Error originates from a native */ +#define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */ +#define SP_ERROR_ABORTED 25 /**< Function call was aborted */ + +/** + * @endsection + */ + +/** + * Gets a function id from a function name. + * + * @param plugin Handle of the plugin that contains the function. + Pass INVALID_HANDLE to search in the calling plugin. + * @param name Name of the function. + * @return Function id or INVALID_FUNCTION if not found. + * @error Invalid or corrupt plugin handle. + */ +native Function GetFunctionByName(Handle plugin, const char[] name); + +/** + * Creates a global forward. + * + * @note The name used to create the forward is used as its public function in all target plugins. + * @note This is ideal for global, static forwards that are never changed. + * @note Global forwards cannot be cloned. + * @note Use CloseHandle() to destroy these. + * + * @param name Name of public function to use in forward. + * @param type Execution type to be used. + * @param ... Variable number of parameter types (up to 32). + * @return Handle to new global forward. + * @error More than 32 paramater types passed. + */ +native Handle CreateGlobalForward(const char[] name, ExecType type, ParamType ...); + +/** + * Creates a private forward. + * + * @note No functions are automatically added. Use AddToForward() to do this. + * @note Private forwards can be cloned. + * @note Use CloseHandle() to destroy these. + * + * @param type Execution type to be used. + * @param ... Variable number of parameter types (up to 32). + * @return Handle to new private forward. + * @error More than 32 paramater types passed. + */ +native Handle CreateForward(ExecType type, ParamType ...); + +/** + * Returns the number of functions in a global or private forward's call list. + * + * @param fwd Handle to global or private forward. + * @return Number of functions in forward. + * @error Invalid or corrupt forward handle. + */ +native int GetForwardFunctionCount(Handle fwd); + +/** + * Adds a function to a private forward's call list. + * + * @note Cannot be used during an incomplete call. + * + * @param fwd Handle to private forward. + * @param plugin Handle of the plugin that contains the function. + * Pass INVALID_HANDLE to specify the calling plugin. + * @param func Function to add to forward. + * @return True on success, false otherwise. + * @error Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function. + */ +native bool AddToForward(Handle fwd, Handle plugin, Function func); + +/** + * Removes a function from a private forward's call list. + * + * @note Only removes one instance. + * @note Functions will be removed automatically if their parent plugin is unloaded. + * + * @param fwd Handle to private forward. + * @param plugin Handle of the plugin that contains the function. + * Pass INVALID_HANDLE to specify the calling plugin. + * @param func Function to remove from forward. + * @return True on success, false otherwise. + * @error Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function. + */ +native bool RemoveFromForward(Handle fwd, Handle plugin, Function func); + +/** + * Removes all instances of a plugin from a private forward's call list. + * + * @note Functions will be removed automatically if their parent plugin is unloaded. + * + * @param fwd Handle to private forward. + * @param plugin Handle of the plugin to remove instances of. + * Pass INVALID_HANDLE to specify the calling plugin. + * @return Number of functions removed from forward. + * @error Invalid or corrupt private forward handle or invalid or corrupt plugin handle. + */ +native int RemoveAllFromForward(Handle fwd, Handle plugin); + +/** + * Starts a call to functions in a forward's call list. + * + * @note Cannot be used during an incomplete call. + * + * @param fwd Handle to global or private forward. + * @error Invalid or corrupt forward handle or called before another call has completed. + */ +native void Call_StartForward(Handle fwd); + +/** + * Starts a call to a function. + * + * @note Cannot be used during an incomplete call. + * + * @param plugin Handle of the plugin that contains the function. + * Pass INVALID_HANDLE to specify the calling plugin. + * @param func Function to call. + * @error Invalid or corrupt plugin handle, invalid function, or called before another call has completed. + */ +native void Call_StartFunction(Handle plugin, Function func); + +/** + * Pushes a cell onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Cell value to push. + * @error Called before a call has been started. + */ +native void Call_PushCell(any value); + +/** + * Pushes a cell by reference onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Cell reference to push. + * @error Called before a call has been started. + */ +native void Call_PushCellRef(any &value); + +/** + * Pushes a float onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Floating point value to push. + * @error Called before a call has been started. + */ +native void Call_PushFloat(float value); + +/** + * Pushes a float by reference onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Floating point reference to push. + * @error Called before a call has been started. + */ +native void Call_PushFloatRef(float &value); + +/** + * Pushes an array onto the current call. + * + * @note Changes to array are not copied back to caller. Use PushArrayEx() to do this. + * @note Cannot be used before a call has been started. + * + * @param value Array to push. + * @param size Size of array. + * @error Called before a call has been started. + */ +native void Call_PushArray(const any[] value, int size); + +/** + * Pushes an array onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value Array to push. + * @param size Size of array. + * @param cpflags Whether or not changes should be copied back to the input array. + * See SP_PARAM_* constants for details. + * @error Called before a call has been started. + */ +native void Call_PushArrayEx(any[] value, int size, int cpflags); + +/** + * Pushes the NULL_VECTOR onto the current call. + * @see IsNullVector + * + * @note Cannot be used before a call has been started. + * + * @error Called before a call has been started. + */ +native void Call_PushNullVector(); + +/** + * Pushes a string onto the current call. + * + * @note Changes to string are not copied back to caller. Use PushStringEx() to do this. + * @note Cannot be used before a call has been started. + * + * @param value String to push. + * @error Called before a call has been started. + */ +native void Call_PushString(const char[] value); + +/** + * Pushes a string onto the current call. + * + * @note Cannot be used before a call has been started. + * + * @param value String to push. + * @param length Length of string buffer. + * @param szflags Flags determining how string should be handled. + * See SM_PARAM_STRING_* constants for details. + * The default (0) is to push ASCII. + * @param cpflags Whether or not changes should be copied back to the input array. + * See SM_PARAM_* constants for details. + * @error Called before a call has been started. + */ +native void Call_PushStringEx(char[] value, int length, int szflags, int cpflags); + +/** + * Pushes the NULL_STRING onto the current call. + * @see IsNullString + * + * @note Cannot be used before a call has been started. + * + * @error Called before a call has been started. + */ +native void Call_PushNullString(); + +/** + * Completes a call to a function or forward's call list. + * + * @note Cannot be used before a call has been started. + * + * @param result Return value of function or forward's call list. + * @return SP_ERROR_NONE on success, any other integer on failure. + * @error Called before a call has been started. + */ +native int Call_Finish(any &result=0); + +/** + * Cancels a call to a function or forward's call list. + * + * @note Cannot be used before a call has been started. + * + * @error Called before a call has been started. + */ +native void Call_Cancel(); + +/** + * Defines a native function. + * + * It is not necessary to validate the parameter count + * + * @param plugin Handle of the calling plugin. + * @param numParams Number of parameters passed to the native. + * @return Value for the native call to return. + */ +typedef NativeCall = function int (Handle plugin, int numParams); + +/** + * Creates a dynamic native. This should only be called in AskPluginLoad(), or + * else you risk not having your native shared with other plugins. + * + * @param name Name of the dynamic native; must be unique among + * all other registered dynamic natives. + * @param func Function to use as the dynamic native. + */ +native void CreateNative(const char[] name, NativeCall func); + +/** + * Throws an error in the calling plugin of a native, instead of your own plugin. + * + * @param error Error code to use. + * @param fmt Error message format. + * @param ... Format arguments. + */ +native int ThrowNativeError(int error, const char[] fmt, any ...); + +/** + * Retrieves the string length from a native parameter string. This is useful + * fetching the entire string using dynamic arrays. + * @note If this function succeeds, Get/SetNativeString will also succeed. + * + * @param param Parameter number, starting from 1. + * @param length Stores the length of the string. + * @return SP_ERROR_NONE on success, any other integer on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native int GetNativeStringLength(int param, int &length); + +/** + * Retrieves a string from a native parameter. + * @note Output conditions are undefined on failure. + * + * @param param Parameter number, starting from 1. + * @param buffer Buffer to store the string in. + * @param maxlength Maximum length of the buffer. + * @param bytes Optionally store the number of bytes written. + * @return SP_ERROR_NONE on success, any other integer on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native int GetNativeString(int param, char[] buffer, int maxlength, int &bytes=0); + +/** + * Sets a string in a native parameter. + * @note Output conditions are undefined on failure. + * + * @param param Parameter number, starting from 1. + * @param source Source string to use. + * @param maxlength Maximum number of bytes to write. + * @param utf8 If false, string will not be written + * with UTF8 safety. + * @param bytes Optionally store the number of bytes written. + * @return SP_ERROR_NONE on success, any other integer on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native int SetNativeString(int param, const char[] source, int maxlength, bool utf8=true, int &bytes=0); + +/** + * Gets a cell from a native parameter. + * + * @param param Parameter number, starting from 1. + * @return Cell value at the parameter number. + * @error Invalid parameter number or calling from a non-native function. + */ +native any GetNativeCell(int param); + +/** + * Gets a function pointer from a native parameter. + * + * @param param Parameter number, starting from 1. + * @return Function pointer at the given parameter number. + * @error Invalid parameter number, or calling from a non-native function. + */ +native Function GetNativeFunction(int param); + +/** + * Gets a cell from a native parameter, by reference. + * + * @param param Parameter number, starting from 1. + * @return Cell value at the parameter number. + * @error Invalid parameter number or calling from a non-native function. + */ +native any GetNativeCellRef(int param); + +/** + * Sets a cell from a native parameter, by reference. + * + * @param param Parameter number, starting from 1. + * @param value Cell value at the parameter number to set by reference. + * @error Invalid parameter number or calling from a non-native function. + */ +native void SetNativeCellRef(int param, any value); + +/** + * Gets an array from a native parameter (always by reference). + * + * @param param Parameter number, starting from 1. + * @param local Local array to copy into. + * @param size Maximum size of local array. + * @return SP_ERROR_NONE on success, anything else on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native int GetNativeArray(int param, any[] local, int size); + +/** + * Copies a local array into a native parameter array (always by reference). + * + * @param param Parameter number, starting from 1. + * @param local Local array to copy from. + * @param size Size of the local array to copy. + * @return SP_ERROR_NONE on success, anything else on failure. + * @error Invalid parameter number or calling from a non-native function. + */ +native int SetNativeArray(int param, const any[] local, int size); + +/** + * Check if the native parameter is the NULL_VECTOR. + * + * @param param Parameter number, starting from 1. + * @return True if NULL_VECTOR, false otherwise. + */ +native bool IsNativeParamNullVector(int param); + +/** + * Check if the native parameter is the NULL_STRING. + * + * @param param Parameter number, starting from 1. + * @return True if NULL_STRING, false otherwise. + */ +native bool IsNativeParamNullString(int param); + +/** + * Formats a string using parameters from a native. + * + * @note All parameter indexes start at 1. + * @note If the input and output buffers overlap, the contents + * of the output buffer at the end is undefined. + * + * @param out_param Output parameter number to write to. If 0, out_string is used. + * @param fmt_param Format parameter number. If 0, fmt_string is used. + * @param vararg_param First variable parameter number. + * @param out_len Output string buffer maximum length (always required). + * @param written Optionally stores the number of bytes written. + * @param out_string Output string buffer to use if out_param is not used. + * @param fmt_string Format string to use if fmt_param is not used. + * @return SP_ERROR_NONE on success, anything else on failure. + */ +native int FormatNativeString(int out_param, + int fmt_param, + int vararg_param, + int out_len, + int &written=0, + char[] out_string="", + const char[] fmt_string=""); + +/** + * Defines a RequestFrame Callback. + * + * @param data Data passed to the RequestFrame native. + */ +typedef RequestFrameCallback = function void (any data); + +/** + * Creates a single use Next Frame hook. + * + * @param Function Function to call on the next frame. + * @param data Value to be passed on the invocation of the Function. + */ +native void RequestFrame(RequestFrameCallback Function, any data=0); diff --git a/scripting/include/geoip.inc b/scripting/include/geoip.inc new file mode 100644 index 0000000..57d0862 --- /dev/null +++ b/scripting/include/geoip.inc @@ -0,0 +1,102 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _geoip_included + #endinput +#endif +#define _geoip_included + +#include + +/** + * @section IP addresses can contain ports, the ports will be stripped out. + */ + +/** + * Gets the two character country code from an IP address. (US, CA, etc) + * + * @param ip Ip to determine the country code. + * @param ccode Destination string buffer to store the code. + * @return True on success, false if no country found. + */ +native bool GeoipCode2(const char[] ip, char ccode[3]); + +/** + * Gets the three character country code from an IP address. (USA, CAN, etc) + * + * @param ip Ip to determine the country code. + * @param ccode Destination string buffer to store the code. + * @return True on success, false if no country found. + */ +native bool GeoipCode3(const char[] ip, char ccode[4]); + +/** + * Gets the full country name. (max length of output string is 45) + * + * @param ip Ip to determine the country code. + * @param name Destination string buffer to store the country name. + * @param maxlength Maximum length of output string buffer. + * @return True on success, false if no country found. + */ +native bool GeoipCountry(const char[] ip, char[] name, int maxlength); + +/** + * @endsection + */ + +/** + * Do not edit below this line! + */ +public Extension __ext_geoip = +{ + name = "GeoIP", + file = "geoip.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public void __ext_geoip_SetNTVOptional() +{ + MarkNativeAsOptional("GeoipCode2"); + MarkNativeAsOptional("GeoipCode3"); + MarkNativeAsOptional("GeoipCountry"); +} +#endif diff --git a/scripting/include/halflife.inc b/scripting/include/halflife.inc new file mode 100644 index 0000000..fd6344d --- /dev/null +++ b/scripting/include/halflife.inc @@ -0,0 +1,706 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2016 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _halflife_included + #endinput +#endif +#define _halflife_included + +#define SOURCE_SDK_UNKNOWN 0 /**< Could not determine the engine version */ +#define SOURCE_SDK_ORIGINAL 10 /**< Original Source engine (still used by "The Ship") */ +#define SOURCE_SDK_DARKMESSIAH 15 /**< Modified version of original engine used by Dark Messiah (no SDK) */ +#define SOURCE_SDK_EPISODE1 20 /**< SDK+Engine released after Episode 1 */ +#define SOURCE_SDK_EPISODE2 30 /**< SDK+Engine released after Episode 2/Orange Box */ +#define SOURCE_SDK_BLOODYGOODTIME 32 /**< Modified version of ep2 engine used by Bloody Good Time (no SDK) */ +#define SOURCE_SDK_EYE 33 /**< Modified version of ep2 engine used by E.Y.E Divine Cybermancy (no SDK) */ +#define SOURCE_SDK_CSS 34 /**< Sometime-older version of Source 2009 SDK+Engine, used for Counter-Strike: Source */ +#define SOURCE_SDK_EPISODE2VALVE 35 /**< SDK+Engine released after Episode 2/Orange Box, "Source 2009" or "Source MP" */ +#define SOURCE_SDK_LEFT4DEAD 40 /**< Engine released after Left 4 Dead (no SDK yet) */ +#define SOURCE_SDK_LEFT4DEAD2 50 /**< Engine released after Left 4 Dead 2 (no SDK yet) */ +#define SOURCE_SDK_ALIENSWARM 60 /**< SDK+Engine released after Alien Swarm */ +#define SOURCE_SDK_CSGO 80 /**< Engine released after CS:GO (no SDK yet) */ +#define SOURCE_SDK_DOTA 90 /**< Engine released after Dota 2 (no SDK) */ + +#define MOTDPANEL_TYPE_TEXT 0 /**< Treat msg as plain text */ +#define MOTDPANEL_TYPE_INDEX 1 /**< Msg is auto determined by the engine */ +#define MOTDPANEL_TYPE_URL 2 /**< Treat msg as an URL link */ +#define MOTDPANEL_TYPE_FILE 3 /**< Treat msg as a filename to be opened */ + +enum DialogType +{ + DialogType_Msg = 0, /**< just an on screen message */ + DialogType_Menu, /**< an options menu */ + DialogType_Text, /**< a richtext dialog */ + DialogType_Entry, /**< an entry box */ + DialogType_AskConnect /**< ask the client to connect to a specified IP */ +}; + +enum EngineVersion +{ + Engine_Unknown, /**< Could not determine the engine version */ + Engine_Original, /**< Original Source Engine (used by The Ship) */ + Engine_SourceSDK2006, /**< Episode 1 Source Engine (second major SDK) */ + Engine_SourceSDK2007, /**< Orange Box Source Engine (third major SDK) */ + Engine_Left4Dead, /**< Left 4 Dead */ + Engine_DarkMessiah, /**< Dark Messiah Multiplayer (based on original engine) */ + Engine_Left4Dead2 = 7, /**< Left 4 Dead 2 */ + Engine_AlienSwarm, /**< Alien Swarm (and Alien Swarm SDK) */ + Engine_BloodyGoodTime, /**< Bloody Good Time */ + Engine_EYE, /**< E.Y.E Divine Cybermancy */ + Engine_Portal2, /**< Portal 2 */ + Engine_CSGO, /**< Counter-Strike: Global Offensive */ + Engine_CSS, /**< Counter-Strike: Source */ + Engine_DOTA, /**< Dota 2 */ + Engine_HL2DM, /**< Half-Life 2 Deathmatch */ + Engine_DODS, /**< Day of Defeat: Source */ + Engine_TF2, /**< Team Fortress 2 */ + Engine_NuclearDawn, /**< Nuclear Dawn */ + Engine_SDK2013, /**< Source SDK 2013 */ + Engine_Blade, /**< Blade Symphony */ + Engine_Insurgency, /**< Insurgency (2013 Retail version)*/ + Engine_Contagion, /**< Contagion */ + Engine_BlackMesa, /**< Black Mesa Multiplayer */ + Engine_DOI, /**< Day of Infamy */ +}; + +enum FindMapResult +{ + // A direct match for this name was found + FindMap_Found, + // No match for this map name could be found. + FindMap_NotFound, + // A fuzzy match for this map name was found. + // Ex: cp_dust -> cp_dustbowl, c1m1 -> c1m1_hotel + // Only supported for maps that the engine knows about. (This excludes workshop maps on Orangebox). + FindMap_FuzzyMatch, + // A non-canonical match for this map name was found. + // Ex: workshop/1234 -> workshop/cp_qualified_name.ugc1234 + // Only supported on "Orangebox" games with workshop support. + FindMap_NonCanonical, + // No currently available match for this map name could be found, but it may be possible to load + // Only supported on "Orangebox" games with workshop support. + FindMap_PossiblyAvailable +}; + +#define INVALID_ENT_REFERENCE 0xFFFFFFFF + +/** + * Logs a generic message to the HL2 logs. + * + * @param format String format. + * @param ... Format arguments. + */ +native void LogToGame(const char[] format, any ...); + +/** + * Sets the seed value for the global Half-Life 2 Random Stream. + * + * @param seed Seed value. + */ +native void SetRandomSeed(int seed); + +/** + * Returns a random floating point number from the Half-Life 2 Random Stream. + * + * @param fMin Minimum random bound. + * @param fMax Maximum random bound. + * @return A random number between (inclusive) fMin and fMax. + */ +native float GetRandomFloat(float fMin=0.0, float fMax=1.0); + +/** + * Returns a random number from the Half-Life 2 Random Stream. + * + * @param nmin Minimum random bound. + * @param nmax Maximum random bound. + * @return A random number between (inclusive) nmin and nmax. + */ +native int GetRandomInt(int nmin, int nmax); + +/** + * Returns whether a map is valid or not. + * + * @param map Map name, excluding .bsp extension. + * @return True if valid, false otherwise. + */ +native bool IsMapValid(const char[] map); + +/** + * Returns whether a full or partial map name is found or can be resolved + * + * @param map Map name (usually same as map path relative to maps/ dir, + * excluding .bsp extension). + * @param foundmap Resolved map name. If the return is FindMap_FuzzyMatch + * or FindMap_NonCanonical the buffer will be the full path. + * @param maxlen Maximum length to write to map var. + * @return Result of the find operation. Not all result types are supported on all games. + */ +native FindMapResult FindMap(const char[] map, char[] foundmap, int maxlen); + +/** + * Get the display name of a workshop map. + * + * Note: You do not need to call FindMap first. This native will call FindMap internally. + * + * @param map Map name (usually same as map path relative to maps/ dir, + * excluding .bsp extension). + * @param displayName Map's display name, i.e. cp_mymapname or de_mymapname. + * If FindMap returns FindMap_PossiblyAvailable or FindMap_NotFound, + * the map cannot be resolved and this native will return false, + * but displayName will be a copy of map. + * @param maxlen Maximum length to write to displayName var. + * @return true if FindMap returns FindMap_Found, FindMap_FuzzyMatch, or + * FindMap_NonCanonical. + * false if FindMap returns FindMap_PossiblyAvailable or FindMap_NotFound. + */ +native bool GetMapDisplayName(const char[] map, char[] displayName, int maxlen); + +/** + * Returns whether the server is dedicated. + * + * @return True if dedicated, false otherwise. + */ +native bool IsDedicatedServer(); + +/** + * Returns a high-precision time value for profiling the engine. + * + * @return A floating point time value. + */ +native float GetEngineTime(); + +/** + * Returns the game time based on the game tick. + * + * @return Game tick time. + */ +native float GetGameTime(); + +/** + * Returns the game's internal tick count. + * + * @return Game tick count. + */ +native int GetGameTickCount(); + +/** + * Returns the time the Game took processing the last frame. + * + * @return Game frame time. + */ +native float GetGameFrameTime(); + +/** + * Returns the game description from the mod. + * + * @param buffer Buffer to store the description. + * @param maxlength Maximum size of the buffer. + * @param original If true, retrieves the original game description, + * ignoring any potential hooks from plugins. + * @return Number of bytes written to the buffer (UTF-8 safe). + */ +native int GetGameDescription(char[] buffer, int maxlength, bool original=false); + +/** + * Returns the name of the game's directory. + * + * @param buffer Buffer to store the directory name. + * @param maxlength Maximum size of the buffer. + * @return Number of bytes written to the buffer (UTF-8 safe). + */ +native int GetGameFolderName(char[] buffer, int maxlength); + +/** + * Returns the current map name. + * + * @param buffer Buffer to store map name. + * @param maxlength Maximum length of buffer. + * @return Number of bytes written (UTF-8 safe). + */ +native int GetCurrentMap(char[] buffer, int maxlength); + +/** + * Precaches a given model. + * + * @param model Name of the model to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns the model index, 0 for error. + */ +native int PrecacheModel(const char[] model, bool preload=false); + +/** + * Precaches a given sentence file. + * + * @param file Name of the sentence file to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns a sentence file index. + */ +native int PrecacheSentenceFile(const char[] file, bool preload=false); + +/** + * Precaches a given decal. + * + * @param decal Name of the decal to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns a decal index. + */ +native int PrecacheDecal(const char[] decal, bool preload=false); + +/** + * Precaches a given generic file. + * + * @param generic Name of the generic file to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return Returns a generic file index. + */ +native int PrecacheGeneric(const char[] generic, bool preload=false); + +/** + * Returns if a given model is precached. + * + * @param model Name of the model to check. + * @return True if precached, false otherwise. + */ +native bool IsModelPrecached(const char[] model); + +/** + * Returns if a given decal is precached. + * + * @param decal Name of the decal to check. + * @return True if precached, false otherwise. + */ +native bool IsDecalPrecached(const char[] decal); + +/** + * Returns if a given generic file is precached. + * + * @param generic Name of the generic file to check. + * @return True if precached, false otherwise. + */ +native bool IsGenericPrecached(const char[] generic); + +/** + * Precaches a given sound. + * + * @param sound Name of the sound to precache. + * @param preload If preload is true the file will be precached before level startup. + * @return True if successfully precached, false otherwise. + */ +native bool PrecacheSound(const char[] sound, bool preload=false); + +/** + * Returns if a given sound is precached. + * + * @param sound Name of the sound to check. + * @return True if precached, false otherwise. + */ +native bool IsSoundPrecached(const char[] sound); + +/** + * Creates different types of ingame messages. + * + * @param client Index of the client. + * @param kv KeyValues handle to set the menu keys and options. (Check iserverplugin.h for more information). + * @param type Message type to display ingame. + * @error Invalid client index, or client not connected. + */ +native void CreateDialog(int client, Handle kv, DialogType type); + +/** + * Guesses the SDK version a mod was compiled against. If nothing + * specific is known about the game, the engine version is used instead. + * + * The return values are guaranteed to increase chronologically (that is, + * a later release will have a higher value). + * + * @return SOURCE_SDK version code. + */ +#pragma deprecated See GetEngineVersion() +native int GuessSDKVersion(); + +/** + * Gets the engine version that the currently-loaded SM core was compiled against. + * + * The engine version values are not guaranteed to be in any particular order, + * and should only be compared by (in)equality. + * + * @return An EngineVersion value. + */ +native EngineVersion GetEngineVersion(); + +/** + * Prints a message to a specific client in the chat area. + * + * @param client Client index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error If the client is not connected an error will be thrown. + */ +native void PrintToChat(int client, const char[] format, any ...); + +/** + * Prints a message to all clients in the chat area. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +stock void PrintToChatAll(const char[] format, any ...) +{ + char buffer[254]; + + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i)) + { + SetGlobalTransTarget(i); + VFormat(buffer, sizeof(buffer), format, 2); + PrintToChat(i, "%s", buffer); + } + } +} + +/** + * Prints a message to a specific client in the center of the screen. + * + * @param client Client index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error If the client is not connected an error will be thrown. + */ +native void PrintCenterText(int client, const char[] format, any ...); + +/** + * Prints a message to all clients in the center of the screen. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +stock void PrintCenterTextAll(const char[] format, any ...) +{ + char buffer[254]; + + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i)) + { + SetGlobalTransTarget(i); + VFormat(buffer, sizeof(buffer), format, 2); + PrintCenterText(i, "%s", buffer); + } + } +} + +/** + * Prints a message to a specific client with a hint box. + * + * @param client Client index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error If the client is not connected an error will be thrown. + */ +native void PrintHintText(int client, const char[] format, any ...); + +/** + * Prints a message to all clients with a hint box. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + */ +stock void PrintHintTextToAll(const char[] format, any ...) +{ + char buffer[254]; + + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i)) + { + SetGlobalTransTarget(i); + VFormat(buffer, sizeof(buffer), format, 2); + PrintHintText(i, "%s", buffer); + } + } +} + +/** + * Shows a VGUI panel to a specific client. + * + * @param client Client index. + * @param name Panel type name (Check viewport_panel_names.h to see a list of + * some panel names). + * @param Kv KeyValues handle with all the data for the panel setup (Depends + * on the panel type and may be unused). + * @param show True to show the panel, or false to remove it from the client screen. + * @error If the client is not connected an error will be thrown. + */ +native void ShowVGUIPanel(int client, const char[] name, Handle Kv=INVALID_HANDLE, bool show=true); + +/** + * Creates a HUD synchronization object. This object is used to automatically assign and + * re-use channels for a set of messages. + * + * The HUD has a hardcoded number of channels (usually 6) for displaying + * text. You can use any channel for any area of the screen. Text on + * different channels can overlap, but text on the same channel will + * erase the old text first. This overlapping and overwriting gets problematic. + * + * A HUD synchronization object automatically selects channels for you based on + * the following heuristics: + * - If channel X was last used by the object, and hasn't been modified again, + * channel X gets re-used. + * - Otherwise, a new channel is chosen based on the least-recently-used channel. + * + * This ensures that if you display text on a sync object, that the previous text + * displayed on it will always be cleared first. This is because your new text + * will either overwrite the old text on the same channel, or because another + * channel has already erased your text. + * + * Note that messages can still overlap if they are on different synchronization + * objects, or they are displayed to manual channels. + * + * These are particularly useful for displaying repeating or refreshing HUD text, in + * addition to displaying multiple message sets in one area of the screen (for example, + * center-say messages that may pop up randomly that you don't want to overlap each + * other). + * + * @return New HUD synchronization object. + * The Handle can be closed with CloseHandle(). + * If HUD text is not supported on this mod, then + * INVALID_HANDLE is returned. + */ +native Handle CreateHudSynchronizer(); + +/** + * Sets the HUD parameters for drawing text. These parameters are stored + * globally, although nothing other than this function and SetHudTextParamsEx + * modify them. + * + * You must call this function before drawing text. If you are drawing + * text to multiple clients, you can set the parameters once, since + * they won't be modified. However, as soon as you pass control back + * to other plugins, you must reset the parameters next time you draw. + * + * @param x x coordinate, from 0 to 1. -1.0 is the center. + * @param y y coordinate, from 0 to 1. -1.0 is the center. + * @param holdTime Number of seconds to hold the text. + * @param r Red color value. + * @param g Green color value. + * @param b Blue color value. + * @param a Alpha transparency value. + * @param effect 0/1 causes the text to fade in and fade out. + * 2 causes the text to flash[?]. + * @param fxTime Duration of chosen effect (may not apply to all effects). + * @param fadeIn Number of seconds to spend fading in. + * @param fadeOut Number of seconds to spend fading out. + */ +native void SetHudTextParams(float x, float y, float holdTime, int r, int g, int b, int a, int effect = 0, + float fxTime=6.0, float fadeIn=0.1, float fadeOut=0.2); + +/** + * Sets the HUD parameters for drawing text. These parameters are stored + * globally, although nothing other than this function and SetHudTextParams + * modify them. + * + * This is the same as SetHudTextParams(), except it lets you set the alternate + * color for when effects require it. + * + * @param x x coordinate, from 0 to 1. -1.0 is the center. + * @param y y coordinate, from 0 to 1. -1.0 is the center. + * @param holdTime Number of seconds to hold the text. + * @param color1 First color set, array values being [red, green, blue, alpha] + * @param color2 Second color set, array values being [red, green, blue, alpha] + * @param effect 0/1 causes the text to fade in and fade out. + * 2 causes the text to flash[?]. + * @param fxTime Duration of chosen effect (may not apply to all effects). + * @param fadeIn Number of seconds to spend fading in. + * @param fadeOut Number of seconds to spend fading out. + */ +native void SetHudTextParamsEx(float x, float y, float holdTime, int color1[4], + int color2[4]={255,255,255,0}, int effect = 0, float fxTime=6.0, + float fadeIn=0.1, float fadeOut=0.2); + +/** + * Shows a synchronized HUD message to a client. + * + * As of this writing, only TF, HL2MP, and SourceForts support HUD Text. + * + * @param client Client index to send the message to. + * @param sync Synchronization object. + * @param message Message text or formatting rules. + * @param ... Message formatting parameters. + * @return -1 on failure, anything else on success. + * This function fails if the mod does not support it. + * @error Client not in-game, or sync object not valid. + */ +native int ShowSyncHudText(int client, Handle sync, const char[] message, any ...); + +/** + * Clears the text on a synchronized HUD channel. + * + * This is not the same as sending "" because it guarantees that it won't + * overwrite text on another channel. For example, consider the scenario: + * + * 1. Your synchronized message goes to channel 3. + * 2. Someone else's non-synchronized message goes to channel 3. + * + * If you were to simply send "" on your synchronized message, + * then someone else's text could be overwritten. + * + * @param client Client index to send the message to. + * @param sync Synchronization object. + * @error Client not in-game, or sync object not valid. + */ +native void ClearSyncHud(int client, Handle sync); + +/** + * Shows a HUD message to a client on the given channel. + * + * As of this writing, only TF, HL2MP, and SourceForts support HUD Text. + * + * @param client Client index to send the message to. + * @param channel A channel number. + * If -1, then a channel will automatically be selected + * based on the least-recently-used channel. If the + * channel is any other number, it will be modulo'd with + * the channel count to get a final channel number. + * @param message Message text or formatting rules. + * @param ... Message formatting parameters. + * @return -1 on failure (lack of mod support). + * Any other return value is the channel number that was + * used to render the text. + */ +native int ShowHudText(int client, int channel, const char[] message, any ...); + +/** + * Shows a MOTD panel to a specific client. + * + * @param client Client index. + * @param title Title of the panel (printed on the top border of the window). + * @param msg Contents of the panel, it can be treated as an url, filename or plain text + * depending on the type parameter (WARNING: msg has to be 192 bytes maximum!) + * @param type Determines the way to treat the message body of the panel. + * @error If the client is not connected an error will be thrown. + */ +stock void ShowMOTDPanel(int client, const char[] title, const char[] msg, int type=MOTDPANEL_TYPE_INDEX) +{ + char num[3]; + IntToString(type, num, sizeof(num)); + + KeyValues kv = new KeyValues("data"); + kv.SetString("title", title); + kv.SetString("type", num); + kv.SetString("msg", msg); + ShowVGUIPanel(client, "info", kv); + delete kv; +} + +/** + * Displays a panel asking the client to connect to a specified IP. + * + * @param client Client index. + * @param time Duration to hold the panel on the client's screen. + * @param ip Destination IP. + * @param password Password to connect to the destination IP. The client will be able to see this. + */ +stock void DisplayAskConnectBox(int client, float time, const char[] ip, const char[] password = "") +{ + char destination[288]; + FormatEx(destination, sizeof(destination), "%s/%s", ip, password); + + KeyValues kv = new KeyValues("data"); + kv.SetFloat("time", time); + kv.SetString("title", destination); + CreateDialog(client, kv, DialogType_AskConnect); + delete kv; +} + +/** + * Converts an entity index into a serial encoded entity reference. + * + * @param entity Entity index. + * @return Entity reference. + */ +native int EntIndexToEntRef(int entity); + +/** + * Retrieves the entity index from a reference. + * + * @param ref Entity reference. + * @return Entity index. + */ +native int EntRefToEntIndex(int ref); + +/** + * Converts a reference into a backwards compatible version. + * + * @param ref Entity reference. + * @return Bcompat reference. + */ +native int MakeCompatEntRef(int ref); + + +enum ClientRangeType +{ + RangeType_Visibility = 0, + RangeType_Audibility, +} + +/** + * Find clients that are potentially in range of a position. + * + * @param origin Coordinates from which to test range. + * @param rangeType Range type to use for filtering clients. + * @param clients Array to which found client indexes will be written. + * @param size Maximum size of clients array. + * @return Number of client indexes written to clients array. + */ +native int GetClientsInRange(float origin[3], ClientRangeType rangeType, int[] clients, int size); + +/** + * Retrieves the server's authentication string (SteamID). + * + * Note: If called before server is connected to Steam, auth id + * will be invalid ([I:0:1], 1, etc.) + * + * @param authType Auth id type and format to use. + * (Only AuthId_Steam3 and AuthId_SteamID64 are supported) + * @param auth Buffer to store the server's auth id. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @error Invalid AuthIdType given. + */ +native void GetServerAuthId(AuthIdType authType, char[] auth, int maxlen); + +/** + * Returns the server's Steam account ID. + * + * @return Steam account ID or 0 if not available. + */ +native int GetServerSteamAccountId(); diff --git a/scripting/include/handles.inc b/scripting/include/handles.inc new file mode 100644 index 0000000..c7d5992 --- /dev/null +++ b/scripting/include/handles.inc @@ -0,0 +1,97 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _handles_included + #endinput +#endif +#define _handles_included + +/** + * Preset Handle values. + */ +enum Handle // Tag disables introducing "Handle" as a symbol. +{ + INVALID_HANDLE = 0, +}; + + +/** + * Closes a Handle. If the handle has multiple copies open, + * it is not destroyed unless all copies are closed. + * + * @note Closing a Handle has a different meaning for each Handle type. Make + * sure you read the documentation on whatever provided the Handle. + * + * @param hndl Handle to close. + * @error Invalid handles will cause a run time error. + */ +native void CloseHandle(Handle hndl); + +/** + * Clones a Handle. When passing handles in between plugins, caching handles + * can result in accidental invalidation when one plugin releases the Handle, or is its owner + * is unloaded from memory. To prevent this, the Handle may be "cloned" with a new owner. + * + * @note Usually, you will be cloning Handles for other plugins. This means that if you clone + * the Handle without specifying the new owner, it will assume the identity of your original calling + * plugin, which is not very useful. You should either specify that the receiving plugin should + * clone the handle on its own, or you should explicitly clone the Handle using the receiving plugin's + * identity Handle. + * + * @param hndl Handle to clone/duplicate. + * @param plugin Optional Handle to another plugin to mark as the new owner. + * If no owner is passed, the owner becomes the calling plugin. + * @return Handle on success, INVALID_HANDLE if not cloneable. + * @error Invalid handles will cause a run time error. + */ +native Handle CloneHandle(Handle hndl, Handle plugin=INVALID_HANDLE); + +using __intrinsics__.Handle; + +/** + * Do not use this function. Returns if a Handle and its contents + * are readable, whereas INVALID_HANDLE only checks for the absence + * of a Handle. + * + * This function is intended only for tests where the validity of a + * Handle can absolutely not be known. + * + * Do not use this to check the return values of functions, or to + * check if timers should be closed (except in very rare cases). + * This function is for very specific usage and using it for general + * purpose routines can and will hide very subtle bugs. + * + * @param hndl Handle to test for validity. + * @return True if handle is valid, false otherwise. + */ +#pragma deprecated Do not use this function. +native bool IsValidHandle(Handle hndl); diff --git a/scripting/include/hashes.inc b/scripting/include/hashes.inc new file mode 100644 index 0000000..e69de29 diff --git a/scripting/include/helpers.inc b/scripting/include/helpers.inc new file mode 100644 index 0000000..aa15a22 --- /dev/null +++ b/scripting/include/helpers.inc @@ -0,0 +1,279 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _helpers_included + #endinput +#endif +#define _helpers_included + +/** + * Formats a user's info as log text. This is usually not needed because + * %L can be used to auto-format client information into a string. + * + * @param client Client index. + * @param buffer Buffer for text. + * @param maxlength Maximum length of text. + */ +stock void FormatUserLogText(int client, char[] buffer, int maxlength) +{ + char auth[32]; + char name[MAX_NAME_LENGTH]; + + int userid = GetClientUserId(client); + if (!GetClientAuthString(client, auth, sizeof(auth))) + { + strcopy(auth, sizeof(auth), "UNKNOWN"); + } + if (!GetClientName(client, name, sizeof(name))) + { + strcopy(name, sizeof(name), "UNKNOWN"); + } + + /** Currently, no team stuff ... */ + + Format(buffer, maxlength, "\"%s<%d><%s><>\"", name, userid, auth); +} + +/** + * Returns plugin handle from plugin filename. + * + * @param filename Filename of the plugin to search for. + * @return Handle to plugin if found, INVALID_HANDLE otherwise. + */ +stock Handle FindPluginByFile(const char[] filename) +{ + char buffer[256]; + + Handle iter = GetPluginIterator(); + Handle pl; + + while (MorePlugins(iter)) + { + pl = ReadPlugin(iter); + + GetPluginFilename(pl, buffer, sizeof(buffer)); + if (strcmp(buffer, filename, false) == 0) + { + CloseHandle(iter); + return pl; + } + } + + CloseHandle(iter); + + return INVALID_HANDLE; +} + +/** + * @deprecated Use FindTarget() or ProcessTargetString(). + */ +#pragma deprecated Use FindTarget() or ProcessTargetString() +stock int SearchForClients(const char[] pattern, int[] clients, int maxClients) +{ + int total = 0; + + if (maxClients == 0) + return 0; + + if (pattern[0] == '#') { + int input = StringToInt(pattern[1]); + if (!input) { + char name[MAX_NAME_LENGTH]; + for (int i=1; i<=MaxClients; i++) { + if (!IsClientInGame(i)) + continue; + GetClientName(i, name, sizeof(name)); + if (strcmp(name, pattern, false) == 0) { + clients[0] = i; + return 1; + } + } + } else { + int client = GetClientOfUserId(input); + if (client) { + clients[0] = client; + return 1; + } + } + } + + char name[MAX_NAME_LENGTH]; + for (int i=1; i<=MaxClients; i++) + { + if (!IsClientInGame(i)) + continue; + GetClientName(i, name, sizeof(name)); + if (StrContains(name, pattern, false) != -1) { + clients[total++] = i; + if (total >= maxClients) + break; + } + } + + return total; +} + +/** + * Wraps ProcessTargetString() and handles producing error messages for + * bad targets. + * + * @param client Client who issued command + * @param target Client's target argument + * @param nobots Optional. Set to true if bots should NOT be targetted + * @param immunity Optional. Set to false to ignore target immunity. + * @return Index of target client, or -1 on error. + */ +stock int FindTarget(int client, const char[] target, bool nobots = false, bool immunity = true) +{ + char target_name[MAX_TARGET_LENGTH]; + int target_list[1], target_count; + bool tn_is_ml; + + int flags = COMMAND_FILTER_NO_MULTI; + if (nobots) + { + flags |= COMMAND_FILTER_NO_BOTS; + } + if (!immunity) + { + flags |= COMMAND_FILTER_NO_IMMUNITY; + } + + if ((target_count = ProcessTargetString( + target, + client, + target_list, + 1, + flags, + target_name, + sizeof(target_name), + tn_is_ml)) > 0) + { + return target_list[0]; + } + else + { + ReplyToTargetError(client, target_count); + return -1; + } +} + +/** + * This function is no longer supported. It has been replaced with ReadMapList(), + * which uses a more unified caching and configuration mechanism. This function also + * has a bug where if the cvar contents changes, the fileTime change won't be recognized. + * + * Loads a specified array with maps. The maps will be either loaded from mapcyclefile, or if supplied + * a cvar containing a file name. If the file in the cvar is bad, it will use mapcyclefile. The fileTime + * parameter is used to store a timestamp of the file. If specified, the file will only be reloaded if it + * has changed. + * + * @param array Valid array handle, should be created with CreateArray(33) or larger. + * @param fileTime Variable containing the "last changed" time of the file. Used to avoid needless reloading. + * @param fileCvar CVAR set to the file to be loaded. Optional. + * @return Number of maps loaded or 0 if in error. + */ +#pragma deprecated Use ReadMapList() instead. + stock int LoadMaps(Handle array, int &fileTime = 0, Handle fileCvar = INVALID_HANDLE) + { + char mapPath[256], mapFile[64]; + bool fileFound = false; + + if (fileCvar != INVALID_HANDLE) + { + GetConVarString(fileCvar, mapFile, 64); + BuildPath(Path_SM, mapPath, sizeof(mapPath), mapFile); + fileFound = FileExists(mapPath); + } + + if (!fileFound) + { + Handle mapCycleFile = FindConVar("mapcyclefile"); + GetConVarString(mapCycleFile, mapPath, sizeof(mapPath)); + fileFound = FileExists(mapPath); + } + + if (!fileFound) + { + LogError("Failed to find a file to load maps from. No maps loaded."); + ClearArray(array); + + return 0; + } + + // If the file hasn't changed, there's no reason to reload + // all of the maps. + int newTime = GetFileTime(mapPath, FileTime_LastChange); + if (fileTime == newTime) + { + return GetArraySize(array); + } + + fileTime = newTime; + + ClearArray(array); + + File file = OpenFile(mapPath, "rt"); + if (!file) { + LogError("Could not open file: %s", mapPath); + return 0; + } + + LogMessage("Loading maps from file: %s", mapPath); + + int len; + char buffer[64]; + while (!file.EndOfFile() && file.ReadLine(buffer, sizeof(buffer))) + { + TrimString(buffer); + + if ((len = StrContains(buffer, ".bsp", false)) != -1) + { + buffer[len] = '\0'; + } + + if (buffer[0] == '\0' || !IsValidConVarChar(buffer[0]) || !IsMapValid(buffer)) + { + continue; + } + + if (FindStringInArray(array, buffer) != -1) + { + continue; + } + + PushArrayString(array, buffer); + } + + file.Close(); + return GetArraySize(array); +} diff --git a/scripting/include/keyvalues.inc b/scripting/include/keyvalues.inc new file mode 100644 index 0000000..134df4d --- /dev/null +++ b/scripting/include/keyvalues.inc @@ -0,0 +1,707 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _keyvalues_included + #endinput +#endif +#define _keyvalues_included + +/** + * KeyValue data value types + */ +enum KvDataTypes +{ + KvData_None = 0, /**< Type could not be identified, or no type */ + KvData_String, /**< String value */ + KvData_Int, /**< Integer value */ + KvData_Float, /**< Floating point value */ + KvData_Ptr, /**< Pointer value (sometimes called "long") */ + KvData_WString, /**< Wide string value */ + KvData_Color, /**< Color value */ + KvData_UInt64, /**< Large integer value */ + /* --- */ + KvData_NUMTYPES, +}; + +methodmap KeyValues < Handle +{ + // Creates a new KeyValues structure. The Handle must be closed with + // CloseHandle() or delete. + // + // @param name Name of the root section. + // @param firstKey If non-empty, specifies the first key value. + // @param firstValue If firstKey is non-empty, specifies the first key's value. + public native KeyValues(const char[] name, const char[] firstKey="", const char[] firstValue=""); + + // Exports a KeyValues tree to a file. The tree is dumped from the current position. + // + // @param file File to dump write to. + // @return True on success, false otherwise. + public native bool ExportToFile(const char[] file); + + // Exports a KeyValues tree to a string. The string is dumped from the current position. + // + // @param buffer Buffer to write to. + // @param maxlength Max length of buffer. + // @return Number of bytes that can be written to buffer. + public native int ExportToString(char[] buffer, int maxlength); + + // Amount of bytes written by ExportToFile & ExportToString. + property int ExportLength { + public native get(); + } + + // Imports a file in KeyValues format. The file is read into the current + // position of the tree. + // + // @param file File to read from. + // @return True on success, false otherwise. + public native bool ImportFromFile(const char[] file); + + // Converts a given string to a KeyValues tree. The string is read into + // the current postion of the tree. + // + // @param buffer String buffer to load into the KeyValues. + // @param resourceName The resource name of the KeyValues, used for error tracking purposes. + // @return True on success, false otherwise. + public native bool ImportFromString(const char[] buffer, const char[] resourceName="StringToKeyValues"); + + // Imports subkeys in the given KeyValues, at the current position in that + // KeyValues, into the current position in this KeyValues. Note that this + // copies keys; it does not embed a reference to them. + // + // @param other Origin KeyValues Handle. + public native void Import(KeyValues other); + + // Sets a string value of a KeyValues key. + // + // @param kv KeyValues Handle. + // @param key Name of the key, or NULL_STRING. + // @param value String value. + public native void SetString(const char[] key, const char[] value); + + // Sets an integer value of a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param value Value number. + public native void SetNum(const char[] key, int value); + + // Sets a large integer value of a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param value Large integer value (0=High bits, 1=Low bits) + public native void SetUInt64(const char[] key, const int value[2]); + + // Sets a floating point value of a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param value Floating point value. + public native void SetFloat(const char[] key, float value); + + // Sets a set of color values of a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param r Red value. + // @param g Green value. + // @param b Blue value. + // @param a Alpha value. + public native void SetColor(const char[] key, int r, int g, int b, int a=0); + + // Sets a set of color values of a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param color Red, green, blue and alpha channels. + public void SetColor4(const char[] key, const int color[4]) { + this.SetColor(key, color[0], color[1], color[2], color[3]); + } + + // Sets a vector value of a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param vec Vector value. + public native void SetVector(const char[] key, const float vec[3]); + + // Retrieves a string value from a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param value Buffer to store key value in. + // @param maxlength Maximum length of the value buffer. + // @param defvalue Optional default value to use if the key is not found. + public native void GetString(const char[] key, char[] value, int maxlength, const char[] defvalue=""); + + // Retrieves an integer value from a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param defvalue Optional default value to use if the key is not found. + // @return Integer value of the key. + public native int GetNum(const char[] key, int defvalue=0); + + // Retrieves a floating point value from a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param defvalue Optional default value to use if the key is not found. + // @return Floating point value of the key. + public native float GetFloat(const char[] key, float defvalue=0.0); + + // Retrieves a set of color values from a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param r Red value, set by reference. + // @param g Green value, set by reference. + // @param b Blue value, set by reference. + // @param a Alpha value, set by reference. + public native void GetColor(const char[] key, int &r, int &g, int &b, int &a); + + // Retrieves a set of color values from a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param color Red, green, blue, and alpha channels. + public void GetColor4(const char[] key, int color[4]) { + int r, g, b, a; + this.GetColor(key, r, g, b, a); + color[0] = r; + color[1] = g; + color[2] = b; + color[3] = a; + } + + // Retrieves a large integer value from a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param value Array to represent the large integer. + // @param defvalue Optional default value to use if the key is not found. + public native void GetUInt64(const char[] key, int value[2], int defvalue[2]={0,0}); + + // Retrieves a vector value from a KeyValues key. + // + // @param key Name of the key, or NULL_STRING. + // @param vec Destination vector to store the value in. + // @param defvalue Optional default value to use if the key is not found. + public native void GetVector(const char[] key, float vec[3], const float defvalue[3]={0.0, 0.0, 0.0}); + + // Sets the current position in the KeyValues tree to the given key. + // + // @param key Name of the key. + // @param create If true, and the key does not exist, it will be created. + // @return True if the key exists, false if it does not and was not created. + public native bool JumpToKey(const char[] key, bool create=false); + + // Sets the current position in the KeyValues tree to the given key. + // + // @param id KeyValues id. + // @return True if the key exists, false if it does not. + public native bool JumpToKeySymbol(int id); + + // Sets the current position in the KeyValues tree to the first sub key. + // This native adds to the internal traversal stack. + // + // @param keyOnly If false, non-keys will be traversed (values). + // @return True on success, false if there was no first sub key. + public native bool GotoFirstSubKey(bool keyOnly=true); + + // Sets the current position in the KeyValues tree to the next sub key. + // This native does NOT add to the internal traversal stack, and thus + // GoBack() is not needed for each successive call to this function. + // + // @param keyOnly If false, non-keys will be traversed (values). + // @return True on success, false if there was no next sub key. + public native bool GotoNextKey(bool keyOnly=true); + + // Saves the current position in the traversal stack onto the traversal + // stack. This can be useful if you wish to use KvGotoNextKey() and + // have the previous key saved for backwards traversal. + // + // @param kv KeyValues Handle. + public native void SavePosition(); + + // Jumps back to the previous position. Returns false if there are no + // previous positions (i.e., at the root node). This should be called + // once for each successful Jump call, in order to return to the top node. + // This function pops one node off the internal traversal stack. + // + // @return True on success, false if there is no higher node. + public native bool GoBack(); + + // Removes the given key from the current position. + // + // @param key Name of the key. + // @return True on success, false if key did not exist. + public native bool DeleteKey(const char[] key); + + // Removes the current sub-key and attempts to set the position + // to the sub-key after the removed one. If no such sub-key exists, + // the position will be the parent key in the traversal stack. + // Given the sub-key having position "N" in the traversal stack, the + // removal will always take place from position "N-1." + // + // @param kv KeyValues Handle. + // @return 1 if removal succeeded and there was another key. + // 0 if the current node was not contained in the + // previous node, or no previous node exists. + // -1 if removal succeeded and there were no more keys, + // thus the state is as if KvGoBack() was called. + public native int DeleteThis(); + + // Sets the position back to the top node, emptying the entire node + // traversal history. This can be used instead of looping KvGoBack() + // if recursive iteration is not important. + // + // @param kv KeyValues Handle. + public native void Rewind(); + + // Retrieves the current section name. + // + // @param section Buffer to store the section name. + // @param maxlength Maximum length of the name buffer. + // @return True on success, false on failure. + public native bool GetSectionName(char[] section, int maxlength); + + // Sets the current section name. + // + // @param section Section name. + public native void SetSectionName(const char[] section); + + // Returns the data type at a key. + // + // @param key Key name. + // @return KvDataType value of the key. + public native KvDataTypes GetDataType(const char[] key); + + // Sets whether or not the KeyValues parser will read escape sequences. + // For example, \n would be read as a literal newline. This defaults + // to false for new KeyValues structures. + // + // @param useEscapes Whether or not to read escape sequences. + public native void SetEscapeSequences(bool useEscapes); + + // Returns the position in the jump stack; I.e. the number of calls + // required for KvGoBack to return to the root node. If at the root node, + // 0 is returned. + // + // @return Number of non-root nodes in the jump stack. + public native int NodesInStack(); + + // Finds a KeyValues name by id. + // + // @param id KeyValues id. + // @param name Buffer to store the name. + // @param maxlength Maximum length of the value buffer. + // @return True on success, false if id not found. + public native bool FindKeyById(int id, char[] name, int maxlength); + + // Finds a KeyValues id inside a KeyValues tree. + // + // @param key Key name. + // @param id Id of the found KeyValue. + // @return True on success, false if key not found. + public native bool GetNameSymbol(const char[] key, int &id); + + // Retrieves the current section id. + // + // @param kv KeyValues Handle. + // @param id Id of the current section. + // @return True on success, false on failure. + public native bool GetSectionSymbol(int &id); +}; + +/** + * Creates a new KeyValues structure. The Handle must always be closed. + * + * @param name Name of the root section. + * @param firstKey If non-empty, specifies the first key value. + * @param firstValue If firstKey is non-empty, specifies the first key's value. + * @return A Handle to a new KeyValues structure. + */ +native KeyValues CreateKeyValues(const char[] name, const char[] firstKey="", const char[] firstValue=""); + +/** + * Sets a string value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param value String value. + * @error Invalid Handle. + */ +native void KvSetString(Handle kv, const char[] key, const char[] value); + +/** + * Sets an integer value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param value Value number. + * @error Invalid Handle. + */ +native void KvSetNum(Handle kv, const char[] key, int value); + +/** + * Sets a large integer value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param value Large integer value (0=High bits, 1=Low bits) + * @error Invalid Handle. + */ +native void KvSetUInt64(Handle kv, const char[] key, const int value[2]); + +/** + * Sets a floating point value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param value Floating point value. + * @error Invalid Handle. + */ +native void KvSetFloat(Handle kv, const char[] key, float value); + +/** + * Sets a set of color values of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param r Red value. + * @param g Green value. + * @param b Blue value. + * @param a Alpha value. + * @error Invalid Handle. + */ +native void KvSetColor(Handle kv, const char[] key, int r, int g, int b, int a=0); + +/** + * Sets a vector value of a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param vec Vector value. + * @error Invalid Handle. + */ +native void KvSetVector(Handle kv, const char[] key, const float vec[3]); + +/** + * Retrieves a string value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param value Buffer to store key value in. + * @param maxlength Maximum length of the value buffer. + * @param defvalue Optional default value to use if the key is not found. + * @error Invalid Handle. + */ +native void KvGetString(Handle kv, const char[] key, char[] value, int maxlength, const char[] defvalue=""); + +/** + * Retrieves an integer value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param defvalue Optional default value to use if the key is not found. + * @return Integer value of the key. + * @error Invalid Handle. + */ +native int KvGetNum(Handle kv, const char[] key, int defvalue=0); + +/** + * Retrieves a floating point value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param defvalue Optional default value to use if the key is not found. + * @return Floating point value of the key. + * @error Invalid Handle. + */ +native float KvGetFloat(Handle kv, const char[] key, float defvalue=0.0); + +/** + * Retrieves a set of color values from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param r Red value, set by reference. + * @param g Green value, set by reference. + * @param b Blue value, set by reference. + * @param a Alpha value, set by reference. + * @error Invalid Handle. + */ +native void KvGetColor(Handle kv, const char[] key, int &r, int &g, int &b, int &a); + +/** + * Retrieves a large integer value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param value Array to represent the large integer. + * @param defvalue Optional default value to use if the key is not found. + * @error Invalid Handle. + */ +native void KvGetUInt64(Handle kv, const char[] key, int value[2], int defvalue[2]={0,0}); + +/** + * Retrieves a vector value from a KeyValues key. + * + * @param kv KeyValues Handle. + * @param key Name of the key, or NULL_STRING. + * @param vec Destination vector to store the value in. + * @param defvalue Optional default value to use if the key is not found. + * @error Invalid Handle. + */ +native void KvGetVector(Handle kv, const char[] key, float vec[3], const float defvalue[3]={0.0, 0.0, 0.0}); + +/** + * Sets the current position in the KeyValues tree to the given key. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @param create If true, and the key does not exist, it will be created. + * @return True if the key exists, false if it does not and was not created. + */ +native bool KvJumpToKey(Handle kv, const char[] key, bool create=false); + +/** + * Sets the current position in the KeyValues tree to the given key. + * + * @param kv KeyValues Handle. + * @param id KeyValues id. + * @return True if the key exists, false if it does not. + */ +native bool KvJumpToKeySymbol(Handle kv, int id); + +/** + * Sets the current position in the KeyValues tree to the first sub key. + * This native adds to the internal traversal stack. + * + * @param kv KeyValues Handle. + * @param keyOnly If false, non-keys will be traversed (values). + * @return True on success, false if there was no first sub key. + * @error Invalid Handle. + */ +native bool KvGotoFirstSubKey(Handle kv, bool keyOnly=true); + +/** + * Sets the current position in the KeyValues tree to the next sub key. + * This native does NOT add to the internal traversal stack, and thus + * KvGoBack() is not needed for each successive call to this function. + * + * @param kv KeyValues Handle. + * @param keyOnly If false, non-keys will be traversed (values). + * @return True on success, false if there was no next sub key. + * @error Invalid Handle. + */ +native bool KvGotoNextKey(Handle kv, bool keyOnly=true); + +/** + * Saves the current position in the traversal stack onto the traversal + * stack. This can be useful if you wish to use KvGotoNextKey() and + * have the previous key saved for backwards traversal. + * + * @param kv KeyValues Handle. + * @error Invalid Handle. + */ +native void KvSavePosition(Handle kv); + +/** + * Removes the given key from the current position. + * + * @param kv KeyValues Handle. + * @param key Name of the key. + * @return True on success, false if key did not exist. + * @error Invalid Handle. + */ +native bool KvDeleteKey(Handle kv, const char[] key); + +/** + * Removes the current sub-key and attempts to set the position + * to the sub-key after the removed one. If no such sub-key exists, + * the position will be the parent key in the traversal stack. + * Given the sub-key having position "N" in the traversal stack, the + * removal will always take place from position "N-1." + * + * @param kv KeyValues Handle. + * @return 1 if removal succeeded and there was another key. + * 0 if the current node was not contained in the + * previous node, or no previous node exists. + * -1 if removal succeeded and there were no more keys, + * thus the state is as if KvGoBack() was called. + * @error Invalid Handle. + */ +native int KvDeleteThis(Handle kv); + +/** + * Jumps back to the previous position. Returns false if there are no + * previous positions (i.e., at the root node). This should be called + * once for each successful Jump call, in order to return to the top node. + * This function pops one node off the internal traversal stack. + * + * @param kv KeyValues Handle. + * @return True on success, false if there is no higher node. + * @error Invalid Handle. + */ +native bool KvGoBack(Handle kv); + +/** + * Sets the position back to the top node, emptying the entire node + * traversal history. This can be used instead of looping KvGoBack() + * if recursive iteration is not important. + * + * @param kv KeyValues Handle. + * @error Invalid Handle. + */ +native void KvRewind(Handle kv); + +/** + * Retrieves the current section name. + * + * @param kv KeyValues Handle. + * @param section Buffer to store the section name. + * @param maxlength Maximum length of the name buffer. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool KvGetSectionName(Handle kv, char[] section, int maxlength); + +/** + * Sets the current section name. + * + * @param kv KeyValues Handle. + * @param section Section name. + * @error Invalid Handle. + */ +native void KvSetSectionName(Handle kv, const char[] section); + +/** + * Returns the data type at a key. + * + * @param kv KeyValues Handle. + * @param key Key name. + * @return KvDataType value of the key. + * @error Invalid Handle. + */ +native KvDataTypes KvGetDataType(Handle kv, const char[] key); + +/** + * Converts a KeyValues tree to a file. The tree is dumped + * from the current position. + * + * @param kv KeyValues Handle. + * @param file File to dump write to. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool KeyValuesToFile(Handle kv, const char[] file); + +/** + * Converts a file to a KeyValues tree. The file is read into + * the current position of the tree. + * + * @param kv KeyValues Handle. + * @param file File to read from. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool FileToKeyValues(Handle kv, const char[] file); + +/** + * Converts a given string to a KeyValues tree. The string is read into + * the current postion of the tree. + * + * @param kv KeyValues Handle. + * @param buffer String buffer to load into the KeyValues. + * @param resourceName The resource name of the KeyValues, used for error tracking purposes. + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool StringToKeyValues(Handle kv, const char[] buffer, const char[] resourceName="StringToKeyValues"); + +/** + * Sets whether or not the KeyValues parser will read escape sequences. + * For example, \n would be read as a literal newline. This defaults + * to false for new KeyValues structures. + * + * @param kv KeyValues Handle. + * @param useEscapes Whether or not to read escape sequences. + * @error Invalid Handle. + */ +native void KvSetEscapeSequences(Handle kv, bool useEscapes); + +/** + * Returns the position in the jump stack; I.e. the number of calls + * required for KvGoBack to return to the root node. If at the root node, + * 0 is returned. + * + * @param kv KeyValues Handle. + * @return Number of non-root nodes in the jump stack. + * @error Invalid Handle. + */ +native int KvNodesInStack(Handle kv); + +/** + * Makes a new copy of all subkeys in the origin KeyValues to + * the destination KeyValues. + * NOTE: All KeyValues are processed from the current location not the root one. + * + * @param origin Origin KeyValues Handle. + * @param dest Destination KeyValues Handle. + * @error Invalid Handle. + */ +native void KvCopySubkeys(Handle origin, Handle dest); + +/** + * Finds a KeyValues name by id. + * + * @param kv KeyValues Handle. + * @param id KeyValues id. + * @param name Buffer to store the name. + * @param maxlength Maximum length of the value buffer. + * @return True on success, false if id not found. + * @error Invalid Handle. + */ +native bool KvFindKeyById(Handle kv, int id, char[] name, int maxlength); + +/** + * Finds a KeyValues id inside a KeyValues tree. + * + * @param kv KeyValues Handle. + * @param key Key name. + * @param id Id of the found KeyValue. + * @return True on success, false if key not found. + * @error Invalid Handle. + */ +native bool KvGetNameSymbol(Handle kv, const char[] key, int &id); + +/** + * Retrieves the current section id. + * + * @param kv KeyValues Handle. + * @param id Id of the current section. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool KvGetSectionSymbol(Handle kv, int &id); diff --git a/scripting/include/lang.inc b/scripting/include/lang.inc new file mode 100644 index 0000000..b92bdb3 --- /dev/null +++ b/scripting/include/lang.inc @@ -0,0 +1,134 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _lang_included + #endinput +#endif +#define _lang_included + +#define LANG_SERVER 0 /**< Translate using the server's language */ + +/** + * Loads a translation file for the plugin calling this native. + * If no extension is specified, .txt is assumed. + * + * @param file Translation file. + */ +native void LoadTranslations(const char[] file); + +/** + * Sets the global language target. This is useful for creating functions + * that will be compatible with the %t format specifier. Note that invalid + * indexes can be specified but the error will occur during translation, + * not during this function call. + * + * @param client Client index or LANG_SERVER. + */ +native void SetGlobalTransTarget(int client); + +/** + * Retrieves the language number of a client. + * + * @param client Client index. + * @return Language number client is using. + * @error Invalid client index or client not connected. + */ +native int GetClientLanguage(int client); + +/** + * Retrieves the server's language. + * + * @return Language number server is using. + */ +native int GetServerLanguage(); + +/** + * Returns the number of languages known in languages.cfg. + * + * @return Language count. + */ +native int GetLanguageCount(); + +/** + * Retrieves info about a given language number. + * + * @param language Language number. + * @param code Language code buffer (2-3 characters usually). + * @param codeLen Maximum length of the language code buffer. + * @param name Language name buffer. + * @param nameLen Maximum length of the language name buffer. + * @error Invalid language number. + */ +native void GetLanguageInfo(int language, char[] code="", int codeLen=0, char[] name="", int nameLen=0); + +/** + * Sets the language number of a client. + * + * @param client Client index. + * @param language Language number. + * @error Invalid client index or client not connected. + */ +native void SetClientLanguage(int client, int language); + +/** + * Retrieves the language number from a language code. + * + * @param code Language code (2-3 characters usually). + * @return Language number. -1 if not found. + */ +native int GetLanguageByCode(const char[] code); + +/** + * Retrieves the language number from a language name. + * + * @param name Language name (case insensitive). + * @return Language number. -1 if not found. + */ +native int GetLanguageByName(const char[] name); + +/** + * Determines if the specified phrase exists within the plugin's + * translation cache. + * + * @param phrase Phrase to look for. + * @return True if phrase exists. + */ +native bool TranslationPhraseExists(const char[] phrase); + +/** + * Determines if there is a translation for the specified language. + * + * @param phrase Phrase to check. + * @param language Language number. + * @return True if translation exists. + */ +native bool IsTranslatedForLanguage(const char[] phrase, int language); diff --git a/scripting/include/logging.inc b/scripting/include/logging.inc new file mode 100644 index 0000000..2683dda --- /dev/null +++ b/scripting/include/logging.inc @@ -0,0 +1,135 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sm_logging_included + #endinput +#endif +#define _sm_logging_included + +/** + * Logs a plugin message to the SourceMod logs. The log message will be + * prefixed by the plugin's logtag (filename). + * + * @param format String format. + * @param ... Format arguments. + */ +native void LogMessage(const char[] format, any ...); + +/** + * Logs a message to any file. The log message will be in the normal + * SourceMod format, with the plugin logtag prepended. + * + * @param file File to write the log message in. + * @param format String format. + * @param ... Format arguments. + * @error File could not be opened/written. + */ +native void LogToFile(const char[] file, const char[] format, any ...); + +/** + * Same as LogToFile(), except no plugin logtag is prepended. + * + * @param file File to write the log message in. + * @param format String format. + * @param ... Format arguments. + * @error File could not be opened/written. + */ +native void LogToFileEx(const char[] file, const char[] format, any ...); + +/** + * Logs an action from a command or event whereby interception and routing may + * be important. This is intended to be a logging version of ShowActivity(). + * + * @param client Client performing the action, 0 for server, or -1 if not + * applicable. + * @param target Client being targetted, or -1 if not applicable. + * @param message Message format. + * @param ... Message formatting parameters. + */ +native void LogAction(int client, int target, const char[] message, any ...); + +/** + * Logs a plugin error message to the SourceMod logs. + * + * @param format String format. + * @param ... Format arguments. + */ +native void LogError(const char[] format, any ...); + +/** + * Called when an action is going to be logged. + * + * @param source Handle to the object logging the action, or INVALID_HANDLE + * if Core is logging the action. + * @param ident Type of object logging the action (plugin, ext, or core). + * @param client Client the action is from; 0 for server, -1 if not applicable. + * @param target Client the action is targetting, or -1 if not applicable. + * @param message Message that is being logged. + * @return Plugin_Continue will perform the default logging behavior. + * Plugin_Handled will stop Core from logging the message. + * Plugin_Stop is the same as Handled, but prevents any other + * plugins from handling the message. + */ +forward Action OnLogAction(Handle source, + Identity ident, + int client, + int target, + const char[] message); + +/** + * Called when a game log message is received. + * + * Any Log*() functions called within this callback will not recursively + * pass through. That is, they will log directly, bypassing this callback. + * + * Note that this does not capture log messages from the engine. It only + * captures log messages being sent from the game/mod itself. + * + * @param message Message contents. + * @return Plugin_Handled or Plugin_Stop will prevent the message + * from being written to the log file. + */ +typedef GameLogHook = function Action (const char[] message); + +/** + * Adds a game log hook. + * + * @param hook Hook function. + */ +native void AddGameLogHook(GameLogHook hook); + +/** + * Removes a game log hook. + * + * @param hook Hook function. + */ +native void RemoveGameLogHook(GameLogHook hook); diff --git a/scripting/include/mapchooser.inc b/scripting/include/mapchooser.inc new file mode 100644 index 0000000..173faf2 --- /dev/null +++ b/scripting/include/mapchooser.inc @@ -0,0 +1,159 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ +#if defined _mapchooser_included_ + #endinput +#endif +#define _mapchooser_included_ + +enum NominateResult +{ + Nominate_Added, /** The map was added to the nominate list */ + Nominate_Replaced, /** A clients existing nomination was replaced */ + Nominate_AlreadyInVote, /** Specified map was already in the vote */ + Nominate_InvalidMap, /** Mapname specified wasn't a valid map */ + Nominate_VoteFull, /** This will only occur if force was set to false */ +}; + +enum MapChange +{ + MapChange_Instant, /** Change map as soon as the voting results have come in */ + MapChange_RoundEnd, /** Change map at the end of the round */ + MapChange_MapEnd, /** Change the sm_nextmap cvar */ +}; + +/** + * Attempt to add a map to the mapchooser map list. + * + * @param map Map to add. + * @param force Should we force the map in even if it requires overwriting an existing nomination? + * @param owner Client index of the nominator. If the client disconnects the nomination will be removed. Use 0 for constant nominations + * @return Nominate Result of the outcome + */ +native NominateResult NominateMap(const char[] map, bool force, int owner); + +/** + * Attempt to remove a map from the mapchooser map list. + * + * @param map Map to remove. + * @return True if the nomination was found and removed, or false if the nomination was not found. + */ +native bool RemoveNominationByMap(const char[] map); + +/** + * Attempt to remove a map from the mapchooser map list. + * + * @param owner Client index of the nominator. + * @return True if the nomination was found and removed, or false if the nomination was not found. + */ +native bool RemoveNominationByOwner(int owner); + +/** + * Gets the current list of excluded maps. + * + * @param array An ADT array handle to add the map strings to. + */ +native void GetExcludeMapList(ArrayList array); + +/** + * Gets the current list of nominated maps. + * + * @param maparray An ADT array handle to add the map strings to. + * @param ownerarray An optional ADT array handle to add the nominator client indexes to. + */ +native void GetNominatedMapList(ArrayList maparray, ArrayList ownerarray = null); + +/** + * Checks if MapChooser will allow a vote + * + * @return True if a vote can be held, or false if mapchooser is already holding a vote. + */ +native bool CanMapChooserStartVote(); + +/** + * Initiates a MapChooser map vote + * + * Note: If no input array is specified mapchooser will use its internal list. This includes + * any nominations and excluded maps (as per mapchoosers convars). + * + * @param when MapChange consant of when the resulting mapchange should occur. + * @param inputarray ADT array list of maps to add to the vote. + */ +native void InitiateMapChooserVote(MapChange when, ArrayList inputarray=null); + +/** + * Checks if MapChooser's end of map vote has completed. + * + * @return True if complete, false otherwise. + */ +native bool HasEndOfMapVoteFinished(); + +/** + * Checks if MapChooser is set to run an end of map vote. + * + * @return True if enabled, false otherwise. + */ +native bool EndOfMapVoteEnabled(); + +/** + * Called when mapchooser removes a nomination from its list. + * Nominations cleared on map start will not trigger this forward + */ +forward void OnNominationRemoved(const char[] map, int owner); + +/** + * Called when mapchooser starts a Map Vote. + */ +forward void OnMapVoteStarted(); + +public SharedPlugin __pl_mapchooser = +{ + name = "mapchooser", + file = "mapchooser.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +public void __pl_mapchooser_SetNTVOptional() +{ + MarkNativeAsOptional("NominateMap"); + MarkNativeAsOptional("RemoveNominationByMap"); + MarkNativeAsOptional("RemoveNominationByOwner"); + MarkNativeAsOptional("GetExcludeMapList"); + MarkNativeAsOptional("GetNominatedMapList"); + MarkNativeAsOptional("CanMapChooserStartVote"); + MarkNativeAsOptional("InitiateMapChooserVote"); + MarkNativeAsOptional("HasEndOfMapVoteFinished"); + MarkNativeAsOptional("EndOfMapVoteEnabled"); +} diff --git a/scripting/include/menus.inc b/scripting/include/menus.inc new file mode 100644 index 0000000..604502e --- /dev/null +++ b/scripting/include/menus.inc @@ -0,0 +1,1121 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _menus_included + #endinput +#endif +#define _menus_included + +/** + * Low-level drawing style of the menu. + */ +enum MenuStyle +{ + MenuStyle_Default = 0, /**< The "default" menu style for the mod */ + MenuStyle_Valve = 1, /**< The Valve provided menu style (Used on HL2DM) */ + MenuStyle_Radio = 2, /**< The simpler menu style commonly used on CS:S */ +}; + +/** + * Different actions for the menu "pump" callback + */ +enum MenuAction +{ + MenuAction_Start = (1<<0), /**< A menu has been started (nothing passed) */ + MenuAction_Display = (1<<1), /**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */ + MenuAction_Select = (1<<2), /**< An item was selected (param1=client, param2=item) */ + MenuAction_Cancel = (1<<3), /**< The menu was cancelled (param1=client, param2=reason) */ + MenuAction_End = (1<<4), /**< A menu display has fully ended. + param1 is the MenuEnd reason, and if it's MenuEnd_Cancelled, then + param2 is the MenuCancel reason from MenuAction_Cancel. + */ + MenuAction_VoteEnd = (1<<5), /**< (VOTE ONLY): A vote sequence has succeeded (param1=chosen item) + This is not called if SetVoteResultCallback has been used on the menu. */ + MenuAction_VoteStart = (1<<6), /**< (VOTE ONLY): A vote sequence has started (nothing passed) */ + MenuAction_VoteCancel = (1<<7), /**< (VOTE ONLY): A vote sequence has been cancelled (param1=reason) */ + MenuAction_DrawItem = (1<<8), /**< An item is being drawn; return the new style (param1=client, param2=item) */ + MenuAction_DisplayItem = (1<<9),/**< Item text is being drawn to the display (param1=client, param2=item) + To change the text, use RedrawMenuItem(). + If you do so, return its return value. Otherwise, return 0. + */ +}; + +/** Default menu actions */ +#define MENU_ACTIONS_DEFAULT MenuAction_Select|MenuAction_Cancel|MenuAction_End +/** All menu actions */ +#define MENU_ACTIONS_ALL view_as(0xFFFFFFFF) + +#define MENU_NO_PAGINATION 0 /**< Menu should not be paginated (10 items max) */ +#define MENU_TIME_FOREVER 0 /**< Menu should be displayed as long as possible */ + +#define ITEMDRAW_DEFAULT (0) /**< Item should be drawn normally */ +#define ITEMDRAW_DISABLED (1<<0) /**< Item is drawn but not selectable */ +#define ITEMDRAW_RAWLINE (1<<1) /**< Item should be a raw line, without a slot */ +#define ITEMDRAW_NOTEXT (1<<2) /**< No text should be drawn */ +#define ITEMDRAW_SPACER (1<<3) /**< Item should be drawn as a spacer, if possible */ +#define ITEMDRAW_IGNORE ((1<<1)|(1<<2)) /**< Item should be completely ignored (rawline + notext) */ +#define ITEMDRAW_CONTROL (1<<4) /**< Item is control text (back/next/exit) */ + +#define MENUFLAG_BUTTON_EXIT (1<<0) /**< Menu has an "exit" button (default if paginated) */ +#define MENUFLAG_BUTTON_EXITBACK (1<<1) /**< Menu has an "exit back" button */ +#define MENUFLAG_NO_SOUND (1<<2) /**< Menu will not have any select sounds */ +#define MENUFLAG_BUTTON_NOVOTE (1<<3) /**< Menu has a "No Vote" button at slot 1 */ + +#define VOTEINFO_CLIENT_INDEX 0 /**< Client index */ +#define VOTEINFO_CLIENT_ITEM 1 /**< Item the client selected, or -1 for none */ +#define VOTEINFO_ITEM_INDEX 0 /**< Item index */ +#define VOTEINFO_ITEM_VOTES 1 /**< Number of votes for the item */ + +#define VOTEFLAG_NO_REVOTES (1<<0) /**< Players cannot change their votes */ + +/** + * Reasons a menu can be cancelled (MenuAction_Cancel). + */ +enum +{ + MenuCancel_Disconnected = -1, /**< Client dropped from the server */ + MenuCancel_Interrupted = -2, /**< Client was interrupted with another menu */ + MenuCancel_Exit = -3, /**< Client exited via "exit" */ + MenuCancel_NoDisplay = -4, /**< Menu could not be displayed to the client */ + MenuCancel_Timeout = -5, /**< Menu timed out */ + MenuCancel_ExitBack = -6, /**< Client selected "exit back" on a paginated menu */ +}; + +/** + * Reasons a vote can be cancelled (MenuAction_VoteCancel). + */ +enum +{ + VoteCancel_Generic = -1, /**< Vote was generically cancelled. */ + VoteCancel_NoVotes = -2, /**< Vote did not receive any votes. */ +}; + +/** + * Reasons a menu ended (MenuAction_End). + */ +enum +{ + MenuEnd_Selected = 0, /**< Menu item was selected */ + MenuEnd_VotingDone = -1, /**< Voting finished */ + MenuEnd_VotingCancelled = -2, /**< Voting was cancelled */ + MenuEnd_Cancelled = -3, /**< Menu was cancelled (reason in param2) */ + MenuEnd_Exit = -4, /**< Menu was cleanly exited via "exit" */ + MenuEnd_ExitBack = -5, /**< Menu was cleanly exited via "back" */ +}; + +/** + * Describes a menu's source + */ +enum MenuSource +{ + MenuSource_None = 0, /**< No menu is being displayed */ + MenuSource_External = 1, /**< External menu */ + MenuSource_Normal = 2, /**< A basic menu is being displayed */ + MenuSource_RawPanel = 3, /**< A display is active, but it is not tied to a menu */ +}; + +/** + * Called when a menu action is completed. + * + * @param menu The menu being acted upon. + * @param action The action of the menu. + * @param param1 First action parameter (usually the client). + * @param param2 Second action parameter (usually the item). + */ +typedef MenuHandler = function int (Menu menu, MenuAction action, int param1, int param2); + +// Panels are used for drawing raw menus without any extra helper functions. +// Handles must be closed via delete or CloseHandle(). +methodmap Panel < Handle +{ + // Constructor for a new Panel. + // + // @param hStyle MenuStyle Handle, or null to use the default style. + public native Panel(Handle hStyle = null); + + // Sets the panel's title. + // + // @param text Text to set as the title. + // @param onlyIfEmpty If true, the title will only be set if no title is set. + public native void SetTitle(const char[] text, bool onlyIfEmpty=false); + + // Draws an item on a panel. If the item takes up a slot, the position + // is returned. + // + // @param text Display text to use. If not a raw line, + // the style may automatically add color markup. + // No numbering or newlines are needed. + // @param style ITEMDRAW style flags. + // @return A slot position, or 0 if item was a rawline or could not be drawn. + public native int DrawItem(const char[] text, int style=ITEMDRAW_DEFAULT); + + // Draws a raw line of text on a panel, without any markup other than a + // newline. + // + // @param text Display text to use. + // @return True on success, false if raw lines are not supported. + public native bool DrawText(const char[] text); + + // Returns whether or not the given drawing flags are supported by + // the menu style. + // + // @param style ITEMDRAW style flags. + // @return True if item is drawable, false otherwise. + public native bool CanDrawFlags(int style); + + // Sets the selectable key map of a panel. This is not supported by + // all styles (only by Radio, as of this writing). + // + // @param keys An integer where each bit N allows key + // N+1 to be selected. If no keys are selectable, + // then key 0 (bit 9) is automatically set. + // @return True if supported, false otherwise. + public native bool SetKeys(int keys); + + // Sends a panel to a client. Unlike full menus, the handler + // function will only receive the following actions, both of + // which will have null for a menu, and the client as param1. + // + // MenuAction_Select (param2 will be the key pressed) + // MenuAction_Cancel (param2 will be the reason) + // + // Also, if the menu fails to display, no callbacks will be called. + // + // @param client A client to draw to. + // @param handler The MenuHandler function to catch actions with. + // @param time Time to hold the menu for. + // @return True on success, false on failure. + public native bool Send(int client, MenuHandler handler, int time); + + // Returns the amount of text the menu can still hold. If this is + // limit is reached or overflowed, the text is silently truncated. + // + // Radio menus: Currently 511 characters (512 bytes). + // Valve menus: Currently -1 (no meaning). + property int TextRemaining { + public native get(); + } + + // Returns or sets the current key position, starting at 1. This cannot be + // used to traverse backwards. + property int CurrentKey { + public native get(); + public native set(int key); + } + + // Returns the panel's style. Style handles are global and cannot be closed. + property Handle Style { + public native get(); + } +}; + +// A menu is a helper object for managing in-game menus. +methodmap Menu < Handle +{ + // Creates a new, empty menu using the default style. + // + // @param handler Function which will receive menu actions. + // @param actions Optionally set which actions to receive. Select, + // Cancel, and End will always be received regardless + // of whether they are set or not. They are also + // the only default actions. + public native Menu(MenuHandler handler, MenuAction actions=MENU_ACTIONS_DEFAULT); + + // Displays a menu to a client. + // + // @param client Client index. + // @param time Maximum time to leave menu on the screen. + // @return True on success, false on failure. + // @error Client not in game. + public native bool Display(int client, int time); + + // Displays a menu to a client, starting from the given item. + // + // @param client Client index. + // @param first_item First item to begin drawing from. + // @param time Maximum time to leave menu on the screen. + // @return True on success, false on failure. + // @error Client not in game. + /// + public native bool DisplayAt(int client, int first_item, int time); + + // Appends a new item to the end of a menu. + // + // @param info Item information string. + // @param display Default item display string. + // @param style Drawing style flags. Anything other than DEFAULT or + // DISABLED will be completely ignored when paginating. + // @return True on success, false on failure. + // @error Item limit reached. + public native bool AddItem(const char[] info, const char[] display, int style=ITEMDRAW_DEFAULT); + + // Inserts an item into the menu before a certain position; the new item will + // be at the given position and all next items pushed forward. + // + // @param position Position, starting from 0. + // @param info Item information string. + // @param display Default item display string. + // @param style Drawing style flags. Anything other than DEFAULT or + // DISABLED will be completely ignored when paginating. + // @return True on success, false on failure. + // @error Invalid menu position. + public native bool InsertItem(int position, const char[] info, + const char[] display, int style=ITEMDRAW_DEFAULT); + + // Removes an item from the menu. + // + // @param position Position, starting from 0. + // @return True on success, false on failure. + // @error Invalid menu position. + public native bool RemoveItem(int position); + + // Removes all items from a menu. + public native void RemoveAllItems(); + + // Retrieves information about a menu item. + // + // @param position Position, starting from 0. + // @param infoBuf Info buffer. + // @param infoBufLen Maximum length of the info buffer. + // @param style By-reference variable to store drawing flags. + // @param dispBuf Display buffer. + // @param dispBufLen Maximum length of the display buffer. + // @return True on success, false if position is invalid. + public native bool GetItem(int position, char[] infoBuf, int infoBufLen, + int &style=0, char[] dispBuf="", int dispBufLen=0); + + // Sets the menu's default title/instruction message. + // + // @param fmt Message string format + // @param ... Message string arguments. + public native void SetTitle(const char[] fmt, any ...); + + // Returns the text of a menu's title. + // + // @param menu Menu Handle. + // @param buffer Buffer to store title. + // @param maxlength Maximum length of the buffer. + // @return Number of bytes written. + public native void GetTitle(char[] buffer, int maxlength); + + // Creates a raw MenuPanel based off the menu's style. + // The Handle must be freed with CloseHandle(). + // + // @param menu Menu Handle. + // @return A new MenuPanel Handle. + public native Panel ToPanel(); + + // Cancels a menu from displaying on all clients. While the + // cancellation is in progress, this menu cannot be re-displayed + // to any clients. + // + // The menu may still exist on the client's screen after this command. + // This simply verifies that the menu is not being used anywhere. + // + // If any vote is in progress on a menu, it will be cancelled. + public native void Cancel(); + + // Broadcasts a menu to a list of clients. The most selected item will be + // returned through MenuAction_End. On a tie, a random item will be returned + // from a list of the tied items. + // + // Note that MenuAction_VoteEnd and MenuAction_VoteStart are both + // default callbacks and do not need to be enabled. + // + // @param clients Array of clients to broadcast to. + // @param numClients Number of clients in the array. + // @param time Maximum time to leave menu on the screen. + // @param flags Optional voting flags. + // @return True on success, false if this menu already has a + // vote session in progress. + // @error A vote is already in progress. + public native bool DisplayVote(int[] clients, int numClients, int time, int flags=0); + + // Sends a vote menu to all clients. See VoteMenu() for more information. + // + // @param time Maximum time to leave menu on the screen. + // @param flags Optional voting flags. + // @return True on success, false if this menu already has a + // vote session in progress. + public bool DisplayVoteToAll(int time, int flags=0) { + int total = 0; + int[] players = new int[MaxClients]; + for (int i = 1; i <= MaxClients; i++) { + if (!IsClientInGame(i) || IsFakeClient(i)) + continue; + players[total++] = i; + } + return this.DisplayVote(players, total, time, flags); + } + + // Get or set the menu's pagination. + // + // If pagination is MENU_NO_PAGINATION, and the exit button flag is set, + // then the exit button flag is removed. It can be re-applied if desired. + property int Pagination { + public native get(); + public native set(int value); + } + + // Get or set the menu's option flags. + // + // If a certain bit is not supported, it will be stripped before being set. + property int OptionFlags { + public native get(); + public native set(int value); + } + + // Returns whether or not the menu has an exit button. By default, menus + // have an exit button. + property bool ExitButton { + public native get(); + public native set(bool value); + } + + // Controls whether or not the menu has an "exit back" button. By default, + // menus do not have an exit back button. + // + // Exit Back buttons appear as "Back" on page 1 of paginated menus and have + // functionality defined by the user in MenuEnd_ExitBack. + property bool ExitBackButton { + public native get(); + public native set(bool value); + } + + // Sets whether or not the menu has a "no vote" button in slot 1. + // By default, menus do not have a no vote button. + property bool NoVoteButton { + public native set(bool value); + } + + // Sets an advanced vote handling callback. If this callback is set, + // MenuAction_VoteEnd will not be called. + property VoteHandler VoteResultCallback { + public native set(VoteHandler handler); + } + + // Returns the number of items in a menu. + property int ItemCount { + public native get(); + } + + // Returns the menu style. The Handle is global and cannot be closed. + property Handle Style { + public native get(); + } + + // Returns the first item on the page of a currently selected menu. + // + // This is only valid inside a MenuAction_Select callback. + property int Selection { + public native get(); + } +} + +/** + * Creates a new, empty menu using the default style. + * + * @param handler Function which will receive menu actions. + * @param actions Optionally set which actions to receive. Select, + * Cancel, and End will always be received regardless + * of whether they are set or not. They are also + * the only default actions. + * @return A new menu Handle. + */ +native Menu CreateMenu(MenuHandler handler, MenuAction actions=MENU_ACTIONS_DEFAULT); + +/** + * Displays a menu to a client. + * + * @param menu Menu Handle. + * @param client Client index. + * @param time Maximum time to leave menu on the screen. + * @return True on success, false on failure. + * @error Invalid Handle or client not in game. + */ +native bool DisplayMenu(Handle menu, int client, int time); + +/** + * Displays a menu to a client, starting from the given item. + * + * @param menu Menu Handle. + * @param client Client index. + * @param first_item First item to begin drawing from. + * @param time Maximum time to leave menu on the screen. + * @return True on success, false on failure. + * @error Invalid Handle or client not in game. + */ +native bool DisplayMenuAtItem(Handle menu, int client, int first_item, int time); + +/** + * Appends a new item to the end of a menu. + * + * @param menu Menu Handle. + * @param info Item information string. + * @param display Default item display string. + * @param style Drawing style flags. Anything other than DEFAULT or + * DISABLED will be completely ignored when paginating. + * @return True on success, false on failure. + * @error Invalid Handle or item limit reached. + */ +native bool AddMenuItem(Handle menu, + const char[] info, + const char[] display, + int style=ITEMDRAW_DEFAULT); + +/** + * Inserts an item into the menu before a certain position; the new item will + * be at the given position and all next items pushed forward. + * + * @param menu Menu Handle. + * @param position Position, starting from 0. + * @param info Item information string. + * @param display Default item display string. + * @param style Drawing style flags. Anything other than DEFAULT or + * DISABLED will be completely ignored when paginating. + * @return True on success, false on failure. + * @error Invalid Handle or menu position. + */ +native bool InsertMenuItem(Handle menu, + position, + const char[] info, + const char[] display, + int style=ITEMDRAW_DEFAULT); + +/** + * Removes an item from the menu. + * + * @param menu Menu Handle. + * @param position Position, starting from 0. + * @return True on success, false on failure. + * @error Invalid Handle or menu position. + */ +native bool RemoveMenuItem(Handle menu, int position); + +/** + * Removes all items from a menu. + * + * @param menu Menu Handle. + * @error Invalid Handle or menu position. + */ +native void RemoveAllMenuItems(Handle menu); + +/** + * Retrieves information about a menu item. + * + * @param menu Menu Handle. + * @param position Position, starting from 0. + * @param infoBuf Info buffer. + * @param infoBufLen Maximum length of the info buffer. + * @param style By-reference variable to store drawing flags. + * @param dispBuf Display buffer. + * @param dispBufLen Maximum length of the display buffer. + * @return True on success, false if position is invalid. + * @error Invalid Handle. + */ +native bool GetMenuItem(Handle menu, + int position, + char[] infoBuf, + int infoBufLen, + int &style=0, + char[] dispBuf="", + int dispBufLen=0); + +/** + * Returns the first item on the page of a currently selected menu. + * + * This is only valid inside a MenuAction_Select callback. + * + * @return First item number on the page the client was viewing + * before selecting the item in the callback. This can + * be used to re-display the menu from the original + * position. + * @error Not called from inside a MenuAction_Select callback. + */ +native int GetMenuSelectionPosition(); + +/** + * Returns the number of items in a menu. + * + * @param menu Menu Handle. + * @return Number of items in the menu. + * @error Invalid Handle. + */ +native int GetMenuItemCount(Handle menu); + +/** + * Sets whether the menu should be paginated or not. + * + * If itemsPerPage is MENU_NO_PAGINATION, and the exit button flag is set, + * then the exit button flag is removed. It can be re-applied if desired. + * + * @param menu Handle to the menu. + * @param itemsPerPage Number of items per page, or MENU_NO_PAGINATION. + * @return True on success, false if pagination is too high or + * low. + * @error Invalid Handle. + */ +native bool SetMenuPagination(Handle menu, int itemsPerPage); + +/** + * Returns a menu's pagination setting. + * + * @param menu Handle to the menu. + * @return Pagination setting. + * @error Invalid Handle. + */ +native int GetMenuPagination(Handle menu); + +/** + * Returns a menu's MenuStyle Handle. The Handle + * is global and cannot be freed. + * + * @param menu Handle to the menu. + * @return Handle to the menu's draw style. + * @error Invalid Handle. + */ +native Handle GetMenuStyle(Handle menu); + +/** + * Sets the menu's default title/instruction message. + * + * @param menu Menu Handle. + * @param fmt Message string format + * @param ... Message string arguments. + * @error Invalid Handle. + */ +native void SetMenuTitle(Handle menu, const char[] fmt, any ...); + +/** + * Returns the text of a menu's title. + * + * @param menu Menu Handle. + * @param buffer Buffer to store title. + * @param maxlength Maximum length of the buffer. + * @return Number of bytes written. + * @error Invalid Handle/ + */ +native int GetMenuTitle(Handle menu, char[] buffer, int maxlength); + +/** + * Creates a raw MenuPanel based off the menu's style. + * The Handle must be freed with CloseHandle(). + * + * @param menu Menu Handle. + * @return A new MenuPanel Handle. + * @error Invalid Handle. + */ +native Panel CreatePanelFromMenu(Handle menu); + +/** + * Returns whether or not the menu has an exit button. + * By default, menus have an exit button. + * + * @param menu Menu Handle. + * @return True if the menu has an exit button; false otherwise. + * @error Invalid Handle. + */ +native bool GetMenuExitButton(Handle menu); + +/** + * Sets whether or not the menu has an exit button. By default, paginated menus + * have an exit button. + * + * If a menu's pagination is changed to MENU_NO_PAGINATION, and the pagination + * was previously a different value, then the Exit button status is changed to + * false. It must be explicitly re-enabled afterwards. + * + * If a non-paginated menu has an exit button, then at most 9 items will be + * displayed. + * + * @param menu Menu Handle. + * @param button True to enable the button, false to remove it. + * @return True if allowed; false on failure. + * @error Invalid Handle. + */ +native bool SetMenuExitButton(Handle menu, bool button); + +/** + * Returns whether or not the menu has an "exit back" button. By default, + * menus do not have an exit back button. + * + * Exit Back buttons appear as "Back" on page 1 of paginated menus and have + * functionality defined by the user in MenuEnd_ExitBack. + * + * @param menu Menu Handle. + * @return True if the menu has an exit back button; false otherwise. + * @error Invalid Handle. + */ +native bool GetMenuExitBackButton(Handle menu); + +/** + * Sets whether or not the menu has an "exit back" button. By default, menus + * do not have an exit back button. + * + * Exit Back buttons appear as "Back" on page 1 of paginated menus and have + * functionality defined by the user in MenuEnd_ExitBack. + * + * @param menu Menu Handle. + * @param button True to enable the button, false to remove it. + * @error Invalid Handle. + */ +native void SetMenuExitBackButton(Handle menu, bool button); + +/** + * Sets whether or not the menu has a "no vote" button in slot 1. + * By default, menus do not have a no vote button. + * + * @param menu Menu Handle. + * @param button True to enable the button, false to remove it. + * @return True if allowed; false on failure. + * @error Invalid Handle. + */ +native bool SetMenuNoVoteButton(Handle menu, bool button); + +/** + * Cancels a menu from displaying on all clients. While the + * cancellation is in progress, this menu cannot be re-displayed + * to any clients. + * + * The menu may still exist on the client's screen after this command. + * This simply verifies that the menu is not being used anywhere. + * + * If any vote is in progress on a menu, it will be cancelled. + * + * @param menu Menu Handle. + * @error Invalid Handle. + */ +native void CancelMenu(Handle menu); + +/** + * Retrieves a menu's option flags. + * + * @param menu Menu Handle. + * @return A bitstring of MENUFLAG bits. + * @error Invalid Handle. + */ +native int GetMenuOptionFlags(Handle menu); + +/** + * Sets a menu's option flags. + * + * If a certain bit is not supported, it will be stripped before being set. + * See SetMenuExitButton() for information on Exit buttons. + * See SetMenuExitBackButton() for information on Exit Back buttons. + * + * @param menu Menu Handle. + * @param flags A new bitstring of MENUFLAG bits. + * @error Invalid Handle. + */ +native void SetMenuOptionFlags(Handle menu, int flags); + +/** + * Returns whether a vote is in progress. + * + * @param menu Deprecated; no longer used. + * @return True if a vote is in progress, false otherwise. + */ +native bool IsVoteInProgress(Handle menu=INVALID_HANDLE); + +/** + * Cancels the vote in progress. + * + * @error If no vote is in progress. + */ +native void CancelVote(); + +/** + * Broadcasts a menu to a list of clients. The most selected item will be + * returned through MenuAction_End. On a tie, a random item will be returned + * from a list of the tied items. + * + * Note that MenuAction_VoteEnd and MenuAction_VoteStart are both + * default callbacks and do not need to be enabled. + * + * @param menu Menu Handle. + * @param clients Array of clients to broadcast to. + * @param numClients Number of clients in the array. + * @param time Maximum time to leave menu on the screen. + * @param flags Optional voting flags. + * @return True on success, false if this menu already has a vote session + * in progress. + * @error Invalid Handle, or a vote is already in progress. + */ +native bool VoteMenu(Handle menu, int[] clients, int numClients, int time, int flags=0); + +/** + * Sends a vote menu to all clients. See VoteMenu() for more information. + * + * @param menu Menu Handle. + * @param time Maximum time to leave menu on the screen. + * @param flags Optional voting flags. + * @return True on success, false if this menu already has a vote session + * in progress. + * @error Invalid Handle. + */ +stock bool VoteMenuToAll(Handle menu, int time, int flags=0) +{ + int total; + int[] players = new int[MaxClients]; + + for (int i=1; i<=MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i)) + { + continue; + } + players[total++] = i; + } + + return VoteMenu(menu, players, total, time, flags); +} + +/** + * Callback for when a vote has ended and results are available. + * + * @param menu The menu being voted on. + * @param num_votes Number of votes tallied in total. + * @param num_clients Number of clients who could vote. + * @param client_info Array of clients. Use VOTEINFO_CLIENT_ defines. + * @param num_items Number of unique items that were selected. + * @param item_info Array of items, sorted by count. Use VOTEINFO_ITEM + * defines. + */ +typeset VoteHandler +{ + // old style + function void( + Menu menu, + int num_votes, + int num_clients, + const int client_info[][2], + int num_items, + const int item_info[][2] + ); + + // new style + function void( + Menu menu, + int num_votes, + int num_clients, + const int[][] client_info, + int num_items, + const int[][] item_info + ); +}; + +/** + * Sets an advanced vote handling callback. If this callback is set, + * MenuAction_VoteEnd will not be called. + * + * @param menu Menu Handle. + * @param callback Callback function. + * @error Invalid Handle or callback. + */ +native void SetVoteResultCallback(Handle menu, VoteHandler callback); + +/** + * Returns the number of seconds you should "wait" before displaying + * a publicly invocable menu. This number is the time remaining until + * (last_vote + sm_vote_delay). + * + * @return Number of seconds to wait, or 0 for none. + */ +native int CheckVoteDelay(); + +/** + * Returns whether a client is in the pool of clients allowed + * to participate in the current vote. This is determined by + * the client list passed to VoteMenu(). + * + * @param client Client index. + * @return True if client is allowed to vote, false otherwise. + * @error If no vote is in progress or client index is invalid. + */ +native bool IsClientInVotePool(int client); + +/** + * Redraws the current vote menu to a client in the voting pool. + * + * @param client Client index. + * @param revotes True to allow revotes, false otherwise. + * @return True on success, false if the client is in the vote pool + * but cannot vote again. + * @error No vote in progress, int client is not in the voting pool, + * or client index is invalid. + */ +native bool RedrawClientVoteMenu(int client, bool revotes=true); + +/** + * Returns a style's global Handle. + * + * @param style Menu Style. + * @return A Handle, or INVALID_HANDLE if not found or unusable. + */ +native Handle GetMenuStyleHandle(MenuStyle style); + +/** + * Creates a MenuPanel from a MenuStyle. Panels are used for drawing raw + * menus without any extra helper functions. The Handle must be closed + * with CloseHandle(). + * + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @return A new MenuPanel Handle. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native Panel CreatePanel(Handle hStyle=INVALID_HANDLE); + +/** + * Creates a Menu from a MenuStyle. The Handle must be closed with + * CloseHandle(). + * + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @param handler Function which will receive menu actions. + * @param actions Optionally set which actions to receive. Select, + * Cancel, and End will always be received regardless + * of whether they are set or not. They are also + * the only default actions. + * @return A new menu Handle. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native Menu CreateMenuEx(Handle hStyle=INVALID_HANDLE, MenuHandler handler, MenuAction actions=MENU_ACTIONS_DEFAULT); + +/** + * Returns whether a client is viewing a menu. + * + * @param client Client index. + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @return A MenuSource value. + * @error Invalid Handle other than null. + */ +native MenuSource GetClientMenu(int client, Handle hStyle=null); + +/** + * Cancels a menu on a client. This will only affect non-external menus. + * + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @param client Client index. + * @param autoIgnore If true, no menus can be re-drawn on the client during + * the cancellation process. + * @return True if a menu was cancelled, false otherwise. + */ +native bool CancelClientMenu(int client, bool autoIgnore=false, Handle hStyle=INVALID_HANDLE); + +/** + * Returns a style's maximum items per page. + * + * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. + * @return Maximum items per page. + * @error Invalid Handle other than INVALID_HANDLE. + */ +native int GetMaxPageItems(Handle hStyle=INVALID_HANDLE); + +/** + * Returns a MenuPanel's parent style. + * + * @param panel A MenuPanel Handle. + * @return The MenuStyle Handle that created the panel. + * @error Invalid Handle. + */ +native Handle GetPanelStyle(Handle panel); + +/** + * Sets the panel's title. + * + * @param panel A MenuPanel Handle. + * @param text Text to set as the title. + * @param onlyIfEmpty If true, the title will only be set if no title is set. + * @error Invalid Handle. + */ +native void SetPanelTitle(Handle panel, const char[] text, bool onlyIfEmpty=false); + +/** + * Draws an item on a panel. If the item takes up a slot, the position + * is returned. + * + * @param panel A MenuPanel Handle. + * @param text Display text to use. If not a raw line, + * the style may automatically add color markup. + * No numbering or newlines are needed. + * @param style ITEMDRAW style flags. + * @return A slot position, or 0 if item was a rawline or could not be drawn. + * @error Invalid Handle. + */ +native int DrawPanelItem(Handle panel, const char[] text, int style=ITEMDRAW_DEFAULT); + +/** + * Draws a raw line of text on a panel, without any markup other than a newline. + * + * @param panel A MenuPanel Handle, or INVALID_HANDLE if inside a + * MenuAction_DisplayItem callback. + * @param text Display text to use. + * @return True on success, false if raw lines are not supported. + * @error Invalid Handle. + */ +native bool DrawPanelText(Handle panel, const char[] text); + +/** + * Returns whether or not the given drawing flags are supported by + * the menu style. + * + * @param panel A MenuPanel Handle. + * @param style ITEMDRAW style flags. + * @return True if item is drawable, false otherwise. + * @error Invalid Handle. + */ +native bool CanPanelDrawFlags(Handle panel, int style); + +/** + * Sets the selectable key map of a panel. This is not supported by + * all styles (only by Radio, as of this writing). + * + * @param panel A MenuPanel Handle. + * @param keys An integer where each bit N allows key + * N+1 to be selected. If no keys are selectable, + * then key 0 (bit 9) is automatically set. + * @return True if supported, false otherwise. + */ +native bool SetPanelKeys(Handle panel, int keys); + +/** + * Sends a panel to a client. Unlike full menus, the handler + * function will only receive the following actions, both of + * which will have INVALID_HANDLE for a menu, and the client + * as param1. + * + * MenuAction_Select (param2 will be the key pressed) + * MenuAction_Cancel (param2 will be the reason) + * + * Also, if the menu fails to display, no callbacks will be called. + * + * @param panel A MenuPanel Handle. + * @param client A client to draw to. + * @param handler The MenuHandler function to catch actions with. + * @param time Time to hold the menu for. + * @return True on success, false on failure. + * @error Invalid Handle. + */ +native bool SendPanelToClient(Handle panel, int client, MenuHandler handler, int time); + +/** + * @brief Returns the amount of text the menu can still hold. If this is + * limit is reached or overflowed, the text is silently truncated. + * + * Radio menus: Currently 511 characters (512 bytes). + * Valve menus: Currently -1 (no meaning). + * + * @param panel A MenuPanel Handle. + * @return Number of characters that the menu can still hold, + * or -1 if there is no known limit. + * @error Invalid Handle. + */ +native int GetPanelTextRemaining(Handle panel); + +/** + * @brief Returns the current key position. + * + * @param panel A MenuPanel Handle. + * @return Current key position starting at 1. + * @error Invalid Handle. + */ +native int GetPanelCurrentKey(Handle panel); + +/** + * @brief Sets the next key position. This cannot be used + * to traverse backwards. + * + * @param panel A MenuPanel Handle. + * @param key Key that is greater or equal to + * GetPanelCurrentKey(). + * @return True on success, false otherwise. + * @error Invalid Handle. + */ +native bool SetPanelCurrentKey(Handle panel, int key); + +/** + * @brief Redraws menu text from inside a MenuAction_DisplayItem callback. + * + * @param text Menu text to draw. + * @return Item position; must be returned via the callback. + */ +native int RedrawMenuItem(const char[] text); + +/** + * This function is provided for legacy code only. Some older plugins may use + * network messages instead of the panel API. This function wraps the panel + * API for eased portability into the SourceMod menu system. + * + * This function is only usable with the Radio Menu style. You do not need to + * split up your menu into multiple packets; SourceMod will break the string + * up internally. + * + * @param client Client index. + * @param str Full menu string as would be passed over the network. + * @param time Time to hold the menu for. + * @param keys Selectable key bitstring. + * @param handler Optional handler function, with the same rules as + * SendPanelToClient(). + * @return True on success, false on failure. + * @error Invalid client index, or radio menus not supported. + */ +native bool InternalShowMenu(int client, const char[] str, int time, int keys=-1, MenuHandler handler=INVALID_FUNCTION); + +/** + * Retrieves voting information from MenuAction_VoteEnd. + * + * @param param2 Second parameter of MenuAction_VoteEnd. + * @param winningVotes Number of votes received by the winning option. + * @param totalVotes Number of total votes received. + */ +stock void GetMenuVoteInfo(int param2, int &winningVotes, int &totalVotes) +{ + winningVotes = param2 & 0xFFFF; + totalVotes = param2 >> 16; +} + +/** + * Quick stock to determine whether voting is allowed. This doesn't let you + * fine-tune a reason for not voting, so it's not recommended for lazily + * telling clients that voting isn't allowed. + * + * @return True if voting is allowed, false if voting is in progress + * or the cooldown is active. + */ +stock bool IsNewVoteAllowed() +{ + if (IsVoteInProgress() || CheckVoteDelay() != 0) + { + return false; + } + + return true; +} diff --git a/scripting/include/nextmap.inc b/scripting/include/nextmap.inc new file mode 100644 index 0000000..cb86b71 --- /dev/null +++ b/scripting/include/nextmap.inc @@ -0,0 +1,82 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _nextmap_included_ + #endinput +#endif +#define _nextmap_included_ + +/** + * Sets SourceMod's internal nextmap. + * Equivalent to changing sm_nextmap but with an added validity check. + * + * @param map Next map to set. + * @return True if the nextmap was set, false if map was invalid. + */ +native bool SetNextMap(const char[] map); + +/** + * Returns SourceMod's internal nextmap. + * + * @param map Buffer to store the nextmap name. + * @param maxlen Maximum length of the map buffer. + * @return True if a Map was found and copied, false if no nextmap is set (map will be unchanged). + */ +native bool GetNextMap(char[] map, int maxlen); + +/** + * Changes the current map and records the reason for the change with maphistory + * + * @param map Map to change to. + * @param reason Reason for change. + */ +native void ForceChangeLevel(const char[] map, const char[] reason); + +/** + * Gets the current number of maps in the map history + * + * @return Number of maps. + */ +native int GetMapHistorySize(); + +/** + * Retrieves a map from the map history list. + * + * @param item Item number. Must be 0 or greater and less than GetMapHistorySize(). + * @param map Buffer to store the map name. + * @param mapLen Length of map buffer. + * @param reason Buffer to store the change reason. + * @param reasonLen Length of the reason buffer. + * @param startTime Time the map started. + * @error Invalid item number. + */ +native void GetMapHistory(int item, char[] map, int mapLen, char[] reason, int reasonLen, int &startTime); diff --git a/scripting/include/ngs_votes.inc b/scripting/include/ngs_votes.inc new file mode 100644 index 0000000..d0a6f06 --- /dev/null +++ b/scripting/include/ngs_votes.inc @@ -0,0 +1,43 @@ +#if defined _ngs_votes_included + #endinput +#endif +#define _ngs_votes_included +#define _ngsvotes_version "0.0.3" + +enum NGSVote_Type +{ + Regular, + Randomized, + Rotated +} + +methodmap Vote < StringMap +{ + /** + * Create a vote object to pass into start vote. + * + * @param type Vote type to make resulting vote. + * @param parameters ArrayList of strings, where first should be question and rest are options. + * @param max_size Max size of string buffers. + * @return New vote object to be used to StartSpecialVote. + */ + public Vote(NGSVote_Type type, ArrayList parameters, int max_size) + { + char[] question = new char[max_size]; + StringMap map = new StringMap(); + map.SetValue("type", type); + map.SetValue("size", max_size); + parameters.GetString(0, question, max_size); + parameters.Erase(0); + map.SetString("question", question); + map.SetValue(parameters); + return view_as(map); + } +} + +/** + * Called when a timed randomized vote is finished. + */ +forward void OnSpecialVoteFinished(Vote vote); + +native bool StartSpecialVote(Vote vote); \ No newline at end of file diff --git a/scripting/include/profiler.inc b/scripting/include/profiler.inc new file mode 100644 index 0000000..ed5a7ee --- /dev/null +++ b/scripting/include/profiler.inc @@ -0,0 +1,97 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _profiler_included + #endinput +#endif +#define _profiler_included + +/** + * ONLY AVAILABLE ON WINDOWS RIGHT NOW K. + */ + +/** + * Creates a new profile object. The Handle must be freed + * using CloseHandle(). + * + * @return Handle to the profiler object. + */ +native Handle CreateProfiler(); + +/** + * Starts profiling. + * + * @param prof Profiling object. + * @error Invalid Handle. + */ +native void StartProfiling(Handle prof); + +/** + * Stops profiling. + * + * @param prof Profiling object. + * @error Invalid Handle or profiling was never started. + */ +native void StopProfiling(Handle prof); + +/** + * Returns the amount of high-precision time in seconds + * that passed during the profiler's last start/stop + * cycle. + * + * @param prof Profiling object. + * @return Time elapsed in seconds. + * @error Invalid Handle. + */ +native float GetProfilerTime(Handle prof); + +/** + * Mark the start of a profiling event. + * + * @param group Budget group. This can be "all" for a default, or a short + * description like "Timers" or "Events". + * @param name A name to attribute to this profiling event. + */ +native void EnterProfilingEvent(const char[] group, const char[] name); + +/** + * Mark the end of the last profiling event. This must be called in the same + * stack frame as StartProfilingEvent(). Not doing so, or throwing errors, + * will make the resulting profile very wrong. + */ +native void LeaveProfilingEvent(); + +/** + * Returns true if the global profiler is enabled; false otherwise. It is + * not necessary to call this before Enter/LeaveProfilingEvent. + */ +native bool IsProfilingActive(); diff --git a/scripting/include/protobuf.inc b/scripting/include/protobuf.inc new file mode 100644 index 0000000..56bebc5 --- /dev/null +++ b/scripting/include/protobuf.inc @@ -0,0 +1,572 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2013 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _protobuf_included +#endinput +#endif +#define _protobuf_included + +#define PB_FIELD_NOT_REPEATED -1 + +methodmap Protobuf < Handle +{ + // Reads an int32, uint32, sint32, fixed32, sfixed32, or enum value from a protobuf message. + // + // @param field Field name. + // @param index Index into repeated field. + // @return Integer value read. + // @error Non-existent field, or incorrect field type. + public native int ReadInt(const char[] field, int index = PB_FIELD_NOT_REPEATED); + + // Reads a float or downcasted double from a protobuf message. + // + // @param field Field name. + // @param index Index into repeated field. + // @return Float value read. + // @error Non-existent field, or incorrect field type. + public native float ReadFloat(const char[] field, int index = PB_FIELD_NOT_REPEATED); + + // Reads a bool from a protobuf message. + // + // @param field Field name. + // @param index Index into repeated field. + // @return Boolean value read. + // @error Non-existent field, or incorrect field type. + public native bool ReadBool(const char[] field, int index = PB_FIELD_NOT_REPEATED); + + // Reads a string from a protobuf message. + // + // @param field Field name. + // @param buffer Destination string buffer. + // @param maxlength Maximum length of output string buffer. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void ReadString(const char[] field, char[] buffer, int maxlength, int index = PB_FIELD_NOT_REPEATED); + + // Reads an RGBA color value from a protobuf message. + // + // @param field Field name. + // @param buffer Destination color buffer. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void ReadColor(const char[] field, int buffer[4], int index = PB_FIELD_NOT_REPEATED); + + // Reads an XYZ angle value from a protobuf message. + // + // @param field Field name. + // @param buffer Destination angle buffer. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void ReadAngle(const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); + + // Reads an XYZ vector value from a protobuf message. + // + // @param pb protobuf handle. + // @param field Field name. + // @param buffer Destination vector buffer. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void ReadVector(const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); + + // Reads an XY vector value from a protobuf message. + // + // @param field Field name. + // @param buffer Destination vector buffer. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void ReadVector2D(const char[] field, float buffer[2], int index = PB_FIELD_NOT_REPEATED); + + // Gets the number of elements in a repeated field of a protobuf message. + // + // @param field Field name. + // @return Number of elements in the field. + // @error Non-existent field, or incorrect field type. + public native int GetRepeatedFieldCount(const char[] field); + + // Sets an int32, uint32, sint32, fixed32, sfixed32, or enum value on a protobuf message. + // + // @param field Field name. + // @param value Integer value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native int SetInt(const char[] field, int value, int index = PB_FIELD_NOT_REPEATED); + + // Sets a float or double on a protobuf message. + // + // @param field Field name. + // @param value Float value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void SetFloat(const char[] field, float value, int index = PB_FIELD_NOT_REPEATED); + + // Sets a bool on a protobuf message. + // + // @param field Field name. + // @param value Boolean value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void SetBool(const char[] field, bool value, int index = PB_FIELD_NOT_REPEATED); + + // Sets a string on a protobuf message. + // + // @param field Field name. + // @param value String value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void SetString(const char[] field, const char[] value, int index = PB_FIELD_NOT_REPEATED); + + // Sets an RGBA color on a protobuf message. + // + // @param field Field name. + // @param color Color value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void SetColor(const char[] field, const int color[4], int index = PB_FIELD_NOT_REPEATED); + + // Sets an XYZ angle on a protobuf message. + // + // @param field Field name. + // @param angle Angle value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void SetAngle(const char[] field, const float angle[3], int index = PB_FIELD_NOT_REPEATED); + + // Sets an XYZ vector on a protobuf message. + // + // @param field Field name. + // @param vec Vector value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void SetVector(const char[] field, const float vec[3], int index = PB_FIELD_NOT_REPEATED); + + // Sets an XY vector on a protobuf message. + // + // @param field Field name. + // @param vec Vector value to set. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void SetVector2D(const char[] field, const float vec[2], int index = PB_FIELD_NOT_REPEATED); + + // Add an int32, uint32, sint32, fixed32, sfixed32, or enum value to a protobuf message repeated field. + // + // @param field Field name. + // @param value Integer value to add. + // @error Non-existent field, or incorrect field type. + public native void AddInt(const char[] field, int value); + + // Add a float or double to a protobuf message repeated field. + // + // @param field Field name. + // @param value Float value to add. + // @error Non-existent field, or incorrect field type. + public native void AddFloat(const char[] field, float value); + + // Add a bool to a protobuf message repeated field. + // + // @param field Field name. + // @param value Boolean value to add. + // @error Non-existent field, or incorrect field type. + public native void AddBool(const char[] field, bool value); + + // Add a string to a protobuf message repeated field. + // + // @param field Field name. + // @param value String value to add. + // @error Non-existent field, or incorrect field type. + public native void AddString(const char[] field, const char[] value); + + // Add an RGBA color to a protobuf message repeated field. + // + // @param field Field name. + // @param color Color value to add. + // @error Non-existent field, or incorrect field type. + public native void AddColor(const char[] field, const int color[4]); + + // Add an XYZ angle to a protobuf message repeated field. + // + // @param field Field name. + // @param angle Angle value to add. + // @error Non-existent field, or incorrect field type. + public native void AddAngle(const char[] field, const float angle[3]); + + // Add an XYZ vector to a protobuf message repeated field. + // + // @param field Field name. + // @param vec Vector value to add. + // @error Non-existent field, or incorrect field type. + public native void AddVector(const char[] field, const float vec[3]); + + // Add an XY vector to a protobuf message repeated field. + // + // @param field Field name. + // @param vec Vector value to add. + // @error Non-existent field, or incorrect field type. + public native void AddVector2D(const char[] field, const float vec[2]); + + // Removes a value by index from a protobuf message repeated field. + // + // @param field Field name. + // @param index Index into repeated field. + // @error Non-existent field, or incorrect field type. + public native void RemoveRepeatedFieldValue(const char[] field, int index); + + // Retrieve a handle to an embedded protobuf message in a protobuf message. + // + // @param field Field name. + // @return Protobuf handle to embedded message. + // @error Non-existent field, or incorrect field type. + public native Protobuf ReadMessage(const char[] field); + + // Retrieve a handle to an embedded protobuf message in a protobuf message + // repeated field. + // + // @param field Field name. + // @param index Index in the repeated field. + // @return Protobuf handle to embedded message. + // @error Non-existent field, or incorrect field type. + public native Protobuf ReadRepeatedMessage(const char[] field, int index); + + // Adds an embedded protobuf message to a protobuf message repeated field. + // + // @param field Field name. + // @return Protobuf handle to added, embedded message. + // @error Non-existent field, or incorrect field type. + public native Protobuf AddMessage(const char[] field); +}; + +/** + * Reads an int32, uint32, sint32, fixed32, sfixed32, or enum value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index into repeated field. + * @return Integer value read. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native int PbReadInt(Handle pb, const char[] field, int index = PB_FIELD_NOT_REPEATED); + +/** + * Reads a float or downcasted double from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index into repeated field. + * @return Float value read. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native float PbReadFloat(Handle pb, const char[] field, int index = PB_FIELD_NOT_REPEATED); + +/** + * Reads a bool from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index into repeated field. + * @return Boolean value read. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native bool PbReadBool(Handle pb, const char[] field, int index = PB_FIELD_NOT_REPEATED); + +/** + * Reads a string from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbReadString(Handle pb, const char[] field, char[] buffer, int maxlength, int index = PB_FIELD_NOT_REPEATED); + +/** + * Reads an RGBA color value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination color buffer. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbReadColor(Handle pb, const char[] field, int buffer[4], int index = PB_FIELD_NOT_REPEATED); + +/** + * Reads an XYZ angle value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination angle buffer. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbReadAngle(Handle pb, const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); + +/** + * Reads an XYZ vector value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination vector buffer. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbReadVector(Handle pb, const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); + +/** + * Reads an XY vector value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination vector buffer. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbReadVector2D(Handle pb, const char[] field, float buffer[2], int index = PB_FIELD_NOT_REPEATED); + +/** + * Gets the number of elements in a repeated field of a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @return Number of elements in the field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native int PbGetRepeatedFieldCount(Handle pb, const char[] field); + +/** + * Sets an int32, uint32, sint32, fixed32, sfixed32, or enum value on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Integer value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetInt(Handle pb, const char[] field, int value, int index = PB_FIELD_NOT_REPEATED); + +/** + * Sets a float or double on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Float value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetFloat(Handle pb, const char[] field, float value, int index = PB_FIELD_NOT_REPEATED); + +/** + * Sets a bool on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Boolean value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetBool(Handle pb, const char[] field, bool value, int index = PB_FIELD_NOT_REPEATED); + +/** + * Sets a string on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value String value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetString(Handle pb, const char[] field, const char[] value, int index = PB_FIELD_NOT_REPEATED); + +/** + * Sets an RGBA color on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param color Color value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetColor(Handle pb, const char[] field, const int color[4], int index = PB_FIELD_NOT_REPEATED); + +/** + * Sets an XYZ angle on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param angle Angle value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetAngle(Handle pb, const char[] field, const float angle[3], int index = PB_FIELD_NOT_REPEATED); + +/** + * Sets an XYZ vector on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param vec Vector value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetVector(Handle pb, const char[] field, const float vec[3], int index = PB_FIELD_NOT_REPEATED); + +/** + * Sets an XY vector on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param vec Vector value to set. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbSetVector2D(Handle pb, const char[] field, const float vec[2], int index = PB_FIELD_NOT_REPEATED); + +/** + * Add an int32, uint32, sint32, fixed32, sfixed32, or enum value to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Integer value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddInt(Handle pb, const char[] field, int value); + +/** + * Add a float or double to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Float value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddFloat(Handle pb, const char[] field, float value); + +/** + * Add a bool to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Boolean value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddBool(Handle pb, const char[] field, bool value); + +/** + * Add a string to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value String value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddString(Handle pb, const char[] field, const char[] value); + +/** + * Add an RGBA color to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param color Color value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddColor(Handle pb, const char[] field, const int color[4]); + +/** + * Add an XYZ angle to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param angle Angle value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddAngle(Handle pb, const char[] field, const float angle[3]); + +/** + * Add an XYZ vector to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param vec Vector value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddVector(Handle pb, const char[] field, const float vec[3]); + +/** + * Add an XY vector to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param vec Vector value to add. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbAddVector2D(Handle pb, const char[] field, const float vec[2]); + +/** + * Removes a value by index from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index into repeated field. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native void PbRemoveRepeatedFieldValue(Handle pb, const char[] field, int index); + +/** + * Retrieve a handle to an embedded protobuf message in a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @return protobuf handle to embedded message. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native Handle PbReadMessage(Handle pb, const char[] field); + +/** + * Retrieve a handle to an embedded protobuf message in a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @return protobuf handle to embedded message. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native Handle PbReadRepeatedMessage(Handle pb, const char[] field, int index); + +/** + * Adds an embedded protobuf message to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @return protobuf handle to added, embedded message. + * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. + */ +native Handle PbAddMessage(Handle pb, const char[] field); diff --git a/scripting/include/regex.inc b/scripting/include/regex.inc new file mode 100644 index 0000000..d946659 --- /dev/null +++ b/scripting/include/regex.inc @@ -0,0 +1,275 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _regex_included + #endinput +#endif +#define _regex_included + +/** + * @section Flags for compiling regex expressions. These come directly from the + * pcre library and can be used in MatchRegex and CompileRegex. + */ +#define PCRE_CASELESS 0x00000001 /* Ignore Case */ +#define PCRE_MULTILINE 0x00000002 /* Multilines (affects ^ and $ so that they match the start/end of a line rather than matching the start/end of the string). */ +#define PCRE_DOTALL 0x00000004 /* Single line (affects . so that it matches any character, even new line characters). */ +#define PCRE_EXTENDED 0x00000008 /* Pattern extension (ignore whitespace and # comments). */ +#define PCRE_ANCHORED 0x00000010 /* Force pattern anchoring. */ +#define PCRE_DOLLAR_ENDONLY 0x00000020 /* $ not to match newline at end. */ +#define PCRE_UNGREEDY 0x00000200 /* Invert greediness of quantifiers */ +#define PCRE_NOTEMPTY 0x00000400 /* An empty string is not a valid match. */ +#define PCRE_UTF8 0x00000800 /* Use UTF-8 Chars */ +#define PCRE_NO_UTF8_CHECK 0x00002000 /* Do not check the pattern for UTF-8 validity (only relevant if PCRE_UTF8 is set) */ +#define PCRE_UCP 0x20000000 /* Use Unicode properties for \ed, \ew, etc. */ + + +/** + * Regex expression error codes. + */ +enum RegexError +{ + REGEX_ERROR_NONE = 0, /* No error */ + + REGEX_ERROR_ASSERT = 1, /* internal error ? */ + REGEX_ERROR_BADBR, /* invalid repeat counts in {} */ + REGEX_ERROR_BADPAT, /* pattern error */ + REGEX_ERROR_BADRPT, /* ? * + invalid */ + REGEX_ERROR_EBRACE, /* unbalanced {} */ + REGEX_ERROR_EBRACK, /* unbalanced [] */ + REGEX_ERROR_ECOLLATE, /* collation error - not relevant */ + REGEX_ERROR_ECTYPE, /* bad class */ + REGEX_ERROR_EESCAPE, /* bad escape sequence */ + REGEX_ERROR_EMPTY, /* empty expression */ + REGEX_ERROR_EPAREN, /* unbalanced () */ + REGEX_ERROR_ERANGE, /* bad range inside [] */ + REGEX_ERROR_ESIZE, /* expression too big */ + REGEX_ERROR_ESPACE, /* failed to get memory */ + REGEX_ERROR_ESUBREG, /* bad back reference */ + REGEX_ERROR_INVARG, /* bad argument */ + + REGEX_ERROR_NOMATCH = -1, /* No match was found */ + REGEX_ERROR_NULL = -2, + REGEX_ERROR_BADOPTION = -3, + REGEX_ERROR_BADMAGIC = -4, + REGEX_ERROR_UNKNOWN_OPCODE = -5, + REGEX_ERROR_NOMEMORY = -6, + REGEX_ERROR_NOSUBSTRING = -7, + REGEX_ERROR_MATCHLIMIT = -8, + REGEX_ERROR_CALLOUT = -9, /* Never used by PCRE itself */ + REGEX_ERROR_BADUTF8 = -10, + REGEX_ERROR_BADUTF8_OFFSET = -11, + REGEX_ERROR_PARTIAL = -12, + REGEX_ERROR_BADPARTIAL = -13, + REGEX_ERROR_INTERNAL = -14, + REGEX_ERROR_BADCOUNT = -15, + REGEX_ERROR_DFA_UITEM = -16, + REGEX_ERROR_DFA_UCOND = -17, + REGEX_ERROR_DFA_UMLIMIT = -18, + REGEX_ERROR_DFA_WSSIZE = -19, + REGEX_ERROR_DFA_RECURSE = -20, + REGEX_ERROR_RECURSIONLIMIT = -21, + REGEX_ERROR_NULLWSLIMIT = -22, /* No longer actually used */ + REGEX_ERROR_BADNEWLINE = -23, + REGEX_ERROR_BADOFFSET = -24, + REGEX_ERROR_SHORTUTF8 = -25, + REGEX_ERROR_RECURSELOOP = -26, + REGEX_ERROR_JIT_STACKLIMIT = -27, + REGEX_ERROR_BADMODE = -28, + REGEX_ERROR_BADENDIANNESS = -29, + REGEX_ERROR_DFA_BADRESTART = -30, + REGEX_ERROR_JIT_BADOPTION = -31, + REGEX_ERROR_BADLENGTH = -32, +}; + +// Regular expression objects are used to match or decompose strings based on +// patterns. +methodmap Regex < Handle +{ + // Compile a regular expression. + // + // @param pattern The regular expression pattern. + // @param flags General flags for the regular expression. + // @param error Error message encountered, if applicable. + // @param maxLen Maximum string length of the error buffer. + // @param errcode Regex type error code encountered, if applicable. + public native Regex(const char[] pattern, int flags = 0, char[] error="", int maxLen = 0, RegexError &errcode = REGEX_ERROR_NONE); + + // Matches a string against a pre-compiled regular expression pattern. + // + // @param str The string to check. + // @param regex Regex Handle from CompileRegex() + // @param ret Error code, if applicable. + // @param offset Offset in the string to start searching from. MatchOffset returns the offset of the match. + // @return Number of captures found or -1 on failure. + // + // @note Use the regex handle passed to this function to extract + // matches with GetSubString(). + public native int Match(const char[] str, RegexError &ret = REGEX_ERROR_NONE, int offset = 0); + + // Gets all matches from a string against a pre-compiled regular expression pattern. + // + // @param str The string to check. + // @param regex Regex Handle from CompileRegex() + // @param ret Error code, if applicable. + // @return Number of matches found or -1 on failure. + // + // @note Use GetSubString() and loop from 0 -> totalmatches - 1. + public native int MatchAll(const char[] str, RegexError &ret = REGEX_ERROR_NONE); + + // Returns a matched substring from a regex handle. + // + // Substring ids start at 0 and end at captures-1, where captures is the + // number returned by Regex.Match or Regex.CaptureCount. + // + // @param regex The regex handle to extract data from. + // @param str_id The index of the expression to get - starts at 0, and ends at captures - 1. + // @param buffer The buffer to set to the matching substring. + // @param maxlen The maximum string length of the buffer. + // @param match Match to get the captures for - starts at 0, and ends at MatchCount() -1 + // @return True if a substring was found, False on fail/error + // + // @note str_id = 0 is the full captured string, anything else is the capture group index. + // if Regex.Match is used match can only be 0 + public native bool GetSubString(int str_id, char[] buffer, int maxlen, int match = 0); + + // Returns number of matches + // + // When using Match this is always 1 or 0 (unless an error occured) + // @return Total number of matches found. + public native int MatchCount(); + + // Returns number of captures for a match + // + // @param match Match to get the number of captures for. Match starts at 0, and ends at MatchCount() -1 + // @return Number of captures in the match. + // + // @note Use GetSubString() and loop from 1 -> captures -1 for str_id to get all captures + public native int CaptureCount(int match = 0); + + // Returns the string offset of a match. + // + // @param match Match to get the offset of. Match starts at 0, and ends at MatchCount() -1 + // @return Offset of the match in the string. + public native int MatchOffset(int match = 0) +}; + +/** + * Precompile a regular expression. Use this if you intend on using the + * same expression multiple times. Pass the regex handle returned here to + * MatchRegex to check for matches. + * + * @param pattern The regular expression pattern. + * @param flags General flags for the regular expression. + * @param error Error message encountered, if applicable. + * @param maxLen Maximum string length of the error buffer. + * @param errcode Regex type error code encountered, if applicable. + * @return Valid regex handle on success, INVALID_HANDLE on failure. + */ +native Regex CompileRegex(const char[] pattern, int flags = 0, char[] error="", int maxLen = 0, RegexError &errcode = REGEX_ERROR_NONE); + +/** + * Matches a string against a pre-compiled regular expression pattern. + * + * @param str The string to check. + * @param regex Regex Handle from CompileRegex() + * @param ret Error code, if applicable. + * @return Number of captures found or -1 on failure. + * + * @note Use the regex handle passed to this function to extract + * matches with GetRegexSubString(). + */ +native int MatchRegex(Handle regex, const char[] str, RegexError &ret = REGEX_ERROR_NONE); + +/** + * Returns a matched substring from a regex handle. + * Substring ids start at 0 and end at captures-1, where captures is the number returned + * by MatchRegex. + * + * @param regex The regex handle to extract data from. + * @param str_id The index of the expression to get - starts at 0, and ends at captures - 1. + * @param buffer The buffer to set to the matching substring. + * @param maxlen The maximum string length of the buffer. + * @return True if a substring was found, False on fail/error + * + * @note str_id = 0 is the full captured string, anything else is the capture group index. + * + */ +native bool GetRegexSubString(Handle regex, int str_id, char[] buffer, int maxlen); + +/** + * Matches a string against a regular expression pattern. + * + * @note If you intend on using the same regular expression pattern + * multiple times, consider using CompileRegex and MatchRegex + * instead of making this function reparse the expression each time. + * + * @param str The string to check. + * @param pattern The regular expression pattern. + * @param flags General flags for the regular expression. + * @param error Error message, if applicable. + * @param maxLen Maximum length of the error buffer. + * @return Number of substrings found or -1 on failure. + */ +stock int SimpleRegexMatch(const char[] str, const char[] pattern, int flags = 0, char[] error="", int maxLen = 0) +{ + Regex regex = new Regex(pattern, flags, error, maxLen); + if (!regex) + return -1; + + int substrings = regex.Match(str); + delete regex; + + return substrings; +} + +/** + * @endsection + */ + +/** + * Do not edit below this line! + */ +public Extension __ext_regex = +{ + name = "Regex Extension", + file = "regex.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; diff --git a/scripting/include/sdkhooks.inc b/scripting/include/sdkhooks.inc new file mode 100644 index 0000000..f58c128 --- /dev/null +++ b/scripting/include/sdkhooks.inc @@ -0,0 +1,412 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2009-2013 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + */ + +#if defined _sdkhooks_included + #endinput +#endif +#define _sdkhooks_included + +// this is obviously _not_ a robust check, but it will solve most conflict and is clean +#if !defined DMG_GENERIC +#define DMG_GENERIC 0 /**< generic damage was done */ +#define DMG_CRUSH (1 << 0) /**< crushed by falling or moving object. + NOTE: It's assumed crush damage is occurring as a result of physics collision, so no extra physics force is generated by crush damage. + DON'T use DMG_CRUSH when damaging entities unless it's the result of a physics collision. You probably want DMG_CLUB instead. */ +#define DMG_BULLET (1 << 1) /**< shot */ +#define DMG_SLASH (1 << 2) /**< cut, clawed, stabbed */ +#define DMG_BURN (1 << 3) /**< heat burned */ +#define DMG_VEHICLE (1 << 4) /**< hit by a vehicle */ +#define DMG_FALL (1 << 5) /**< fell too far */ +#define DMG_BLAST (1 << 6) /**< explosive blast damage */ +#define DMG_CLUB (1 << 7) /**< crowbar, punch, headbutt */ +#define DMG_SHOCK (1 << 8) /**< electric shock */ +#define DMG_SONIC (1 << 9) /**< sound pulse shockwave */ +#define DMG_ENERGYBEAM (1 << 10) /**< laser or other high energy beam */ +#define DMG_PREVENT_PHYSICS_FORCE (1 << 11) /**< Prevent a physics force */ +#define DMG_NEVERGIB (1 << 12) /**< with this bit OR'd in, no damage type will be able to gib victims upon death */ +#define DMG_ALWAYSGIB (1 << 13) /**< with this bit OR'd in, any damage type can be made to gib victims upon death. */ +#define DMG_DROWN (1 << 14) /**< Drowning */ +#define DMG_PARALYZE (1 << 15) /**< slows affected creature down */ +#define DMG_NERVEGAS (1 << 16) /**< nerve toxins, very bad */ +#define DMG_POISON (1 << 17) /**< blood poisoning - heals over time like drowning damage */ +#define DMG_RADIATION (1 << 18) /**< radiation exposure */ +#define DMG_DROWNRECOVER (1 << 19) /**< drowning recovery */ +#define DMG_ACID (1 << 20) /**< toxic chemicals or acid burns */ +#define DMG_SLOWBURN (1 << 21) /**< in an oven */ +#define DMG_REMOVENORAGDOLL (1 << 22) /**< with this bit OR'd in, no ragdoll will be created, and the target will be quietly removed. + use this to kill an entity that you've already got a server-side ragdoll for */ +#define DMG_PHYSGUN (1 << 23) /**< Hit by manipulator. Usually doesn't do any damage. */ +#define DMG_PLASMA (1 << 24) /**< Shot by Cremator */ +#define DMG_AIRBOAT (1 << 25) /**< Hit by the airboat's gun */ +#define DMG_DISSOLVE (1 << 26) /**< Dissolving! */ +#define DMG_BLAST_SURFACE (1 << 27) /**< A blast on the surface of water that cannot harm things underwater */ +#define DMG_DIRECT (1 << 28) +#define DMG_BUCKSHOT (1 << 29) /**< not quite a bullet. Little, rounder, different. */ +#endif + +#if !defined DMG_CRIT + // TF2 crits and minicrits + #define DMG_CRIT DMG_ACID +#endif + +enum SDKHookType +{ + SDKHook_EndTouch, + SDKHook_FireBulletsPost, + SDKHook_OnTakeDamage, + SDKHook_OnTakeDamagePost, + SDKHook_PreThink, + SDKHook_PostThink, + SDKHook_SetTransmit, + SDKHook_Spawn, + SDKHook_StartTouch, + SDKHook_Think, + SDKHook_Touch, + SDKHook_TraceAttack, + SDKHook_TraceAttackPost, + SDKHook_WeaponCanSwitchTo, + SDKHook_WeaponCanUse, + SDKHook_WeaponDrop, + SDKHook_WeaponEquip, + SDKHook_WeaponSwitch, + SDKHook_ShouldCollide, + SDKHook_PreThinkPost, + SDKHook_PostThinkPost, + SDKHook_ThinkPost, + SDKHook_EndTouchPost, + SDKHook_GroundEntChangedPost, + SDKHook_SpawnPost, + SDKHook_StartTouchPost, + SDKHook_TouchPost, + SDKHook_VPhysicsUpdate, + SDKHook_VPhysicsUpdatePost, + SDKHook_WeaponCanSwitchToPost, + SDKHook_WeaponCanUsePost, + SDKHook_WeaponDropPost, + SDKHook_WeaponEquipPost, + SDKHook_WeaponSwitchPost, + SDKHook_Use, + SDKHook_UsePost, + SDKHook_Reload, + SDKHook_ReloadPost, + SDKHook_GetMaxHealth, /**< ep2v and later */ + SDKHook_Blocked, + SDKHook_BlockedPost, + SDKHook_OnTakeDamageAlive, + SDKHook_OnTakeDamageAlivePost, + SDKHook_CanBeAutobalanced, +}; + +/* + Alphabetized for easy readability + + SDKHook_Blocked, + SDKHook_BlockedPost, + + SDKHook_CanBeAutobalanced, + + SDKHook_EndTouch, + SDKHook_EndTouchPost, + + SDKHook_FireBulletsPost, + + SDKHook_GetMaxHealth, (ep2v and later) + + SDKHook_GroundEntChangedPost, + + SDKHook_OnTakeDamage, + SDKHook_OnTakeDamagePost, + + SDKHook_OnTakeDamageAlive, + SDKHook_OnTakeDamageAlivePost, + + SDKHook_PreThink, + SDKHook_PreThinkPost, + + SDKHook_PostThink, + SDKHook_PostThinkPost, + + SDKHook_Reload, + SDKHook_ReloadPost, + + SDKHook_SetTransmit, + + SDKHook_ShouldCollide, + + SDKHook_Spawn, + SDKHook_SpawnPost, + + SDKHook_StartTouch, + SDKHook_StartTouchPost, + + SDKHook_Think, + SDKHook_ThinkPost, + + SDKHook_Touch, + SDKHook_TouchPost, + + SDKHook_TraceAttack, + SDKHook_TraceAttackPost, + + SDKHook_Use, + SDKHook_UsePost, + + SDKHook_VPhysicsUpdate, + SDKHook_VPhysicsUpdatePost, + + SDKHook_WeaponCanSwitchTo, + SDKHook_WeaponCanSwitchToPost, + + SDKHook_WeaponCanUse, + SDKHook_WeaponCanUsePost, + + SDKHook_WeaponDrop, + SDKHook_WeaponDropPost, + + SDKHook_WeaponEquip, + SDKHook_WeaponEquipPost, + + SDKHook_WeaponSwitch, + SDKHook_WeaponSwitchPost +*/ + +enum UseType +{ + Use_Off, + Use_On, + Use_Set, + Use_Toggle +}; + +typeset SDKHookCB +{ + // PreThink/Post + // PostThink/Post + function void (int client); + + // Spawn + function Action (int entity); + + // GroundEntChanged + // SpawnPost + // Think/Post + // VPhysicsUpdate/Post + function void (int entity); + + // EndTouch + // StartTouch + // Touch + // Blocked + function Action (int entity, int other); + + // EndTouchPost + // StartTouchPost + // TouchPost + function void (int entity, int other); + + // SetTransmit + function Action (int entity, int client); + + // WeaponCanSwitchTo + // WeaponCanUse + // WeaponDrop + // WeaponEquip + // WeaponSwitch + function Action (int client, int weapon); + + // WeaponCanSwitchToPost + // WeaponCanUsePost + // WeaponDropPost + // WeaponEquipPost + // WeaponSwitchPost + function void (int client, int weapon); + + // GetMaxHealth (ep2v and later) + function Action (int entity, int &maxhealth); + + // OnTakeDamage + // OnTakeDamageAlive + // Note: The weapon parameter is not used by all games and damage sources. + // Note: Force application is dependent on game and damage type(s) + // SDKHooks 1.0+ + function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype); + // SDKHooks 2.0+ + function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3]); + // SDKHooks 2.1+ (can check for support at runtime using GetFeatureStatus on SDKHook_DmgCustomInOTD capability. + // DON'T attempt to access 'damagecustom' var if feature status != available + function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, + float damageForce[3], float damagePosition[3], int damagecustom); + + // OnTakeDamagePost + // OnTakeDamageAlivePost + function void (int victim, int attacker, int inflictor, float damage, int damagetype); + function void (int victim, int attacker, int inflictor, float damage, int damagetype, int weapon, const float damageForce[3], const float damagePosition[3]); + function void (int victim, int attacker, int inflictor, float damage, int damagetype, int weapon, + const float damageForce[3], const float damagePosition[3], int damagecustom); + + // FireBulletsPost + function void (int client, int shots, const char[] weaponname); + + // TraceAttack + function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &ammotype, int hitbox, int hitgroup); + + // TraceAttackPost + function void (int victim, int attacker, int inflictor, float damage, int damagetype, int ammotype, int hitbox, int hitgroup); + + // ShouldCollide + function bool (int entity, int collisiongroup, int contentsmask, bool originalResult); + + // Use + function Action (int entity, int activator, int caller, UseType type, float value); + + // UsePost + function void (int entity, int activator, int caller, UseType type, float value); + + // Reload + function Action (int weapon); + + // Reload post + function void (int weapon, bool bSuccessful); + + // CanBeAutobalanced + function bool (int client, bool origRet); +}; + + +/** + * @brief When an entity is created + * + * @param entity Entity index + * @param classname Class name + */ +forward void OnEntityCreated(int entity, const char[] classname); + +/** + * @brief When an entity is destroyed + * + * @param entity Entity index + */ +forward void OnEntityDestroyed(int entity); + +/** + * @brief When the game description is retrieved + * + * @note Not supported on ep2v. + * + * @param gameDesc Game description + * @return Plugin_Changed if gameDesc has been edited, else no change. + */ +forward Action OnGetGameDescription(char gameDesc[64]); + +/** + * @brief When the level is initialized + * + * @param mapName Name of the map + * @param mapEntities Entities of the map + * @return Plugin_Changed if mapEntities has been edited, else no change. + */ +forward Action OnLevelInit(const char[] mapName, char mapEntities[2097152]); + +/** + * @brief Hooks an entity + * + * @param entity Entity index + * @param type Type of function to hook + * @param callback Function to call when hook is called + */ +native void SDKHook(int entity, SDKHookType type, SDKHookCB callback); + +/** + * @brief Hooks an entity + * + * @param entity Entity index + * @param type Type of function to hook + * @param callback Function to call when hook is called + * @return bool Hook Successful + */ +native bool SDKHookEx(int entity, SDKHookType type, SDKHookCB callback); + +/** + * @brief Unhooks an entity + * + * @param entity Entity index + * @param type Type of function to unhook + * @param callback Callback function to unhook + */ +native void SDKUnhook(int entity, SDKHookType type, SDKHookCB callback); + +/** + * @brief Applies damage to an entity + * + * @note Force application is dependent on game and damage type(s) + * + * @param entity Entity index taking damage + * @param inflictor Inflictor entity index + * @param attacker Attacker entity index + * @param damage Amount of damage + * @param damageType Bitfield of damage types + * @param weapon Weapon index (orangebox and later) or -1 for unspecified + * @param damageForce Velocity of damage force + * @param damagePosition Origin of damage + */ +native void SDKHooks_TakeDamage(int entity, int inflictor, int attacker, + float damage, int damageType=DMG_GENERIC, int weapon=-1, + const float damageForce[3]=NULL_VECTOR, const float damagePosition[3]=NULL_VECTOR); + +/** + * @brief Forces a client to drop the specified weapon + * + * @param client Client index. + * @param weapon Weapon entity index. + * @param vecTarget Location to toss weapon to, or NULL_VECTOR for default. + * @param vecVelocity Velocity at which to toss weapon, or NULL_VECTOR for default. + * @error Invalid client or weapon entity, weapon not owned by client. + */ +native void SDKHooks_DropWeapon(int client, int weapon, const float vecTarget[3]=NULL_VECTOR, + const float vecVelocity[3]=NULL_VECTOR); + +/** + * Do not edit below this line! + */ +public Extension __ext_sdkhooks = +{ + name = "SDKHooks", + file = "sdkhooks.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; diff --git a/scripting/include/sdktools.inc b/scripting/include/sdktools.inc new file mode 100644 index 0000000..15d5ffc --- /dev/null +++ b/scripting/include/sdktools.inc @@ -0,0 +1,229 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_included + #endinput +#endif +#define _sdktools_included + +#include +#include +#include +#if !defined SDKTOOLS_DISABLE_SOUNDAPI +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum SDKCallType +{ + SDKCall_Static, /**< Static call */ + SDKCall_Entity, /**< CBaseEntity call */ + SDKCall_Player, /**< CBasePlayer call */ + SDKCall_GameRules, /**< CGameRules call */ + SDKCall_EntityList, /**< CGlobalEntityList call */ + SDKCall_Raw, /**< |this| pointer with an arbitrary address */ +}; + +enum SDKLibrary +{ + SDKLibrary_Server, /**< server.dll/server_i486.so */ + SDKLibrary_Engine, /**< engine.dll/engine_*.so */ +}; + +enum SDKFuncConfSource +{ + SDKConf_Virtual = 0, /**< Read a virtual index from the Offsets section */ + SDKConf_Signature = 1, /**< Read a signature from the Signatures section */ + SDKConf_Address = 2, /**< Read an address from the Addresses section */ +}; + +enum SDKType +{ + SDKType_CBaseEntity, /**< CBaseEntity (always as pointer) */ + SDKType_CBasePlayer, /**< CBasePlayer (always as pointer) */ + SDKType_Vector, /**< Vector (pointer, byval, or byref) */ + SDKType_QAngle, /**< QAngles (pointer, byval, or byref) */ + SDKType_PlainOldData, /**< Integer/generic data <=32bit (any) */ + SDKType_Float, /**< Float (any) */ + SDKType_Edict, /**< edict_t (always as pointer) */ + SDKType_String, /**< NULL-terminated string (always as pointer) */ + SDKType_Bool, /**< Boolean (any) */ +}; + +enum SDKPassMethod +{ + SDKPass_Pointer, /**< Pass as a pointer */ + SDKPass_Plain, /**< Pass as plain data */ + SDKPass_ByValue, /**< Pass an object by value */ + SDKPass_ByRef, /**< Pass an object by reference */ +}; + +#define VDECODE_FLAG_ALLOWNULL (1<<0) /**< Allow NULL for pointers */ +#define VDECODE_FLAG_ALLOWNOTINGAME (1<<1) /**< Allow players not in game */ +#define VDECODE_FLAG_ALLOWWORLD (1<<2) /**< Allow World entity */ +#define VDECODE_FLAG_BYREF (1<<3) /**< Floats/ints by reference */ + +#define VENCODE_FLAG_COPYBACK (1<<0) /**< Copy back data once done */ + +/** + * Starts the preparation of an SDK call. + * + * @param type Type of function call this will be. + */ +native void StartPrepSDKCall(SDKCallType type); + +/** + * Sets the virtual index of the SDK call if it is virtual. + * + * @param vtblidx Virtual table index. + */ +native void PrepSDKCall_SetVirtual(int vtblidx); + +/** + * Finds an address in a library and sets it as the address to use for the SDK call. + * + * @param lib Library to use. + * @param signature Binary data to search for in the library. If it starts with '@', + * the bytes parameter is ignored and the signature is interpreted + * as a symbol lookup in the library. + * @param bytes Number of bytes in the binary search string. + * @return True on success, false if nothing was found. + */ +native bool PrepSDKCall_SetSignature(SDKLibrary lib, const char[] signature, int bytes); + +/** + * Uses the given function address for the SDK call. + * + * @param addr Address of function to use. + * @return True on success, false on failure. + */ +native bool PrepSDKCall_SetAddress(Address addr); + +/** + * Finds an address or virtual function index in a GameConfig file and sets it as + * the calling information for the SDK call. + * + * @param gameconf GameConfig Handle, or INVALID_HANDLE to use sdktools.games.txt. + * @param source Whether to look in Offsets or Signatures. + * @param name Name of the property to find. + * @return True on success, false if nothing was found. + */ +native bool PrepSDKCall_SetFromConf(Handle gameconf, SDKFuncConfSource source, const char[] name); + +/** + * Sets the return information of an SDK call. Do not call this if there is no return data. + * This must be called if there is a return value (i.e. it is not necessarily safe to ignore + * the data). + * + * @param type Data type to convert to/from. + * @param pass How the data is passed in C++. + * @param decflags Flags on decoding from the plugin to C++. + * @param encflags Flags on encoding from C++ to the plugin. + */ +native void PrepSDKCall_SetReturnInfo(SDKType type, SDKPassMethod pass, int decflags=0, int encflags=0); + +/** + * Adds a parameter to the calling convention. This should be called in normal ascending order. + * + * @param type Data type to convert to/from. + * @param pass How the data is passed in C++. + * @param decflags Flags on decoding from the plugin to C++. + * @param encflags Flags on encoding from C++ to the plugin. + */ +native void PrepSDKCall_AddParameter(SDKType type, SDKPassMethod pass, int decflags=0, int encflags=0); + +/** + * Finalizes an SDK call preparation and returns the resultant Handle. + * + * @return A new SDKCall Handle on success, or INVALID_HANDLE on failure. + */ +native Handle EndPrepSDKCall(); + +/** + * Calls an SDK function with the given parameters. + * + * If the call type is Entity or Player, the index MUST ALWAYS be the FIRST parameter passed. + * If the call type is GameRules, then nothing special needs to be passed. + * If the return value is a Vector or QAngles, the SECOND parameter must be a Float[3]. + * If the return value is a string, the THIRD parameter must be a String buffer, and the + * FOURTH parameter must be the maximum length. + * All parameters must be passed after the above is followed. Failure to follow these + * rules will result in crashes or wildly unexpected behavior! + * + * If the return value is a float or integer, the return value will be this value. + * If the return value is a CBaseEntity, CBasePlayer, or edict, the return value will + * always be the entity index, or -1 for NULL. + * + * @param call SDKCall Handle. + * @param ... Call Parameters. + * @return Simple return value, if any. + * @error Invalid Handle or internal decoding error. + */ +native any SDKCall(Handle call, any ...); + +/** + * Returns the entity index of the player resource/manager entity. + * + * @return Index of resource entity or -1 if not found. + */ +native int GetPlayerResourceEntity(); + +#include + +/** + * Do not edit below this line! + */ +public Extension __ext_sdktools = +{ + name = "SDKTools", + file = "sdktools.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; diff --git a/scripting/include/sdktools_client.inc b/scripting/include/sdktools_client.inc new file mode 100644 index 0000000..0044634 --- /dev/null +++ b/scripting/include/sdktools_client.inc @@ -0,0 +1,50 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_client_included + #endinput +#endif +#define _sdktools_client_included + +/** + * Sets the client to an inactive state waiting for a new map + * + * @param client The client index + */ +native void InactivateClient(int client); + +/** + * Reconnect a client without dropping the netchannel + * + * @param client The client index + */ +native void ReconnectClient(int client); diff --git a/scripting/include/sdktools_engine.inc b/scripting/include/sdktools_engine.inc new file mode 100644 index 0000000..280d970 --- /dev/null +++ b/scripting/include/sdktools_engine.inc @@ -0,0 +1,66 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_engine_included + #endinput +#endif +#define _sdktools_engine_included + +#define MAX_LIGHTSTYLES 64 + +/** + * Sets a client's "viewing entity." + * + * @param client Client index. + * @param entity Entity index. + * @error Invalid client or entity, lack of mod support, or client not in + * game. + */ +native void SetClientViewEntity(int client, int entity); + +/** + * Sets a light style. + * + * @param style Light style (from 0 to MAX_LIGHTSTYLES-1) + * @param value Light value string (see world.cpp/light.cpp in dlls) + * @error Light style index is out of range. + */ +native void SetLightStyle(int style, const char[] value); + +/** + * Returns the client's eye position. + * + * @param client Player's index. + * @param pos Destination vector to store the client's eye position. + * @error Invalid client index, client not in game, or no mod support. + */ +native void GetClientEyePosition(int client, float pos[3]); diff --git a/scripting/include/sdktools_entinput.inc b/scripting/include/sdktools_entinput.inc new file mode 100644 index 0000000..0b502c2 --- /dev/null +++ b/scripting/include/sdktools_entinput.inc @@ -0,0 +1,51 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_entinput_included + #endinput +#endif +#define _sdktools_entinput_included + +/** + * Invokes a named input method on an entity. + * + * After completion (successful or not), the current global variant is re-initialized. + * + * @param dest Destination entity index. + * @param input Input action. + * @param activator Entity index which initiated the sequence of actions (-1 for a NULL entity). + * @param caller Entity index from which this event is sent (-1 for a NULL entity). + * @param outputid Unknown. + * @return True if successful otherwise false. + * @error Invalid entity index or no mod support. + */ +native bool AcceptEntityInput(int dest, const char[] input, int activator=-1, int caller=-1, int outputid=0); \ No newline at end of file diff --git a/scripting/include/sdktools_entoutput.inc b/scripting/include/sdktools_entoutput.inc new file mode 100644 index 0000000..68931e1 --- /dev/null +++ b/scripting/include/sdktools_entoutput.inc @@ -0,0 +1,108 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_entoutput_included + #endinput +#endif +#define _sdktools_entoutput_included + +/** + * Called when an entity output is fired. + * + * @param output Name of the output that fired. + * @param caller Entity index of the caller. + * @param activator Entity index of the activator. + * @param delay Delay in seconds? before the event gets fired. + * @return Anything other than Plugin_Continue will supress this event, + * returning Plugin_Continue will allow it to propagate the results + * of this output to any entity inputs. + */ +typeset EntityOutput +{ + function void (const char[] output, int caller, int activator, float delay); + function Action (const char[] output, int caller, int activator, float delay); +}; + +/** + * Add an entity output hook on a entity classname + * + * @param classname The classname to hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @error Entity Outputs disabled. + */ +native void HookEntityOutput(const char[] classname, const char[] output, EntityOutput callback); + +/** + * Remove an entity output hook. + * @param classname The classname to hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @return True on success, false if no valid hook was found. + * @error Entity Outputs disabled. + */ +native bool UnhookEntityOutput(const char[] classname, const char[] output, EntityOutput callback); + +/** + * Add an entity output hook on a single entity instance + * + * @param entity The entity on which to add a hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @param once Only fire this hook once and then remove itself. + * @error Entity Outputs disabled or Invalid Entity index. + */ +native void HookSingleEntityOutput(int entity, const char[] output, EntityOutput callback, bool once=false); + +/** + * Remove a single entity output hook. + * + * @param entity The entity on which to remove the hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @return True on success, false if no valid hook was found. + * @error Entity Outputs disabled or Invalid Entity index. + */ +native bool UnhookSingleEntityOutput(int entity, const char[] output, EntityOutput callback); + +/** + * Fire a named output on an entity. + * + * After completion (successful or not), the current global variant is re-initialized. + * + * @param caller Entity index from where the output is fired. + * @param output Output name. + * @param activator Entity index which initiated the sequence of actions (-1 for a NULL entity). + * @param delay Delay before firing the output. + * @error Invalid entity index or no mod support. + */ +native void FireEntityOutput(int caller, const char[] output, int activator=-1, float delay=0.0); \ No newline at end of file diff --git a/scripting/include/sdktools_functions.inc b/scripting/include/sdktools_functions.inc new file mode 100644 index 0000000..c0e42e6 --- /dev/null +++ b/scripting/include/sdktools_functions.inc @@ -0,0 +1,352 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_functions_included + #endinput +#endif +#define _sdktools_functions_included + +/** + * Removes a player's item. + * + * @param client Client index. + * @param item CBaseCombatWeapon entity index. + * @return True on success, false otherwise. + * @error Invalid client or entity, lack of mod support, or client not in + * game. + */ +native bool RemovePlayerItem(int client, int item); + +/** + * Gives a named item to a player. + * + * @param client Client index. + * @param item Item classname (such as weapon_ak47). + * @param iSubType Unknown. + * @return Entity index on success, or -1 on failure. + * @error Invalid client or client not in game, or lack of mod support. + */ +native int GivePlayerItem(int client, const char[] item, int iSubType=0); + +/** + * Returns the weapon in a player's slot. + * + * @param client Client index. + * @param slot Slot index (mod specific). + * @return Entity index on success, -1 if no weapon existed. + * @error Invalid client or client not in game, or lack of mod support. + */ +native int GetPlayerWeaponSlot(int client, int slot); + +/** + * Ignites an entity on fire. + * + * @param entity Entity index. + * @param time Number of seconds to set on fire. + * @param npc True to only affect NPCs. + * @param size Unknown. + * @param level Unknown. + * @error Invalid entity or client not in game, or lack of mod support. + */ +native void IgniteEntity(int entity, float time, bool npc=false, float size=0.0, bool level=false); + +/** + * Extinguishes an entity that is on fire. + * + * @param entity Entity index. + * @error Invalid entity or client not in game, or lack of mod support. + */ +native void ExtinguishEntity(int entity); + +/** + * Teleports an entity. + * + * @param entity Client index. + * @param origin New origin, or NULL_VECTOR for no change. + * @param angles New angles, or NULL_VECTOR for no change. + * @param velocity New velocity, or NULL_VECTOR for no change. + * @error Invalid entity or client not in game, or lack of mod support. + */ +native void TeleportEntity(int entity, const float origin[3], const float angles[3], const float velocity[3]); + +/** + * Forces a player to commit suicide. + * + * @param client Client index. + * @error Invalid client or client not in game, or lack of mod support. + */ +native void ForcePlayerSuicide(int client); + +/** + * Slaps a player in a random direction. + * + * @param client Client index. + * @param health Health to subtract. + * @param sound False to disable the sound effects. + * @error Invalid client or client not in game, or lack of mod support. + */ +native void SlapPlayer(int client, int health=5, bool sound=true); + +/** + * Searches for an entity by classname. + * + * @param startEnt The entity index after which to begin searching from. + * Use -1 to start from the first entity. + * @param classname Classname of the entity to find. + * @return Entity index >= 0 if found, -1 otherwise. + * @error Lack of mod support. + */ +native int FindEntityByClassname(int startEnt, const char[] classname); + +/** + * Returns the client's eye angles. + * + * @param client Player's index. + * @param ang Destination vector to store the client's eye angles. + * @return True on success, false on failure. + * @error Invalid client index, client not in game, or no mod support. + */ +native bool GetClientEyeAngles(int client, float ang[3]); + +/** + * Creates an entity by string name, but does not spawn it (see DispatchSpawn). + * If ForceEdictIndex is not -1, then it will use the edict by that index. If the index is + * invalid or there is already an edict using that index, it will error out. + * + * @param classname Entity classname. + * @param ForceEdictIndex Edict index used by the created entity (ignored on Orangebox and above). + * @return Entity index on success, or -1 on failure. + * @error Invalid edict index, or no mod support. + */ +native int CreateEntityByName(const char[] classname, int ForceEdictIndex=-1); + +/** + * Spawns an entity into the game. + * + * @param entity Entity index of the created entity. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. + */ +native bool DispatchSpawn(int entity); + +/** + * Dispatches a KeyValue into given entity using a string value. + * + * @param entity Destination entity index. + * @param keyName Name of the key. + * @param value String value. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. + */ +native bool DispatchKeyValue(int entity, const char[] keyName, const char[] value); + +/** + * Dispatches a KeyValue into given entity using a floating point value. + * + * @param entity Destination entity index. + * @param keyName Name of the key. + * @param value Floating point value. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. + */ +native bool DispatchKeyValueFloat(int entity, const char[] keyName, float value); + +/** + * Dispatches a KeyValue into given entity using a vector value. + * + * @param entity Destination entity index. + * @param keyName Name of the key. + * @param vec Vector value. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. + */ +native bool DispatchKeyValueVector(int entity, const char[] keyName, const float vec[3]); + +/** + * Returns the entity a client is aiming at. + * + * @param client Client performing the aiming. + * @param only_clients True to exclude all entities but clients. + * @return Entity index being aimed at. + * -1 if no entity is being aimed at. + * -2 if the function is not supported. + * @error Invalid client index or client not in game. + */ +native int GetClientAimTarget(int client, bool only_clients=true); + +/** + * Returns the total number of teams in a game. + * Note: This native should not be called before OnMapStart. + * + * @return Total number of teams. + */ +native int GetTeamCount(); + +/** + * Retrieves the team name based on a team index. + * Note: This native should not be called before OnMapStart. + * + * @param index Team index. + * @param name Buffer to store string in. + * @param maxlength Maximum length of string buffer. + * @error Invalid team index. + */ +native void GetTeamName(int index, char[] name, int maxlength); + +/** + * Returns the score of a team based on a team index. + * Note: This native should not be called before OnMapStart. + * + * @param index Team index. + * @return Score. + * @error Invalid team index. + */ +native int GetTeamScore(int index); + +/** + * Sets the score of a team based on a team index. + * Note: This native should not be called before OnMapStart. + * + * @param index Team index. + * @param value New score value. + * @error Invalid team index. + */ +native void SetTeamScore(int index, int value); + +/** + * Retrieves the number of players in a certain team. + * Note: This native should not be called before OnMapStart. + * + * @param index Team index. + * @return Number of players in the team. + * @error Invalid team index. + */ +native int GetTeamClientCount(int index); + +/** + * Returns the entity index of a team. + * + * @param teamIndex Team index. + * @return Entity index of team. + * @error Invalid team index. + */ +native int GetTeamEntity(int teamIndex); + +/** + * Sets the model to a given entity. + * + * @param entity Entity index. + * @param model Model name. + * @error Invalid entity index, or no mod support. + */ +native void SetEntityModel(int entity, const char[] model); + +/** + * Retrieves the decal file name associated with a given client. + * + * @param client Player's index. + * @param hex Buffer to store the logo filename. + * @param maxlength Maximum length of string buffer. + * @return True on success, otherwise false. + * @error Invalid client or client not in game. + */ +native bool GetPlayerDecalFile(int client, char[] hex, int maxlength); + +/** + * Retrieves the jingle file name associated with a given client. + * + * @param client Player's index. + * @param hex Buffer to store the jingle filename. + * @param maxlength Maximum length of string buffer. + * @return True on success, otherwise false. + * @error Invalid client or client not in game. + */ +native bool GetPlayerJingleFile(int client, char[] hex, int maxlength); + +/** + * Returns the average server network traffic in bytes/sec. + * + * @param in Buffer to store the input traffic velocity. + * @param out Buffer to store the output traffic velocity. + */ +native void GetServerNetStats(float &inAmount, float &outAmout); + +/** + * Equip's a player's weapon. + * + * @param client Client index. + * @param weapon CBaseCombatWeapon entity index. + * @error Invalid client or entity, lack of mod support, or client not in + * game. + */ +native void EquipPlayerWeapon(int client, int weapon); + +/** + * Activates an entity (CBaseAnimating::Activate) + * + * @param entity Entity index. + * @error Invalid entity or lack of mod support. + */ +native void ActivateEntity(int entity); + +/** + * Sets values to client info buffer keys and notifies the engine of the change. + * The change does not get propagated to mods until the next frame. + * + * @param client Player's index. + * @param key Key string. + * @param value Value string. + * @error Invalid client index, or client not connected. + */ +native void SetClientInfo(int client, const char[] key, const char[] value); + +/** + * Changes a client's name. + * + * @param client Player's index. + * @param name New name. + * @error Invalid client index, or client not connected. + */ +native void SetClientName(int client, const char[] name); + +/** + * Gives ammo of a certain type to a player. + * This natives obeys the maximum amount of ammo a player can carry per ammo type. + * + * @param client The client index. + * @param amount Amount of ammo to give. Is capped at ammotype's limit. + * @param ammotype Type of ammo to give to player. + * @param suppressSound If true, don't play the ammo pickup sound. + * + * @return Amount of ammo actually given. + */ +native int GivePlayerAmmo(int client, int amount, int ammotype, bool suppressSound=false); diff --git a/scripting/include/sdktools_gamerules.inc b/scripting/include/sdktools_gamerules.inc new file mode 100644 index 0000000..30527fc --- /dev/null +++ b/scripting/include/sdktools_gamerules.inc @@ -0,0 +1,197 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_gamerules_included + #endinput +#endif +#define _sdktools_gamerules_included + +enum RoundState { + // initialize the game, create teams + RoundState_Init, + + //Before players have joined the game. Periodically checks to see if enough players are ready + //to start a game. Also reverts to this when there are no active players + RoundState_Pregame, + + //The game is about to start, wait a bit and spawn everyone + RoundState_StartGame, + + //All players are respawned, frozen in place + RoundState_Preround, + + //Round is on, playing normally + RoundState_RoundRunning, + + //Someone has won the round + RoundState_TeamWin, + + //Noone has won, manually restart the game, reset scores + RoundState_Restart, + + //Noone has won, restart the game + RoundState_Stalemate, + + //Game is over, showing the scoreboard etc + RoundState_GameOver, + + //Game is over, doing bonus round stuff + RoundState_Bonus, + + //Between rounds + RoundState_BetweenRounds, +}; + +/** + * Retrieves an integer value from a property of the gamerules entity. + * + * @param prop Property name. + * @param size Number of bytes to read (valid values are 1, 2, or 4). + * This value is auto-detected, and the size parameter is + * only used as a fallback in case detection fails. + * @param element Element # (starting from 0) if property is an array. + * @return Value at the given property offset. + * @error Not supported. + */ +native int GameRules_GetProp(const char[] prop, int size=4, int element=0); + +/** + * Sets an integer value for a property of the gamerules entity. + * + * @param prop Property name. + * @param value Value to set. + * @param size Number of bytes to write (valid values are 1, 2, or 4). + * This value is auto-detected, and the size parameter is + * only used as a fallback in case detection fails. + * @param element Element # (starting from 0) if property is an array. + * @param changeState This parameter is ignored. + * @error Not supported. + */ +native void GameRules_SetProp(const char[] prop, any value, int size=4, int element=0, bool changeState=false); + +/** + * Retrieves a float value from a property of the gamerules entity. + * + * @param prop Property name. + * @param element Element # (starting from 0) if property is an array. + * @return Value at the given property offset. + * @error Not supported. + */ +native float GameRules_GetPropFloat(const char[] prop, int element=0); + +/** + * Sets a float value for a property of the gamerules entity. + * + * @param prop Property name. + * @param value Value to set. + * @param element Element # (starting from 0) if property is an array. + * @param changeState This parameter is ignored. + * @error Not supported. + */ +native void GameRules_SetPropFloat(const char[] prop, float value, int element=0, bool changeState=false); + +/** + * Retrieves a entity index from a property of the gamerules entity. + * + * @param prop Property name. + * @param element Element # (starting from 0) if property is an array. + * @return Entity index at the given property. + * If there is no entity, or the entity is not valid, + * then -1 is returned. + * @error Not supported. + */ +native int GameRules_GetPropEnt(const char[] prop, int element=0); + +/** + * Sets an entity index for a property of the gamerules entity. + * + * @param prop Property name. + * @param other Entity index to set, or -1 to unset. + * @param element Element # (starting from 0) if property is an array. + * @param changeState This parameter is ignored. + * @error Not supported. + */ +native void GameRules_SetPropEnt(const char[] prop, int other, int element=0, bool changeState=false); + +/** + * Retrieves a vector of floats from the gamerules entity, given a named network property. + * + * @param prop Property name. + * @param vec Vector buffer to store data in. + * @param element Element # (starting from 0) if property is an array. + * @error Not supported. + */ +native void GameRules_GetPropVector(const char[] prop, float vec[3], int element=0); + +/** + * Sets a vector of floats in the gamerules entity, given a named network property. + * + * @param prop Property name. + * @param vec Vector to set. + * @param element Element # (starting from 0) if property is an array. + * @param changeState This parameter is ignored. + * @error Not supported. + */ +native void GameRules_SetPropVector(const char[] prop, const float vec[3], int element=0, bool changeState=false); + +/** + * Gets a gamerules property as a string. + * + * @param prop Property to use. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @return Number of non-null bytes written. + * @error Not supported. + */ +native int GameRules_GetPropString(const char[] prop, char[] buffer, int maxlen); + +/** + * Sets a gamerules property as a string. + * + * @param prop Property to use. + * @param buffer String to set. + * @param changeState This parameter is ignored. + * @return Number of non-null bytes written. + * @error Not supported. + */ +native int GameRules_SetPropString(const char[] prop, const char[] buffer, bool changeState=false); + +/** + * Gets the current round state. + * + * @return Round state. + * @error Game doesn't support round state. + */ +stock RoundState GameRules_GetRoundState() +{ + return view_as(GameRules_GetProp("m_iRoundState")); +} diff --git a/scripting/include/sdktools_hooks.inc b/scripting/include/sdktools_hooks.inc new file mode 100644 index 0000000..fc0f14a --- /dev/null +++ b/scripting/include/sdktools_hooks.inc @@ -0,0 +1,96 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_hooks_included + #endinput +#endif +#define _sdktools_hooks_included + +#define FEATURECAP_PLAYERRUNCMD_11PARAMS "SDKTools PlayerRunCmd 11Params" + +/** + * @brief Called when a clients movement buttons are being processed + * + * @param client Index of the client. + * @param buttons Copyback buffer containing the current commands (as bitflags - see entity_prop_stocks.inc). + * @param impulse Copyback buffer containing the current impulse command. + * @param vel Players desired velocity. + * @param angles Players desired view angles. + * @param weapon Entity index of the new weapon if player switches weapon, 0 otherwise. + * @param subtype Weapon subtype when selected from a menu. + * @param cmdnum Command number. Increments from the first command sent. + * @param tickcount Tick count. A client's prediction based on the server's GetGameTickCount value. + * @param seed Random seed. Used to determine weapon recoil, spread, and other predicted elements. + * @param mouse Mouse direction (x, y). + * @return Plugin_Handled to block the commands from being processed, Plugin_Continue otherwise. + * + * @note To see if all 11 params are available, use FeatureType_Capability and + * FEATURECAP_PLAYERRUNCMD_11PARAMS. + */ +forward Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]); + +/** + * @brief Called after a clients movement buttons were processed. + * + * @param client Index of the client. + * @param buttons The current commands (as bitflags - see entity_prop_stocks.inc). + * @param impulse The current impulse command. + * @param vel Players desired velocity. + * @param angles Players desired view angles. + * @param weapon Entity index of the new weapon if player switches weapon, 0 otherwise. + * @param subtype Weapon subtype when selected from a menu. + * @param cmdnum Command number. Increments from the first command sent. + * @param tickcount Tick count. A client's prediction based on the server's GetGameTickCount value. + * @param seed Random seed. Used to determine weapon recoil, spread, and other predicted elements. + * @param mouse Mouse direction (x, y). + */ +forward void OnPlayerRunCmdPost(int client, int buttons, int impulse, const float vel[3], const float angles[3], int weapon, int subtype, int cmdnum, int tickcount, int seed, const int mouse[2]); + +/** + * @brief Called when a client requests a file from the server. + * + * @param client Client index. + * @param sFile Requested file path. + * + * @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed. + */ +forward Action OnFileSend(int client, const char[] sFile); + +/** + * @brief Called when a client sends a file to the server. + * + * @param client Client index. + * @param sFile Requested file path. + * + * @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed. + */ +forward Action OnFileReceive(int client, const char[] sFile); diff --git a/scripting/include/sdktools_sound.inc b/scripting/include/sdktools_sound.inc new file mode 100644 index 0000000..aceeafd --- /dev/null +++ b/scripting/include/sdktools_sound.inc @@ -0,0 +1,725 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_sound_included + #endinput +#endif +#define _sdktools_sound_included + +/** + * Sound should be from the target client. + */ +#define SOUND_FROM_PLAYER -2 + +/** + * Sound should be from the listen server player. + */ +#define SOUND_FROM_LOCAL_PLAYER -1 + +/** + * Sound is from the world. + */ +#define SOUND_FROM_WORLD 0 + +/** + * Sound channels. + */ +enum +{ + SNDCHAN_REPLACE = -1, /**< Unknown */ + SNDCHAN_AUTO = 0, /**< Auto */ + SNDCHAN_WEAPON = 1, /**< Weapons */ + SNDCHAN_VOICE = 2, /**< Voices */ + SNDCHAN_ITEM = 3, /**< Items */ + SNDCHAN_BODY = 4, /**< Player? */ + SNDCHAN_STREAM = 5, /**< "Stream channel from the static or dynamic area" */ + SNDCHAN_STATIC = 6, /**< "Stream channel from the static area" */ + SNDCHAN_VOICE_BASE = 7, /**< "Channel for network voice data" */ + SNDCHAN_USER_BASE = 135 /**< Anything >= this is allocated to game code */ +}; + +/** + * Sound flags for the sound emitter system. + */ +enum +{ + SND_NOFLAGS= 0, /**< Nothing */ + SND_CHANGEVOL = 1, /**< Change sound volume */ + SND_CHANGEPITCH = 2, /**< Change sound pitch */ + SND_STOP = 3, /**< Stop the sound */ + SND_SPAWNING = 4, /**< Used in some cases for ambients */ + SND_DELAY = 5, /**< Sound has an initial delay */ + SND_STOPLOOPING = 6, /**< Stop looping all sounds on the entity */ + SND_SPEAKER = 7, /**< Being played by a mic through a speaker */ + SND_SHOULDPAUSE = 8, /**< Pause if game is paused */ +}; + +/** + * Various predefined sound levels in dB. + */ +enum +{ + SNDLEVEL_NONE = 0, /**< None */ + SNDLEVEL_RUSTLE = 20, /**< Rustling leaves */ + SNDLEVEL_WHISPER = 25, /**< Whispering */ + SNDLEVEL_LIBRARY = 30, /**< In a library */ + SNDLEVEL_FRIDGE = 45, /**< Refrigerator */ + SNDLEVEL_HOME = 50, /**< Average home (3.9 attn) */ + SNDLEVEL_CONVO = 60, /**< Normal conversation (2.0 attn) */ + SNDLEVEL_DRYER = 60, /**< Clothes dryer */ + SNDLEVEL_DISHWASHER = 65, /**< Dishwasher/washing machine (1.5 attn) */ + SNDLEVEL_CAR = 70, /**< Car or vacuum cleaner (1.0 attn) */ + SNDLEVEL_NORMAL = 75, /**< Normal sound level */ + SNDLEVEL_TRAFFIC = 75, /**< Busy traffic (0.8 attn) */ + SNDLEVEL_MINIBIKE = 80, /**< Mini-bike, alarm clock (0.7 attn) */ + SNDLEVEL_SCREAMING = 90, /**< Screaming child (0.5 attn) */ + SNDLEVEL_TRAIN = 100, /**< Subway train, pneumatic drill (0.4 attn) */ + SNDLEVEL_HELICOPTER = 105, /**< Helicopter */ + SNDLEVEL_SNOWMOBILE = 110, /**< Snow mobile */ + SNDLEVEL_AIRCRAFT = 120, /**< Auto horn, aircraft */ + SNDLEVEL_RAIDSIREN = 130, /**< Air raid siren */ + SNDLEVEL_GUNFIRE = 140, /**< Gunshot, jet engine (0.27 attn) */ + SNDLEVEL_ROCKET = 180, /**< Rocket launching (0.2 attn) */ +}; + +#define SNDVOL_NORMAL 1.0 /**< Normal volume */ +#define SNDPITCH_NORMAL 100 /**< Normal pitch */ +#define SNDPITCH_LOW 95 /**< A low pitch */ +#define SNDPITCH_HIGH 120 /**< A high pitch */ +#define SNDATTN_NONE 0.0 /**< No attenuation */ +#define SNDATTN_NORMAL 0.8 /**< Normal attenuation */ +#define SNDATTN_STATIC 1.25 /**< Static attenuation? */ +#define SNDATTN_RICOCHET 1.5 /**< Ricochet effect */ +#define SNDATTN_IDLE 2.0 /**< Idle attenuation? */ + +/** + * Prefetches a sound. + * + * @param name Sound file name relative to the "sounds" folder. + */ +native void PrefetchSound(const char[] name); + +/** + * This function is not known to work, and may crash. You should + * not use it. It is provided for backwards compatibility only. + * + * @param name Sound file name relative to the "sounds" folder. + * @return Duration in seconds. + */ +#pragma deprecated Does not work, may crash. +native float GetSoundDuration(const char[] name); + +/** + * Emits an ambient sound. + * + * @param name Sound file name relative to the "sounds" folder. + * @param pos Origin of sound. + * @param entity Entity index to associate sound with. + * @param level Sound level (from 0 to 255). + * @param flags Sound flags. + * @param vol Volume (from 0.0 to 1.0). + * @param pitch Pitch (from 0 to 255). + * @param delay Play delay. + */ +native void EmitAmbientSound(const char[] name, + const float pos[3], + int entity = SOUND_FROM_WORLD, + int level = SNDLEVEL_NORMAL, + int flags = SND_NOFLAGS, + float vol = SNDVOL_NORMAL, + int pitch = SNDPITCH_NORMAL, + float delay = 0.0); + +/** + * Fades a client's volume level toward silence or a given percentage. + * + * @param client Client index. + * @param percent Fade percentage. + * @param outtime Fade out time, in seconds. + * @param holdtime Hold time, in seconds. + * @param intime Fade in time, in seconds. + * @error Invalid client index or client not in game. + */ +native void FadeClientVolume(int client, float percent, float outtime, float holdtime, float intime); + +/** + * Stops a sound. + * + * @param entity Entity index. + * @param channel Channel number. + * @param name Sound file name relative to the "sounds" folder. + */ +native void StopSound(int entity, int channel, const char[] name); + +/** + * Emits a sound to a list of clients. + * + * @param clients Array of client indexes. + * @param numClients Number of clients in the array. + * @param sample Sound file name relative to the "sounds" folder. + * @param entity Entity to emit from. + * @param channel Channel to emit with. + * @param level Sound level. + * @param flags Sound flags. + * @param volume Sound volume. + * @param pitch Sound pitch. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @param ... Optional list of Float[3] arrays to specify additional origins. + * @error Invalid client index. + */ +native void EmitSound(const int[] clients, + int numClients, + const char[] sample, + int entity = SOUND_FROM_PLAYER, + int channel = SNDCHAN_AUTO, + int level = SNDLEVEL_NORMAL, + int flags = SND_NOFLAGS, + float volume = SNDVOL_NORMAL, + int pitch = SNDPITCH_NORMAL, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0, + any ...); + +/** + * Emits a sound or game sound to a list of clients using the latest version of the engine sound interface. + * This native is only available in engines that are greater than or equal to Portal 2. + * + * @param clients Array of client indexes. + * @param numClients Number of clients in the array. + * @param soundEntry Sound entry name. + * @param sample Sound file name relative to the "sounds" folder. + * @param entity Entity to emit from. + * @param channel Channel to emit with. + * @param level Sound level. + * @param seed Sound seed. + * @param flags Sound flags. + * @param volume Sound volume. + * @param pitch Sound pitch. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @param ... Optional list of Float[3] arrays to specify additional origins. + * @error Invalid client index. + */ +native void EmitSoundEntry(const int[] clients, + int numClients, + const char[] soundEntry, + const char[] sample, + int entity = SOUND_FROM_PLAYER, + int channel = SNDCHAN_AUTO, + int level = SNDLEVEL_NORMAL, + int seed = 0, + int flags = SND_NOFLAGS, + float volume = SNDVOL_NORMAL, + int pitch = SNDPITCH_NORMAL, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0, + any ...); + +/** + * Emits a sentence to a list of clients. + * + * @param clients Array of client indexes. + * @param numClients Number of clients in the array. + * @param sentence Sentence index (from PrecacheSentenceFile). + * @param entity Entity to emit from. + * @param channel Channel to emit with. + * @param level Sound level. + * @param flags Sound flags. + * @param volume Sound volume. + * @param pitch Sound pitch. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @param ... Optional list of Float[3] arrays to specify additional origins. + * @error Invalid client index. + */ +native void EmitSentence(const int[] clients, + int numClients, + int sentence, + int entity, + int channel = SNDCHAN_AUTO, + int level = SNDLEVEL_NORMAL, + int flags = SND_NOFLAGS, + float volume = SNDVOL_NORMAL, + int pitch = SNDPITCH_NORMAL, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0, + any ...); + +/** + * Calculates gain of sound on given distance with given sound level in decibel + * + * @param soundlevel decibel of sound, like SNDLEVEL_NORMAL or integer value + * @param distance distance of sound to calculate, not meter or feet, but Source Engine`s normal Coordinate unit + * @return gain of sound. you can multiply this with original sound`s volume to calculate volume on given distance + */ +native float GetDistGainFromSoundLevel(int soundlevel, float distance); + +/** + * Called when an ambient sound is about to be emitted to one or more clients. + * + * NOTICE: all parameters can be overwritten to modify the default behavior. + * + * @param sample Sound file name relative to the "sounds" folder. + * @param entity Entity index associated to the sound. + * @param volume Volume (from 0.0 to 1.0). + * @param level Sound level (from 0 to 255). + * @param pitch Pitch (from 0 to 255). + * @param pos Origin of sound. + * @param flags Sound flags. + * @param delay Play delay. + * @return Plugin_Continue to allow the sound to be played, Plugin_Stop to block it, + * Plugin_Changed when any parameter has been modified. + */ +typedef AmbientSHook = function Action ( + char sample[PLATFORM_MAX_PATH], + int &entity, + float &volume, + int &level, + int &pitch, + float pos[3], + int &flags, + float &delay +); + +typeset NormalSHook +{ + // Called when a sound is going to be emitted to one or more clients. + // NOTICE: all params can be overwritten to modify the default behavior. + // + // @param clients Array of client indexes. + // @param numClients Number of clients in the array (modify this value if you add/remove elements from the client array). + // @param sample Sound file name relative to the "sounds" folder. + // @param entity Entity emitting the sound. + // @param channel Channel emitting the sound. + // @param volume Sound volume. + // @param level Sound level. + // @param pitch Sound pitch. + // @param flags Sound flags. + // @param soundEntry Game sound entry name. (Used in engines newer than Portal 2) + // @param seed Sound seed. (Used in engines newer than Portal 2) + // @return Plugin_Continue to allow the sound to be played, Plugin_Stop to block it, + // Plugin_Changed when any parameter has been modified. + function Action (int clients[MAXPLAYERS], int &numClients, char sample[PLATFORM_MAX_PATH], + int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, + char soundEntry[PLATFORM_MAX_PATH], int &seed); + + // Deprecated. Use other prototype. + function Action (int clients[64], int &numClients, char sample[PLATFORM_MAX_PATH], + int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, + char soundEntry[PLATFORM_MAX_PATH], int &seed); + + // Deprecated. Use other prototype. + function Action (int clients[64], int &numClients, char sample[PLATFORM_MAX_PATH], + int &entity, int &channel, float &volume, int &level, int &pitch, int &flags); +}; + +/** + * Hooks all played ambient sounds. + * + * @param hook Function to use as a hook. + * @error Invalid function hook. + */ +native void AddAmbientSoundHook(AmbientSHook hook); + +/** + * Hooks all played normal sounds. + * + * @param hook Function to use as a hook. + * @error Invalid function hook. + */ +native void AddNormalSoundHook(NormalSHook hook); + +/** + * Unhooks all played ambient sounds. + * + * @param hook Function used for the hook. + * @error Invalid function hook. + */ +native void RemoveAmbientSoundHook(AmbientSHook hook); + +/** + * Unhooks all played normal sounds. + * + * @param hook Function used for the hook. + * @error Invalid function hook. + */ +native void RemoveNormalSoundHook(NormalSHook hook); + +/** + * Wrapper to emit sound to one client. + * + * @param client Client index. + * @param sample Sound file name relative to the "sounds" folder. + * @param entity Entity to emit from. + * @param channel Channel to emit with. + * @param level Sound level. + * @param flags Sound flags. + * @param volume Sound volume. + * @param pitch Sound pitch. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @error Invalid client index. + */ +stock void EmitSoundToClient(int client, + const char[] sample, + int entity = SOUND_FROM_PLAYER, + int channel = SNDCHAN_AUTO, + int level = SNDLEVEL_NORMAL, + int flags = SND_NOFLAGS, + float volume = SNDVOL_NORMAL, + int pitch = SNDPITCH_NORMAL, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0) +{ + int clients[1]; + clients[0] = client; + /* Save some work for SDKTools and remove SOUND_FROM_PLAYER references */ + entity = (entity == SOUND_FROM_PLAYER) ? client : entity; + EmitSound(clients, 1, sample, entity, channel, + level, flags, volume, pitch, speakerentity, + origin, dir, updatePos, soundtime); +} + +/** + * Wrapper to emit sound to all clients. + * + * @param sample Sound file name relative to the "sounds" folder. + * @param entity Entity to emit from. + * @param channel Channel to emit with. + * @param level Sound level. + * @param flags Sound flags. + * @param volume Sound volume. + * @param pitch Sound pitch. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @error Invalid client index. + */ +stock void EmitSoundToAll(const char[] sample, + int entity = SOUND_FROM_PLAYER, + int channel = SNDCHAN_AUTO, + int level = SNDLEVEL_NORMAL, + int flags = SND_NOFLAGS, + float volume = SNDVOL_NORMAL, + int pitch = SNDPITCH_NORMAL, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0) +{ + int[] clients = new int[MaxClients]; + int total = 0; + + for (int i=1; i<=MaxClients; i++) + { + if (IsClientInGame(i)) + { + clients[total++] = i; + } + } + + if (!total) + { + return; + } + + EmitSound(clients, total, sample, entity, channel, + level, flags, volume, pitch, speakerentity, + origin, dir, updatePos, soundtime); +} + +/** + * Converts an attenuation value to a sound level. + * This function is from the HL2SDK. + * + * @param attn Attenuation value. + * @return Integer sound level. + */ +stock int ATTN_TO_SNDLEVEL(float attn) +{ + if (attn > 0.0) + { + return RoundFloat(50.0 + (20.0 / attn)); + } + return 0; +} + +/** + * Retrieves the parameters for a game sound. + * + * Game sounds are found in a game's scripts/game_sound.txt or other files + * referenced from it + * + * Note that if a game sound has a rndwave section, one of them will be returned + * at random. + * + * @param gameSound Name of game sound. + * @param channel Channel to emit with. + * @param level Sound level. + * @param volume Sound volume. + * @param pitch Sound pitch. + * @param sample Sound file name relative to the "sounds" folder. + * @param maxlength Maximum length of sample string buffer. + * @param entity Entity the sound is being emitted from. + * @return True if the sound was successfully retrieved, false if it + * was not found + */ +native bool GetGameSoundParams(const char[] gameSound, + int &channel, + int &soundLevel, + float &volume, + int &pitch, + char[] sample, + int maxlength, + int entity=SOUND_FROM_PLAYER); + +/** + * Emits a game sound to a list of clients. + * + * Game sounds are found in a game's scripts/game_sound.txt or other files + * referenced from it + * + * Note that if a game sound has a rndwave section, one of them will be returned + * at random. + * + * @param clients Array of client indexes. + * @param numClients Number of clients in the array. + * @param gameSound Name of game sound. + * @param entity Entity to emit from. + * @param flags Sound flags. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @return True if the sound was played successfully, false if it failed + * @error Invalid client index. + */ +stock bool EmitGameSound(const int[] clients, + int numClients, + const char[] gameSound, + int entity = SOUND_FROM_PLAYER, + int flags = SND_NOFLAGS, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0) +{ + int channel; + int level; + float volume; + int pitch; + char sample[PLATFORM_MAX_PATH]; + + if (GetGameSoundParams(gameSound, channel, level, volume, pitch, sample, sizeof(sample), entity)) + { + EmitSound(clients, numClients, sample, entity, channel, level, flags, volume, pitch, speakerentity, origin, dir, updatePos, soundtime); + return true; + } + else + { + return false; + } +} + +/** + * Emits an ambient game sound. + * + * Game sounds are found in a game's scripts/game_sound.txt or other files + * referenced from it + * + * Note that if a game sound has a rndwave section, one of them will be returned + * at random. + * + * @param gameSound Name of game sound. + * @param pos Origin of sound. + * @param entity Entity index to associate sound with. + * @param flags Sound flags. + * @param delay Play delay. + */ +stock bool EmitAmbientGameSound(const char[] gameSound, + const float pos[3], + int entity = SOUND_FROM_WORLD, + int flags = SND_NOFLAGS, + float delay = 0.0) +{ + int channel; // This is never actually used for Ambients, but it's a mandatory field to GetGameSoundParams + int level; + float volume; + int pitch; + char sample[PLATFORM_MAX_PATH]; + + if (GetGameSoundParams(gameSound, channel, level, volume, pitch, sample, sizeof(sample), entity)) + { + EmitAmbientSound(sample, pos, entity, level, flags, volume, pitch, delay); + return true; + } + else + { + return false; + } +} + +/** + * Wrapper to emit a game sound to one client. + * + * Game sounds are found in a game's scripts/game_sound.txt or other files + * referenced from it + * + * Note that if a game sound has a rndwave section, one of them will be returned + * at random. + * + * @param client Client index. + * @param gameSound Name of game sound. + * @param entity Entity to emit from. + * @param flags Sound flags. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @error Invalid client index. + */ +stock bool EmitGameSoundToClient(int client, + const char[] gameSound, + int entity = SOUND_FROM_PLAYER, + int flags = SND_NOFLAGS, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0) +{ + int clients[1]; + clients[0] = client; + /* Save some work for SDKTools and remove SOUND_FROM_PLAYER references */ + entity = (entity == SOUND_FROM_PLAYER) ? client : entity; + return EmitGameSound(clients, 1, gameSound, entity, flags, + speakerentity, origin, dir, updatePos, soundtime); +} + +/** + * Wrapper to emit game sound to all clients. + * + * Game sounds are found in a game's scripts/game_sound.txt or other files + * referenced from it + * + * Note that if a game sound has a rndwave section, one of them will be returned + * at random. + * + * @param gameSound Name of game sound. + * @param entity Entity to emit from. + * @param flags Sound flags. + * @param speakerentity Unknown. + * @param origin Sound origin. + * @param dir Sound direction. + * @param updatePos Unknown (updates positions?) + * @param soundtime Alternate time to play sound for. + * @error Invalid client index. + */ +stock bool EmitGameSoundToAll(const char[] gameSound, + int entity = SOUND_FROM_PLAYER, + int flags = SND_NOFLAGS, + int speakerentity = -1, + const float origin[3] = NULL_VECTOR, + const float dir[3] = NULL_VECTOR, + bool updatePos = true, + float soundtime = 0.0) +{ + int[] clients = new int[MaxClients]; + int total = 0; + + for (int i=1; i<=MaxClients; i++) + { + if (IsClientInGame(i)) + { + clients[total++] = i; + } + } + + if (!total) + { + return false; + } + + return EmitGameSound(clients, total, gameSound, entity, flags, + speakerentity, origin, dir, updatePos, soundtime); +} + +/** + * Precache a game sound. + * + * Most games will precache all game sounds on map start, but this is not guaranteed... + * Team Fortress 2 is known to not pre-cache MvM game mode sounds on non-MvM maps. + * + * Due to the above, this native should be called before any calls to GetGameSoundParams, + * EmitGameSound*, or EmitAmbientGameSound. + * + * It should be safe to pass already precached game sounds to this function. + * + * Note: It precaches all files for a game sound. + * + * @param soundname Game sound to precache + * + * @return True if the game sound was found, false if sound did not exist + * or had no files + */ +native bool PrecacheScriptSound(const char[] soundname); diff --git a/scripting/include/sdktools_stocks.inc b/scripting/include/sdktools_stocks.inc new file mode 100644 index 0000000..2af01a8 --- /dev/null +++ b/scripting/include/sdktools_stocks.inc @@ -0,0 +1,75 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_stocks_included + #endinput +#endif +#define _sdktools_stocks_included + +/** + * Given a partial team name, attempts to find a matching team. + * + * The search is performed case insensitively and only against the + * first N characters of the team names, where N is the number of + * characters in the search pattern. + * + * @param name Partial or full team name. + * @return A valid team index on success. + * -1 if no team matched. + * -2 if more than one team matched. + */ +stock int FindTeamByName(const char[] name) +{ + int name_len = strlen(name); + int num_teams = GetTeamCount(); + char team_name[32]; + int found_team = -1; + + for (int i = 0; i < num_teams; i++) + { + GetTeamName(i, team_name, sizeof(team_name)); + + if (strncmp(team_name, name, name_len, false) == 0) + { + if (found_team >= 0) + { + return -2; + } + else + { + found_team = i; + } + } + } + + return found_team; +} diff --git a/scripting/include/sdktools_stringtables.inc b/scripting/include/sdktools_stringtables.inc new file mode 100644 index 0000000..59e13f1 --- /dev/null +++ b/scripting/include/sdktools_stringtables.inc @@ -0,0 +1,180 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_stringtables_included + #endinput +#endif +#define _sdktools_stringtables_included + +#define INVALID_STRING_TABLE -1 /**< An invalid string table index */ +#define INVALID_STRING_INDEX -1 /**< An invalid string index in a table */ + +/** + * Searches for a string table. + * + * @param name Name of string table to find. + * @return A string table index number if found, INVALID_STRING_TABLE otherwise. + */ +native int FindStringTable(const char[] name); + +/** + * Returns the number of string tables that currently exist. + * + * @return Number of string tables that currently exist. + */ +native int GetNumStringTables(); + +/** + * Returns the number of strings that currently exist in a given string table. + * + * @param tableidx A string table index. + * @return Number of strings that currently exist. + * @error Invalid string table index. + */ +native int GetStringTableNumStrings(int tableidx); + +/** + * Returns the maximum number of strings that are allowed in a given string table. + * + * @param tableidx A string table index. + * @return Maximum number of strings allowed. + * @error Invalid string table index. + */ +native int GetStringTableMaxStrings(int tableidx); + +/** + * Retrieves the name of a string table. + * + * @param tableidx A string table index. + * @param name Buffer to store the name of the string table. + * @param maxlength Maximum length of string buffer. + * @return Number of bytes written to the buffer (UTF-8 safe). + * @error Invalid string table index. + */ +native int GetStringTableName(int tableidx, char[] name, int maxlength); + +/** + * Searches for the index of a given string in a string table. + * + * @param tableidx A string table index. + * @param str String to find. + * @return String index if found, INVALID_STRING_INDEX otherwise. + * @error Invalid string table index. + */ +native int FindStringIndex(int tableidx, const char[] str); + +/** + * Retrieves the string at a given index of a string table. + * + * @param tableidx A string table index. + * @param stringidx A string index. + * @param str Buffer to store the string value. + * @param maxlength Maximum length of string buffer. + * @return Number of bytes written to the buffer (UTF-8 safe). + * @error Invalid string table index or string index. + */ +native int ReadStringTable(int tableidx, int stringidx, char[] str, int maxlength); + +/** + * Returns the length of the user data associated with a given string index. + * + * @param tableidx A string table index. + * @param stringidx A string index. + * @return Length of user data. This will be 0 if there is no user data. + * @error Invalid string table index or string index. + */ +native int GetStringTableDataLength(int tableidx, int stringidx); + +/** + * Retrieves the user data associated with a given string index. + * + * @param tableidx A string table index. + * @param stringidx A string index. + * @param userdata Buffer to store the user data. This will be set to "" if there is no user data. + * @param maxlength Maximum length of string buffer. + * @return Number of bytes written to the buffer (UTF-8 safe). + * @error Invalid string table index or string index. + */ +native int GetStringTableData(int tableidx, int stringidx, char[] userdata, int maxlength); + +/** + * Sets the user data associated with a given string index. + * + * @param tableidx A string table index. + * @param stringidx A string index. + * @param userdata User data string that will be set. + * @param length Length of user data string. This should include the null terminator. + * @return Number of bytes written to the buffer (UTF-8 safe). + * @error Invalid string table index or string index. + */ +native int SetStringTableData(int tableidx, int stringidx, const char[] userdata, int length); + +/** + * Adds a string to a given string table. + * + * @param tableidx A string table index. + * @param str String to add. + * @param userdata An optional user data string. + * @param length Length of user data string. This should include the null terminator. + * If set to -1, then user data will be not be altered if the specified string + * already exists in the string table. + */ +native void AddToStringTable(int tableidx, const char[] str, const char[] userdata="", int length=-1); + +/** + * Locks or unlocks the network string tables. + * + * @param lock Determines whether network string tables should be locked. + * True means the tables should be locked for writing; false means unlocked. + * @return Previous lock state. + */ +native bool LockStringTables(bool lock); + +/** + * Adds a file to the downloadables network string table. + * This forces a client to download the file if they do not already have it. + * + * @param filename File that will be added to downloadables table. + */ +stock void AddFileToDownloadsTable(const char[] filename) +{ + static int table = INVALID_STRING_TABLE; + + if (table == INVALID_STRING_TABLE) + { + table = FindStringTable("downloadables"); + } + + bool save = LockStringTables(false); + AddToStringTable(table, filename); + LockStringTables(save); +} diff --git a/scripting/include/sdktools_tempents.inc b/scripting/include/sdktools_tempents.inc new file mode 100644 index 0000000..41c2f33 --- /dev/null +++ b/scripting/include/sdktools_tempents.inc @@ -0,0 +1,232 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_tempents_included + #endinput +#endif +#define _sdktools_tempents_included + +/** + * Called when a temp entity is going to be sent. + * + * @param te_name TE name. + * @param Players Array containing target player indexes. + * @param numClients Number of players in the array. + * @param delay Delay in seconds to send the TE. + * @return Plugin_Continue to allow the transmission of the TE, Plugin_Stop to block it. + */ +typedef TEHook = function Action (const char[] te_name, const int[] Players, int numClients, float delay); + +/** + * Hooks a temp entity. + * + * @param te_name TE name to hook. + * @param hook Function to use as a hook. + * @error Temp Entity name not available or invalid function hook. + */ +native void AddTempEntHook(const char[] te_name, TEHook hook); + +/** + * Removes a temp entity hook. + * + * @param te_name TE name to unhook. + * @param hook Function used for the hook. + * @error Temp Entity name not available or invalid function hook. + */ +native void RemoveTempEntHook(const char[] te_name, TEHook hook); + +/** + * Starts a temp entity transmission. + * + * @param te_name TE name. + * @error Temp Entity name not available. + */ +native void TE_Start(const char[] te_name); + +/** + * Checks if a certain TE property exists. + * + * @param prop Property to use. + * @return True if the property exists, otherwise false. + */ +native bool TE_IsValidProp(const char[] prop); + +/** + * Sets an integer value in the current temp entity. + * + * @param prop Property to use. + * @param value Integer value to set. + * @error Property not found. + */ +native void TE_WriteNum(const char[] prop, int value); + +/** + * Reads an integer value in the current temp entity. + * + * @param prop Property to use. + * @return Property value. + * @error Property not found. + */ +native int TE_ReadNum(const char[] prop); + +/** + * Sets a floating point number in the current temp entity. + * + * @param prop Property to use. + * @param value Floating point number to set. + * @error Property not found. + */ +native void TE_WriteFloat(const char[] prop, float value); + +/** + * Reads a floating point number in the current temp entity. + * + * @param prop Property to use. + * @return Property value. + * @error Property not found. + */ +native float TE_ReadFloat(const char[] prop); + +/** + * Sets a vector in the current temp entity. + * + * @param prop Property to use. + * @param vector Vector to set. + * @error Property not found. + */ +native void TE_WriteVector(const char[] prop, const float vector[3]); + +/** + * Reads a vector in the current temp entity. + * + * @param prop Property to use. + * @param vector Vector to read. + * @error Property not found. + */ +native void TE_ReadVector(const char[] prop, float vector[3]); + +/** + * Sets a QAngle in the current temp entity. + * + * @param prop Property to use. + * @param angles Angles to set. + * @error Property not found. + */ +native void TE_WriteAngles(const char[] prop, const float angles[3]); + +/** + * Sets an array of floats in the current temp entity. + * + * @param prop Property to use. + * @param array Array of values to copy. + * @param arraySize Number of values to copy. + * @error Property not found. + */ +native void TE_WriteFloatArray(const char[] prop, const float[] array, int arraySize); + +/** + * Sends the current temp entity to one or more clients. + * + * @param clients Array containing player indexes to broadcast to. + * @param numClients Number of players in the array. + * @param delay Delay in seconds to send the TE. + * @error Invalid client index or client not in game. + */ +native void TE_Send(const int[] clients, int numClients, float delay=0.0); + +/** + * Sets an encoded entity index in the current temp entity. + * (This is usually used for m_nStartEntity and m_nEndEntity). + * + * @param prop Property to use. + * @param value Value to set. + * @error Property not found. + */ +stock void TE_WriteEncodedEnt(const char[] prop, int value) +{ + int encvalue = (value & 0x0FFF) | ((1 & 0xF)<<12); + TE_WriteNum(prop, encvalue); +} + +/** + * Broadcasts the current temp entity to all clients. + * @note See TE_Start(). + * + * @param delay Delay in seconds to send the TE. + */ +stock void TE_SendToAll(float delay=0.0) +{ + int total = 0; + int[] clients = new int[MaxClients]; + for (int i=1; i<=MaxClients; i++) + { + if (IsClientInGame(i)) + { + clients[total++] = i; + } + } + TE_Send(clients, total, delay); +} + +/** + * Sends the current TE to only a client. + * @note See TE_Start(). + * + * @param client Client to send to. + * @param delay Delay in seconds to send the TE. + * @error Invalid client index or client not in game. + */ +stock void TE_SendToClient(int client, float delay=0.0) +{ + int players[1]; + + players[0] = client; + + TE_Send(players, 1, delay); +} + +/** + * Sends the current TE to all clients that are in + * visible or audible range of the origin. + * @note See TE_Start(). + * @note See GetClientsInRange() + * + * @param origin Coordinates from which to test range. + * @param rangeType Range type to use for filtering clients. + * @param delay Delay in seconds to send the TE. + */ +stock void TE_SendToAllInRange(float origin[3], ClientRangeType rangeType, float delay=0.0) +{ + int[] clients = new int[MaxClients]; + int total = GetClientsInRange(origin, rangeType, clients, MaxClients); + TE_Send(clients, total, delay); +} diff --git a/scripting/include/sdktools_tempents_stocks.inc b/scripting/include/sdktools_tempents_stocks.inc new file mode 100644 index 0000000..853e464 --- /dev/null +++ b/scripting/include/sdktools_tempents_stocks.inc @@ -0,0 +1,443 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _te_stocks_included + #endinput +#endif +#define _te_stocks_included + +/** + * @section TE Explosion flags. + */ +#define TE_EXPLFLAG_NONE 0x0 /**< all flags clear makes default Half-Life explosion */ +#define TE_EXPLFLAG_NOADDITIVE 0x1 /**< sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) */ +#define TE_EXPLFLAG_NODLIGHTS 0x2 /**< do not render dynamic lights */ +#define TE_EXPLFLAG_NOSOUND 0x4 /**< do not play client explosion sound */ +#define TE_EXPLFLAG_NOPARTICLES 0x8 /**< do not draw particles */ +#define TE_EXPLFLAG_DRAWALPHA 0x10 /**< sprite will be drawn alpha */ +#define TE_EXPLFLAG_ROTATE 0x20 /**< rotate the sprite randomly */ +#define TE_EXPLFLAG_NOFIREBALL 0x40 /**< do not draw a fireball */ +#define TE_EXPLFLAG_NOFIREBALLSMOKE 0x80 /**< do not draw smoke with the fireball */ + +/** + * @endsection + */ + +/** + * @section TE Beam flags. + */ +#define FBEAM_STARTENTITY 0x00000001 +#define FBEAM_ENDENTITY 0x00000002 +#define FBEAM_FADEIN 0x00000004 +#define FBEAM_FADEOUT 0x00000008 +#define FBEAM_SINENOISE 0x00000010 +#define FBEAM_SOLID 0x00000020 +#define FBEAM_SHADEIN 0x00000040 +#define FBEAM_SHADEOUT 0x00000080 +#define FBEAM_ONLYNOISEONCE 0x00000100 /**< Only calculate our noise once */ +#define FBEAM_NOTILE 0x00000200 +#define FBEAM_USE_HITBOXES 0x00000400 /**< Attachment indices represent hitbox indices instead when this is set. */ +#define FBEAM_STARTVISIBLE 0x00000800 /**< Has this client actually seen this beam's start entity yet? */ +#define FBEAM_ENDVISIBLE 0x00001000 /**< Has this client actually seen this beam's end entity yet? */ +#define FBEAM_ISACTIVE 0x00002000 +#define FBEAM_FOREVER 0x00004000 +#define FBEAM_HALOBEAM 0x00008000 /**< When drawing a beam with a halo, don't ignore the segments and endwidth */ + +/** + * @endsection + */ + +/** + * Sets up a sparks effect. + * + * @param pos Position of the sparks. + * @param dir Direction of the sparks. + * @param Magnitude Sparks size. + * @param TrailLength Trail lenght of the sparks. + */ +stock void TE_SetupSparks(const float pos[3], const float dir[3], int Magnitude, int TrailLength) +{ + TE_Start("Sparks"); + TE_WriteVector("m_vecOrigin[0]", pos); + TE_WriteVector("m_vecDir", dir); + TE_WriteNum("m_nMagnitude", Magnitude); + TE_WriteNum("m_nTrailLength", TrailLength); +} + +/** + * Sets up a smoke effect. + * + * @param pos Position of the smoke. + * @param Model Precached model index. + * @param Scale Scale of the smoke. + * @param FrameRate Frame rate of the smoke. + */ +stock void TE_SetupSmoke(const float pos[3], int Model, float Scale, int FrameRate) +{ + TE_Start("Smoke"); + TE_WriteVector("m_vecOrigin", pos); + TE_WriteNum("m_nModelIndex", Model); + TE_WriteFloat("m_fScale", Scale); + TE_WriteNum("m_nFrameRate", FrameRate); +} + +/** + * Sets up a dust cloud effect. + * + * @param pos Position of the dust. + * @param dir Direction of the dust. + * @param Size Dust cloud size. + * @param Speed Dust cloud speed. + */ +stock void TE_SetupDust(const float pos[3], const float dir[3], float Size, float Speed) +{ + TE_Start("Dust"); + TE_WriteVector("m_vecOrigin[0]", pos); + TE_WriteVector("m_vecDirection", dir); + TE_WriteFloat("m_flSize", Size); + TE_WriteFloat("m_flSpeed", Speed); +} + +/** + * Sets up a muzzle flash effect. + * + * @param pos Position of the muzzle flash. + * @param angles Rotation angles of the muzzle flash. + * @param Scale Scale of the muzzle flash. + * @param Type Muzzle flash type to render (Mod specific). + */ +stock void TE_SetupMuzzleFlash(const float pos[3], const float angles[3], float Scale, int Type) +{ + TE_Start("MuzzleFlash"); + TE_WriteVector("m_vecOrigin", pos); + TE_WriteVector("m_vecAngles", angles); + TE_WriteFloat("m_flScale", Scale); + TE_WriteNum("m_nType", Type); +} + +/** + * Sets up a metal sparks effect. + * + * @param pos Position of the metal sparks. + * @param dir Direction of the metal sparks. + */ +stock void TE_SetupMetalSparks(const float pos[3], const float dir[3]) +{ + TE_Start("Metal Sparks"); + TE_WriteVector("m_vecPos", pos); + TE_WriteVector("m_vecDir", dir); +} + +/** + * Sets up an energy splash effect. + * + * @param pos Position of the energy splash. + * @param dir Direction of the energy splash. + * @param Explosive Makes the effect explosive. + */ +stock void TE_SetupEnergySplash(const float pos[3], const float dir[3], bool Explosive) +{ + TE_Start("Energy Splash"); + TE_WriteVector("m_vecPos", pos); + TE_WriteVector("m_vecDir", dir); + TE_WriteNum("m_bExplosive", Explosive); +} + +/** + * Sets up an armor ricochet effect. + * + * @param pos Position of the armor ricochet. + * @param dir Direction of the armor ricochet. + */ +stock void TE_SetupArmorRicochet(const float pos[3], const float dir[3]) +{ + TE_Start("Armor Ricochet"); + TE_WriteVector("m_vecPos", pos); + TE_WriteVector("m_vecDir", dir); +} + +/** + * Sets up a glowing sprite effect. + * + * @param pos Position of the sprite. + * @param Model Precached model index. + * @param Life Time duration of the sprite. + * @param Size Sprite size. + * @param Brightness Sprite brightness. + */ +stock void TE_SetupGlowSprite(const float pos[3], int Model, float Life, float Size, int Brightness) +{ + TE_Start("GlowSprite"); + TE_WriteVector("m_vecOrigin", pos); + TE_WriteNum("m_nModelIndex", Model); + TE_WriteFloat("m_fScale", Size); + TE_WriteFloat("m_fLife", Life); + TE_WriteNum("m_nBrightness", Brightness); +} + +/** + * Sets up a explosion effect. + * + * @param pos Explosion position. + * @param Model Precached model index. + * @param Scale Explosion scale. + * @param Framerate Explosion frame rate. + * @param Flags Explosion flags. + * @param Radius Explosion radius. + * @param Magnitude Explosion size. + * @param normal Normal vector to the explosion. + * @param MaterialType Exploded material type. + */ +stock void TE_SetupExplosion(const float pos[3], int Model, float Scale, int Framerate, int Flags, int Radius, int Magnitude, const float normal[3]={0.0, 0.0, 1.0}, int MaterialType='C') +{ + TE_Start("Explosion"); + TE_WriteVector("m_vecOrigin[0]", pos); + TE_WriteVector("m_vecNormal", normal); + TE_WriteNum("m_nModelIndex", Model); + TE_WriteFloat("m_fScale", Scale); + TE_WriteNum("m_nFrameRate", Framerate); + TE_WriteNum("m_nFlags", Flags); + TE_WriteNum("m_nRadius", Radius); + TE_WriteNum("m_nMagnitude", Magnitude); + TE_WriteNum("m_chMaterialType", MaterialType); +} + +/** + * Sets up a blood sprite effect. + * + * @param pos Position of the sprite. + * @param dir Sprite direction. + * @param color Color array (r, g, b, a). + * @param Size Sprite size. + * @param SprayModel Precached model index. + * @param BloodDropModel Precached model index. + */ +stock void TE_SetupBloodSprite(const float pos[3], const float dir[3], const int color[4], int Size, int SprayModel, int BloodDropModel) +{ + TE_Start("Blood Sprite"); + TE_WriteVector("m_vecOrigin", pos); + TE_WriteVector("m_vecDirection", dir); + TE_WriteNum("r", color[0]); + TE_WriteNum("g", color[1]); + TE_WriteNum("b", color[2]); + TE_WriteNum("a", color[3]); + TE_WriteNum("m_nSize", Size); + TE_WriteNum("m_nSprayModel", SprayModel); + TE_WriteNum("m_nDropModel", BloodDropModel); +} + +/** + * Sets up a beam ring point effect. + * + * @param center Center position of the ring. + * @param Start_Radius Initial ring radius. + * @param End_Radius Final ring radius. + * @param ModelIndex Precached model index. + * @param HaloIndex Precached model index. + * @param StartFrame Initial frame to render. + * @param FrameRate Ring frame rate. + * @param Life Time duration of the ring. + * @param Width Beam width. + * @param Amplitude Beam amplitude. + * @param Color Color array (r, g, b, a). + * @param Speed Speed of the beam. + * @param Flags Beam flags. + */ +stock void TE_SetupBeamRingPoint(const float center[3], float Start_Radius, float End_Radius, int ModelIndex, int HaloIndex, int StartFrame, + int FrameRate, float Life, float Width, float Amplitude, const int Color[4], int Speed, int Flags) +{ + TE_Start("BeamRingPoint"); + TE_WriteVector("m_vecCenter", center); + TE_WriteFloat("m_flStartRadius", Start_Radius); + TE_WriteFloat("m_flEndRadius", End_Radius); + TE_WriteNum("m_nModelIndex", ModelIndex); + TE_WriteNum("m_nHaloIndex", HaloIndex); + TE_WriteNum("m_nStartFrame", StartFrame); + TE_WriteNum("m_nFrameRate", FrameRate); + TE_WriteFloat("m_fLife", Life); + TE_WriteFloat("m_fWidth", Width); + TE_WriteFloat("m_fEndWidth", Width); + TE_WriteFloat("m_fAmplitude", Amplitude); + TE_WriteNum("r", Color[0]); + TE_WriteNum("g", Color[1]); + TE_WriteNum("b", Color[2]); + TE_WriteNum("a", Color[3]); + TE_WriteNum("m_nSpeed", Speed); + TE_WriteNum("m_nFlags", Flags); + TE_WriteNum("m_nFadeLength", 0); +} + +/** + * Sets up a point to point beam effect. + * + * @param start Start position of the beam. + * @param end End position of the beam. + * @param ModelIndex Precached model index. + * @param HaloIndex Precached model index. + * @param StartFrame Initial frame to render. + * @param FrameRate Beam frame rate. + * @param Life Time duration of the beam. + * @param Width Initial beam width. + * @param EndWidth Final beam width. + * @param FadeLength Beam fade time duration. + * @param Amplitude Beam amplitude. + * @param Color Color array (r, g, b, a). + * @param Speed Speed of the beam. + */ +stock void TE_SetupBeamPoints(const float start[3], const float end[3], int ModelIndex, int HaloIndex, int StartFrame, int FrameRate, float Life, + float Width, float EndWidth, int FadeLength, float Amplitude, const int Color[4], int Speed) +{ + TE_Start("BeamPoints"); + TE_WriteVector("m_vecStartPoint", start); + TE_WriteVector("m_vecEndPoint", end); + TE_WriteNum("m_nModelIndex", ModelIndex); + TE_WriteNum("m_nHaloIndex", HaloIndex); + TE_WriteNum("m_nStartFrame", StartFrame); + TE_WriteNum("m_nFrameRate", FrameRate); + TE_WriteFloat("m_fLife", Life); + TE_WriteFloat("m_fWidth", Width); + TE_WriteFloat("m_fEndWidth", EndWidth); + TE_WriteFloat("m_fAmplitude", Amplitude); + TE_WriteNum("r", Color[0]); + TE_WriteNum("g", Color[1]); + TE_WriteNum("b", Color[2]); + TE_WriteNum("a", Color[3]); + TE_WriteNum("m_nSpeed", Speed); + TE_WriteNum("m_nFadeLength", FadeLength); +} + +/** + * Sets up an entity to entity laser effect. + * + * @param StartEntity Entity index from where the beam starts. + * @param EndEntity Entity index from where the beam ends. + * @param ModelIndex Precached model index. + * @param HaloIndex Precached model index. + * @param StartFrame Initial frame to render. + * @param FrameRate Beam frame rate. + * @param Life Time duration of the beam. + * @param Width Initial beam width. + * @param EndWidth Final beam width. + * @param FadeLength Beam fade time duration. + * @param Amplitude Beam amplitude. + * @param Color Color array (r, g, b, a). + * @param Speed Speed of the beam. + */ +stock void TE_SetupBeamLaser(int StartEntity, int EndEntity, int ModelIndex, int HaloIndex, int StartFrame, int FrameRate, float Life, + float Width, float EndWidth, int FadeLength, float Amplitude, const int Color[4], int Speed) +{ + TE_Start("BeamLaser"); + TE_WriteEncodedEnt("m_nStartEntity", StartEntity); + TE_WriteEncodedEnt("m_nEndEntity", EndEntity); + TE_WriteNum("m_nModelIndex", ModelIndex); + TE_WriteNum("m_nHaloIndex", HaloIndex); + TE_WriteNum("m_nStartFrame", StartFrame); + TE_WriteNum("m_nFrameRate", FrameRate); + TE_WriteFloat("m_fLife", Life); + TE_WriteFloat("m_fWidth", Width); + TE_WriteFloat("m_fEndWidth", EndWidth); + TE_WriteFloat("m_fAmplitude", Amplitude); + TE_WriteNum("r", Color[0]); + TE_WriteNum("g", Color[1]); + TE_WriteNum("b", Color[2]); + TE_WriteNum("a", Color[3]); + TE_WriteNum("m_nSpeed", Speed); + TE_WriteNum("m_nFadeLength", FadeLength); +} + +/** + * Sets up a beam ring effect. + * + * @param StartEntity Entity index from where the ring starts. + * @param EndEntity Entity index from where the ring ends. + * @param ModelIndex Precached model index. + * @param HaloIndex Precached model index. + * @param StartFrame Initial frame to render. + * @param FrameRate Ring frame rate. + * @param Life Time duration of the ring. + * @param Width Beam width. + * @param Amplitude Beam amplitude. + * @param Color Color array (r, g, b, a). + * @param Speed Speed of the beam. + * @param Flags Beam flags. + */ +stock void TE_SetupBeamRing(int StartEntity, int EndEntity, int ModelIndex, int HaloIndex, int StartFrame, int FrameRate, float Life, float Width, float Amplitude, const int Color[4], int Speed, int Flags) +{ + TE_Start("BeamRing"); + TE_WriteEncodedEnt("m_nStartEntity", StartEntity); + TE_WriteEncodedEnt("m_nEndEntity", EndEntity); + TE_WriteNum("m_nModelIndex", ModelIndex); + TE_WriteNum("m_nHaloIndex", HaloIndex); + TE_WriteNum("m_nStartFrame", StartFrame); + TE_WriteNum("m_nFrameRate", FrameRate); + TE_WriteFloat("m_fLife", Life); + TE_WriteFloat("m_fWidth", Width); + TE_WriteFloat("m_fEndWidth", Width); + TE_WriteFloat("m_fAmplitude", Amplitude); + TE_WriteNum("r", Color[0]); + TE_WriteNum("g", Color[1]); + TE_WriteNum("b", Color[2]); + TE_WriteNum("a", Color[3]); + TE_WriteNum("m_nSpeed", Speed); + TE_WriteNum("m_nFadeLength", 0); + TE_WriteNum("m_nFlags", Flags); +} + +/** + * Sets up a follow beam effect. + * + * @param EntIndex Entity index from where the beam starts. + * @param ModelIndex Precached model index. + * @param HaloIndex Precached model index. + * @param Life Time duration of the beam. + * @param Width Initial beam width. + * @param EndWidth Final beam width. + * @param FadeLength Beam fade time duration. + * @param Color Color array (r, g, b, a). + */ +stock void TE_SetupBeamFollow(int EntIndex, int ModelIndex, int HaloIndex, float Life, float Width, float EndWidth, int FadeLength, const int Color[4]) +{ + TE_Start("BeamFollow"); + TE_WriteEncodedEnt("m_iEntIndex", EntIndex); + TE_WriteNum("m_nModelIndex", ModelIndex); + TE_WriteNum("m_nHaloIndex", HaloIndex); + TE_WriteNum("m_nStartFrame", 0); + TE_WriteNum("m_nFrameRate", 0); + TE_WriteFloat("m_fLife", Life); + TE_WriteFloat("m_fWidth", Width); + TE_WriteFloat("m_fEndWidth", EndWidth); + TE_WriteNum("m_nFadeLength", FadeLength); + TE_WriteNum("r", Color[0]); + TE_WriteNum("g", Color[1]); + TE_WriteNum("b", Color[2]); + TE_WriteNum("a", Color[3]); +} diff --git a/scripting/include/sdktools_trace.inc b/scripting/include/sdktools_trace.inc new file mode 100644 index 0000000..3b9d5ee --- /dev/null +++ b/scripting/include/sdktools_trace.inc @@ -0,0 +1,368 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_trace_included + #endinput +#endif +#define _sdktools_trace_included + +#define CONTENTS_EMPTY 0 /**< No contents. */ +#define CONTENTS_SOLID 0x1 /**< an eye is never valid in a solid . */ +#define CONTENTS_WINDOW 0x2 /**< translucent, but not watery (glass). */ +#define CONTENTS_AUX 0x4 +#define CONTENTS_GRATE 0x8 /**< alpha-tested "grate" textures. Bullets/sight pass through, but solids don't. */ +#define CONTENTS_SLIME 0x10 +#define CONTENTS_WATER 0x20 +#define CONTENTS_MIST 0x40 +#define CONTENTS_OPAQUE 0x80 /**< things that cannot be seen through (may be non-solid though). */ +#define LAST_VISIBLE_CONTENTS 0x80 +#define ALL_VISIBLE_CONTENTS (LAST_VISIBLE_CONTENTS | (LAST_VISIBLE_CONTENTS-1)) +#define CONTENTS_TESTFOGVOLUME 0x100 +#define CONTENTS_UNUSED5 0x200 +#define CONTENTS_UNUSED6 0x4000 +#define CONTENTS_TEAM1 0x800 /**< per team contents used to differentiate collisions. */ +#define CONTENTS_TEAM2 0x1000 /**< between players and objects on different teams. */ +#define CONTENTS_IGNORE_NODRAW_OPAQUE 0x2000 /**< ignore CONTENTS_OPAQUE on surfaces that have SURF_NODRAW. */ +#define CONTENTS_MOVEABLE 0x4000 /**< hits entities which are MOVETYPE_PUSH (doors, plats, etc) */ +#define CONTENTS_AREAPORTAL 0x8000 /**< remaining contents are non-visible, and don't eat brushes. */ +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +/** + * @section currents can be added to any other contents, and may be mixed + */ +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +/** + * @endsection + */ + +#define CONTENTS_ORIGIN 0x1000000 /**< removed before bsp-ing an entity. */ +#define CONTENTS_MONSTER 0x2000000 /**< should never be on a brush, only in game. */ +#define CONTENTS_DEBRIS 0x4000000 +#define CONTENTS_DETAIL 0x8000000 /**< brushes to be added after vis leafs. */ +#define CONTENTS_TRANSLUCENT 0x10000000 /**< auto set if any surface has trans. */ +#define CONTENTS_LADDER 0x20000000 +#define CONTENTS_HITBOX 0x40000000 /**< use accurate hitboxes on trace. */ + +/** + * @section Trace masks. + */ +#define MASK_ALL (0xFFFFFFFF) +#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) /**< everything that is normally solid */ +#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) /**< everything that blocks player movement */ +#define MASK_NPCSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) /**< blocks npc movement */ +#define MASK_WATER (CONTENTS_WATER|CONTENTS_MOVEABLE|CONTENTS_SLIME) /**< water physics in these contents */ +#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_OPAQUE) /**< everything that blocks line of sight for AI, lighting, etc */ +#define MASK_OPAQUE_AND_NPCS (MASK_OPAQUE|CONTENTS_MONSTER) /**< everything that blocks line of sight for AI, lighting, etc, but with monsters added. */ +#define MASK_VISIBLE (MASK_OPAQUE|CONTENTS_IGNORE_NODRAW_OPAQUE) /**< everything that blocks line of sight for players */ +#define MASK_VISIBLE_AND_NPCS (MASK_OPAQUE_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE) /**< everything that blocks line of sight for players, but with monsters added. */ +#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_HITBOX) /**< bullets see these as solid */ +#define MASK_SHOT_HULL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_GRATE) /**< non-raycasted weapons see this as solid (includes grates) */ +#define MASK_SHOT_PORTAL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW) /**< hits solids (not grates) and passes through everything else */ +#define MASK_SOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_GRATE) /**< everything normally solid, except monsters (world+brush only) */ +#define MASK_PLAYERSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_PLAYERCLIP|CONTENTS_GRATE) /**< everything normally solid for player movement, except monsters (world+brush only) */ +#define MASK_NPCSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) /**< everything normally solid for npc movement, except monsters (world+brush only) */ +#define MASK_NPCWORLDSTATIC (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) /**< just the world, used for route rebuilding */ +#define MASK_SPLITAREAPORTAL (CONTENTS_WATER|CONTENTS_SLIME) /**< These are things that can split areaportals */ + +/** + * @endsection + */ + +enum RayType +{ + RayType_EndPoint, /**< The trace ray will go from the start position to the end position. */ + RayType_Infinite /**< The trace ray will go from the start position to infinity using a direction vector. */ +}; + +typeset TraceEntityFilter +{ + /** + * Called on entity filtering. + * + * @param entity Entity index. + * @param contentsMask Contents Mask. + * @return True to allow the current entity to be hit, otherwise false. + */ + function bool (int entity, int contentsMask); + + /** + * Called on entity filtering. + * + * @param entity Entity index. + * @param contentsMask Contents Mask. + * @param data Data value, if used. + * @return True to allow the current entity to be hit, otherwise false. + */ + function bool (int entity, int contentsMask, any data); +}; + +/** + * Get the contents mask and the entity index at the given position. + * + * @param pos World position to test. + * @param entindex Entity index found at the given position (by reference). + * @return Contents mask. + */ +native int TR_GetPointContents(const float pos[3], int &entindex=-1); + +/** + * Get the point contents testing only the given entity index. + * + * @param entindex Entity index to test. + * @param pos World position. + * @return Contents mask. + */ +native int TR_GetPointContentsEnt(int entindex, const float pos[3]); + +/** + * Starts up a new trace ray using a global trace result. + * + * @param pos Starting position of the ray. + * @param vec Depending on RayType, it will be used as the + * ending point, or the direction angle. + * @param flags Trace flags. + * @param rtype Method to calculate the ray direction. + */ +native void TR_TraceRay(const float pos[3], + const float vec[3], + int flags, + RayType rtype); + +/** + * Starts up a new trace hull using a global trace result. + * + * @param pos Starting position of the ray. + * @param vec Ending position of the ray. + * @param mins Hull minimum size. + * @param maxs Hull maximum size. + * @param flags Trace flags. + */ +native void TR_TraceHull(const float pos[3], + const float vec[3], + const float mins[3], + const float maxs[3], + int flags); + +/** + * Starts up a new trace ray using a global trace result and a customized + * trace ray filter. + * + * Calling TR_Trace*Filter or TR_Trace*FilterEx from inside a filter + * function is currently not allowed and may not work. + * + * @param pos Starting position of the ray. + * @param vec Depending on RayType, it will be used as the ending + * point, or the direction angle. + * @param flags Trace flags. + * @param rtype Method to calculate the ray direction. + * @param filter Function to use as a filter. + * @param data Arbitrary data value to pass through to the filter + * function. + */ +native void TR_TraceRayFilter(const float pos[3], + const float vec[3], + int flags, + RayType rtype, + TraceEntityFilter filter, + any data=0); + +/** + * Starts up a new trace hull using a global trace result and a customized + * trace ray filter. + * + * Calling TR_Trace*Filter or TR_Trace*FilterEx from inside a filter + * function is currently not allowed and may not work. + * + * @param pos Starting position of the ray. + * @param vec Depending on RayType, it will be used as the ending + * point, or the direction angle. + * @param mins Hull minimum size. + * @param maxs Hull maximum size. + * @param flags Trace flags. + * @param filter Function to use as a filter. + * @param data Arbitrary data value to pass through to the filter + * function. + */ +native void TR_TraceHullFilter(const float pos[3], + const float vec[3], + const float mins[3], + const float maxs[3], + int flags, + TraceEntityFilter filter, + any data=0); + +/** + * Starts up a new trace ray using a new trace result. + * + * @param pos Starting position of the ray. + * @param vec Depending on RayType, it will be used as the ending + * point, or the direction angle. + * @param flags Trace flags. + * @param rtype Method to calculate the ray direction. + * @return Ray trace handle, which must be closed via CloseHandle(). + */ +native Handle TR_TraceRayEx(const float pos[3], + const float vec[3], + int flags, + RayType rtype); + +/** + * Starts up a new trace hull using a new trace result. + * + * @param pos Starting position of the ray. + * @param vec Ending position of the ray. + * @param mins Hull minimum size. + * @param maxs Hull maximum size. + * @param flags Trace flags. + * @return Ray trace handle, which must be closed via CloseHandle(). + */ +native Handle TR_TraceHullEx(const float pos[3], + const float vec[3], + const float mins[3], + const float maxs[3], + int flags); + +/** + * Starts up a new trace ray using a new trace result and a customized + * trace ray filter. + * + * Calling TR_Trace*Filter or TR_TraceRay*Ex from inside a filter + * function is currently not allowed and may not work. + * + * @param pos Starting position of the ray. + * @param vec Depending on RayType, it will be used as the ending + * point, or the direction angle. + * @param flags Trace flags. + * @param rtype Method to calculate the ray direction. + * @param filter Function to use as a filter. + * @param data Arbitrary data value to pass through to the filter function. + * @return Ray trace handle, which must be closed via CloseHandle(). + */ +native Handle TR_TraceRayFilterEx(const float pos[3], + const float vec[3], + int flags, + RayType rtype, + TraceEntityFilter filter, + any data=0); + +/** + * Starts up a new trace hull using a new trace result and a customized + * trace ray filter. + * + * Calling TR_Trace*Filter or TR_Trace*FilterEx from inside a filter + * function is currently not allowed and may not work. + * + * @param pos Starting position of the ray. + * @param vec Ending position of the ray. + * @param mins Hull minimum size. + * @param maxs Hull maximum size. + * @param flags Trace flags. + * @param filter Function to use as a filter. + * @param data Arbitrary data value to pass through to the filter function. + * @return Ray trace handle, which must be closed via CloseHandle(). + */ +native Handle TR_TraceHullFilterEx(const float pos[3], + const float vec[3], + const float mins[3], + const float maxs[3], + int flags, + TraceEntityFilter filter, + any data=0); + +/** + * Returns the time fraction from a trace result (1.0 means no collision). + * + * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. + * @return Time fraction value of the trace. + * @error Invalid Handle. + */ +native float TR_GetFraction(Handle hndl=INVALID_HANDLE); + +/** + * Returns the collision position of a trace result. + * + * @param pos Vector buffer to store data in. + * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. + * @error Invalid Handle. + */ +native void TR_GetEndPosition(float pos[3], Handle hndl=INVALID_HANDLE); + +/** + * Returns the entity index that collided with the trace. + * + * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. + * @return Entity index or -1 for no collision. + * @error Invalid Handle. + */ +native int TR_GetEntityIndex(Handle hndl=INVALID_HANDLE); + +/** + * Returns if there was any kind of collision along the trace ray. + * + * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. + * @return True if any collision found, otherwise false. + * @error Invalid Handle. + */ +native bool TR_DidHit(Handle hndl=INVALID_HANDLE); + +/** + * Returns in which body hit group the trace collided if any. + * + * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. + * @return Body hit group. + * @error Invalid Handle. + */ +native int TR_GetHitGroup(Handle hndl=INVALID_HANDLE); + +/** + * Find the normal vector to the collision plane of a trace. + * + * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. + * @param normal Vector buffer to store the vector normal to the collision plane + * @error Invalid Handle + */ +native void TR_GetPlaneNormal(Handle hndl, float normal[3]); + +/** + * Tests a point to see if it's outside any playable area + * + * @param pos Vector buffer to store data in. + * @return True if outside world, otherwise false. + */ +native bool TR_PointOutsideWorld(float pos[3]); diff --git a/scripting/include/sdktools_variant_t.inc b/scripting/include/sdktools_variant_t.inc new file mode 100644 index 0000000..9934816 --- /dev/null +++ b/scripting/include/sdktools_variant_t.inc @@ -0,0 +1,93 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_variant_t_included + #endinput +#endif +#define _sdktools_variant_t_included + +/** + * Sets a bool value in the global variant object. + * + * @param val Input value. + */ +native void SetVariantBool(bool val); + +/** + * Sets a string in the global variant object. + * + * @param str Input string. + */ +native void SetVariantString(const char[] str); + +/** + * Sets an integer value in the global variant object. + * + * @param val Input value. + */ +native void SetVariantInt(int val); + +/** + * Sets a floating point value in the global variant object. + * + * @param val Input value. + */ +native void SetVariantFloat(float val); + +/** + * Sets a 3D vector in the global variant object. + * + * @param vec Input vector. + */ +native void SetVariantVector3D(const float vec[3]); + +/** + * Sets a 3D position vector in the global variant object. + * + * @param vec Input position vector. + */ +native void SetVariantPosVector3D(const float vec[3]); + +/** + * Sets a color in the global variant object. + * + * @param color Input color. + */ +native void SetVariantColor(const int color[4]); + +/** + * Sets an entity in the global variant object. + * + * @param entity Entity index. + * @error Invalid entity index. + */ +native void SetVariantEntity(int entity); \ No newline at end of file diff --git a/scripting/include/sdktools_voice.inc b/scripting/include/sdktools_voice.inc new file mode 100644 index 0000000..505a0ab --- /dev/null +++ b/scripting/include/sdktools_voice.inc @@ -0,0 +1,122 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sdktools_voice_included + #endinput +#endif +#define _sdktools_voice_included + +/** + * @section voice flags. + */ +#define VOICE_NORMAL 0 /**< Allow the client to listen and speak normally. */ +#define VOICE_MUTED 1 /**< Mutes the client from speaking to everyone. */ +#define VOICE_SPEAKALL 2 /**< Allow the client to speak to everyone. */ +#define VOICE_LISTENALL 4 /**< Allow the client to listen to everyone. */ +#define VOICE_TEAM 8 /**< Allow the client to always speak to team, even when dead. */ +#define VOICE_LISTENTEAM 16 /**< Allow the client to always hear teammates, including dead ones. */ + +/** + * @endsection + */ + +enum ListenOverride +{ + Listen_Default = 0, /**< Leave it up to the game */ + Listen_No, /**< Can't hear */ + Listen_Yes, /**< Can hear */ +}; + +/** + * Set the client listening flags. + * + * @param client The client index + * @param flags The voice flags + */ +native void SetClientListeningFlags(int client, int flags); + +/** + * Retrieve the client current listening flags. + * + * @param client The client index + * @return The current voice flags + */ +native int GetClientListeningFlags(int client); + +/** + * Set the receiver ability to listen to the sender. + * + * @param iReceiver The listener index. + * @param iSender The sender index. + * @param bListen True if the receiver can listen to the sender, false otherwise. + * @return True if successful otherwise false. + */ +#pragma deprecated Use SetListenOverride() instead +native bool SetClientListening(int iReceiver, int iSender, bool bListen); + +/** + * Retrieves if the receiver can listen to the sender. + * + * @param iReceiver The listener index. + * @param iSender The sender index. + * @return True if successful otherwise false. + */ +#pragma deprecated GetListenOverride() instead +native bool GetClientListening(int iReceiver, int iSender); + +/** + * Override the receiver's ability to listen to the sender. + * + * @param iReceiver The listener index. + * @param iSender The sender index. + * @param override The override of the receiver's ability to listen to the sender. + * @return True if successful otherwise false. + */ +native bool SetListenOverride(int iReceiver, int iSender, ListenOverride override); + +/** + * Retrieves the override of the receiver's ability to listen to the sender. + * + * @param iReceiver The listener index. + * @param iSender The sender index. + * @return The override value. + */ +native ListenOverride GetListenOverride(int iReceiver, int iSender); + +/** + * Retrieves if the muter has muted the mutee. + * + * @param iMuter The muter index. + * @param iMutee The mutee index. + * @return True if muter has muted mutee, false otherwise. + */ +native bool IsClientMuted(int iMuter, int iMutee); diff --git a/scripting/include/sorting.inc b/scripting/include/sorting.inc new file mode 100644 index 0000000..b7e8bf8 --- /dev/null +++ b/scripting/include/sorting.inc @@ -0,0 +1,169 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + + +#if defined _sorting_included + #endinput +#endif +#define _sorting_included + +/** + * Contains sorting orders. + */ +enum SortOrder +{ + Sort_Ascending = 0, /**< Ascending order */ + Sort_Descending = 1, /**< Descending order */ + Sort_Random = 2 /**< Random order */ +}; + +/** + * Data types for ADT Array Sorts + */ +enum SortType +{ + Sort_Integer = 0, + Sort_Float, + Sort_String, +}; + +/** + * Sorts an array of integers. + * + * @param array Array of integers to sort in-place. + * @param array_size Size of the array. + * @param order Sorting order to use. + */ +native void SortIntegers(int[] array, int array_size, SortOrder order = Sort_Ascending); + +/** + * Sorts an array of float point numbers. + * + * @param array Array of floating point numbers to sort in-place. + * @param array_size Size of the array. + * @param order Sorting order to use. + */ +native void SortFloats(float[] array, int array_size, SortOrder order = Sort_Ascending); + +/** + * Sorts an array of strings. + * + * @param array Array of strings to sort in-place. + * @param array_size Size of the array. + * @param order Sorting order to use. + */ +native void SortStrings(char[][] array, int array_size, SortOrder order = Sort_Ascending); + +/** + * Sort comparison function for 1D array elements. + * @note You may need to use explicit tags in order to use data properly. + * + * @param elem1 First element to compare. + * @param elem2 Second element to compare. + * @param array Array that is being sorted (order is undefined). + * @param hndl Handle optionally passed in while sorting. + * @return -1 if first should go before second + * 0 if first is equal to second + * 1 if first should go after second + */ +typedef SortFunc1D = function int (int elem1, int elem2, const int[] array, Handle hndl); + +/** + * Sorts a custom 1D array. You must pass in a comparison function. + * + * @param array Array to sort. + * @param array_size Size of the array to sort. + * @param sortfunc Sort function. + * @param hndl Optional Handle to pass through the comparison calls. + */ +native void SortCustom1D(int[] array, int array_size, SortFunc1D sortfunc, Handle hndl=INVALID_HANDLE); + +/** + * Sort comparison function for 2D array elements (sub-arrays). + * @note You may need to use explicit tags in order to use data properly. + * + * @param elem1 First array to compare. + * @param elem2 Second array to compare. + * @param array Array that is being sorted (order is undefined). + * @param hndl Handle optionally passed in while sorting. + * @return -1 if first should go before second + * 0 if first is equal to second + * 1 if first should go after second + */ +typeset SortFunc2D +{ + function int (int[] elem1, int[] elem2, const int[][] array, Handle hndl); + function int (char[] elem1, char[] elem2, const char[][] array, Handle hndl); +}; + +/** + * Sorts a custom 2D array. You must pass in a comparison function. + * + * @param array Array to sort. + * @param array_size Size of the major array to sort (first index, outermost). + * @param sortfunc Sort comparison function to use. + * @param hndl Optional Handle to pass through the comparison calls. + */ +native void SortCustom2D(any[][] array, int array_size, SortFunc2D sortfunc, Handle hndl=INVALID_HANDLE); + +/** + * Sort an ADT Array. Specify the type as Integer, Float, or String. + * + * @param array Array Handle to sort + * @param order Sort order to use, same as other sorts. + * @param type Data type stored in the ADT Array + */ +native void SortADTArray(Handle array, SortOrder order, SortType type); + +/** + * Sort comparison function for ADT Array elements. Function provides you with + * indexes currently being sorted, use ADT Array functions to retrieve the + * index values and compare. + * + * @param index1 First index to compare. + * @param index2 Second index to compare. + * @param array Array that is being sorted (order is undefined). + * @param hndl Handle optionally passed in while sorting. + * @return -1 if first should go before second + * 0 if first is equal to second + * 1 if first should go after second + */ +typedef SortFuncADTArray = function int (int index1, int index2, Handle array, Handle hndl); + +/** + * Custom sorts an ADT Array. You must pass in a comparison function. + * + * @param array Array Handle to sort + * @param sortfunc Sort comparison function to use + * @param hndl Optional Handle to pass through the comparison calls. + */ +native void SortADTArrayCustom(Handle array, SortFuncADTArray sortfunc, Handle hndl=INVALID_HANDLE); diff --git a/scripting/include/sourcebanspp.inc b/scripting/include/sourcebanspp.inc new file mode 100644 index 0000000..02ab423 --- /dev/null +++ b/scripting/include/sourcebanspp.inc @@ -0,0 +1,106 @@ +// ************************************************************************* +// This file is part of SourceBans++. +// +// Copyright (C) 2014-2016 SourceBans++ Dev Team +// +// SourceBans++ is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, per version 3 of the License. +// +// SourceBans++ is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SourceBans++. If not, see . +// +// This file based off work(s) covered by the following copyright(s): +// +// SourceBans 1.4.11 +// Copyright (C) 2007-2015 SourceBans Team - Part of GameConnect +// Licensed under GNU GPL version 3, or later. +// Page: - +// +// ************************************************************************* + +#if defined _sourcebanspp_included +#endinput +#endif +#define _sourcebanspp_included + +public SharedPlugin __pl_sourcebanspp = +{ + name = "sourcebans++", + file = "sbpp_main.smx", + #if defined REQUIRE_PLUGIN + required = 1 + #else + required = 0 + #endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_sourcebanspp_SetNTVOptional() +{ + MarkNativeAsOptional("SBBanPlayer"); + MarkNativeAsOptional("SBPP_BanPlayer"); + MarkNativeAsOptional("SBPP_ReportPlayer"); +} +#endif + + +/********************************************************* + * Ban Player from server + * + * @param iAdmin The client index of the admin who is banning the client + * @param iTarget The client index of the player to ban + * @param iTime The time to ban the player for (in minutes, 0 = permanent) + * @param sReason The reason to ban the player from the server + * @noreturn + *********************************************************/ +#pragma deprecated Use SBPP_BanPlayer() instead. +native void SBBanPlayer(int iAdmin, int iTarget, int iTime, const char[] sReason); + +/********************************************************* + * Ban Player from server + * + * @param iAdmin The client index of the admin who is banning the client + * @param iTarget The client index of the player to ban + * @param iTime The time to ban the player for (in minutes, 0 = permanent) + * @param sReason The reason to ban the player from the server + * @noreturn + *********************************************************/ +native void SBPP_BanPlayer(int iAdmin, int iTarget, int iTime, const char[] sReason); + +/********************************************************* + * Reports a player + * + * @param iReporter The client index of the reporter + * @param iTarget The client index of the player to report + * @param sReason The reason to report the player + * @noreturn + *********************************************************/ +native void SBPP_ReportPlayer(int iReporter, int iTarget, const char[] sReason); + +/********************************************************* + * Called when the admin banning the player. + * + * @param iAdmin The client index of the admin who is banning the client + * @param iTarget The client index of the player to ban + * @param iTime The time to ban the player for (in minutes, 0 = permanent) + * @param sReason The reason to ban the player from the server + *********************************************************/ +forward void SBPP_OnBanPlayer(int iAdmin, int iTarget, int iTime, const char[] sReason); + +/********************************************************* + * Called when a new report is inserted + * + * @param iReporter The client index of the reporter + * @param iTarget The client index of the player to report + * @param sReason The reason to report the player + * @noreturn + *********************************************************/ +forward void SBPP_OnReportPlayer(int iReporter, int iTarget, const char[] sReason); + +//Yarr! diff --git a/scripting/include/sourcemod.inc b/scripting/include/sourcemod.inc new file mode 100644 index 0000000..3b18863 --- /dev/null +++ b/scripting/include/sourcemod.inc @@ -0,0 +1,681 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _sourcemod_included + #endinput +#endif +#define _sourcemod_included + +/** + * Plugin public information. + */ +struct Plugin +{ + public const char[] name; /**< Plugin Name */ + public const char[] description; /**< Plugin Description */ + public const char[] author; /**< Plugin Author */ + public const char[] version; /**< Plugin Version */ + public const char[] url; /**< Plugin URL */ +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum APLRes +{ + APLRes_Success = 0, /**< Plugin should load */ + APLRes_Failure, /**< Plugin shouldn't load and should display an error */ + APLRes_SilentFailure /**< Plugin shouldn't load but do so silently */ +}; + +/** + * Called when the plugin is fully initialized and all known external references + * are resolved. This is only called once in the lifetime of the plugin, and is + * paired with OnPluginEnd(). + * + * If any run-time error is thrown during this callback, the plugin will be marked + * as failed. + */ +forward void OnPluginStart(); + +/** + * @deprecated Use AskPluginLoad2() instead. + * If a plugin contains both AskPluginLoad() and AskPluginLoad2(), the former will + * not be called, but old plugins with only AskPluginLoad() will work. + */ +#pragma deprecated Use AskPluginLoad2() instead +forward bool AskPluginLoad(Handle myself, bool late, char[] error, int err_max); + +/** + * Called before OnPluginStart, in case the plugin wants to check for load failure. + * This is called even if the plugin type is "private." Any natives from modules are + * not available at this point. Thus, this forward should only be used for explicit + * pre-emptive things, such as adding dynamic natives, setting certain types of load + * filters (such as not loading the plugin for certain games). + * + * @note It is not safe to call externally resolved natives until OnPluginStart(). + * @note Any sort of RTE in this function will cause the plugin to fail loading. + * @note If you do not return anything, it is treated like returning success. + * @note If a plugin has an AskPluginLoad2(), AskPluginLoad() will not be called. + * + * + * @param myself Handle to the plugin. + * @param late Whether or not the plugin was loaded "late" (after map load). + * @param error Error message buffer in case load failed. + * @param err_max Maximum number of characters for error message buffer. + * @return APLRes_Success for load success, APLRes_Failure or APLRes_SilentFailure otherwise + */ +forward APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max); + +/** + * Called when the plugin is about to be unloaded. + * + * It is not necessary to close any handles or remove hooks in this function. + * SourceMod guarantees that plugin shutdown automatically and correctly releases + * all resources. + */ +forward void OnPluginEnd(); + +/** + * Called when the plugin's pause status is changing. + * + * @param pause True if the plugin is being paused, false otherwise. + */ +forward void OnPluginPauseChange(bool pause); + +/** + * Called before every server frame. Note that you should avoid + * doing expensive computations or declaring large local arrays. + */ +forward void OnGameFrame(); + +/** + * Called when the map is loaded. + * + * @note This used to be OnServerLoad(), which is now deprecated. + * Plugins still using the old forward will work. + */ +forward void OnMapStart(); + +/** + * Called right before a map ends. + */ +forward void OnMapEnd(); + +/** + * Called when the map has loaded, servercfgfile (server.cfg) has been + * executed, and all plugin configs are done executing. This is the best + * place to initialize plugin functions which are based on cvar data. + * + * @note This will always be called once and only once per map. It will be + * called after OnMapStart(). + */ +forward void OnConfigsExecuted(); + +/** + * This is called once, right after OnMapStart() but any time before + * OnConfigsExecuted(). It is called after the "exec sourcemod.cfg" + * command and all AutoExecConfig() exec commands have been added to + * the ServerCommand() buffer. + * + * If you need to load per-map settings that override default values, + * adding commands to the ServerCommand() buffer here will guarantee + * that they're set before OnConfigsExecuted(). + * + * Unlike OnMapStart() and OnConfigsExecuted(), this is not called on + * late loads that occur after OnMapStart(). + */ +forward void OnAutoConfigsBuffered(); + +/** + * @deprecated Use OnConfigsExecuted() instead. + */ +#pragma deprecated Use OnConfigsExecuted() instead +forward void OnServerCfg(); + +/** + * Called after all plugins have been loaded. This is called once for + * every plugin. If a plugin late loads, it will be called immediately + * after OnPluginStart(). + */ +forward void OnAllPluginsLoaded(); + +/** + * Returns the calling plugin's Handle. + * + * @return Handle of the calling plugin. + */ +native Handle GetMyHandle(); + +/** + * Returns an iterator that can be used to search through plugins. + * + * @return Handle to iterate with. Must be closed via + * CloseHandle(). + * @error Invalid Handle. + */ +native Handle GetPluginIterator(); + +/** + * Returns whether there are more plugins available in the iterator. + * + * @param iter Handle to the plugin iterator. + * @return True on more plugins, false otherwise. + * @error Invalid Handle. + */ +native bool MorePlugins(Handle iter); + +/** + * Returns the current plugin in the iterator and advances the iterator. + * + * @param iter Handle to the plugin iterator. + * @return Current plugin the iterator is at, before + * the iterator is advanced. + * @error Invalid Handle. + */ +native Handle ReadPlugin(Handle iter); + +/** + * Returns a plugin's status. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @return Status code for the plugin. + * @error Invalid Handle. + */ +native PluginStatus GetPluginStatus(Handle plugin); + +/** + * Retrieves a plugin's file name relative to the plugins folder. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @param buffer Buffer to the store the file name. + * @param maxlength Maximum length of the name buffer. + * @error Invalid Handle. + */ +native void GetPluginFilename(Handle plugin, char[] buffer, int maxlength); + +/** + * Retrieves whether or not a plugin is being debugged. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @return True if being debugged, false otherwise. + * @error Invalid Handle. + */ +native bool IsPluginDebugging(Handle plugin); + +/** + * Retrieves a plugin's public info. + * + * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). + * @param info Plugin info property to retrieve. + * @param buffer Buffer to store info in. + * @param maxlength Maximum length of buffer. + * @return True on success, false if property is not available. + * @error Invalid Handle. + */ +native bool GetPluginInfo(Handle plugin, PluginInfo info, char[] buffer, int maxlength); + +/** + * Finds a plugin by its order in the list from the "plugins list" server + * "sm" command. You should not use this function to loop through all plugins, + * use the iterator instead. Looping through all plugins using this native + * is O(n^2), whereas using the iterator is O(n). + * + * @param order_num Number of the plugin as it appears in "sm plugins list". + * @return Plugin Handle on success, INVALID_HANDLE if no plugin + * matches the given number. + */ +native Handle FindPluginByNumber(int order_num); + +/** + * Causes the plugin to enter a failed state. An error will be thrown and + * the plugin will be paused until it is unloaded or reloaded. + * + * For backwards compatibility, if no extra arguments are passed, no + * formatting is applied. If one or more additional arguments is passed, + * the string is formatted using Format(). If any errors are encountered + * during formatting, both the format specifier string and an additional + * error message are written. + * + * This function does not return, and no further code in the plugin is + * executed. + * + * @param string Format specifier string. + * @param ... Formatting arguments. + * @error Always throws SP_ERROR_ABORT. + */ +native void SetFailState(const char[] string, any ...); + +/** + * Aborts the current callback and throws an error. This function + * does not return in that no code is executed following it. + * + * @param fmt String format. + * @param ... Format arguments. + * @error Always! + */ +native void ThrowError(const char[] fmt, any ...); + +/** + * Gets the system time as a unix timestamp. + * + * @param bigStamp Optional array to store the 64bit timestamp in. + * @return 32bit timestamp (number of seconds since unix epoch). + */ +native int GetTime(int bigStamp[2]={0,0}); + +/** + * Produces a date and/or time string value for a timestamp. + * + * See this URL for valid parameters: + * http://cplusplus.com/reference/clibrary/ctime/strftime.html + * + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules (passing NULL_STRING will use the rules defined in sm_datetime_format). + * @param stamp Optional time stamp. + * @error Buffer too small or invalid time format. + */ +native void FormatTime(char[] buffer, int maxlength, const char[] format, int stamp=-1); + +/** + * Loads a game config file. + * + * @param file File to load. The path must be relative to the 'gamedata' folder under the config folder + * and the extension should be omitted. + * @return A handle to the game config file or INVALID_HANDLE in failure. + */ +native Handle LoadGameConfigFile(const char[] file); + +/** + * Returns an offset value. + * + * @param gc Game config handle. + * @param key Key to retrieve from the offset section. + * @return An offset, or -1 on failure. + */ +native int GameConfGetOffset(Handle gc, const char[] key); + +/** + * Gets the value of a key from the "Keys" section. + * + * @param gc Game config handle. + * @param key Key to retrieve from the Keys section. + * @param buffer Destination string buffer. + * @param maxlen Maximum length of output string buffer. + * @return True if key existed, false otherwise. + */ +native bool GameConfGetKeyValue(Handle gc, const char[] key, char[] buffer, int maxlen); + +/** + * Finds an address calculation in a GameConfig file, + * performs LoadFromAddress on it as appropriate, then returns the final address. + * + * @param gameconf GameConfig Handle, or INVALID_HANDLE to use sdktools.games.txt. + * @param name Name of the property to find. + * @return An address calculated on success, or 0 on failure. + */ +native Address GameConfGetAddress(Handle gameconf, const char[] name); + +/** + * Returns the operating system's "tick count," which is a number of + * milliseconds since the operating system loaded. This can be used + * for basic benchmarks. + * + * @return Tick count in milliseconds. + */ +native int GetSysTickCount(); + +/** + * Specifies that the given config file should be executed after plugin load. + * OnConfigsExecuted() will not be called until the config file has executed, + * but it will be called if the execution fails. + * + * @param autoCreate If true, and the config file does not exist, such a config + * file will be automatically created and populated with + * information from the plugin's registered cvars. + * @param name Name of the config file, excluding the .cfg extension. + * If empty, is assumed. + * @param folder Folder under cfg/ to use. By default this is "sourcemod." + */ +native void AutoExecConfig(bool autoCreate=true, const char[] name="", const char[] folder="sourcemod"); + +/** + * Registers a library name for identifying as a dependency to + * other plugins. + * + * @param name Library name. + */ +native void RegPluginLibrary(const char[] name); + +/** + * Returns whether a library exists. This function should be considered + * expensive; it should only be called on plugin to determine availability + * of resources. Use OnLibraryAdded()/OnLibraryRemoved() to detect changes + * in optional resources. + * + * @param name Library name of a plugin or extension. + * @return True if exists, false otherwise. + */ +native bool LibraryExists(const char[] name); + +/** + * Returns the status of an extension, by filename. + * + * @param name Extension name (like "sdktools.ext"). + * @param error Optional error message buffer. + * @param maxlength Length of optional error message buffer. + * @return -2 if the extension was not found. + * -1 if the extension was found but failed to load. + * 0 if the extension loaded but reported an error. + * 1 if the extension is running without error. + */ +native int GetExtensionFileStatus(const char[] name, char[] error="", int maxlength=0); + +/** + * Called after a library is added that the current plugin references + * optionally. A library is either a plugin name or extension name, as + * exposed via its include file. + * + * @param name Library name. + */ +forward void OnLibraryAdded(const char[] name); + +/** + * Called right before a library is removed that the current plugin references + * optionally. A library is either a plugin name or extension name, as + * exposed via its include file. + * + * @param name Library name. + */ +forward void OnLibraryRemoved(const char[] name); + +#define MAPLIST_FLAG_MAPSFOLDER (1<<0) /**< On failure, use all maps in the maps folder. */ +#define MAPLIST_FLAG_CLEARARRAY (1<<1) /**< If an input array is specified, clear it before adding. */ +#define MAPLIST_FLAG_NO_DEFAULT (1<<2) /**< Do not read "default" or "mapcyclefile" on failure. */ + +/** + * Loads a map list to an ADT Array. + * + * A map list is a list of maps from a file. SourceMod allows easy configuration of + * maplists through addons/sourcemod/configs/maplists.cfg. Each entry is given a + * name and a file (for example, "rtv" => "rtv.cfg"), or a name and a redirection + * (for example, "rtv" => "default"). This native will read a map list entry, + * cache the file, and return the list of maps it holds. + * + * Serial change numbers are used to identify if a map list has changed. Thus, if + * you pass a serial change number and it's equal to what SourceMod currently knows + * about the map list, then SourceMod won't re-parse the file. + * + * If the maps end up being read from the maps folder (MAPLIST_FLAG_MAPSFOLDER), they + * are automatically sorted in alphabetical, ascending order. + * + * Arrays created by this function are temporary and must be freed via CloseHandle(). + * Modifying arrays created by this function will not affect future return values or + * or the contents of arrays returned to other plugins. + * + * @param array Array to store the map list. If INVALID_HANDLE, a new blank + * array will be created. The blocksize should be at least 16; + * otherwise results may be truncated. Items are added to the array + * as strings. The array is never checked for duplicates, and it is + * not read beforehand. Only the serial number is used to detect + * changes. + * @param serial Serial number to identify last known map list change. If -1, the + * the value will not be checked. If the map list has since changed, + * the serial is updated (even if -1 was passed). If there is an error + * finding a valid maplist, then the serial is set to -1. + * @param str Config name, or "default" for the default map list. Config names + * should be somewhat descriptive. For example, the admin menu uses + * a config name of "admin menu". The list names can be configured + * by users in addons/sourcemod/configs/maplists.cfg. + * @param flags MAPLIST_FLAG flags. + * @return On failure: + * INVALID_HANDLE is returned, the serial is set to -1, and the input + * array (if any) is left unchanged. + * On no change: + INVALID_HANDLE is returned, the serial is unchanged, and the input + array (if any) is left unchanged. + * On success: + * A valid array Handle is returned, containing at least one map string. + * If an array was passed, the return value is equal to the passed Array + * Handle. If the passed array was not cleared, it will have grown by at + * least one item. The serial number is updated to a positive number. + * @error Invalid array Handle that is not INVALID_HANDLE. + */ +native Handle ReadMapList(Handle array=INVALID_HANDLE, + int &serial=-1, + const char[] str="default", + int flags=MAPLIST_FLAG_CLEARARRAY); + +/** + * Makes a compatibility binding for map lists. For example, if a function previously used + * "clam.cfg" for map lists, this function will insert a "fake" binding to "clam.cfg" that + * will be overridden if it's in the maplists.cfg file. + * + * @param name Configuration name that would be used with ReadMapList(). + * @param file Default file to use. + */ +native void SetMapListCompatBind(const char[] name, const char[] file); + +/** + * Called when a client has sent chat text. This must return either true or + * false to indicate that a client is or is not spamming the server. + * + * The return value is a hint only. Core or another plugin may decide + * otherwise. + * + * @param client Client index. The server (0) will never be passed. + * @return True if client is spamming the server, false otherwise. + */ +forward bool OnClientFloodCheck(int client); + +/** + * Called after a client's flood check has been computed. This can be used + * by antiflood algorithms to decay/increase flooding weights. + * + * Since the result from "OnClientFloodCheck" isn't guaranteed to be the + * final result, it is generally a good idea to use this to play with other + * algorithms nicely. + * + * @param client Client index. The server (0) will never be passed. + * @param blocked True if client flooded last "say", false otherwise. + */ +forward void OnClientFloodResult(int client, bool blocked); + +/** + * Feature types. + */ +enum FeatureType +{ + /** + * A native function call. + */ + FeatureType_Native, + + /** + * A named capability. This is distinctly different from checking for a + * native, because the underlying functionality could be enabled on-demand + * to improve loading time. Thus a native may appear to exist, but it might + * be part of a set of features that are not compatible with the current game + * or version of SourceMod. + */ + FeatureType_Capability +}; + +/** + * Feature statuses. + */ +enum FeatureStatus +{ + /** + * Feature is available for use. + */ + FeatureStatus_Available, + + /** + * Feature is not available. + */ + FeatureStatus_Unavailable, + + /** + * Feature is not known at all. + */ + FeatureStatus_Unknown +}; + +/** + * Returns whether "GetFeatureStatus" will work. Using this native + * or this function will not cause SourceMod to fail loading on older versions, + * however, GetFeatureStatus will only work if this function returns true. + * + * @return True if GetFeatureStatus will work, false otherwise. + */ +stock bool CanTestFeatures() +{ + return LibraryExists("__CanTestFeatures__"); +} + +/** + * Returns whether a feature exists, and if so, whether it is usable. + * + * @param type Feature type. + * @param name Feature name. + * @return Feature status. + */ +native FeatureStatus GetFeatureStatus(FeatureType type, const char[] name); + +/** + * Requires that a given feature is available. If it is not, SetFailState() + * is called with the given message. + * + * @param type Feature type. + * @param name Feature name. + * @param fmt Message format string, or empty to use default. + * @param ... Message format parameters, if any. + */ +native void RequireFeature(FeatureType type, const char[] name, + const char[] fmt="", any ...); + +/** + * Represents how many bytes we can read from an address with one load + */ +enum NumberType +{ + NumberType_Int8, + NumberType_Int16, + NumberType_Int32 +}; + +enum Address +{ + Address_Null = 0, // a typical invalid result when an address lookup fails +}; + +/** + * Load up to 4 bytes from a memory address. + * + * @param addr Address to a memory location. + * @param size How many bytes should be read. + * @return The value that is stored at that address. + */ +native int LoadFromAddress(Address addr, NumberType size); + +/** + * Store up to 4 bytes to a memory address. + * + * @param addr Address to a memory location. + * @param data Value to store at the address. + * @param size How many bytes should be written. + */ +native void StoreToAddress(Address addr, int data, NumberType size); + +methodmap FrameIterator < Handle { + // Creates a stack frame iterator to build your own stack traces. + // @return New handle to a FrameIterator. + public native FrameIterator(); + + // Advances the iterator to the next stack frame. + // @return True if another frame was fetched and data can be successfully read. + // @error No next element exception. + public native bool Next(); + + // Resets the iterator back to it's starting position. + public native void Reset(); + + // Returns the line number of the current function call. + property bool LineNumber { + public native get(); + } + + // Gets the name of the current function in the call stack. + // + // @param buffer Buffer to copy to. + // @param maxlen Max size of the buffer. + public native void GetFunctionName(char[] buffer, int maxlen); + + // Gets the file path to the current call in the call stack. + // + // @param buffer Buffer to copy to. + // @param maxlen Max size of the buffer. + public native void GetFilePath(char[] buffer, int maxlen); +} + +#include +#include +#include diff --git a/scripting/include/store/store-stocks.inc b/scripting/include/store/store-stocks.inc new file mode 100644 index 0000000..b2d7219 --- /dev/null +++ b/scripting/include/store/store-stocks.inc @@ -0,0 +1,142 @@ +#if defined _store_stocks_included +#endinput +#endif +#define _store_stocks_included + +////////////////////////////////////////////// +//General Stocks for the Store system to use. Some are from SMLib, some are from other places. + +#define SIZE_OF_INT 2147483647 // without 0 + +//From SMLib +stock int String_GetRandom(char[] buffer, int size, int length = 32, const char[] chrs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234556789") +{ + int random; int len; + size--; + + if (chrs[0] != '\0') + { + len = strlen(chrs) - 1; + } + + int n = 0; + while (n < length && n < size) + { + if (chrs[0] == '\0') + { + random = Math_GetRandomInt(33, 126); + buffer[n] = random; + } + else + { + random = Math_GetRandomInt(0, len); + buffer[n] = chrs[random]; + } + + n++; + } + + buffer[length] = '\0'; +} + +//From SMLib +stock Math_GetRandomInt(min, max) +{ + new random = GetURandomInt(); + + if (random == 0) { + random++; + } + + return RoundToCeil(float(random) / (float(SIZE_OF_INT) / float(max - min + 1))) + min - 1; +} + +//My own Invention (Drixevel) (Designed for handles) +stock bool ClearArray2(Handle hGlobalArray) +{ + if (hGlobalArray != null) + { + for (int i = 0; i < GetArraySize(hGlobalArray); i++) + { + Handle hArray = GetArrayCell(hGlobalArray, i); + + if (hArray != null) + { + CloseHandle(hArray); + hArray = null; + } + } + + ClearArray(hGlobalArray); + + return true; + } + + return false; +} + +//Debug Stock... Don't ask why. +stock void GenerateDebugPrint(const char[] sFunc = "N/A") +{ + char sName[64]; + GetPluginFilename(INVALID_HANDLE, sName, sizeof(sName)); + PrintToServer("Name: %s - Function Call: %s", sName, sFunc); +} + +//Because Useful (Kappas all around to KissLick) +stock void PushMenuCell(Handle hndl, const char[] id, int data) +{ + char DataString[64]; + IntToString(data, DataString, sizeof(DataString)); + AddMenuItem(hndl, id, DataString, ITEMDRAW_IGNORE); +} + +stock int GetMenuCell(Handle hndl, const char[] id, int DefaultValue = 0) +{ + int ItemCount = GetMenuItemCount(hndl); + char info[64]; char data[64]; + + for (int i = 0; i < ItemCount; i++) + { + GetMenuItem(hndl, i, info, sizeof(info), _, data, sizeof(data)); + + if (StrEqual(info, id)) + { + return StringToInt(data); + } + } + + return DefaultValue; +} + +stock bool AddMenuItemFormat(Handle &menu, const char[] info, int style = ITEMDRAW_DEFAULT, const char[] format, any...) +{ + char display[128]; + VFormat(display, sizeof(display), format, 5); + + return AddMenuItem(menu, info, display, style); +} + +stock void PushMenuString(Handle hndl, const char[] id, const char[] data) +{ + AddMenuItem(hndl, id, data, ITEMDRAW_IGNORE); +} + +stock bool GetMenuString(Handle hndl, const char[] id, char[] Buffer, int size) +{ + int ItemCount = GetMenuItemCount(hndl); + char info[64]; char data[64]; + + for (int i = 0; i < ItemCount; i++) + { + GetMenuItem(hndl, i, info, sizeof(info), _, data, sizeof(data)); + + if (StrEqual(info, id)) + { + strcopy(Buffer, size, data); + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/scripting/include/string.inc b/scripting/include/string.inc new file mode 100644 index 0000000..a4febcd --- /dev/null +++ b/scripting/include/string.inc @@ -0,0 +1,548 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _string_included + #endinput +#endif +#define _string_included + +/** + * @global Unless otherwise noted, all string functions which take in a + * writable buffer and maximum length should have the null terminator INCLUDED + * in the length. This means that this is valid: + * strcopy(string, sizeof(string), ...) + */ + +/** + * Calculates the length of a string. + * + * @param str String to check. + * @return Number of valid character bytes in the string. + */ +native int strlen(const char[] str); + +/** + * Tests whether a string is found inside another string. + * + * @param str String to search in. + * @param substr Substring to find inside the original string. + * @param caseSensitive If true (default), search is case sensitive. + * If false, search is case insensitive. + * @return -1 on failure (no match found). Any other value + * indicates a position in the string where the match starts. + */ +native int StrContains(const char[] str, const char[] substr, bool caseSensitive=true); + +/** + * Compares two strings lexographically. + * + * @param str1 First string (left). + * @param str2 Second string (right). + * @param caseSensitive If true (default), comparison is case sensitive. + * If false, comparison is case insensitive. + * @return -1 if str1 < str2 + * 0 if str1 == str2 + * 1 if str1 > str2 + */ +native int strcmp(const char[] str1, const char[] str2, bool caseSensitive=true); + +/** + * Compares two strings parts lexographically. + * + * @param str1 First string (left). + * @param str2 Second string (right). + * @param num Number of characters to compare. + * @param caseSensitive If true (default), comparison is case sensitive. + * If false, comparison is case insensitive. + * @return -1 if str1 < str2 + * 0 if str1 == str2 + * 1 if str1 > str2 + */ +native int strncmp(const char[] str1, const char[] str2, int num, bool caseSensitive=true); + +/** + * Backwards compatible stock - StrCompare is now strcmp + * @deprecated Renamed to strcmp + */ +#pragma deprecated Use strcmp() instead +stock int StrCompare(const char[] str1, const char[] str2, bool caseSensitive=true) +{ + return strcmp(str1, str2, caseSensitive); +} + +/** + * Returns whether two strings are equal. + * + * @param str1 First string (left). + * @param str2 Second string (right). + * @param caseSensitive If true (default), comparison is case sensitive. + * If false, comparison is case insensitive. + * @return True if equal, false otherwise. + */ +stock bool StrEqual(const char[] str1, const char[] str2, bool caseSensitive=true) +{ + return (strcmp(str1, str2, caseSensitive) == 0); +} + +/** + * Copies one string to another string. + * @note If the destination buffer is too small to hold the source string, the + * destination will be truncated. + * + * @param dest Destination string buffer to copy to. + * @param destLen Destination buffer length (includes null terminator). + * @param source Source string buffer to copy from. + * @return Number of cells written. + */ +native int strcopy(char[] dest, int destLen, const char[] source); + +/** + * Backwards compatibility stock - use strcopy + * @deprecated Renamed to strcopy + */ +#pragma deprecated Use strcopy() instead +stock int StrCopy(char[] dest, int destLen, const char[] source) +{ + return strcopy(dest, destLen, source); +} + +/** + * Formats a string according to the SourceMod format rules (see documentation). + * + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @return Number of cells written. + */ +native int Format(char[] buffer, int maxlength, const char[] format, any ...); + +/** + * Formats a string according to the SourceMod format rules (see documentation). + * @note This is the same as Format(), except none of the input buffers can + * overlap the same memory as the output buffer. Since this security + * check is removed, it is slightly faster. + * + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @return Number of cells written. + */ +native int FormatEx(char[] buffer, int maxlength, const char[] format, any ...); + +/** + * Formats a string according to the SourceMod format rules (see documentation). + * @note This is the same as Format(), except it grabs parameters from a + * parent parameter stack, rather than a local. This is useful for + * implementing your own variable argument functions. + * + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @param format Formatting rules. + * @param varpos Argument number which contains the '...' symbol. + * Note: Arguments start at 1. + * @return Number of bytes written. + */ +native int VFormat(char[] buffer, int maxlength, const char[] format, int varpos); + +/** + * Converts a string to an integer. + * + * @param str String to convert. + * @param nBase Numerical base to use. 10 is default. + * @return Integer conversion of string, or 0 on failure. + */ +native int StringToInt(const char[] str, int nBase=10); + +/** + * Converts a string to an integer with some more options. + * + * @param str String to convert. + * @param result Variable to store the result in. + * @param nBase Numerical base to use. 10 is default. + * @return Number of characters consumed. + */ +native int StringToIntEx(const char[] str, int &result, int nBase=10); + +/** + * Converts an integer to a string. + * + * @param num Integer to convert. + * @param str Buffer to store string in. + * @param maxlength Maximum length of string buffer. + * @return Number of cells written to buffer. + */ +native int IntToString(int num, char[] str, int maxlength); + +/** + * Converts a string to a floating point number. + * + * @param str String to convert to a float. + * @return Floating point result, or 0.0 on error. + */ +native float StringToFloat(const char[] str); + +/** + * Converts a string to a floating point number with some more options. + * + * @param str String to convert to a float. + * @param result Variable to store result in. + * @return Number of characters consumed. + */ +native int StringToFloatEx(const char[] str, float &result); + +/** + * Converts a floating point number to a string. + * + * @param num Floating point number to convert. + * @param str Buffer to store string in. + * @param maxlength Maximum length of string buffer. + * @return Number of cells written to buffer. + */ +native int FloatToString(float num, char[] str, int maxlength); + +/** + * Finds the first "argument" in a string; either a set of space + * terminated characters, or a fully quoted string. After the + * argument is found, whitespace is read until the next portion + * of the string is reached. If nothing remains, -1 is returned. + * Otherwise, the index to the first character is returned. + * + * @param source Source input string. + * @param arg Stores argument read from string. + * @param argLen Maximum length of argument buffer. + * @return Index to next piece of string, or -1 if none. + */ +native int BreakString(const char[] source, char[] arg, int argLen); + +/** + * Backwards compatibility stock - use BreakString + * @deprecated Renamed to BreakString. + */ +#pragma deprecated Use BreakString() instead +stock int StrBreak(const char[] source, char[] arg, int argLen) +{ + return BreakString(source, arg, argLen); +} + +/** + * Removes whitespace characters from the beginning and end of a string. + * + * @param str The string to trim. + * @return Number of bytes written (UTF-8 safe). + */ +native int TrimString(char[] str); + +/** + * Returns text in a string up until a certain character sequence is reached. + * + * @param source Source input string. + * @param split A string which specifies a search point to break at. + * @param part Buffer to store string part. + * @param partLen Maximum length of the string part buffer. + * @return -1 if no match was found; otherwise, an index into source + * marking the first index after the searched text. The + * index is always relative to the start of the input string. + */ +native int SplitString(const char[] source, const char[] split, char[] part, int partLen); + +/** + * Given a string, replaces all occurrences of a search string with a + * replacement string. + * + * @param text String to perform search and replacements on. + * @param maxlength Maximum length of the string buffer. + * @param search String to search for. + * @param replace String to replace the search string with. + * @param caseSensitive If true (default), search is case sensitive. + * @return Number of replacements that were performed. + */ +native int ReplaceString(char[] text, int maxlength, const char[] search, const char[] replace, bool caseSensitive=true); + +/** + * Given a string, replaces the first occurrence of a search string with a + * replacement string. + * + * @param text String to perform search and replacements on. + * @param maxlength Maximum length of the string buffer. + * @param search String to search for. + * @param replace String to replace the search string with. + * @param searchLen If higher than -1, its value will be used instead of + * a strlen() call on the search parameter. + * @param replaceLen If higher than -1, its value will be used instead of + * a strlen() call on the replace parameter. + * @param caseSensitive If true (default), search is case sensitive. + * @return Index into the buffer (relative to the start) from where + * the last replacement ended, or -1 if no replacements were + * made. + */ +native int ReplaceStringEx(char[] text, int maxlength, const char[] search, const char[] replace, int searchLen=-1, int replaceLen=-1, bool caseSensitive=true); + +/** + * Returns the number of bytes a character is using. This is + * for multi-byte characters (UTF-8). For normal ASCII characters, + * this will return 1. + * + * @param source Source input string. + * @return Number of bytes the current character uses. + */ +native int GetCharBytes(const char[] source); + +/** + * Returns whether a character is an ASCII alphabet character. + * + * @note Multi-byte characters will always return false. + * + * @param chr Character to test. + * @return True if character is alphabetical, otherwise false. + */ +native bool IsCharAlpha(int chr); + +/** + * Returns whether a character is numeric. + * + * @note Multi-byte characters will always return false. + * + * @param chr Character to test. + * @return True if character is numeric, otherwise false. + */ +native bool IsCharNumeric(int chr); + +/** + * Returns whether a character is whitespace. + * + * @note Multi-byte characters will always return false. + * + * @param chr Character to test. + * @return True if character is whitespace, otherwise false. + */ +native bool IsCharSpace(int chr); + +/** + * Returns if a character is multi-byte or not. + * + * @param chr Character to test. + * @return 0 for a normal 7-bit ASCII character, + * otherwise number of bytes in multi-byte character. + */ +native int IsCharMB(int chr); + +/** + * Returns whether an alphabetic character is uppercase. + * + * @note Multi-byte characters will always return false. + * + * @param chr Character to test. + * @return True if character is uppercase, otherwise false. + */ +native bool IsCharUpper(int chr); + +/** + * Returns whether an alphabetic character is lowercase. + * + * @note Multi-byte characters will always return false. + * + * @param chr Character to test. + * @return True if character is lowercase, otherwise false. + */ +native bool IsCharLower(int chr); + +/** + * Strips a quote pair off a string if it exists. That is, the following + * replace rule is applied once: ^"(.*)"$ -> ^\1$ + * + * Note that the leading and trailing quotes will only be removed if both + * exist. Otherwise, the string is left unmodified. This function should + * be considered O(k) (all characters get shifted down). + * + * @param text String to modify (in place). + * @return True if string was modified, false if there was no + * set of quotes. + */ +native bool StripQuotes(char[] text); + +/** + * Returns a lowercase character to an uppercase character. + * + * @param chr Character to convert. + * @return Uppercase character on success, + * no change on failure. + */ +stock int CharToUpper(int chr) +{ + if (IsCharLower(chr)) + { + return (chr & ~(1<<5)); + } + return chr; +} + +/** + * Returns an uppercase character to a lowercase character. + * + * @param chr Character to convert. + * @return Lowercase character on success, + * no change on failure. + */ +stock int CharToLower(int chr) +{ + if (IsCharUpper(chr)) + { + return (chr | (1<<5)); + } + return chr; +} + +/** + * Finds the first occurrence of a character in a string. + * + * @param str String. + * @param c Character to search for. + * @param reverse False (default) to search forward, true to search + * backward. + * @return The index of the first occurrence of the character + * in the string, or -1 if the character was not found. + */ +stock int FindCharInString(const char[] str, char c, bool reverse = false) +{ + int len = strlen(str); + + if (!reverse) { + for (int i = 0; i < len; i++) { + if (str[i] == c) + return i; + } + } else { + for (int i = len - 1; i >= 0; i--) { + if (str[i] == c) + return i; + } + } + + return -1; +} + +/** + * Concatenates one string onto another. + * + * @param buffer String to append to. + * @param maxlength Maximum length of entire buffer. + * @param source Source string to concatenate. + * @return Number of bytes written. + */ +stock int StrCat(char[] buffer, int maxlength, const char[] source) +{ + int len = strlen(buffer); + if (len >= maxlength) + { + return 0; + } + + return Format(buffer[len], maxlength-len, "%s", source); +} + +/** + * Breaks a string into pieces and stores each piece into an array of buffers. + * + * @param text The string to split. + * @param split The string to use as a split delimiter. + * @param buffers An array of string buffers (2D array). + * @param maxStrings Number of string buffers (first dimension size). + * @param maxStringLength Maximum length of each string buffer. + * @param copyRemainder False (default) discard excess pieces, true to ignore + * delimiters after last piece. + * @return Number of strings retrieved. + */ +stock int ExplodeString(const char[] text, const char[] split, char[][] buffers, int maxStrings, + int maxStringLength, bool copyRemainder = false) +{ + int reloc_idx, idx, total; + + if (maxStrings < 1 || !split[0]) + { + return 0; + } + + while ((idx = SplitString(text[reloc_idx], split, buffers[total], maxStringLength)) != -1) + { + reloc_idx += idx; + if (++total == maxStrings) + { + if (copyRemainder) + { + strcopy(buffers[total-1], maxStringLength, text[reloc_idx-idx]); + } + return total; + } + } + + strcopy(buffers[total++], maxStringLength, text[reloc_idx]); + + return total; +} + +/** + * Joins an array of strings into one string, with a "join" string inserted in + * between each given string. This function complements ExplodeString. + * + * @param strings An array of strings. + * @param numStrings Number of strings in the array. + * @param join The join string to insert between each string. + * @param buffer Output buffer to write the joined string to. + * @param maxLength Maximum length of the output buffer. + * @return Number of bytes written to the output buffer. + */ +stock int ImplodeStrings(const char[][] strings, int numStrings, const char[] join, char[] buffer, int maxLength) +{ + int total, length, part_length; + int join_length = strlen(join); + for (int i=0; i. + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +static int TestNumber = 0; +static char TestContext[255]; + +stock void SetTestContext(const char[] context) +{ + strcopy(TestContext, sizeof(TestContext), context); +} + +stock void AssertEq(const char[] text, int cell1, int cell2) +{ + TestNumber++; + if (cell1 == cell2) { + PrintToServer("[%d] %s: %s == %d OK", TestNumber, TestContext, text, cell2); + } else { + PrintToServer("[%d] %s FAIL: %s should be %d, got %d", TestNumber, TestContext, text, cell2, cell1); + ThrowError("test %d (%s in %s) failed", TestNumber, text, TestContext); + } +} + +stock void AssertFalse(const char[] text, bool value) +{ + TestNumber++; + if (!value) { + PrintToServer("[%d] %s: %s == false OK", TestNumber, TestContext, text, value); + } else { + PrintToServer("[%d] %s FAIL: %s should be false, got true", TestNumber, TestContext, text); + ThrowError("test %d (%s in %s) failed", TestNumber, text, TestContext); + } +} + +stock void AssertTrue(const char[] text, bool value) +{ + TestNumber++; + if (value) { + PrintToServer("[%d] %s: %s == true OK", TestNumber, TestContext, text, value); + } else { + PrintToServer("[%d] %s FAIL: %s should be true, got false", TestNumber, TestContext, text); + ThrowError("test %d (%s in %s) failed", TestNumber, text, TestContext); + } +} diff --git a/scripting/include/textparse.inc b/scripting/include/textparse.inc new file mode 100644 index 0000000..4680179 --- /dev/null +++ b/scripting/include/textparse.inc @@ -0,0 +1,243 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _textparse_included + #endinput +#endif +#define _textparse_included + + +/******************************** + * Everything below describes the SMC Parse, or "SourceMod Configuration" format. + * This parser is entirely event based. You must hook events to receive data. + * The file format itself is nearly identical to Valve's KeyValues format. + ********************************/ + +/** + * Parse result directive. + */ +enum SMCResult +{ + SMCParse_Continue, /**< Continue parsing */ + SMCParse_Halt, /**< Stop parsing here */ + SMCParse_HaltFail /**< Stop parsing and return failure */ +}; + +/** + * Parse error codes. + */ +enum SMCError +{ + SMCError_Okay = 0, /**< No error */ + SMCError_StreamOpen, /**< Stream failed to open */ + SMCError_StreamError, /**< The stream died... somehow */ + SMCError_Custom, /**< A custom handler threw an error */ + SMCError_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */ + SMCError_InvalidSection2, /**< A section was declared without any header */ + SMCError_InvalidSection3, /**< A section ending was declared with too many unknown tokens */ + SMCError_InvalidSection4, /**< A section ending has no matching beginning */ + SMCError_InvalidSection5, /**< A section beginning has no matching ending */ + SMCError_InvalidTokens, /**< There were too many unidentifiable strings on one line */ + SMCError_TokenOverflow, /**< The token buffer overflowed */ + SMCError_InvalidProperty1, /**< A property was declared outside of any section */ +}; + +// Called when parsing is started. +// +// @param smc The SMC Parse Handle. +typedef SMC_ParseStart = function void (SMCParser smc); + +// Called when the parser is entering a new section or sub-section. +// +// Note: Enclosing quotes are always stripped. +// +// @param smc The SMC Parser. +// @param name String containing section name. +// @param opt_quotes True if the section name was quote-enclosed in the file. +// @return An SMCResult action to take. +typedef SMC_NewSection = function SMCResult (SMCParser smc, const char[] name, bool opt_quotes); + +// Called when the parser finds a new key/value pair. +// +// Note: Enclosing quotes are always stripped. +// +// @param smc The SMCParser. +// @param key String containing key name. +// @param value String containing value name. +// @param key_quotes Whether or not the key was enclosed in quotes. +// @param value_quotes Whether or not the value was enclosed in quotes. +// @return An SMCResult action to take. +typedef SMC_KeyValue = function SMCResult (SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes); + +// Called when the parser finds the end of the current section. +// +// @param smc The SMCParser. +// @return An SMCResult action to take. +typedef SMC_EndSection = function SMCResult (SMCParser smc); + +// Called when parsing is halted. +// +// @param smc The SMCParser. +// @param halted True if abnormally halted, false otherwise. +// @param failed True if parsing failed, false otherwise. +typedef SMC_ParseEnd = function void (SMCParser smc, bool halted, bool failed); + +// Callback for whenever a new line of text is about to be parsed. +// +// @param smc The SMCParser. +// @param line A string containing the raw line from the file. +// @param lineno The line number it occurs on. +// @return An SMCResult action to take. +typedef SMC_RawLine = function SMCResult (SMCParser smc, const char[] line, int lineno); + +// An SMCParser is a callback-driven parser for SourceMod configuration files. +// SMC files are similar to Valve KeyValues format, with two key differences: +// (1) SMC cannot handle single-item entries (that is, a key with no value). +// (2) SMC files can have multi-line comment blocks, whereas KeyValues cannot. +methodmap SMCParser < Handle +{ + // Create a new SMC file format parser. + public native SMCParser(); + + // Parses an SMC file. + // + // @param file A string containing the file path. + // @param line An optional variable to store the last line number read. + // @param col An optional variable to store the last column number read. + // @return An SMCParseError result. + public native SMCError ParseFile(const char[] file, int &line = 0, int &col = 0); + + // Sets the callback for receiving SMC_ParseStart events. + property SMC_ParseStart OnStart { + public native set(SMC_ParseStart func); + } + + // Sets the callback for receiving SMC_ParseEnd events. + property SMC_ParseEnd OnEnd { + public native set(SMC_ParseEnd func); + } + + // Sets the callback for receiving SMC_NewSection events. + property SMC_NewSection OnEnterSection { + public native set(SMC_NewSection func); + } + + // Sets the callback for receiving SMC_EndSection events. + property SMC_EndSection OnLeaveSection { + public native set(SMC_EndSection func); + } + + // Sets the callback for receiving SMC_KeyValue events. + property SMC_KeyValue OnKeyValue { + public native set(SMC_KeyValue func); + } + + // Sets the callback for receiving SMC_RawLine events. + property SMC_RawLine OnRawLine { + public native set(SMC_RawLine func); + } + + // Gets an error string for an SMCError code. + // + // @param error The SMCParseError code. + // @param buffer A string buffer for the error (contents undefined on failure). + // @param buf_max The maximum size of the buffer. + // @return The number of characters written to buffer. + public native void GetErrorString(SMCError error, char[] buffer, int buf_max); +}; + +/** + * Creates a new SMC file format parser. This is used to set parse hooks. + * + * @return A new Handle to an SMC Parse structure. + */ +native SMCParser SMC_CreateParser(); + +/** + * Parses an SMC file. + * + * @param smc A Handle to an SMC Parse structure. + * @param file A string containing the file path. + * @param line An optional by reference cell to store the last line number read. + * @param col An optional by reference cell to store the last column number read. + * @return An SMCParseError result. + * @error Invalid or corrupt Handle. + */ +native SMCError SMC_ParseFile(Handle smc, const char[] file, int &line=0, int &col=0); + +/** + * Gets an error string for an SMCError code. + * @note SMCError_Okay returns false. + * @note SMCError_Custom (which is thrown on SMCParse_HaltFail) returns false. + * + * @param error The SMCParseError code. + * @param buffer A string buffer for the error (contents undefined on failure). + * @param buf_max The maximum size of the buffer. + * @return True on success, false otherwise. + */ +native bool SMC_GetErrorString(SMCError error, char[] buffer, int buf_max); + +/** + * Sets the SMC_ParseStart function of a parse Handle. + * + * @param smc Handle to an SMC Parse. + * @param func SMC_ParseStart function. + * @error Invalid or corrupt Handle. + */ +native void SMC_SetParseStart(Handle smc, SMC_ParseStart func); + +/** + * Sets the SMC_ParseEnd of a parse handle. + * + * @param smc Handle to an SMC Parse. + * @param func SMC_ParseEnd function. + * @error Invalid or corrupt Handle. + */ +native void SMC_SetParseEnd(Handle smc, SMC_ParseEnd func); + +/** + * Sets the three main reader functions. + * + * @param smc An SMC parse Handle. + * @param ns An SMC_NewSection function pointer. + * @param kv An SMC_KeyValue function pointer. + * @param es An SMC_EndSection function pointer. + */ +native void SMC_SetReaders(Handle smc, SMC_NewSection ns, SMC_KeyValue kv, SMC_EndSection es); + +/** + * Sets a raw line reader on an SMC parser Handle. + * + * @param smc Handle to an SMC Parse. + * @param func SMC_RawLine function. + */ +native void SMC_SetRawLine(Handle smc, SMC_RawLine func); diff --git a/scripting/include/tf2.inc b/scripting/include/tf2.inc new file mode 100644 index 0000000..f93d5da --- /dev/null +++ b/scripting/include/tf2.inc @@ -0,0 +1,493 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _tf2_included + #endinput +#endif +#define _tf2_included + +#define TF_STUNFLAG_SLOWDOWN (1 << 0) /**< activates slowdown modifier */ +#define TF_STUNFLAG_BONKSTUCK (1 << 1) /**< bonk sound, stuck */ +#define TF_STUNFLAG_LIMITMOVEMENT (1 << 2) /**< disable forward/backward movement */ +#define TF_STUNFLAG_CHEERSOUND (1 << 3) /**< cheering sound */ +#define TF_STUNFLAG_NOSOUNDOREFFECT (1 << 5) /**< no sound or particle */ +#define TF_STUNFLAG_THIRDPERSON (1 << 6) /**< panic animation */ +#define TF_STUNFLAG_GHOSTEFFECT (1 << 7) /**< ghost particles */ +#define TF_STUNFLAG_SOUND (1 << 8) /**< sound */ + +#define TF_STUNFLAGS_LOSERSTATE TF_STUNFLAG_SLOWDOWN|TF_STUNFLAG_NOSOUNDOREFFECT|TF_STUNFLAG_THIRDPERSON +#define TF_STUNFLAGS_GHOSTSCARE TF_STUNFLAG_GHOSTEFFECT|TF_STUNFLAG_THIRDPERSON +#define TF_STUNFLAGS_SMALLBONK TF_STUNFLAG_THIRDPERSON|TF_STUNFLAG_SLOWDOWN +#define TF_STUNFLAGS_NORMALBONK TF_STUNFLAG_BONKSTUCK +#define TF_STUNFLAGS_BIGBONK TF_STUNFLAG_CHEERSOUND|TF_STUNFLAG_BONKSTUCK + +enum TFClassType +{ + TFClass_Unknown = 0, + TFClass_Scout, + TFClass_Sniper, + TFClass_Soldier, + TFClass_DemoMan, + TFClass_Medic, + TFClass_Heavy, + TFClass_Pyro, + TFClass_Spy, + TFClass_Engineer +}; + +enum TFTeam +{ + TFTeam_Unassigned = 0, + TFTeam_Spectator = 1, + TFTeam_Red = 2, + TFTeam_Blue = 3 +}; + +enum TFCond +{ + TFCond_Slowed = 0, + TFCond_Zoomed, + TFCond_Disguising, + TFCond_Disguised, + TFCond_Cloaked, + TFCond_Ubercharged, + TFCond_TeleportedGlow, + TFCond_Taunting, + TFCond_UberchargeFading, + TFCond_Unknown1, //9 + TFCond_CloakFlicker = 9, + TFCond_Teleporting, + TFCond_Kritzkrieged, + TFCond_Unknown2, //12 + TFCond_TmpDamageBonus = 12, + TFCond_DeadRingered, + TFCond_Bonked, + TFCond_Dazed, + TFCond_Buffed, + TFCond_Charging, + TFCond_DemoBuff, + TFCond_CritCola, + TFCond_InHealRadius, + TFCond_Healing, + TFCond_OnFire, + TFCond_Overhealed, + TFCond_Jarated, + TFCond_Bleeding, + TFCond_DefenseBuffed, + TFCond_Milked, + TFCond_MegaHeal, + TFCond_RegenBuffed, + TFCond_MarkedForDeath, + TFCond_NoHealingDamageBuff, + TFCond_SpeedBuffAlly, // 32 + TFCond_HalloweenCritCandy, + TFCond_CritCanteen, + TFCond_CritDemoCharge, + TFCond_CritHype, + TFCond_CritOnFirstBlood, + TFCond_CritOnWin, + TFCond_CritOnFlagCapture, + TFCond_CritOnKill, + TFCond_RestrictToMelee, + TFCond_DefenseBuffNoCritBlock, + TFCond_Reprogrammed, + TFCond_CritMmmph, + TFCond_DefenseBuffMmmph, + TFCond_FocusBuff, + TFCond_DisguiseRemoved, + TFCond_MarkedForDeathSilent, + TFCond_DisguisedAsDispenser, + TFCond_Sapped, + TFCond_UberchargedHidden, + TFCond_UberchargedCanteen, + TFCond_HalloweenBombHead, + TFCond_HalloweenThriller, + TFCond_RadiusHealOnDamage, + TFCond_CritOnDamage, + TFCond_UberchargedOnTakeDamage, + TFCond_UberBulletResist, + TFCond_UberBlastResist, + TFCond_UberFireResist, + TFCond_SmallBulletResist, + TFCond_SmallBlastResist, + TFCond_SmallFireResist, + TFCond_Stealthed, // 64 + TFCond_MedigunDebuff, + TFCond_StealthedUserBuffFade, + TFCond_BulletImmune, + TFCond_BlastImmune, + TFCond_FireImmune, + TFCond_PreventDeath, + TFCond_MVMBotRadiowave, + TFCond_HalloweenSpeedBoost, + TFCond_HalloweenQuickHeal, + TFCond_HalloweenGiant, + TFCond_HalloweenTiny, + TFCond_HalloweenInHell, + TFCond_HalloweenGhostMode, + TFCond_MiniCritOnKill, + TFCond_DodgeChance, //79 + TFCond_ObscuredSmoke = 79, + TFCond_Parachute, + TFCond_BlastJumping, + TFCond_HalloweenKart, + TFCond_HalloweenKartDash, + TFCond_BalloonHead, + TFCond_MeleeOnly, + TFCond_SwimmingCurse, + TFCond_HalloweenKartNoTurn, //87 + TFCond_FreezeInput = 87, + TFCond_HalloweenKartCage, + TFCond_HasRune, + TFCond_RuneStrength, + TFCond_RuneHaste, + TFCond_RuneRegen, + TFCond_RuneResist, + TFCond_RuneVampire, + TFCond_RuneWarlock, + TFCond_RunePrecision, // 96 + TFCond_RuneAgility, + TFCond_GrapplingHook, + TFCond_GrapplingHookSafeFall, + TFCond_GrapplingHookLatched, + TFCond_GrapplingHookBleeding, + TFCond_AfterburnImmune, + TFCond_RuneKnockout, + TFCond_RuneImbalance, + TFCond_CritRuneTemp, + TFCond_PasstimeInterception, + TFCond_SwimmingNoEffects, + TFCond_EyeaductUnderworld, + TFCond_KingRune, + TFCond_PlagueRune, + TFCond_SupernovaRune, + TFCond_Plague, + TFCond_KingAura, + TFCond_SpawnOutline, //114 + TFCond_KnockedIntoAir, + TFCond_CompetitiveWinner, + TFCond_CompetitiveLoser, + TFCond_NoTaunting_DEPRECATED, + TFCond_HealingDebuff = 118, + TFCond_PasstimePenaltyDebuff, + TFCond_GrappledToPlayer, + TFCond_GrappledByPlayer, + TFCond_ParachuteDeployed, + TFCond_Gas, + TFCond_BurningPyro, + TFCond_RocketPack, + TFCond_LostFooting, + TFCond_AirCurrent, +}; + +const float TFCondDuration_Infinite = -1.0; + +enum TFHoliday +{ + TFHoliday_Invalid = -1 +}; + +public const TFHoliday TFHoliday_Birthday; +public const TFHoliday TFHoliday_Halloween; +public const TFHoliday TFHoliday_Christmas; +public const TFHoliday TFHoliday_EndOfTheLine; +public const TFHoliday TFHoliday_CommunityUpdate; +public const TFHoliday TFHoliday_ValentinesDay; +public const TFHoliday TFHoliday_MeetThePyro; +public const TFHoliday TFHoliday_FullMoon; +public const TFHoliday TFHoliday_HalloweenOrFullMoon; +public const TFHoliday TFHoliday_HalloweenOrFullMoonOrValentines; +public const TFHoliday TFHoliday_AprilFools; + +enum TFObjectType +{ + TFObject_CartDispenser = 0, + TFObject_Dispenser = 0, + TFObject_Teleporter = 1, + TFObject_Sentry = 2, + TFObject_Sapper = 3 +}; + +enum TFObjectMode +{ + TFObjectMode_None = 0, + TFObjectMode_Entrance = 0, + TFObjectMode_Exit = 1 +}; + +/** + * Sets a client on fire for 10 seconds. + * + * @param client Player's index. + * @param attacker Attacker's index. + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_IgnitePlayer(int client, int attacker); + +/** + * Respawns a client + * + * @param client Player's index. + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_RespawnPlayer(int client); + +/** + * Regenerates a client's health and ammunition + * + * @param client Player's index. + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_RegeneratePlayer(int client); + +/** + * Adds a condition to a player + * + * @param client Player's index. + * @param condition Integer identifier of condition to apply. + * @param duration Duration of condition (does not apply to all conditions). + * Pass TFCondDuration_Infinite to apply until manually removed. + * @param inflictor Condition inflictor's index (0 for no inflictor). + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_AddCondition(int client, TFCond condition, float duration=TFCondDuration_Infinite, int inflictor=0); + +/** + * Removes a condition from a player + * + * @param client Player's index. + * @param condition Integer identifier of condition to remove. + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_RemoveCondition(int client, TFCond condition); + +/** + * Enables/disables PowerPlay mode on a player. + * + * @param client Player's index. + * @param enabled Whether to enable or disable PowerPlay on player. + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_SetPlayerPowerPlay(int client, bool enabled); + +/** + * Disguises a client to the given model and team. Only has an effect on spies. + * + * Note: This only starts the disguise process and a delay occurs before the spy is fully disguised + * + * @param client Player's index. + * @param team Team to disguise the player as (only TFTeam_Red and TFTeam_Blue have an effect) + * @param classType TFClassType class to disguise the player as + * @param target Specific target player to disguise as (0 for any) + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_DisguisePlayer(int client, TFTeam team, TFClassType classType, int target=0); + +/** + * Removes the current disguise from a client. Only has an effect on spies. + * + * @param client Player's index. + * @error Invalid client index, client not in game, or no mod support. + */ +native void TF2_RemovePlayerDisguise(int client); + +/** + * Stuns a client + * + * @param client Player's index. + * @param duration Duration of stun. + * @param slowdown Slowdown percent (as decimal, 0.00-1.00) + * Ignored if TF_STUNFLAG_SLOWDOWN is not set. + * @param stunflags Stun flags. + * @param attacker Attacker's index (0 is allowed for world). + */ +native void TF2_StunPlayer(int client, float duration, float slowdown=0.0, int stunflags, int attacker=0); + +/** + * Induces the bleed effect on a client + * + * @param client Player's index. + * @param attacker Attacker's index. + * @param duration Duration of bleeding (in seconds). + */ +native void TF2_MakeBleed(int client, int attacker, float duration); + +/** + * Retrieves the entity index of the CPlayerResource entity + * + * @return The current resource entity index. + */ +#pragma deprecated Use GetPlayerResourceEntity instead +native int TF2_GetResourceEntity(); + +/** + * Finds the TFClassType for a given class name. + * + * @param classname A classname string such as "sniper" or "demoman" + * @return A TFClassType constant. + */ +native TFClassType TF2_GetClass(const char[] classname); + +/** + * Called on weapon fire to decide if the current shot should be critical. + * Return Plugin_Continue to let the original calculation or return a higher + * action to override the decision with the value of 'result' + * + * @note Since critical shots are also calculated client side any changes made with + * this will not show for the shooter. Projectile weapons such as the rocketlauncher + * and demoman weapons will show a critical bullet but no critical sound effect. + * Bullet hits should appear as expected. + * + * @param client Client Index. + * @param weapon Weapon entity Index. + * @param weaponname Classname of the weapon. + * @param result Buffer param for the result of the decision. + */ +forward Action TF2_CalcIsAttackCritical(int client, int weapon, char[] weaponname, bool &result); + +/** + * @deprecated No longer called. Use TF2_OnIsHolidayActive. + */ +#pragma deprecated No longer called. Use TF2_OnIsHolidayActive. +forward Action TF2_OnGetHoliday(TFHoliday &holiday); + +/** + * Called at various times when the game checks to see if the given holiday is active. + * Return Plugin_Continue to let the original calculation or return a higher + * action to override the decision with the value of 'result' + * + * @param holiday Holiday being checked. + * @param result Buffer param for the result of the decision. + * @return Plugin_Continue for original calculation, higher value to use 'result'. + */ +forward Action TF2_OnIsHolidayActive(TFHoliday holiday, bool &result); + +/** + * Returns whether or not a holiday is active + * + * @param holiday Holiday being checked. + * @return Boolean of whether or not the holiday is active. + */ +native bool TF2_IsHolidayActive(TFHoliday holiday); + +/** + * Returns whether or not a client (Player) is in a duel. + * + * @param client Client Index. + * @return Boolean of whether or not the client/player is dueling. + */ +native bool TF2_IsPlayerInDuel(int client); + +/** + * Removes an econ wearable (hat, misc, etc) from a player. + * This also deletes the wearable entity. + * + * @param client Client index. + * @param wearable Index of the wearable entity. + * @error Invalid client index, client not in game, invalid wearable entity, or no mod support. +*/ +native void TF2_RemoveWearable(int client, int wearable); + +/** + * Called after a condition is added to a player + * + * @param client Index of the client to which the condition is being added. + * @param condition Condition that is being added. + */ +forward void TF2_OnConditionAdded(int client, TFCond condition); + +/** + * Called after a condition is removed from a player + * + * @param client Index of the client to which the condition is being removed. + * @param condition Condition that is being removed. + */ +forward void TF2_OnConditionRemoved(int client, TFCond condition); + +/** + * Called when the server enters the Waiting for Players round state + */ +forward void TF2_OnWaitingForPlayersStart(); + +/** + * Called when the server exits the Waiting for Players round state + */ +forward void TF2_OnWaitingForPlayersEnd(); + +/** + * Called when a player attempts to use a teleporter to decide if the player should be allowed to teleport. + * Return Plugin_Continue to let the original calculation or return a higher + * action to override the decision with the value of 'result' + * + * @param client Client index. + * @param teleporter Teleporter entity index. + * @param result Buffer param for the result of the decision. + * This is prepopulated with the game's original decision to let a player teleport. + * @return Plugin_Continue for original calculation, higher value to use 'result'. + */ +forward Action TF2_OnPlayerTeleport(int client, int teleporter, bool &result); + +/** + * Do not edit below this line! + */ +public Extension __ext_tf2 = +{ + name = "TF2 Tools", + file = "game.tf2.ext", + autoload = 0, +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public void __ext_tf2_SetNTVOptional() +{ + MarkNativeAsOptional("TF2_IgnitePlayer"); + MarkNativeAsOptional("TF2_RespawnPlayer"); + MarkNativeAsOptional("TF2_RegeneratePlayer"); + MarkNativeAsOptional("TF2_AddCondition"); + MarkNativeAsOptional("TF2_RemoveCondition"); + MarkNativeAsOptional("TF2_SetPlayerPowerPlay"); + MarkNativeAsOptional("TF2_DisguisePlayer"); + MarkNativeAsOptional("TF2_RemovePlayerDisguise"); + MarkNativeAsOptional("TF2_StunPlayer"); + MarkNativeAsOptional("TF2_MakeBleed"); + MarkNativeAsOptional("TF2_GetResourceEntity"); + MarkNativeAsOptional("TF2_GetClass"); + MarkNativeAsOptional("TF2_IsPlayerInDuel"); + MarkNativeAsOptional("TF2_IsHolidayActive"); + MarkNativeAsOptional("TF2_RemoveWearable"); +} +#endif diff --git a/scripting/include/tf2_stocks.inc b/scripting/include/tf2_stocks.inc new file mode 100644 index 0000000..0d68e11 --- /dev/null +++ b/scripting/include/tf2_stocks.inc @@ -0,0 +1,637 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _tf2_stocks_included + #endinput +#endif +#define _tf2_stocks_included + +#include +#include + +#define TF_CONDFLAG_NONE 0 +#define TF_CONDFLAG_SLOWED (1 << 0) +#define TF_CONDFLAG_ZOOMED (1 << 1) +#define TF_CONDFLAG_DISGUISING (1 << 2) +#define TF_CONDFLAG_DISGUISED (1 << 3) +#define TF_CONDFLAG_CLOAKED (1 << 4) +#define TF_CONDFLAG_UBERCHARGED (1 << 5) +#define TF_CONDFLAG_TELEPORTGLOW (1 << 6) +#define TF_CONDFLAG_TAUNTING (1 << 7) +#define TF_CONDFLAG_UBERCHARGEFADE (1 << 8) +#define TF_CONDFLAG_CLOAKFLICKER (1 << 9) +#define TF_CONDFLAG_TELEPORTING (1 << 10) +#define TF_CONDFLAG_KRITZKRIEGED (1 << 11) +#define TF_CONDFLAG_DEADRINGERED (1 << 13) +#define TF_CONDFLAG_BONKED (1 << 14) +#define TF_CONDFLAG_DAZED (1 << 15) +#define TF_CONDFLAG_BUFFED (1 << 16) +#define TF_CONDFLAG_CHARGING (1 << 17) +#define TF_CONDFLAG_DEMOBUFF (1 << 18) +#define TF_CONDFLAG_CRITCOLA (1 << 19) +#define TF_CONDFLAG_INHEALRADIUS (1 << 20) +#define TF_CONDFLAG_HEALING (1 << 21) +#define TF_CONDFLAG_ONFIRE (1 << 22) +#define TF_CONDFLAG_OVERHEALED (1 << 23) +#define TF_CONDFLAG_JARATED (1 << 24) +#define TF_CONDFLAG_BLEEDING (1 << 25) +#define TF_CONDFLAG_DEFENSEBUFFED (1 << 26) +#define TF_CONDFLAG_MILKED (1 << 27) +#define TF_CONDFLAG_MEGAHEAL (1 << 28) +#define TF_CONDFLAG_REGENBUFFED (1 << 29) +#define TF_CONDFLAG_MARKEDFORDEATH (1 << 30) + +#define TF_DEATHFLAG_KILLERDOMINATION (1 << 0) +#define TF_DEATHFLAG_ASSISTERDOMINATION (1 << 1) +#define TF_DEATHFLAG_KILLERREVENGE (1 << 2) +#define TF_DEATHFLAG_ASSISTERREVENGE (1 << 3) +#define TF_DEATHFLAG_FIRSTBLOOD (1 << 4) +#define TF_DEATHFLAG_DEADRINGER (1 << 5) +#define TF_DEATHFLAG_INTERRUPTED (1 << 6) +#define TF_DEATHFLAG_GIBBED (1 << 7) +#define TF_DEATHFLAG_PURGATORY (1 << 8) +#define TF_DEATHFLAG_MINIBOSS (1 << 9) +#define TF_DEATHFLAG_AUSTRALIUM (1 << 10) + +// Custom kill identifiers for the customkill property on the player_death event +enum { + TF_CUSTOM_HEADSHOT = 1, + TF_CUSTOM_BACKSTAB, + TF_CUSTOM_BURNING, + TF_CUSTOM_WRENCH_FIX, + TF_CUSTOM_MINIGUN, + TF_CUSTOM_SUICIDE, + TF_CUSTOM_TAUNT_HADOUKEN, + TF_CUSTOM_BURNING_FLARE, + TF_CUSTOM_TAUNT_HIGH_NOON, + TF_CUSTOM_TAUNT_GRAND_SLAM, + TF_CUSTOM_PENETRATE_MY_TEAM, + TF_CUSTOM_PENETRATE_ALL_PLAYERS, + TF_CUSTOM_TAUNT_FENCING, + TF_CUSTOM_PENETRATE_HEADSHOT, + TF_CUSTOM_TAUNT_ARROW_STAB, + TF_CUSTOM_TELEFRAG, + TF_CUSTOM_BURNING_ARROW, + TF_CUSTOM_FLYINGBURN, + TF_CUSTOM_PUMPKIN_BOMB, + TF_CUSTOM_DECAPITATION, + TF_CUSTOM_TAUNT_GRENADE, + TF_CUSTOM_BASEBALL, + TF_CUSTOM_CHARGE_IMPACT, + TF_CUSTOM_TAUNT_BARBARIAN_SWING, + TF_CUSTOM_AIR_STICKY_BURST, + TF_CUSTOM_DEFENSIVE_STICKY, + TF_CUSTOM_PICKAXE, + TF_CUSTOM_ROCKET_DIRECTHIT, + TF_CUSTOM_TAUNT_UBERSLICE, + TF_CUSTOM_PLAYER_SENTRY, + TF_CUSTOM_STANDARD_STICKY, + TF_CUSTOM_SHOTGUN_REVENGE_CRIT, + TF_CUSTOM_TAUNT_ENGINEER_SMASH, + TF_CUSTOM_BLEEDING, + TF_CUSTOM_GOLD_WRENCH, + TF_CUSTOM_CARRIED_BUILDING, + TF_CUSTOM_COMBO_PUNCH, + TF_CUSTOM_TAUNT_ENGINEER_ARM, + TF_CUSTOM_FISH_KILL, + TF_CUSTOM_TRIGGER_HURT, + TF_CUSTOM_DECAPITATION_BOSS, + TF_CUSTOM_STICKBOMB_EXPLOSION, + TF_CUSTOM_AEGIS_ROUND, + TF_CUSTOM_FLARE_EXPLOSION, + TF_CUSTOM_BOOTS_STOMP, + TF_CUSTOM_PLASMA, + TF_CUSTOM_PLASMA_CHARGED, + TF_CUSTOM_PLASMA_GIB, + TF_CUSTOM_PRACTICE_STICKY, + TF_CUSTOM_EYEBALL_ROCKET, + TF_CUSTOM_HEADSHOT_DECAPITATION, + TF_CUSTOM_TAUNT_ARMAGEDDON, + TF_CUSTOM_FLARE_PELLET, + TF_CUSTOM_CLEAVER, + TF_CUSTOM_CLEAVER_CRIT, + TF_CUSTOM_SAPPER_RECORDER_DEATH, + TF_CUSTOM_MERASMUS_PLAYER_BOMB, + TF_CUSTOM_MERASMUS_GRENADE, + TF_CUSTOM_MERASMUS_ZAP, + TF_CUSTOM_MERASMUS_DECAPITATION, + TF_CUSTOM_CANNONBALL_PUSH, + TF_CUSTOM_TAUNT_ALLCLASS_GUITAR_RIFF, + TF_CUSTOM_THROWABLE, + TF_CUSTOM_THROWABLE_KILL, + TF_CUSTOM_SPELL_TELEPORT, + TF_CUSTOM_SPELL_SKELETON, + TF_CUSTOM_SPELL_MIRV, + TF_CUSTOM_SPELL_METEOR, + TF_CUSTOM_SPELL_LIGHTNING, + TF_CUSTOM_SPELL_FIREBALL, + TF_CUSTOM_SPELL_MONOCULUS, + TF_CUSTOM_SPELL_BLASTJUMP, + TF_CUSTOM_SPELL_BATS, + TF_CUSTOM_SPELL_TINY, + TF_CUSTOM_KART, + TF_CUSTOM_GIANT_HAMMER, + TF_CUSTOM_RUNE_REFLECT, + TF_CUSTOM_DRAGONS_FURY_IGNITE, + TF_CUSTOM_DRAGONS_FURY_BONUS_BURNING, + TF_CUSTOM_SLAP_KILL, + TF_CUSTOM_CROC, + TF_CUSTOM_TAUNTATK_GASBLAST, +}; + +// Weapon codes as used in some events, such as player_death +// (not to be confused with Item Definition Indexes) +enum { + TF_WEAPON_NONE = 0, + TF_WEAPON_BAT, + TF_WEAPON_BAT_WOOD, + TF_WEAPON_BOTTLE, + TF_WEAPON_FIREAXE, + TF_WEAPON_CLUB, + TF_WEAPON_CROWBAR, + TF_WEAPON_KNIFE, + TF_WEAPON_FISTS, + TF_WEAPON_SHOVEL, + TF_WEAPON_WRENCH, + TF_WEAPON_BONESAW, + TF_WEAPON_SHOTGUN_PRIMARY, + TF_WEAPON_SHOTGUN_SOLDIER, + TF_WEAPON_SHOTGUN_HWG, + TF_WEAPON_SHOTGUN_PYRO, + TF_WEAPON_SCATTERGUN, + TF_WEAPON_SNIPERRIFLE, + TF_WEAPON_MINIGUN, + TF_WEAPON_SMG, + TF_WEAPON_SYRINGEGUN_MEDIC, + TF_WEAPON_TRANQ, + TF_WEAPON_ROCKETLAUNCHER, + TF_WEAPON_GRENADELAUNCHER, + TF_WEAPON_PIPEBOMBLAUNCHER, + TF_WEAPON_FLAMETHROWER, + TF_WEAPON_GRENADE_NORMAL, + TF_WEAPON_GRENADE_CONCUSSION, + TF_WEAPON_GRENADE_NAIL, + TF_WEAPON_GRENADE_MIRV, + TF_WEAPON_GRENADE_MIRV_DEMOMAN, + TF_WEAPON_GRENADE_NAPALM, + TF_WEAPON_GRENADE_GAS, + TF_WEAPON_GRENADE_EMP, + TF_WEAPON_GRENADE_CALTROP, + TF_WEAPON_GRENADE_PIPEBOMB, + TF_WEAPON_GRENADE_SMOKE_BOMB, + TF_WEAPON_GRENADE_HEAL, + TF_WEAPON_GRENADE_STUNBALL, + TF_WEAPON_GRENADE_JAR, + TF_WEAPON_GRENADE_JAR_MILK, + TF_WEAPON_PISTOL, + TF_WEAPON_PISTOL_SCOUT, + TF_WEAPON_REVOLVER, + TF_WEAPON_NAILGUN, + TF_WEAPON_PDA, + TF_WEAPON_PDA_ENGINEER_BUILD, + TF_WEAPON_PDA_ENGINEER_DESTROY, + TF_WEAPON_PDA_SPY, + TF_WEAPON_BUILDER, + TF_WEAPON_MEDIGUN, + TF_WEAPON_GRENADE_MIRVBOMB, + TF_WEAPON_FLAMETHROWER_ROCKET, + TF_WEAPON_GRENADE_DEMOMAN, + TF_WEAPON_SENTRY_BULLET, + TF_WEAPON_SENTRY_ROCKET, + TF_WEAPON_DISPENSER, + TF_WEAPON_INVIS, + TF_WEAPON_FLAREGUN, + TF_WEAPON_LUNCHBOX, + TF_WEAPON_JAR, + TF_WEAPON_COMPOUND_BOW, + TF_WEAPON_BUFF_ITEM, + TF_WEAPON_PUMPKIN_BOMB, + TF_WEAPON_SWORD, + TF_WEAPON_DIRECTHIT, + TF_WEAPON_LIFELINE, + TF_WEAPON_LASER_POINTER, + TF_WEAPON_DISPENSER_GUN, + TF_WEAPON_SENTRY_REVENGE, + TF_WEAPON_JAR_MILK, + TF_WEAPON_HANDGUN_SCOUT_PRIMARY, + TF_WEAPON_BAT_FISH, + TF_WEAPON_CROSSBOW, + TF_WEAPON_STICKBOMB, + TF_WEAPON_HANDGUN_SCOUT_SEC, + TF_WEAPON_SODA_POPPER, + TF_WEAPON_SNIPERRIFLE_DECAP, + TF_WEAPON_RAYGUN, + TF_WEAPON_PARTICLE_CANNON, + TF_WEAPON_MECHANICAL_ARM, + TF_WEAPON_DRG_POMSON, + TF_WEAPON_BAT_GIFTWRAP, + TF_WEAPON_GRENADE_ORNAMENT, + TF_WEAPON_RAYGUN_REVENGE, + TF_WEAPON_PEP_BRAWLER_BLASTER, + TF_WEAPON_CLEAVER, + TF_WEAPON_GRENADE_CLEAVER, + TF_WEAPON_STICKY_BALL_LAUNCHER, + TF_WEAPON_GRENADE_STICKY_BALL, + TF_WEAPON_SHOTGUN_BUILDING_RESCUE, + TF_WEAPON_CANNON, + TF_WEAPON_THROWABLE, + TF_WEAPON_GRENADE_THROWABLE, + TF_WEAPON_PDA_SPY_BUILD, + TF_WEAPON_GRENADE_WATERBALLOON, + TF_WEAPON_HARVESTER_SAW, + TF_WEAPON_SPELLBOOK, + TF_WEAPON_SPELLBOOK_PROJECTILE, + TF_WEAPON_SNIPERRIFLE_CLASSIC, + TF_WEAPON_PARACHUTE, + TF_WEAPON_GRAPPLINGHOOK, + TF_WEAPON_PASSTIME_GUN, + TF_WEAPON_CHARGED_SMG, + TF_WEAPON_BREAKABLE_SIGN, + TF_WEAPON_ROCKETPACK, + TF_WEAPON_SLAP, + TF_WEAPON_JAR_GAS, + TF_WEAPON_GRENADE_JAR_GAS, + TF_WEAPON_FLAME_BALL, +}; + +// TF2 Weapon Loadout Slots +enum +{ + TFWeaponSlot_Primary, + TFWeaponSlot_Secondary, + TFWeaponSlot_Melee, + TFWeaponSlot_Grenade, + TFWeaponSlot_Building, + TFWeaponSlot_PDA, + TFWeaponSlot_Item1, + TFWeaponSlot_Item2 +}; + +// Identifiers for the eventtype property on the teamplay_flag_event event +enum { + TF_FLAGEVENT_PICKEDUP = 1, + TF_FLAGEVENT_CAPTURED, + TF_FLAGEVENT_DEFENDED, + TF_FLAGEVENT_DROPPED, + TF_FLAGEVENT_RETURNED +}; + +enum TFResourceType +{ + TFResource_Ping, + TFResource_Score, + TFResource_Deaths, + TFResource_TotalScore, + TFResource_Captures, + TFResource_Defenses, + TFResource_Dominations, + TFResource_Revenge, + TFResource_BuildingsDestroyed, + TFResource_Headshots, + TFResource_Backstabs, + TFResource_HealPoints, + TFResource_Invulns, + TFResource_Teleports, + TFResource_ResupplyPoints, + TFResource_KillAssists, + TFResource_MaxHealth, + TFResource_PlayerClass +}; + +static const char TFResourceNames[TFResourceType][] = +{ + "m_iPing", + "m_iScore", + "m_iDeaths", + "m_iTotalScore", + "m_iCaptures", + "m_iDefenses", + "m_iDominations", + "m_iRevenge", + "m_iBuildingsDestroyed", + "m_iHeadshots", + "m_iBackstabs", + "m_iHealPoints", + "m_iInvulns", + "m_iTeleports", + "m_iResupplyPoints", + "m_iKillAssists", + "m_iMaxHealth", + "m_iPlayerClass" +}; + +/** + * Gets a client's current team. + * + * @param client Client index. + * @return Current TFTeam of client. + * @error Invalid client index. + */ +stock TFTeam TF2_GetClientTeam(int client) +{ + return view_as(GetClientTeam(client)); +} + +/** + * Changes a client's current team. + * + * @param client Client index. + * @param team TFTeam team symbol. + * @error Invalid client index. + */ +stock void TF2_ChangeClientTeam(int client, TFTeam team) +{ + ChangeClientTeam(client, view_as(team)); +} + +/** + * Gets a client's current class. + * + * @param client Player's index. + * @return Current TFClassType of player. + * @error Invalid client index. + */ +stock TFClassType TF2_GetPlayerClass(int client) +{ + return view_as(GetEntProp(client, Prop_Send, "m_iClass")); +} + +/** + * Sets a client's class. + * + * Note: If setting player class in a player spawn hook weapons should be set to false. + * + * @param client Player's index. + * @param classType TFClassType class symbol. + * @param weapons This parameter is ignored. + * @param persistent If true, changes the player's desired class so the change stays after death. + * @error Invalid client index. + */ +stock void TF2_SetPlayerClass(int client, TFClassType classType, bool weapons=true, bool persistent=true) +{ + SetEntProp(client, Prop_Send, "m_iClass", view_as(classType)); + + if (persistent) + { + SetEntProp(client, Prop_Send, "m_iDesiredPlayerClass", view_as(classType)); + } +} + +/** + * Retrieves client data from the resource entity + * + * @param client Player's index. + * @param type ResourceType constant + * @return Value or -1 on failure. + * @error Invalid client index, client not in game or failed to find resource entity. + */ +#pragma deprecated Use GetPlayerResourceEntity and GetEntProp instead +stock int TF2_GetPlayerResourceData(int client, TFResourceType type) +{ + if (!IsClientConnected(client)) + { + return -1; + } + + int offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); + + if (offset < 1) + { + return -1; + } + + int entity = TF2_GetResourceEntity(); + + if (entity == -1) + { + return -1; + } + + return GetEntData(entity, offset + (client*4)); +} + +/** + * Sets client data in the resource entity + * + * Note: The game overwrites these values every frame, so changing them will have very little effect. + * + * @param client Player's index. + * @param type ResourceType constant + * @param value Value to set. + * @return Value or -1 on failure. + * @error Invalid client index, client not in game or failed to find resource entity. + */ +#pragma deprecated Use GetPlayerResourceEntity and SetEntProp instead +stock bool TF2_SetPlayerResourceData(int client, TFResourceType type, any value) +{ + if (!IsClientConnected(client)) + { + return false; + } + + int offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); + + if (offset < 1) + { + return false; + } + + int entity = TF2_GetResourceEntity(); + + if (entity == -1) + { + return false; + } + + SetEntData(entity, offset + (client*4), value); + + return true; +} + +/** + * Removes all weapons from a client's weapon slot + * + * @param client Player's index. + * @param slot Slot index (0-5) + * @error Invalid client, invalid slot or lack of mod support + */ +stock void TF2_RemoveWeaponSlot(int client, int slot) +{ + int weaponIndex; + while ((weaponIndex = GetPlayerWeaponSlot(client, slot)) != -1) + { + // bug #6206 + // papering over a valve bug where a weapon's extra wearables aren't properly removed from the weapon's owner + int extraWearable = GetEntPropEnt(weaponIndex, Prop_Send, "m_hExtraWearable"); + if (extraWearable != -1) + { + TF2_RemoveWearable(client, extraWearable); + } + + extraWearable = GetEntPropEnt(weaponIndex, Prop_Send, "m_hExtraWearableViewModel"); + if (extraWearable != -1) + { + TF2_RemoveWearable(client, extraWearable); + } + + RemovePlayerItem(client, weaponIndex); + AcceptEntityInput(weaponIndex, "Kill"); + } +} + +/** + * Removes all weapons from a client + * + * @param client Player's index. + */ +stock void TF2_RemoveAllWeapons(int client) +{ + for (int i = 0; i <= 5; i++) + { + TF2_RemoveWeaponSlot(client, i); + } +} + +/** + * Gets a player's condition bits + * + * @param client Player's index. + * @return Player's condition bits + */ +#pragma deprecated Use TF2_IsPlayerInCondition instead. +stock int TF2_GetPlayerConditionFlags(int client) +{ + return GetEntProp(client, Prop_Send, "m_nPlayerCond")|GetEntProp(client, Prop_Send, "_condition_bits"); +} + +/** + * Check whether or not a condition is set on a player + * + * @param client Player's index. + * @param cond TFCond constant + * @return True if set, false otherwise + */ +stock bool TF2_IsPlayerInCondition(int client, TFCond cond) +{ + // Conditions are stored across multiple netprops now, one for each 32-bit segment. + int iCond = view_as(cond); + switch (iCond / 32) + { + case 0: + { + int bit = 1 << iCond; + if ((GetEntProp(client, Prop_Send, "m_nPlayerCond") & bit) == bit) + { + return true; + } + + if ((GetEntProp(client, Prop_Send, "_condition_bits") & bit) == bit) + { + return true; + } + } + case 1: + { + int bit = (1 << (iCond - 32)); + if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx") & bit) == bit) + { + return true; + } + } + case 2: + { + int bit = (1 << (iCond - 64)); + if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx2") & bit) == bit) + { + return true; + } + } + case 3: + { + int bit = (1 << (iCond - 96)); + if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx3") & bit) == bit) + { + return true; + } + } + case 4: + { + int bit = (1 << (iCond - 128)); + if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx4") & bit) == bit) + { + return true; + } + } + default: + ThrowError("Invalid TFCond value %d", iCond); + } + + return false; +} + +/** + * Gets an entity's object type. + * + * @param entity Entity index. + * @return Current TFObjectType of entity. + * @error Invalid entity index. + */ +stock TFObjectType TF2_GetObjectType(int entity) +{ + int offset = GetEntSendPropOffs(entity, "m_iObjectType"); + + if (offset <= 0) + { + ThrowError("Entity index %d is not an object", entity); + } + + return view_as(GetEntData(entity, offset)); +} + +/** + * Gets an entity's object mode. + * + * @param entity Entity index. + * @return Current TFObjectMode of entity. + * @error Invalid entity index. + */ +stock TFObjectMode TF2_GetObjectMode(int entity) +{ + int offset = GetEntSendPropOffs(entity, "m_iObjectMode"); + + if (offset <= 0) + { + ThrowError("Entity index %d is not an object", entity); + } + + return view_as(GetEntData(entity, offset)); +} diff --git a/scripting/include/timber.inc b/scripting/include/timber.inc new file mode 100644 index 0000000..821d4a4 --- /dev/null +++ b/scripting/include/timber.inc @@ -0,0 +1,124 @@ +#if defined _timber_included +#endinput +#endif +#define _timber_included + +// Name from the wonderful Timber library by JakeWharton + +enum TimberLogLevel { + Log_Error = 0, + Log_Warning, + Log_Info, + Log_Debug, + Log_Verbose +} + +ConVar timber__cvarLogThroughTimber; +ConVar timber__cvarLogToFile; + +methodmap Timber +{ + // From DrMckay's LogItem stock, modified for Timber :) + public static void log(TimberLogLevel level, const char[] log) + { + if (timber__cvarLogThroughTimber == null) + { + return; + } + + int logLevel = timber__cvarLogThroughTimber.IntValue; + if(logLevel < view_as(level)) + { + return; + } + + char pluginName[128]; + GetPluginFilename(null, pluginName, sizeof(pluginName)); + char logPrefixes[][] = {"[ERROR]", "[WARNING]", "[INFO]", "[DEBUG]", "[VERBOSE]"}; + if (timber__cvarLogToFile != null && timber__cvarLogToFile.BoolValue) + { + char file[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, file, sizeof(file), "logs/%s.log", pluginName); + LogToFileEx(file, "%s %s", logPrefixes[view_as(level)], log); + } + else + { + LogMessage("%s %s", logPrefixes[view_as(level)], log); + } + } + + public static void v(const char[] log, any ...) + { + if (timber__cvarLogThroughTimber != null) + { + char logLine[8192]; + VFormat(logLine, sizeof(logLine), log, 2); + this.log(Log_Verbose, log); + } + } + + public static void d(const char[] log, any ...) + { + if (timber__cvarLogThroughTimber != null) + { + char logLine[8192]; + VFormat(logLine, sizeof(logLine), log, 2); + Timber.log(Log_Debug, log); + } + } + + public static void e(const char[] log, any ...) + { + if (timber__cvarLogThroughTimber != null) + { + char logLine[8192]; + VFormat(logLine, sizeof(logLine), log, 2); + Timber.log(Log_Error, log); + } + } + + public static void w(const char[] log, any ...) + { + if (timber__cvarLogThroughTimber != null) + { + char logLine[8192]; + VFormat(logLine, sizeof(logLine), log, 2); + Timber.log(Log_Warning, log); + } + } + + public static void i(const char[] log, any ...) + { + if (timber__cvarLogThroughTimber != null) + { + char logLine[8192]; + VFormat(logLine, sizeof(logLine), log, 2); + Timber.log(Log_Verbose, log); + } + } + + public static void plant(bool &appended = false) + { + char pluginName[128], cvarName[256]; + GetPluginFilename(null, pluginName, sizeof(pluginName)); + Format(cvarName, sizeof(cvarName), "%s_log_level", pluginName); + #if defined _autoexecconfig_included + timber__cvarLogThroughTimber = AutoExecConfig_CreateConVarCheckAppend(appended, cvarName, "0", "-1: None\n0: Errors\n1: Warnings\n2: Info\n3: Debug\n4: Verbose"); + #else + timber__cvarLogThroughTimber = CreateConVar(cvarName, "0", "-1: None\n0: Errors\n1: Warnings\n2: Info\n3: Debug\n4: Verbose"); + #endif + } + + public static void plantToFile(bool &appended = false) + { + char pluginName[128], cvarName[256]; + GetPluginFilename(null, pluginName, sizeof(pluginName)); + Format(cvarName, sizeof(cvarName), "%s_log_file", pluginName); + #if defined _autoexecconfig_included + timber__cvarLogToFile = AutoExecConfig_CreateConVarCheckAppend(appended, cvarName, "0", "0: Don't log to file.\n1: Log to file."); + #else + timber__cvarLogToFile = CreateConVar(cvarName, "0", "0: Don't log to file.\n1: Log to file."); + #endif + Timber.plant(appended); + } +} \ No newline at end of file diff --git a/scripting/include/timers.inc b/scripting/include/timers.inc new file mode 100644 index 0000000..1676263 --- /dev/null +++ b/scripting/include/timers.inc @@ -0,0 +1,209 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _timers_included + #endinput +#endif +#define _timers_included + +#include + +#define TIMER_REPEAT (1<<0) /**< Timer will repeat until it returns Plugin_Stop */ +#define TIMER_FLAG_NO_MAPCHANGE (1<<1) /**< Timer will not carry over mapchanges */ +#define TIMER_HNDL_CLOSE (1<<9) /**< Deprecated define, replaced by below */ +#define TIMER_DATA_HNDL_CLOSE (1<<9) /**< Timer will automatically call CloseHandle() on its data when finished */ + +/** + * Any of the following prototypes will work for a timed function. + */ +typeset Timer +{ + /** + * Called when the timer interval has elapsed. + * + * @param timer Handle to the timer object. + * @param hndl Handle passed to CreateTimer() when timer was created. + * @return Plugin_Stop to stop a repeating timer, any other value for + * default behavior. + */ + function Action(Handle timer, Handle hndl); + + /** + * Called when the timer interval has elapsed. + * + * @param timer Handle to the timer object. + * @param data Data passed to CreateTimer() when timer was created. + * @return Plugin_Stop to stop a repeating timer, any other value for + * default behavior. + */ + function Action(Handle timer, any data); + + /** + * Called when the timer interval has elapsed. + * + * @param timer Handle to the timer object. + * @return Plugin_Stop to stop a repeating timer, any other value for + * default behavior. + */ + function Action(Handle timer); +}; + +/** + * Creates a basic timer. Calling CloseHandle() on a timer will end the timer. + * + * @param interval Interval from the current game time to execute the given function. + * @param func Function to execute once the given interval has elapsed. + * @param data Handle or value to pass through to the timer callback function. + * @param flags Flags to set (such as repeatability or auto-Handle closing). + * @return Handle to the timer object. You do not need to call CloseHandle(). + * If the timer could not be created, INVALID_HANDLE will be returned. + */ +native Handle CreateTimer(float interval, Timer func, any data=INVALID_HANDLE, int flags=0); + +/** + * Kills a timer. Use this instead of CloseHandle() if you need more options. + * + * @param timer Timer Handle to kill. + * @param autoClose If autoClose is true, the data that was passed to CreateTimer() will + * be closed as a handle if TIMER_DATA_HNDL_CLOSE was not specified. + * @error Invalid handles will cause a run time error. + */ +native void KillTimer(Handle timer, bool autoClose=false); + +/** + * Manually triggers a timer so its function will be called. + * + * @param timer Timer Handle to trigger. + * @param reset If reset is true, the elapsed time counter is reset + * so the full interval must pass again. + */ +native void TriggerTimer(Handle timer, bool reset=false); + +/** + * Returns the simulated game time. + * + * This time is internally maintained by SourceMod and is based on the game + * tick count and tick rate. Unlike GetGameTime(), it will increment past + * map changes and while no players are connected. Unlike GetEngineTime(), + * it will not increment based on the system clock (i.e. it is still bound + * to the ticking process). + * + * @return Time based on the game tick count. + */ +native float GetTickedTime(); + +/** + * Returns an estimate of the time left before the map ends. If the server + * has not processed any frames yet (i.e. no players have joined the map yet), + * then the time left returned will always be infinite. + * + * @param timeleft Variable to store the time, in seconds. If the + * value is less than 0, the time limit is infinite. + * @return True if the operation is supported, false otherwise. + */ +native bool GetMapTimeLeft(int &timeleft); + +/** + * Retrieves the current map time limit. If the server has not processed any + * frames yet (i.e. no players have joined the map yet), then the time limit + * returned will always be 0. + * + * @param time Set to the number of total seconds in the map time + * limit, or 0 if there is no time limit set. + * @return True on success, false if operation is not supported. + */ +native bool GetMapTimeLimit(int &time); + +/** + * Extends the map time limit in a way that will notify all plugins. + * + * @param time Number of seconds to extend map time limit by. + * The number can be negative to decrease the time limit. + * If 0, the map will be set to have no time limit. + * @return True on success, false if operation is not supported. + */ +native bool ExtendMapTimeLimit(int time); + +/** + * Returns the number of seconds in between game server ticks. + * + * Note: A tick, in this context, is a frame. + * + * @return Number of seconds in between ticks. + */ +native float GetTickInterval(); + +/** + * Notification that the map's time left has changed via a change in the time + * limit or a change in the game rules (such as mp_restartgame). This is useful + * for plugins trying to create timers based on the time left in the map. + * + * Calling ExtendMapTimeLimit() from here, without proper precaution, will + * cause infinite recursion. + * + * If the operation is not supported, this will never be called. + + * If the server has not yet processed any frames (i.e. no players have joined + * the map yet), then this will be called once the server begins ticking, even + * if there is no time limit set. + */ +forward void OnMapTimeLeftChanged(); + +/** + * Returns whether or not the server is processing frames or not. + * + * The server does not process frames until at least one client joins the game. + * Once the first player has in, even if that player, leaves, the server's + * timers and entities will work. + * + * @return True if the server is ticking, false otherwise. + */ +native bool IsServerProcessing(); + +/** + * Creates a timer associated with a new datapack, and returns the datapack. + * @note The datapack is automatically freed when the timer ends. + * @note The position of the datapack is not reset or changed for the timer function. + * + * @param interval Interval from the current game time to execute the given function. + * @param func Function to execute once the given interval has elapsed. + * @param datapack The newly created datapack is passed though this by-reference + * parameter to the timer callback function. + * @param flags Timer flags. + * @return Handle to the timer object. You do not need to call CloseHandle(). + */ +stock Handle CreateDataTimer(float interval, Timer func, Handle &datapack, int flags=0) +{ + datapack = new DataPack(); + flags |= TIMER_DATA_HNDL_CLOSE; + return CreateTimer(interval, func, datapack, flags); +} diff --git a/scripting/include/topmenus.inc b/scripting/include/topmenus.inc new file mode 100644 index 0000000..a4cb793 --- /dev/null +++ b/scripting/include/topmenus.inc @@ -0,0 +1,434 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet: + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _topmenus_included + #endinput +#endif +#define _topmenus_included + +#include + +/** + * Actions a top menu will take on an topobj. + */ +enum TopMenuAction +{ + /** + * An option is being drawn for a menu (or for sorting purposes). + * + * INPUT : TopMenu Handle, topobj ID, client index. + * OUTPUT: Buffer for rendering, maxlength of buffer. + */ + TopMenuAction_DisplayOption = 0, + + /** + * The title of a menu is being drawn for a given topobj. + * + * Note: The Object ID will be INVALID_TOPMENUOBJECT if drawing the + * root title. Otherwise, the Object ID is a category. + * + * INPUT : TopMenu Handle, topobj ID, client index. + * OUTPUT: Buffer for rendering, maxlength of buffer. + */ + TopMenuAction_DisplayTitle = 1, + + /** + * A menu option has been selected. + * + * The Object ID will always be an item (not a category). + * + * INPUT : TopMenu Handle, topobj ID, client index. + */ + TopMenuAction_SelectOption = 2, + + /** + * A menu option is being drawn and its flags can be overridden. + * + * INPUT : TopMenu Handle, topobj ID, client index. + * OUTPUT: The first byte of the 'buffer' string should be set + * to the desired flags. By default, it will contain + * ITEMDRAW_DEFAULT. + */ + TopMenuAction_DrawOption = 3, + + /** + * Called when an topobj is being removed from the menu. + * This can be used to clean up data stored in the info string. + * + * INPUT : TopMenu Handle, topobj ID. + */ + TopMenuAction_RemoveObject = 4, +}; + +/** + * Top menu topobj types. + */ +enum TopMenuObjectType +{ + TopMenuObject_Category = 0, /**< Category (sub-menu branching from root) */ + TopMenuObject_Item = 1 /**< Item on a sub-menu */ +}; + +/** + * Top menu starting positions for display. + */ +enum TopMenuPosition +{ + TopMenuPosition_Start = 0, /**< Start/root of the menu */ + TopMenuPosition_LastRoot = 1, /**< Last position in the root menu */ + TopMenuPosition_LastCategory = 3, /**< Last position in their last category */ +}; + +/** + * Top menu topobj tag for type checking. + */ +enum TopMenuObject +{ + INVALID_TOPMENUOBJECT = 0, +}; + +/** + * TopMenu callback prototype. + * + * @param topmenu Handle to the TopMenu. + * @param action TopMenuAction being performed. + * @param topobj_id The topobj ID (if used). + * @param param Extra parameter (if used). + * @param buffer Output buffer (if used). + * @param maxlength Output buffer (if used). + */ +typedef TopMenuHandler = function void ( + TopMenu topmenu, + TopMenuAction action, + TopMenuObject topobj_id, + int param, + char[] buffer, + int maxlength +); + +// TopMenu objects are used for constructing multi-layer menus. Currently, they +// support at most two levels. The first level of items are called "categories". +methodmap TopMenu < Handle +{ + // Creates a new TopMenu. + // + // @param handler Handler to use for drawing the root title. + // @return A new TopMenu. + public native TopMenu(TopMenuHandler handler); + + // Returns a TopMenu handle from a generic handle. If the given handle is + // a TopMenu, the handle is simply casted back. Otherwise, an error is + // raised. + public static native TopMenu FromHandle(Handle handle); + + // Re-sorts the items in a TopMenu via a configuration file. + // + // The format of the configuration file should be a Valve Key-Values + // formatted file that SourceMod can parse. There should be one root + // section, and one sub-section for each category. Each sub-section's + // name should match the category name. + // + // Each sub-section may only contain key/value pairs in the form of: + // key: "item" + // value: Name of the item as passed to AddToTopMenu(). + // + // The TopMenu will draw items in the order declared in the configuration + // file. If items do not appear in the configuration file, they are sorted + // per-player based on how the handler function renders for that player. + // These items appear after the configuration sorted items. + // + // @param topmenu TopMenu Handle. + // @param file File path. + // @param error Error buffer. + // @param maxlength Maximum size of the error buffer. Error buffer + // will be filled with a zero-terminated string if + // false is returned. + // @return True on success, false on failure. + public native bool LoadConfig(const char[] file, char[] error, int maxlength); + + // Adds a category to a TopMenu. + // + // @param name Object name (MUST be unique). + // @param handler Handler for topobj. + // @param cmdname Command name (for access overrides). + // @param flags Default access flags. + // @param info_string Arbitrary storage (max 255 bytes). + // @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on failure. + public native TopMenuObject AddCategory(const char[] name, TopMenuHandler handler, + const char[] cmdname = "", int flags = 0, + const char[] info_string = ""); + + // Adds an item to a TopMenu category. + // + // @param name Object name (MUST be unique). + // @param handler Handler for topobj. + // @param category The object of the parent category for the item. + // @param cmdname Command name (for access overrides). + // @param flags Default access flags. + // @param info_string Arbitrary storage (max 255 bytes). + // @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on failure. + public native TopMenuObject AddItem(const char[] name, TopMenuHandler handler, + TopMenuObject parent, const char[] cmdname = "", + int flags = 0, const char[] info_string = ""); + + // Retrieves the info string of a top menu item. + // + // @param parent TopMenuObject ID. + // @param buffer Buffer to store info string. + // @param maxlength Maximum size of info string. + // @return Number of bytes written, not including the null terminator. + public native int GetInfoString(TopMenuObject parent, char[] buffer, int maxlength); + + // Retrieves the name string of a top menu item. + // + // @param topobj TopMenuObject ID. + // @param buffer Buffer to store info string. + // @param maxlength Maximum size of info string. + // @return Number of bytes written, not including the null terminator. + public native int GetObjName(TopMenuObject topobj, char[] buffer, int maxlength); + + // Removes an topobj from a TopMenu. + // + // Plugins' topobjs are automatically removed all TopMenus when the given + // plugin unloads or pauses. In the case of unpausing, all items are restored. + // + // @param topobj TopMenuObject ID. + public native void Remove(TopMenuObject topobj); + + // Displays a TopMenu to a client. + // + // @param client Client index. + // @param position Position to display from. + // @return True on success, false on failure. + public native bool Display(int client, TopMenuPosition position); + + // Displays a TopMenu category to a client. + // + // @param category Category topobj id. + // @param client Client index. + // @return True on success, false on failure. + public native bool DisplayCategory(TopMenuObject category, int client); + + // Finds a category's topobj ID in a TopMenu. + // + // @param name Object's unique name. + // @return TopMenuObject ID on success, or + // INVALID_TOPMENUOBJECT on failure. + public native TopMenuObject FindCategory(const char[] name); + + // Set the menu title caching behavior of the TopMenu. By default titles + // are cached to reduce overhead. If you need dynamic menu titles which + // change each time the menu is displayed to a user, set this to false. + property bool CacheTitles { + public native set(bool value); + } +}; + +/** + * Creates a TopMenu. + * + * @param handler Handler to use for drawing the root title. + * @return A new TopMenu Handle, or INVALID_HANDLE on failure. + */ +native TopMenu CreateTopMenu(TopMenuHandler handler); + +/** + * Re-sorts the items in a TopMenu via a configuration file. + * + * The format of the configuration file should be a Valve Key-Values + * formatted file that SourceMod can parse. There should be one root + * section, and one sub-section for each category. Each sub-section's + * name should match the category name. + * + * Each sub-section may only contain key/value pairs in the form of: + * key: "item" + * value: Name of the item as passed to AddToTopMenu(). + * + * The TopMenu will draw items in the order declared in the configuration + * file. If items do not appear in the configuration file, they are sorted + * per-player based on how the handler function renders for that player. + * These items appear after the configuration sorted items. + * + * @param topmenu TopMenu Handle. + * @param file File path. + * @param error Error buffer. + * @param maxlength Maximum size of the error buffer. + * Error buffer will be filled with a + * zero-terminated string if false is + * returned. + * @return True on success, false on failure. + * @error Invalid TopMenu Handle. + */ +native bool LoadTopMenuConfig(Handle topmenu, const char[] file, char[] error, int maxlength); + +/** + * Adds an topobj to a TopMenu. + * + * @param topmenu TopMenu Handle. + * @param name Object name (MUST be unique). + * @param type Object type. + * @param handler Handler for topobj. + * @param parent Parent topobj ID, or INVALID_TOPMENUOBJECT for none. + * Items must have a category parent. + * Categories must not have a parent. + * @param cmdname Command name (for access overrides). + * @param flags Default access flags. + * @param info_string Arbitrary storage (max 255 bytes). + * @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on + * failure. + * @error Invalid TopMenu Handle. + */ +native TopMenuObject AddToTopMenu(Handle topmenu, + const char[] name, + TopMenuObjectType type, + TopMenuHandler handler, + TopMenuObject parent, + const char[] cmdname="", + int flags=0, + const char[] info_string=""); + +/** + * Retrieves the info string of a top menu item. + * + * @param topmenu TopMenu Handle. + * @param parent TopMenuObject ID. + * @param buffer Buffer to store info string. + * @param maxlength Maximum size of info string. + * @return Number of bytes written, not including the + * null terminator. + * @error Invalid TopMenu Handle or TopMenuObject ID. + */ +native int GetTopMenuInfoString(Handle topmenu, TopMenuObject parent, char[] buffer, int maxlength); + +/** + * Retrieves the name string of a top menu item. + * + * @param topmenu TopMenu Handle. + * @param topobj TopMenuObject ID. + * @param buffer Buffer to store info string. + * @param maxlength Maximum size of info string. + * @return Number of bytes written, not including the + * null terminator. + * @error Invalid TopMenu Handle or TopMenuObject ID. + */ +native int GetTopMenuObjName(Handle topmenu, TopMenuObject topobj, char[] buffer, int maxlength); + +/** + * Removes an topobj from a TopMenu. + * + * Plugins' topobjs are automatically removed all TopMenus when the given + * plugin unloads or pauses. In the case of unpausing, all items are restored. + * + * @param topmenu TopMenu Handle. + * @param topobj TopMenuObject ID. + * @error Invalid TopMenu Handle. + */ +native void RemoveFromTopMenu(Handle topmenu, TopMenuObject topobj); + +/** + * Displays a TopMenu to a client. + * + * @param topmenu TopMenu Handle. + * @param client Client index. + * @param position Position to display from. + * @return True on success, false on failure. + * @error Invalid TopMenu Handle or client not in game. + */ +native bool DisplayTopMenu(Handle topmenu, int client, TopMenuPosition position); + +/** + * Displays a TopMenu category to a client. + * + * @param topmenu TopMenu Handle. + * @param category Category topobj id. + * @param client Client index. + * @return True on success, false on failure. + * @error Invalid TopMenu Handle or client not in game. + */ +native bool DisplayTopMenuCategory(Handle topmenu, TopMenuObject category, int client); + +/** + * Finds a category's topobj ID in a TopMenu. + * + * @param topmenu TopMenu Handle. + * @param name Object's unique name. + * @return TopMenuObject ID on success, or + * INVALID_TOPMENUOBJECT on failure. + * @error Invalid TopMenu Handle. + */ +native TopMenuObject FindTopMenuCategory(Handle topmenu, const char[] name); + +/** + * Change the menu title caching behavior of the TopMenu. By default the + * titles are cached to reduce overhead. If you need dynamic menu titles, which + * can change everytime the menu is displayed to a user, set this to false. + * + * @param topmenu TopMenu Handle. + * @param cache_titles Cache the menu titles and don't call the handler with + * TopMenuAction_DisplayTitle everytime the menu is drawn? + * @error Invalid TopMenu Handle + */ +native void SetTopMenuTitleCaching(Handle topmenu, bool cache_titles); + + +/** + * Do not edit below this line! + */ +public Extension __ext_topmenus = +{ + name = "TopMenus", + file = "topmenus.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public void __ext_topmenus_SetNTVOptional() +{ + MarkNativeAsOptional("CreateTopMenu"); + MarkNativeAsOptional("LoadTopMenuConfig"); + MarkNativeAsOptional("AddToTopMenu"); + MarkNativeAsOptional("RemoveFromTopMenu"); + MarkNativeAsOptional("DisplayTopMenu"); + MarkNativeAsOptional("DisplayTopMenuCategory"); + MarkNativeAsOptional("FindTopMenuCategory"); + MarkNativeAsOptional("SetTopMenuTitleCaching"); +} +#endif diff --git a/scripting/include/usermessages.inc b/scripting/include/usermessages.inc new file mode 100644 index 0000000..baf3d8f --- /dev/null +++ b/scripting/include/usermessages.inc @@ -0,0 +1,257 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _eventsmsgs_included + #endinput +#endif +#define _eventsmsgs_included + +/** + * UserMsg helper values. + */ +enum UserMsg +{ + INVALID_MESSAGE_ID = -1, +}; + +/** + * UserMsg message serialization formats + */ +enum UserMessageType +{ + UM_BitBuf = 0, + UM_Protobuf, +}; + +/** + * @section Message Flags. + */ +#define USERMSG_RELIABLE (1<<2) /**< Message will be set on the reliable stream */ +#define USERMSG_INITMSG (1<<3) /**< Message will be considered to be an initmsg */ +#define USERMSG_BLOCKHOOKS (1<<7) /**< Prevents the message from triggering SourceMod and Metamod hooks */ + +/** + * @endsection + */ + +/** + * Returns usermessage serialization type used for the current engine + * + * @return The supported usermessage type. + */ +native UserMessageType GetUserMessageType(); + +stock Protobuf UserMessageToProtobuf(Handle msg) +{ + if (GetUserMessageType() != UM_Protobuf) + return null; + return view_as(msg); +} + +// Make sure to only call this on writable buffers (eg from StartMessage). +stock BfWrite UserMessageToBfWrite(Handle msg) +{ + if (GetUserMessageType() == UM_Protobuf) + return null; + return view_as(msg); +} + +// Make sure to only call this on readable buffers (eg from a message hook). +stock BfRead UserMessageToBfRead(Handle msg) +{ + if (GetUserMessageType() == UM_Protobuf) + return null; + return view_as(msg); +} + +/** + * Returns the ID of a given message, or -1 on failure. + * + * @param msg String containing message name (case sensitive). + * @return A message index, or INVALID_MESSAGE_ID on failure. + */ +native UserMsg GetUserMessageId(const char[] msg); + +/** + * Retrieves the name of a message by ID. + * + * @param msg_id Message index. + * @param msg Buffer to store the name of the message. + * @param maxlength Maximum length of string buffer. + * @return True if message index is valid, false otherwise. + */ +native bool GetUserMessageName(UserMsg msg_id, char[] msg, int maxlength); + +/** + * Starts a usermessage (network message). + * @note Only one message can be active at a time. + * @note It is illegal to send any message while a non-intercept hook is in progress. + * + * @param msgname Message name to start. + * @param clients Array containing player indexes to broadcast to. + * @param numClients Number of players in the array. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + * @error Invalid message name, unable to start a message, invalid client, + * or client not connected. + */ +native Handle StartMessage(const char[] msgname, const int[] clients, int numClients, int flags=0); + +/** + * Starts a usermessage (network message). + * @note Only one message can be active at a time. + * @note It is illegal to send any message while a non-intercept hook is in progress. + * + * @param msg Message index to start. + * @param clients Array containing player indexes to broadcast to. + * @param numClients Number of players in the array. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + * @error Invalid message name, unable to start a message, invalid client, + * or client not connected. + */ +native Handle StartMessageEx(UserMsg msg, const int[] clients, int numClients, int flags=0); + +/** + * Ends a previously started user message (network message). + */ +native void EndMessage(); + +/** + * Hook function types for user messages. +*/ +typeset MsgHook +{ + /** + * Called when a bit buffer based usermessage is hooked + * + * @param msg_id Message index. + * @param msg Handle to the input bit buffer. + * @param players Array containing player indexes. + * @param playersNum Number of players in the array. + * @param reliable True if message is reliable, false otherwise. + * @param init True if message is an initmsg, false otherwise. + * @return Ignored for normal hooks. For intercept hooks, Plugin_Handled + * blocks the message from being sent, and Plugin_Continue + * resumes normal functionality. + */ + function Action (UserMsg msg_id, BfRead msg, const int[] players, int playersNum, bool reliable, bool init); + /** + * Called when a protobuf based usermessage is hooked + * + * @param msg_id Message index. + * @param msg Handle to the input protobuf. + * @param players Array containing player indexes. + * @param playersNum Number of players in the array. + * @param reliable True if message is reliable, false otherwise. + * @param init True if message is an initmsg, false otherwise. + * @return Ignored for normal hooks. For intercept hooks, Plugin_Handled + * blocks the message from being sent, and Plugin_Continue + * resumes normal functionality. + */ + function Action (UserMsg msg_id, Protobuf msg, const int[] players, int playersNum, bool reliable, bool init); +}; + +/** + * Called when a message hook has completed. + * + * @param msg_id Message index. + * @param sent True if message was sent, false if blocked. + */ +typedef MsgPostHook = function void (UserMsg msg_id, bool sent); + +/** + * Hooks a user message. + * + * @param msg_id Message index. + * @param hook Function to use as a hook. + * @param intercept If intercept is true, message will be fully intercepted, + * allowing the user to block the message. Otherwise, + * the hook is normal and ignores the return value. + * @param post Notification function. + * @error Invalid message index. + */ +native void HookUserMessage(UserMsg msg_id, MsgHook hook, bool intercept=false, MsgPostHook post=INVALID_FUNCTION); + +/** + * Removes one usermessage hook. + * + * @param msg_id Message index. + * @param hook Function used for the hook. + * @param intercept Specifies whether the hook was an intercept hook or not. + * @error Invalid message index. + */ +native void UnhookUserMessage(UserMsg msg_id, MsgHook hook, bool intercept=false); + +/** + * Starts a usermessage (network message) that broadcasts to all clients. + * @note See StartMessage or StartMessageEx(). + * + * @param msgname Message name to start. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +stock Handle StartMessageAll(const char[] msgname, int flags=0) +{ + int total = 0; + int[] clients = new int[MaxClients]; + for (int i=1; i<=MaxClients; i++) + { + if (IsClientConnected(i)) + { + clients[total++] = i; + } + } + return StartMessage(msgname, clients, total, flags); +} + +/** + * Starts a simpler usermessage (network message) for one client. + * @note See StartMessage or StartMessageEx(). + * + * @param msgname Message name to start. + * @param client Client to send to. + * @param flags Optional flags to set. + * @return A handle to a bf_write bit packing structure, or + * INVALID_HANDLE on failure. + */ +stock Handle StartMessageOne(const char[] msgname, int client, int flags=0) +{ + int players[1]; + + players[0] = client; + + return StartMessage(msgname, players, 1, flags); +} diff --git a/scripting/include/vector.inc b/scripting/include/vector.inc new file mode 100644 index 0000000..a6aea08 --- /dev/null +++ b/scripting/include/vector.inc @@ -0,0 +1,179 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _vector_included + #endinput +#endif +#define _vector_included + +/** + * Calculates a vector's length. + * + * @param vec Vector. + * @param squared If true, the result will be squared (for optimization). + * @return Vector length (magnitude). + */ +native float GetVectorLength(const float vec[3], bool squared=false); + +/** + * Calculates the distance between two vectors. + * + * @param vec1 First vector. + * @param vec2 Second vector. + * @param squared If true, the result will be squared (for optimization). + * @return Vector distance. + */ +native float GetVectorDistance(const float vec1[3], const float vec2[3], bool squared=false); + +/** + * Calculates the dot product of two vectors. + * + * @param vec1 First vector. + * @param vec2 Second vector. + * @return Dot product of the two vectors. + */ +native float GetVectorDotProduct(const float vec1[3], const float vec2[3]); + +/** + * Computes the cross product of two vectors. Any input array can be the same + * as the output array. + * + * @param vec1 First vector. + * @param vec2 Second vector. + * @param result Resultant vector. + */ +native void GetVectorCrossProduct(const float vec1[3], const float vec2[3], float result[3]); + +/** + * Normalizes a vector. The input array can be the same as the output array. + * + * @param vec Vector. + * @param result Resultant vector. + * @return Vector length. + */ +native float NormalizeVector(const float vec[3], float result[3]); + +/** + * Returns vectors in the direction of an angle. + * + * @param angle Angle. + * @param fwd Forward vector buffer or NULL_VECTOR. + * @param right Right vector buffer or NULL_VECTOR. + * @param up Up vector buffer or NULL_VECTOR. + */ +native void GetAngleVectors(const float angle[3], float fwd[3], float right[3], float up[3]); + +/** + * Returns angles from a vector. + * + * @param vec Vector. + * @param angle Angle buffer. + */ +native void GetVectorAngles(const float vec[3], float angle[3]); + +/** + * Returns direction vectors from a vector. + * + * @param vec Vector. + * @param right Right vector buffer or NULL_VECTOR. + * @param up Up vector buffer or NULL_VECTOR. + */ +native void GetVectorVectors(const float vec[3], float right[3], float up[3]); + +/** + * Adds two vectors. It is safe to use either input buffer as an output + * buffer. + * + * @param vec1 First vector. + * @param vec2 Second vector. + * @param result Result buffer. + */ +stock void AddVectors(const float vec1[3], const float vec2[3], float result[3]) +{ + result[0] = vec1[0] + vec2[0]; + result[1] = vec1[1] + vec2[1]; + result[2] = vec1[2] + vec2[2]; +} + +/** + * Subtracts a vector from another vector. It is safe to use either input + * buffer as an output buffer. + * + * @param vec1 First vector. + * @param vec2 Second vector to subtract from first. + * @param result Result buffer. + */ +stock void SubtractVectors(const float vec1[3], const float vec2[3], float result[3]) +{ + result[0] = vec1[0] - vec2[0]; + result[1] = vec1[1] - vec2[1]; + result[2] = vec1[2] - vec2[2]; +} + +/** + * Scales a vector. + * + * @param vec Vector. + * @param scale Scale value. + */ +stock void ScaleVector(float vec[3], float scale) +{ + vec[0] *= scale; + vec[1] *= scale; + vec[2] *= scale; +} + +/** + * Negatives a vector. + * + * @param vec Vector. + */ +stock void NegateVector(float vec[3]) +{ + vec[0] = -vec[0]; + vec[1] = -vec[1]; + vec[2] = -vec[2]; +} + +/** + * Builds a vector from two points by subtracting the points. + * + * @param pt1 First point (to be subtracted from the second). + * @param pt2 Second point. + * @param output Output vector buffer. + */ +stock void MakeVectorFromPoints(const float pt1[3], const float pt2[3], float output[3]) +{ + output[0] = pt2[0] - pt1[0]; + output[1] = pt2[1] - pt1[1]; + output[2] = pt2[2] - pt1[2]; +} diff --git a/scripting/include/version.inc b/scripting/include/version.inc new file mode 100644 index 0000000..8519560 --- /dev/null +++ b/scripting/include/version.inc @@ -0,0 +1,49 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _version_included + #endinput +#endif +#define _version_included + +#tryinclude + +#if !defined _auto_version_included +#define SOURCEMOD_V_TAG "manual" +#define SOURCEMOD_V_REV 0 +#define SOURCEMOD_V_CSET "0" +#define SOURCEMOD_V_MAJOR 1 /**< SourceMod Major version */ +#define SOURCEMOD_V_MINOR 8 /**< SourceMod Minor version */ +#define SOURCEMOD_V_RELEASE 0 /**< SourceMod Release version */ + +#define SOURCEMOD_VERSION "1.8.0-manual" /**< SourceMod version string (major.minor.release-tag) */ +#endif diff --git a/scripting/include/version_auto.inc b/scripting/include/version_auto.inc new file mode 100644 index 0000000..32281ec --- /dev/null +++ b/scripting/include/version_auto.inc @@ -0,0 +1,15 @@ + +#if defined _auto_version_included + #endinput +#endif +#define _auto_version_included + +#define SOURCEMOD_V_TAG "" +#define SOURCEMOD_V_CSET "50b5bb1" +#define SOURCEMOD_V_MAJOR 1 +#define SOURCEMOD_V_MINOR 9 +#define SOURCEMOD_V_RELEASE 0 +#define SOURCEMOD_V_REV 6245 + +#define SOURCEMOD_VERSION "1.9.0.6245" + \ No newline at end of file diff --git a/scripting/include/vgui_motd_stocks.inc b/scripting/include/vgui_motd_stocks.inc new file mode 100644 index 0000000..3346aa9 --- /dev/null +++ b/scripting/include/vgui_motd_stocks.inc @@ -0,0 +1,87 @@ +/** + * MOTD stocks with VGUI URL Cache Buster (VUCB)-specific extensions + * + * KeyValue entries prefixed with "x-vgui-" are values handled by VUCB. + */ + +#if defined _vgui_motd_stocks_included + #endinput +#endif + +#define _vgui_motd_stocks_included + +// TODO register cache buster as a shared plugin? +// have to figure out some way to ensure these extended features are discoverable + +// if 0 cache buster will not pass dimensions to proxy page and assume default +#define CSGO_POPUP_FULL 0 +#define POPUP_FULL_SIZE 0 + +/** + * Displays an MOTD panel with CS:GO-specific options. + */ +stock void CSGO_ShowMOTDPanel(int client, const char[] title, const char[] url, + bool show = false, int width = POPUP_FULL_SIZE, int height = POPUP_FULL_SIZE) { + KeyValues kv = new KeyValues("data"); + + kv.SetString("title", title); + kv.SetNum("type", MOTDPANEL_TYPE_URL); + kv.SetString("msg", url); + + // x-vgui-popup is implicitly true in the core plugin and will remain true + // as long as normal MOTDs are broken + + if (show) { + // extended options handled by cache buster + kv.SetNum("x-vgui-width", width); + kv.SetNum("x-vgui-height", height); + } + + ShowVGUIPanel(client, "info", kv, show); + + delete kv; +} + +/** + * Displays an MOTD panel with TF2-specific options. + * All these options are native to TF2. + */ +stock void TF2_ShowMOTDPanel(int client, const char[] title, const char[] url, bool show = true, + bool big = false) { + KeyValues kv = new KeyValues("data"); + + kv.SetString("title", title); + kv.SetNum("type", MOTDPANEL_TYPE_URL); + kv.SetString("msg", url); + + if (big) { + kv.SetNum("customsvr", 1); + } + + ShowVGUIPanel(client, "info", kv, show); + + delete kv; +} + +/** + * Displays a popup web panel using VUCB extensions. + */ +stock void ShowMOTDPopupPanel(int client, const char[] title, const char[] url, + int width = POPUP_FULL_SIZE, int height = POPUP_FULL_SIZE) { + KeyValues kv = new KeyValues("data"); + + kv.SetString("title", title); + kv.SetNum("type", MOTDPANEL_TYPE_URL); + kv.SetString("msg", url); + + kv.SetNum("x-vgui-popup", true); + + if (width || height) { + kv.SetNum("x-vgui-width", width); + kv.SetNum("x-vgui-height", height); + } + + ShowVGUIPanel(client, "info", kv, false); + + delete kv; +} diff --git a/scripting/include/websocket.inc b/scripting/include/websocket.inc new file mode 100644 index 0000000..e9f46d3 --- /dev/null +++ b/scripting/include/websocket.inc @@ -0,0 +1,182 @@ +#if defined _websocket_included + #endinput +#endif +#define _websocket_included + +enum WebsocketReadyState { + State_Connecting = 0, + State_Open, + State_Closing, + State_Closed // Kinda unused +} + +enum WebsocketHandle { + INVALID_WEBSOCKET_HANDLE = 0 +} + +enum WebsocketSendType { + SendType_Text = 0, + SendType_Binary +} + +/** + * called if an unrecoverable error occured on the master socket + * + * @param WebsocketHandle websocket The websocket handle pointing to the calling websocket + * @param cell_t errorType The error type, see defines in socket.inc + * @param cell_t errorNum The errno, see errno.h for details + * @noreturn + */ +typedef WebsocketErrorCB = function void (WebsocketHandle websocket, const int errorType, const int errorNum); + +/** + * called if a master websocket is closed + * + * @param WebsocketHandle websocket The websocket handle pointing to the calling websocket + * @noreturn + */ +typedef WebsocketCloseCB = function void (WebsocketHandle websocket); + +/** + * triggered when a client connected to our websocket + * + * @param Handle websocket The websocket handle pointing to the calling listen-socket + * @param Handle newWebsocket The websocket handle to the newly spawned child socket + * @param String remoteIP The remote IP + * @param cell_t remotePort The remote port + * @param String protocols The subprotocols the client supports seperated by commas. You have to choose one of the list, so "protocols" is only that one protocol. + * @param String getPath The GET path transmitted upon connection by the client. + * @noreturn + */ +typeset WebsocketIncomingCB +{ + function Action (WebsocketHandle websocket, WebsocketHandle newWebsocket, const char[] remoteIP, int remotePort, char protocols[256]); + function Action (WebsocketHandle websocket, WebsocketHandle newWebsocket, const char[] remoteIP, int remotePort, char protocols[256], char getPath[2000]); +}; + +/** + * triggered if a websocket receives data + * + * @note This is binary safe if you always use dataSize for operations on receiveData[] + * @note packets may be split up into multiple chunks -> multiple calls to the receive callback + * @note if not set otherwise by SocketSetOption(..., ConcatenateCallbacks, ...) receiveData will + * never be longer than 4096 characters including \0 terminator + * + * @param Handle websocket The socket handle pointing to the calling socket + * @param String receiveData The data which arrived, 0-terminated at receiveData[dataSize] + * @param cell_t dataSize The length of the arrived data excluding the 0-termination + * @noreturn + */ +typedef WebsocketReceiveCB = function void (WebsocketHandle websocket, WebsocketSendType iType, const char[] receiveData, const int dataSize); + +/** + * called if a socket has been properly disconnected by the remote side + * + * @param Handle websocket The socket handle pointing to the calling socket + * @noreturn + */ +typedef WebsocketDisconnectCB = function void (WebsocketHandle websocket); + +/** + * called if the readystate of a childsocket changes. + * Only fires for ReadyState_Open and ReadyState_Closing. + * + * @param Handle websocket The socket handle pointing to the calling socket + * @param WebsocketReadyState readystate The new readystate of the childsocket. + * @noreturn + */ +typedef WebsocketReadyStateChangedCB = function void (WebsocketHandle websocket, WebsocketReadyState readystate); + +/** + * Creates a websocket server which listens on the supplied ip:port combination. + * + * @param sHostName The IP to bind to. + * @param iPort The port to listen on + * @param inc The incoming child connection callback + * @param we The error callback + * @return A WebsocketHandle or INVALID_WEBSOCKET_HANDLE on error. + */ +native WebsocketHandle Websocket_Open(const char[] sHostName, int iPort, WebsocketIncomingCB inc, WebsocketErrorCB we, WebsocketCloseCB clo); + +/** + * Hooks child socket's events + * + * @param childwebsocket The child websocket to hook. + * @param recv Data receive callback + * @param disc The disconnect callback + * @param we The error callback + * @return True if child socket was hooked, false otherwise + */ +native bool Websocket_HookChild(WebsocketHandle childwebsocket, WebsocketReceiveCB recv, WebsocketDisconnectCB disc, WebsocketErrorCB we); + +/** + * Hooks child socket's readystate changes + * + * @param childwebsocket The child websocket to hook. + * @param readystate ReadyState change callback + * @return True if child socket was hooked, false otherwise + */ +native bool Websocket_HookReadyStateChange(WebsocketHandle childwebsocket, WebsocketReadyStateChangedCB readystate); + + +/** + * Sends text or binary data through the websocket + * + * @param childwebsocket The child websocket to send to + * @param type The datatype SendType_Text or SendType_Binary + * @param sPayLoad The data to send + * @param dataSize If set, it's used as maxlength. Useful for binary data where \0 might be used before the end of the data. + * @return True if child socket was hooked, false otherwise + */ +native bool Websocket_Send(WebsocketHandle childwebsocket, WebsocketSendType type, const char[] sPayload, const int dataSize=-1); + +/** + * Gets a child websocket's readyState. + * + * @param childwebsocket The child websocket + * @return The readyState + */ +native WebsocketReadyState Websocket_GetReadyState(WebsocketHandle childwebsocket); + +/** + * Unhooks a child socket's events: If there's no plugin listening anymore, the socket is closed. + * + * @param childwebsocket The child websocket + * @noreturn + */ +native void Websocket_UnhookChild(WebsocketHandle childwebsocket); + +/** + * Closes a listening master socket, created with Websocket_Open. + * Note: The socket will still be open, if there are more plugins using it. + * + * Call this in OnPluginEnd()! + * + * @param websocket The master websocket + * @noreturn + */ +native void Websocket_Close(WebsocketHandle websocket); + +public SharedPlugin __pl_websocket = +{ + name = "websocket", + file = "websocket.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_websocket_SetNTVOptional() +{ + MarkNativeAsOptional("Websocket_Open"); + MarkNativeAsOptional("Websocket_HookReadyStateChange"); + MarkNativeAsOptional("Websocket_HookChild"); + MarkNativeAsOptional("Websocket_Send"); + MarkNativeAsOptional("Websocket_GetReadyState"); + MarkNativeAsOptional("Websocket_UnhookChild"); + MarkNativeAsOptional("Websocket_Close"); +} +#endif \ No newline at end of file diff --git a/scripting/ngs_steamrepchecker.sp b/scripting/ngs_steamrepchecker.sp deleted file mode 100644 index 9401056..0000000 --- a/scripting/ngs_steamrepchecker.sp +++ /dev/null @@ -1,561 +0,0 @@ -/** -* TheXeon -* ngs_steamrepchecker.sp -* -* Files: -* addons/sourcemod/plugins/ngs_steamrepchecker.smx -* cfg/sourcemod/plugin.steamrep_checker.cfg -* -* Dependencies: -* sdktools.inc, SteamWorks.inc, multicolors.inc, ngsutils.inc, -* ngsupdater.inc, ccc.inc, scp.inc, sourcebans.inc -*/ -#pragma newdecls required -#pragma semicolon 1 - -#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" -#define RELOAD_ON_UPDATE 1 - -#include -#include -#include -#include -#include - -#undef REQUIRE_PLUGIN -#include -#include -#include -#define REQUIRE_PLUGIN - -#define STEAMREP_URL "http://steamrep.com/id2rep.php" -#define STEAM_API_URL "https://api.steampowered.com/ISteamUser/GetPlayerBans/v1/" - -enum LogLevel { - Log_Error = 0, - Log_Info, - Log_Debug -} - -enum TagType { - TagType_None = 0, - TagType_Scammer, - TagType_TradeBanned, - TagType_TradeProbation -} - -public Plugin myinfo = { - name = "[NGS] SteamRep Checker (Redux)", - author = "Dr. McKay / TheXeon", - description = "Checks a user's SteamRep upon connection", - version = "2.2.0", - url = "https://www.neogenesisnetwork.net" -} - -ConVar cvarDealMethod; -ConVar cvarSteamIDBanLength; -ConVar cvarIPBanLength; -ConVar cvarKickTaggedScammers; -ConVar cvarValveBanDealMethod; -ConVar cvarValveCautionDealMethod; -ConVar cvarSteamAPIKey; -ConVar cvarSendIP; -ConVar cvarExcludedTags; -ConVar cvarEnableExclusion; -ConVar cvarSpawnMessage; -ConVar cvarLogLevel; - -TagType clientTag[MAXPLAYERS + 1]; -bool messageDisplayed[MAXPLAYERS + 1]; - -public void OnPluginStart() { - cvarDealMethod = CreateConVar("steamrep_checker_deal_method", "2", "How to deal with reported scammers.\n0 = Disabled\n1 = Prefix chat with [SCAMMER] tag and warn users in chat (requires Custom Chat Colors)\n2 = Kick\n3 = Ban Steam ID\n4 = Ban IP\n5 = Ban Steam ID + IP", _, true, 0.0, true, 5.0); - cvarSteamIDBanLength = CreateConVar("steamrep_checker_steamid_ban_length", "0", "Duration in minutes to ban Steam IDs for if steamrep_checker_deal_method = 3 or 5 (0 = permanent)", _, true, 0.0); - cvarIPBanLength = CreateConVar("steamrep_checker_ip_ban_length", "0", "Duration in minutes to ban IP addresses for if steamrep_checker_deal_method = 4 or 5 (0 = permanent)"); - cvarKickTaggedScammers = CreateConVar("steamrep_checker_kick_tagged_scammers", "1", "Kick chat-tagged scammers if the server gets full?", _, true, 0.0, true, 1.0); - cvarValveBanDealMethod = CreateConVar("steamrep_checker_valve_ban_deal_method", "2", "How to deal with Valve trade-banned players (requires API key to be set)\n0 = Disabled\n1 = Prefix chat with [TRADE BANNED] tag and warn users in chat (requires Custom Chat Colors)\n2 = Kick\n3 = Ban Steam ID\n4 = Ban IP\n5 = Ban Steam ID + IP", _, true, 0.0, true, 5.0); - cvarValveCautionDealMethod = CreateConVar("steamrep_checker_valve_probation_deal_method", "1", "How to deal with Valve trade-probation players (requires API key to be set)\n0 = Disabled\n1 = Prefix chat with [TRADE PROBATION] tag and warn users in chat (requires Custom Chat Colors)\n2 = Kick\n3 = Ban Steam ID\n4 = Ban IP\n5 = Ban Steam ID + IP", _, true, 0.0, true, 5.0); - cvarSteamAPIKey = CreateConVar("steamrep_checker_steam_api_key", "", "API key obtained from http://steamcommunity.com/dev (only required for Valve trade-ban or trade-probation detection", FCVAR_PROTECTED); - cvarSendIP = CreateConVar("steamrep_checker_send_ip", "0", "Send IP addresses of connecting players to SteamRep?", _, true, 0.0, true, 1.0); - cvarEnableExclusion = CreateConVar("steamrep_checker_exclusion", "1", "Allow exclusion via SkipSR override?", _, true, 0.0, true, 1.0); - cvarExcludedTags = CreateConVar("steamrep_checker_untrusted_tags", "", "Input the tags of any community whose bans you do not trust here."); - cvarSpawnMessage = CreateConVar("steamrep_checker_spawn_message", "1", "Display messages upon first spawn that this server is protected by SteamRep?", _, true, 0.0, true, 1.0); - cvarLogLevel = CreateConVar("steamrep_checker_log_level", "1", "Level of logging\n0 = Errors only\n1 = Info + errors\n2 = Info, errors, and debug", _, true, 0.0, true, 2.0); - AutoExecConfig(true, "plugin.steamrep_checker"); - - HookEvent("player_spawn", Event_PlayerSpawn); - HookEvent("player_changename", Event_PlayerChangeName); - - RegConsoleCmd("sm_rep", Command_Rep, "Checks a user's SteamRep"); - RegConsoleCmd("sm_sr", Command_Rep, "Checks a user's SteamRep"); -} - -public void OnClientConnected(int client) -{ - clientTag[client] = TagType_None; -} - -public void OnClientPostAdminCheck(int client) -{ - PerformKicks(); - if(!IsValidClient(client) || (cvarEnableExclusion.BoolValue && CheckCommandAccess(client, "SkipSR", ADMFLAG_ROOT))) { - return; - } - char auth[32]; - if (GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth))) - { - char excludedTags[64], ip[64]; - cvarExcludedTags.GetString(excludedTags, sizeof(excludedTags)); - if(cvarSendIP.BoolValue) { - GetClientIP(client, ip, sizeof(ip)); - } - SWHTTPRequest request = new SWHTTPRequest(k_EHTTPMethodGET, STEAMREP_URL); - request.SetParam("steamID32", auth); - request.SetParam("ignore", excludedTags); - request.SetParam("IP", ip); - request.SetContextValue(GetClientUserId(client)); - request.SetCallbacks(OnSteamRepChecked); - request.Send(); - #if defined DEBUG - LogItem(Log_Debug, "Sending HTTP request for %L", client); - #endif - } - else - { - LogItem(Log_Error, "Could not get SteamID2 for client %L!", client); - } -} - -void PerformKicks() { - if((GetClientCount() >= MaxClients - 1) && cvarKickTaggedScammers.BoolValue) { - if(cvarDealMethod.IntValue == 1) { - for(int i = 1; i <= MaxClients; i++) { - if(IsClientInGame(i) && clientTag[i] == TagType_Scammer) { - KickClient(i, "You were kicked to free a slot because you are a reported scammer"); - return; - } - } - } - if(cvarValveBanDealMethod.IntValue == 1) { - for(int i = 1; i <= MaxClients; i++) { - if(IsClientInGame(i) && clientTag[i] == TagType_TradeBanned) { - KickClient(i, "You were kicked to free a slot because you are trade banned"); - return; - } - } - } - if(cvarValveCautionDealMethod.IntValue == 1) { - for(int i= 1; i <= MaxClients; i++) { - if(IsClientInGame(i) && clientTag[i] == TagType_TradeProbation) { - KickClient(i, "You were kicked to free a slot because you are on trade probation"); - return; - } - } - } - } -} - -public void OnSteamRepChecked(SWHTTPRequest request, bool bFailure, bool successful, EHTTPStatusCode code, any userid) { - int client = GetClientOfUserId(userid); - if(client == 0) { - LogItem(Log_Debug, "Client with User ID %d left.", userid); - delete request; - return; - } - if(!successful || code != k_EHTTPStatusCode200OK) { - LogItem(Log_Error, "Error checking SteamRep for client %L. Status code: %d, Successful: %s", client, view_as(code), successful ? "true" : "false"); - delete request; - return; - } - char data[4096]; - request.GetBodyData(data, sizeof(data)); - delete request; - LogItem(Log_Debug, "Received rep for %L: '%s'", client, data); - char exploded[3][35]; - ExplodeString(data, "&", exploded, sizeof(exploded), sizeof(exploded[])); - if(StrContains(exploded[1], "SCAMMER", false) != -1) { - LogItem(Log_Debug, "%L is a scammer, handling", client); - HandleScammer(client, exploded[2]); - } else { - char apiKey[64]; - cvarSteamAPIKey.GetString(apiKey, sizeof(apiKey)); - if(apiKey[0] != '\0') { - LogItem(Log_Debug, "%L is not a SR scammer, checking Steam...", client); - char steamid[64]; - if (GetClientAuthId(client, AuthId_SteamID64, steamid, sizeof(steamid))) - { - request = new SWHTTPRequest(k_EHTTPMethodGET, STEAM_API_URL); - request.SetCallbacks(OnSteamAPI); - request.SetParam("key", apiKey); - request.SetParam("steamids", steamid); - request.SetParam("format", "vdf"); - request.SetContextValue(userid); - request.Send(); - } - else - { - LogItem(Log_Error, "Could not get SteamID64 for client %L!", client); - } - } - } -} - -void HandleScammer(int client, const char[] auth) { - char clientAuth[32]; - if (!GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth))) - { - LogItem(Log_Error, "Error handling potential scammer. (Unverified) Auth is %s.", auth); - return; - } - if(!StrEqual(auth, clientAuth)) { - LogItem(Log_Error, "Steam ID for %L (%s) didn't match SteamRep's response (%s)", client, clientAuth, auth); - return; - } - switch(cvarDealMethod.IntValue) { - case 0: { - // Disabled - } - case 1: { - // Chat tag - if(!LibraryExists("scp")) { - LogItem(Log_Info, "Simple Chat Processor (Redux) is not loaded, so tags will not be colored in chat.", client); - return; - } - LogItem(Log_Info, "Tagged %L as a scammer", client); - SetClientTag(client, TagType_Scammer); - } - case 2: { - // Kick - LogItem(Log_Info, "Kicked %L as a scammer", client); - KickClient(client, "You are a reported scammer. Visit http://www.steamrep.com for more information"); - } - case 3: { - // Ban Steam ID - LogItem(Log_Info, "Banned %L by Steam ID as a scammer", client); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, "Player is a reported scammer via SteamRep.com"); - } else { - BanClient(client, cvarSteamIDBanLength.IntValue, BANFLAG_AUTHID, "Player is a reported scammer via SteamRep.com", "You are a reported scammer. Visit http://www.steamrep.com for more information", "steamrep_checker"); - } - } - case 4: { - // Ban IP - LogItem(Log_Info, "Banned %L by IP as a scammer", client); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { - // SourceBans doesn't currently expose a native to ban an IP! - char ip[64]; - GetClientIP(client, ip, sizeof(ip)); - ServerCommand("sm_banip \"%s\" %d A scammer has connected from this IP. Steam ID: %s", ip, cvarIPBanLength.IntValue, clientAuth); - } else { - char banMessage[256]; - Format(banMessage, sizeof(banMessage), "A scammer has connected from this IP. Steam ID: %s", clientAuth); - BanClient(client, cvarIPBanLength.IntValue, BANFLAG_IP, banMessage, "You are a reported scammer. Visit http://www.steamrep.com for more information", "steamrep_checker"); - } - } - case 5: { - // Ban Steam ID + IP - LogItem(Log_Info, "Banned %L by Steam ID and IP as a scammer", client); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { - char ip[64]; - GetClientIP(client, ip, sizeof(ip)); - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, "Player is a reported scammer via SteamRep.com"); - ServerCommand("sm_banip \"%s\" %d A scammer has connected from this IP. Steam ID: %s", ip, cvarIPBanLength.IntValue, clientAuth); - } else { - BanClient(client, cvarSteamIDBanLength.IntValue, BANFLAG_AUTHID, "Player is a reported scammer via SteamRep.com", "You are a reported scammer. Visit http://www.steamrep.com for more information", "steamrep_checker"); - BanClient(client, cvarIPBanLength.IntValue, BANFLAG_IP, "Player is a reported scammer via SteamRep.com", "You are a reported scammer. Visit http://www.steamrep.com for more information", "steamrep_checker"); - } - } - } -} - -public void OnSteamAPI(SWHTTPRequest request, bool bFailure, bool successful, EHTTPStatusCode code, any userid) { - int client = GetClientOfUserId(userid); - char getResponse[4096]; - if(client == 0) { - LogItem(Log_Debug, "Client with User ID %d left when checking Valve status.", userid); - delete request; - return; - } - if(!successful || code != k_EHTTPStatusCode200OK) { - LogItem(Log_Error, "Error checking Steam for client %L. Status code: %d, Successful: %s", client, view_as(code), successful ? "true" : "false"); - delete request; - return; - } - request.GetBodyData(getResponse, request.ResponseSize); - delete request; - KeyValues kv = new KeyValues("response"); - #if defined DEBUG - PrintToServer(getResponse); - #endif - if(!kv.ImportFromString(getResponse)) { - LogItem(Log_Error, "Steam returned invalid KeyValues for %L, returned %s.", client, getResponse); - delete kv; - return; - } - kv.JumpToKey("players"); - kv.JumpToKey("0"); - char banStatus[64]; - kv.GetString("EconomyBan", banStatus, sizeof(banStatus)); - delete kv; - if(StrEqual(banStatus, "banned")) { - LogItem(Log_Debug, "%L is trade-banned, handling...", client); - HandleValvePlayer(client, true); - } else if(StrEqual(banStatus, "probation")) { - LogItem(Log_Debug, "%L is on trade probation, handling...", client); - HandleValvePlayer(client, false); - } else { - LogItem(Log_Debug, "Steam reports that %L is OK", client); - } -} - -void HandleValvePlayer(int client, bool banned) { - char clientAuth[32]; - if (GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth))) - { - switch((banned) ? cvarValveBanDealMethod.IntValue : cvarValveCautionDealMethod.IntValue) { - case 0: { - // Disabled - } - case 1: { - // Chat tag - if(!LibraryExists("scp")) { - LogItem(Log_Info, "Simple Chat Processor (Redux) is not loaded, so tags will not be colored in chat.", client); - return; - } - LogItem(Log_Info, "Tagged %L as %s", client, banned ? "trade banned" : "trade probation"); - SetClientTag(client, banned ? TagType_TradeBanned : TagType_TradeProbation); - } - case 2: { - // Kick - LogItem(Log_Info, "Kicked %L as %s", client, banned ? "trade banned" : "trade probation"); - KickClient(client, "You are %s", banned ? "trade banned" : "on trade probation"); - } - case 3: { - // Ban Steam ID - LogItem(Log_Info, "Banned %L by Steam ID as %s", client, banned ? "trade banned" : "trade probation"); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { - char message[256]; - Format(message, sizeof(message), "Player is %s", banned ? "trade banned" : "on trade probation"); - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, message); - } else { - char message[256], kickMessage[256]; - Format(message, sizeof(message), "Player is %s", banned ? "trade banned" : "on trade probation"); - Format(kickMessage, sizeof(kickMessage), "You are %s", banned ? "trade banned" : "on trade probation"); - BanClient(client, cvarSteamIDBanLength.IntValue, BANFLAG_AUTHID, message, kickMessage, "steamrep_checker"); - } - } - case 4: { - // Ban IP - LogItem(Log_Info, "Banned %L by IP as %s", client, banned ? "trade banned" : "trade probation"); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { - // SourceBans doesn't currently expose a native to ban an IP! - ServerCommand("sm_banip #%d %d A %s has connected from this IP. Steam ID: %s", banned ? "trade banned player" : "player on trade probation", GetClientUserId(client), cvarIPBanLength.IntValue, clientAuth); - } else { - char message[256], kickMessage[256]; - Format(message, sizeof(message), "A %s has connected from this IP. Steam ID: %s", banned ? "trade banned player" : "player on trade probation", clientAuth); - Format(kickMessage, sizeof(kickMessage), "You are %s", banned ? "trade banned" : "on trade probation"); - BanClient(client, cvarIPBanLength.IntValue, BANFLAG_IP, message, kickMessage, "steamrep_checker"); - } - } - case 5: { - // Ban Steam ID + IP - LogItem(Log_Info, "Banned %L by Steam ID and IP as %s", client, banned ? "trade banned" : "trade probation"); - if(GetFeatureStatus(FeatureType_Native, "SourceBans_BanPlayer") == FeatureStatus_Available) { - char message[256]; - Format(message, sizeof(message), "Player is %s", banned ? "trade banned" : "on trade probation"); - SourceBans_BanPlayer(0, client, cvarSteamIDBanLength.IntValue, message); - ServerCommand("sm_banip #%d %d A %s has connected from this IP. Steam ID: %s", banned ? "trade banned player" : "player on trade probation", GetClientUserId(client), cvarIPBanLength.IntValue, clientAuth); - } else { - char message[256], kickMessage[256]; - Format(message, sizeof(message), "A %s has connected from this IP. Steam ID: %s", banned ? "trade banned player" : "player on trade probation", clientAuth); - Format(kickMessage, sizeof(kickMessage), "You are %s", banned ? "trade banned" : "on trade probation"); - BanClient(client, cvarSteamIDBanLength.IntValue, BANFLAG_AUTHID, message, kickMessage, "steamrep_checker"); - BanClient(client, cvarIPBanLength.IntValue, BANFLAG_IP, message, kickMessage, "steamrep_checker"); - } - } - } - } - else - { - LogItem(Log_Error, "Could not get SteamID2 for client %L in HandleValvePlayer!", client); - } -} - -void SetClientTag(int client, TagType type) { - char name[MAX_NAME_LENGTH]; - switch(type) { - case TagType_Scammer: { - CPrintToChatAll("{DARKORANGE}WARNING: {LIGHTGREEN}%N{DEFAULT} is a reported scammer at SteamRep.com", client); - Format(name, sizeof(name), "[SCAMMER] %N", client); - SetClientInfo(client, "name", name); - } - case TagType_TradeBanned: { - PrintToChatAll("{DARKORANGE}WARNING: {LIGHTGREEN}%N{DEFAULT} is trade banned", client); - Format(name, sizeof(name), "[TRADE BANNED] %N", client); - SetClientInfo(client, "name", name); - } - case TagType_TradeProbation: { - PrintToChatAll("{CORAL}CAUTION: {LIGHTGREEN}%N{DEFAULT} is on trade probation", client); - Format(name, sizeof(name), "[TRADE PROBATION] %N", client); - SetClientInfo(client, "name", name); - } - } - clientTag[client] = type; -} - -public Action OnChatMessage(int &author, Handle recipients, char[] name, char[] message) { - switch(clientTag[author]) { - case TagType_None: return Plugin_Continue; - case TagType_Scammer: ReplaceString(name, MAXLENGTH_NAME, "[SCAMMER]", "\x07FF0000[SCAMMER]\x03"); - case TagType_TradeBanned: ReplaceString(name, MAXLENGTH_NAME, "[TRADE BANNED]", "\x07FF0000[TRADE BANNED]\x03"); - case TagType_TradeProbation: ReplaceString(name, MAXLENGTH_NAME, "[TRADE PROBATION]", "\x07FF7F00[TRADE PROBATION]\x03"); - } - return Plugin_Changed; -} - -public Action CCC_OnColor(int client, const char[] message, CCC_ColorType type) { - if(type == CCC_TagColor && clientTag[client] != TagType_None) { - return Plugin_Handled; - } - return Plugin_Continue; -} - -public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) { - if(!cvarSpawnMessage.BoolValue) { - return; - } - int client = GetClientOfUserId(event.GetInt("userid")); - if(GetClientTeam(client) < 2 || messageDisplayed[client]) { - return; - } - CPrintToChat(client, "{GREEN}[SR]{DEFAULT} This server is protected by {GREEN}SteamRep{DEFAULT}. Visit {GREEN}SteamRep.com{DEFAULT} for more information."); - messageDisplayed[client] = true; -} - -public void Event_PlayerChangeName(Event event, const char[] name, bool dontBroadcast) { - int client = GetClientOfUserId(event.GetInt("userid")); - if(clientTag[client] == TagType_None) { - return; - } - char clientName[MAX_NAME_LENGTH]; - event.GetString("newname", clientName, sizeof(clientName)); - if(clientTag[client] == TagType_Scammer && StrContains(clientName, "[SCAMMER]") != 0) { - KickClient(client, "Kicked from server\n\nDo not attempt to remove the [SCAMMER] tag"); - } else if(clientTag[client] == TagType_TradeBanned && StrContains(clientName, "[TRADE BANNED]") != 0) { - KickClient(client, "Kicked from server\n\nDo not attempt to remove the [TRADE BANNED] tag"); - } else if(clientTag[client] == TagType_TradeProbation && StrContains(clientName, "[TRADE PROBATION]") != 0) { - KickClient(client, "Kicked from server\n\nDo not attempt to remove the [TRADE PROBATION] tag"); - } -} - -public Action Command_Rep(int client, int args) { - int target; - if(args == 0) { - target = GetClientAimTarget(client); - if(target <= 0) { - DisplayClientMenu(client); - return Plugin_Handled; - } - } else { - char arg1[MAX_NAME_LENGTH]; - GetCmdArg(1, arg1, sizeof(arg1)); - target = FindTargetEx(client, arg1, true, false, false); - if(target == -1) { - DisplayClientMenu(client); - return Plugin_Handled; - } - } - char steamID[64]; - if (GetClientAuthId(target, AuthId_SteamID64, steamID, sizeof(steamID))) - { - char url[256]; - Format(url, sizeof(url), "https://steamrep.com/profiles/%s", steamID); - KeyValues Kv = new KeyValues("data"); - Kv.SetString("title", ""); - Kv.SetString("type", "2"); - Kv.SetString("msg", url); - Kv.SetNum("customsvr", 1); - ShowVGUIPanel(client, "info", Kv); - delete Kv; - } - else - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Could not get SteamRep profile, try again shortly!"); - } - return Plugin_Handled; -} - -void DisplayClientMenu(int client) { - Menu menu = new Menu(Handler_ClientMenu); - menu.SetTitle("Select Player"); - char name[MAX_NAME_LENGTH], index[8]; - for(int i= 1; i <= MaxClients; i++) { - if(!IsValidClient(i)) { - continue; - } - GetClientName(i, name, sizeof(name)); - IntToString(GetClientUserId(i), index, sizeof(index)); - menu.AddItem(index, name); - } - menu.Display(client, MENU_TIME_FOREVER); -} - -public int Handler_ClientMenu(Menu menu, MenuAction action, int client, int param) { - if(action == MenuAction_End) { - delete menu; - } - if(action != MenuAction_Select) { - return; - } - char selection[32]; - if (menu.GetItem(param, selection, sizeof(selection)) && IsValidClient(client)) - { - FakeClientCommand(client, "sm_rep #%s", selection); - } -} - -int FindTargetEx(int client, const char[] target, bool nobots = false, bool immunity = true, bool replyToError = true) { - char target_name[MAX_TARGET_LENGTH]; - int target_list[1], target_count; - bool tn_is_ml; - - int flags = COMMAND_FILTER_NO_MULTI; - if(nobots) { - flags |= COMMAND_FILTER_NO_BOTS; - } - if(!immunity) { - flags |= COMMAND_FILTER_NO_IMMUNITY; - } - - if((target_count = ProcessTargetString( - target, - client, - target_list, - 1, - flags, - target_name, - sizeof(target_name), - tn_is_ml)) > 0) - { - return target_list[0]; - } else { - if(replyToError) { - ReplyToTargetError(client, target_count); - } - return -1; - } -} - -void LogItem(LogLevel level, const char[] format, any ...) -{ - int logLevel = cvarLogLevel.IntValue; - if(logLevel < view_as(level)) - { - return; - } - char logPrefixes[][] = {"[ERROR]", "[INFO]", "[DEBUG]"}; - char buffer[512], file[PLATFORM_MAX_PATH]; - VFormat(buffer, sizeof(buffer), format, 3); - BuildPath(Path_SM, file, sizeof(file), "logs/steamrep_checker.log"); - LogToFileEx(file, "%s %s", logPrefixes[view_as(level)], buffer); -} From 8d4735102b2a1542b9c8e246115c3d14b480f967 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:11:08 -0800 Subject: [PATCH 04/29] Line endings changes --- scripting/include/json.inc | 642 ++-- scripting/include/json/decode_helpers.inc | 624 +-- scripting/include/json/object.inc | 1428 +++---- scripting/include/socket.inc | 4 +- scripting/include/sourcecomms.inc | 255 +- scripting/ngs_admin_toolkit.sp | 1070 +++--- scripting/ngs_adminlist.sp | 362 +- scripting/ngs_celebrateunusual.sp | 210 +- scripting/ngs_donor_toolkit.sp | 118 +- scripting/ngs_freeduels.sp | 4240 ++++++++++----------- scripting/ngs_friendly.sp | 18 +- scripting/ngs_player_feedback.sp | 168 +- updater/ngs_freeduels.txt | 40 +- 13 files changed, 4589 insertions(+), 4590 deletions(-) diff --git a/scripting/include/json.inc b/scripting/include/json.inc index 52aca6b..5dfff16 100644 --- a/scripting/include/json.inc +++ b/scripting/include/json.inc @@ -1,321 +1,321 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * sm-json - * Provides a pure SourcePawn implementation of JSON encoding and decoding. - * https://github.com/clugg/sm-json - * - * sm-json (C)2018 James D. (clug) - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - */ - -#if defined _json_included - #endinput -#endif -#define _json_included - -#include -#include -#include -#include -#include -#include - -/** - * Encodes a JSON_Object into its string representation. - * - * @param obj Object to encode. - * @param output String buffer to store output. - * @param maxlen Maximum size of string buffer. - */ -stock void json_encode(JSON_Object obj, char[] output, int maxlen) { - char[] key = new char[maxlen]; - bool is_array = obj.IsArray; - int builder_size; - int keys_used = 0; - - // used in key iterator - int str_length = 1; - int int_value; - int cell_length = 0; - - strcopy(output, maxlen, (is_array) ? "[" : "{"); - - StringMapSnapshot snap = obj.Snapshot(); - for (int i = 0; i < obj.Length; ++i) { - if (is_array) { - obj.GetIndexString(key, maxlen, i); - } else { - snap.GetKey(i, key, maxlen); - } - - if (json_is_meta_key(key)) continue; // skip meta-keys - if (obj.GetKeyHidden(key)) continue; // skip hidden keys - - JSON_CELL_TYPE type = obj.GetKeyType(key); - if (type == Type_Invalid) continue; // skip keys of unknown type - - str_length = 1; - if (type == Type_String) { - str_length = obj.GetKeyLength(key); - } - char[] str_value = new char[str_length + 1]; - - cell_length = 0; - switch (type) { - case Type_String: { - obj.GetString(key, str_value, str_length + 1); - cell_length = json_cell_string_size(str_length) + 1; - } - case Type_Int: { - int_value = obj.GetInt(key); - cell_length = json_cell_int_size(int_value); - } - case Type_Float: { - cell_length = json_cell_float_size(); - } - case Type_Bool: { - cell_length = json_cell_bool_size(); - } - case Type_Null: { - cell_length = json_cell_null_size(); - } - case Type_Object: { - cell_length = maxlen; - } - } - - char[] cell = new char[cell_length]; - switch (type) { - case Type_String: { - json_cell_string(str_value, cell, cell_length); - } - case Type_Int: { - json_cell_int(int_value, cell, cell_length); - } - case Type_Float: { - float value = obj.GetFloat(key); - json_cell_float(value, cell, cell_length); - } - case Type_Bool: { - bool value = obj.GetBool(key); - json_cell_bool(value, cell, cell_length); - } - case Type_Null: { - json_cell_null(cell, cell_length); - } - case Type_Object: { - JSON_Object value = obj.GetObject(key); - json_encode(value, cell, cell_length); - } - } - - // make the builder fit our key:value - builder_size = cell_length + 1; // cell_length is length of value and null terminator, +1 for , - if (!is_array) { - builder_size += json_cell_string_size(strlen(key)) + 1; // get the length of the key, +1 for : - } - - char[] builder = new char[builder_size]; - strcopy(builder, builder_size, ""); - // add the key if it's an object - if (!is_array) { - json_cell_string(key, builder, builder_size); - StrCat(builder, builder_size, ":"); - } - - // add the value and a trailing comma, then send builder to output - StrCat(builder, builder_size, cell); - StrCat(builder, builder_size, ","); - StrCat(output, maxlen, builder); - - keys_used += 1; - } - - delete snap; - - if (keys_used == 0) { - // empty objects and arrays, just chuck a comma in so it gets replaced later - StrCat(output, maxlen, ","); - } - - // replace final , with closing bracket - output[strlen(output) - 1] = (is_array) ? ']' : '}'; -} - -/** - * Decodes a JSON string into its JSON_Object representation. - * - * @param buffer Buffer to decode. - * @param result Object to store output in. Setting this allows loading over an existing JSON_Object, 'refreshing' it as opposed to creating a new one. [optional, default: null] - * @param pos Current position of the decoder as a bytes offset into the buffer. - * @return JSON_Object representation of buffer, or null if decoding failed (buffer didn't contain valid JSON). - */ -stock JSON_Object json_decode(const char[] buffer, JSON_Object result = null, int &pos = 0) { - int length = strlen(buffer); - bool is_array = false; - - if (json_is_object(buffer[pos])) { - is_array = false; - } else if (json_is_array(buffer[pos])) { - is_array = true; - } else { - LogError("json_decode: character not identified as object or array at %d", pos); - return null; - } - - if (result == null) result = new JSON_Object(is_array); - - char key[JSON_BUFFER_SIZE]; - char string[JSON_BUFFER_SIZE]; - while ((!is_array && !json_is_object_end(buffer[pos])) || - (is_array && !json_is_array_end(buffer[pos]))) { - ++pos; - if (!json_skip_whitespace(buffer, length, pos)) { - LogError("json_decode: buffer ended early at %d", pos); - return null; - } - - if (!is_array) { - if (!json_is_string(buffer[pos])) { - LogError("json_decode: expected key string at %d", pos); - return null; - } - - json_extract_string(buffer, length, pos, key, sizeof(key), is_array); // fetch object key first - if (!json_skip_whitespace(buffer, length, pos)) { - LogError("json_decode: buffer ended early at %d", pos); - return null; - } - if (buffer[pos++] != ':') { - LogError("json_decode: expected colon after key at %d", pos); - return null; - } - } - - if (!json_skip_whitespace(buffer, length, pos)) { - LogError("json_decode: buffer ended early at %d", pos); - return null; - } - - if (json_is_object(buffer[pos]) || json_is_array(buffer[pos])) { - JSON_Object current = (!is_array) ? result.GetObject(key) : null; - - JSON_Object value = json_decode(buffer, current, pos); - if (value == null) return null; // drop back a call, the recursive decode failed - - if (is_array) { - result.PushObject(value); - } else { - result.SetObject(key, value); - } - // increment past end bracket - ++pos; - } else if (json_is_string(buffer[pos])) { - if (!json_extract_string(buffer, length, pos, string, sizeof(string), is_array)) { - LogError("json_decode: couldn't extract string at %d", pos); - return null; - } - - if (is_array) { - result.PushString(string); - } else { - result.SetString(key, string); - } - } else { - if (!json_extract_until_end(buffer, length, pos, string, sizeof(string), is_array)) { - LogError("json_decode: couldn't extract until end at %d", pos); - return null; - } - - if (json_is_int(string)) { - int value = json_extract_int(string); - if (is_array) { - result.PushInt(value); - } else { - result.SetInt(key, value); - } - } else if (json_is_float(string)) { - float value = json_extract_float(string); - if (is_array) { - result.PushFloat(value); - } else { - result.SetFloat(key, value); - } - } else if (json_is_bool(string)) { - bool value = json_extract_bool(string); - if (is_array) { - result.PushBool(value); - } else { - result.SetBool(key, value); - } - } else if (json_is_null(string)) { - if (is_array) { - result.PushHandle(null); - } else { - result.SetHandle(key, null); - } - } - } - - if (!json_skip_whitespace(buffer, length, pos)) { - LogError("json_decode: buffer ended early at %d", pos); - return null; - } - } - - return result; -} - -/** - * Recursively cleans up JSON_Objects and any objects referenced within. - * - * @param obj JSON_Object to clean up. - */ -void json_cleanup(JSON_Object obj) { - char key[JSON_BUFFER_SIZE]; - bool is_array = obj.IsArray; - StringMapSnapshot snap = obj.Snapshot(); - for (int i = 0; i < snap.Length; ++i) { - snap.GetKey(i, key, sizeof(key)); - if (json_is_meta_key(key)) continue; - - JSON_CELL_TYPE type = obj.GetKeyType(key); - if (type != Type_Object) continue; - - JSON_Object nested_obj = obj.GetObject(key); - if (nested_obj != null) { - nested_obj.Cleanup(); - delete nested_obj; - } - } - - obj.Clear(); - delete snap; - - if (is_array) { - obj.SetValue(JSON_ARRAY_INDEX_KEY, 0); - } -} +/** + * vim: set ts=4 : + * ============================================================================= + * sm-json + * Provides a pure SourcePawn implementation of JSON encoding and decoding. + * https://github.com/clugg/sm-json + * + * sm-json (C)2018 James D. (clug) + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + */ + +#if defined _json_included + #endinput +#endif +#define _json_included + +#include +#include +#include +#include +#include +#include + +/** + * Encodes a JSON_Object into its string representation. + * + * @param obj Object to encode. + * @param output String buffer to store output. + * @param maxlen Maximum size of string buffer. + */ +stock void json_encode(JSON_Object obj, char[] output, int maxlen) { + char[] key = new char[maxlen]; + bool is_array = obj.IsArray; + int builder_size; + int keys_used = 0; + + // used in key iterator + int str_length = 1; + int int_value; + int cell_length = 0; + + strcopy(output, maxlen, (is_array) ? "[" : "{"); + + StringMapSnapshot snap = obj.Snapshot(); + for (int i = 0; i < obj.Length; ++i) { + if (is_array) { + obj.GetIndexString(key, maxlen, i); + } else { + snap.GetKey(i, key, maxlen); + } + + if (json_is_meta_key(key)) continue; // skip meta-keys + if (obj.GetKeyHidden(key)) continue; // skip hidden keys + + JSON_CELL_TYPE type = obj.GetKeyType(key); + if (type == Type_Invalid) continue; // skip keys of unknown type + + str_length = 1; + if (type == Type_String) { + str_length = obj.GetKeyLength(key); + } + char[] str_value = new char[str_length + 1]; + + cell_length = 0; + switch (type) { + case Type_String: { + obj.GetString(key, str_value, str_length + 1); + cell_length = json_cell_string_size(str_length) + 1; + } + case Type_Int: { + int_value = obj.GetInt(key); + cell_length = json_cell_int_size(int_value); + } + case Type_Float: { + cell_length = json_cell_float_size(); + } + case Type_Bool: { + cell_length = json_cell_bool_size(); + } + case Type_Null: { + cell_length = json_cell_null_size(); + } + case Type_Object: { + cell_length = maxlen; + } + } + + char[] cell = new char[cell_length]; + switch (type) { + case Type_String: { + json_cell_string(str_value, cell, cell_length); + } + case Type_Int: { + json_cell_int(int_value, cell, cell_length); + } + case Type_Float: { + float value = obj.GetFloat(key); + json_cell_float(value, cell, cell_length); + } + case Type_Bool: { + bool value = obj.GetBool(key); + json_cell_bool(value, cell, cell_length); + } + case Type_Null: { + json_cell_null(cell, cell_length); + } + case Type_Object: { + JSON_Object value = obj.GetObject(key); + json_encode(value, cell, cell_length); + } + } + + // make the builder fit our key:value + builder_size = cell_length + 1; // cell_length is length of value and null terminator, +1 for , + if (!is_array) { + builder_size += json_cell_string_size(strlen(key)) + 1; // get the length of the key, +1 for : + } + + char[] builder = new char[builder_size]; + strcopy(builder, builder_size, ""); + // add the key if it's an object + if (!is_array) { + json_cell_string(key, builder, builder_size); + StrCat(builder, builder_size, ":"); + } + + // add the value and a trailing comma, then send builder to output + StrCat(builder, builder_size, cell); + StrCat(builder, builder_size, ","); + StrCat(output, maxlen, builder); + + keys_used += 1; + } + + delete snap; + + if (keys_used == 0) { + // empty objects and arrays, just chuck a comma in so it gets replaced later + StrCat(output, maxlen, ","); + } + + // replace final , with closing bracket + output[strlen(output) - 1] = (is_array) ? ']' : '}'; +} + +/** + * Decodes a JSON string into its JSON_Object representation. + * + * @param buffer Buffer to decode. + * @param result Object to store output in. Setting this allows loading over an existing JSON_Object, 'refreshing' it as opposed to creating a new one. [optional, default: null] + * @param pos Current position of the decoder as a bytes offset into the buffer. + * @return JSON_Object representation of buffer, or null if decoding failed (buffer didn't contain valid JSON). + */ +stock JSON_Object json_decode(const char[] buffer, JSON_Object result = null, int &pos = 0) { + int length = strlen(buffer); + bool is_array = false; + + if (json_is_object(buffer[pos])) { + is_array = false; + } else if (json_is_array(buffer[pos])) { + is_array = true; + } else { + LogError("json_decode: character not identified as object or array at %d", pos); + return null; + } + + if (result == null) result = new JSON_Object(is_array); + + char key[JSON_BUFFER_SIZE]; + char string[JSON_BUFFER_SIZE]; + while ((!is_array && !json_is_object_end(buffer[pos])) || + (is_array && !json_is_array_end(buffer[pos]))) { + ++pos; + if (!json_skip_whitespace(buffer, length, pos)) { + LogError("json_decode: buffer ended early at %d", pos); + return null; + } + + if (!is_array) { + if (!json_is_string(buffer[pos])) { + LogError("json_decode: expected key string at %d", pos); + return null; + } + + json_extract_string(buffer, length, pos, key, sizeof(key), is_array); // fetch object key first + if (!json_skip_whitespace(buffer, length, pos)) { + LogError("json_decode: buffer ended early at %d", pos); + return null; + } + if (buffer[pos++] != ':') { + LogError("json_decode: expected colon after key at %d", pos); + return null; + } + } + + if (!json_skip_whitespace(buffer, length, pos)) { + LogError("json_decode: buffer ended early at %d", pos); + return null; + } + + if (json_is_object(buffer[pos]) || json_is_array(buffer[pos])) { + JSON_Object current = (!is_array) ? result.GetObject(key) : null; + + JSON_Object value = json_decode(buffer, current, pos); + if (value == null) return null; // drop back a call, the recursive decode failed + + if (is_array) { + result.PushObject(value); + } else { + result.SetObject(key, value); + } + // increment past end bracket + ++pos; + } else if (json_is_string(buffer[pos])) { + if (!json_extract_string(buffer, length, pos, string, sizeof(string), is_array)) { + LogError("json_decode: couldn't extract string at %d", pos); + return null; + } + + if (is_array) { + result.PushString(string); + } else { + result.SetString(key, string); + } + } else { + if (!json_extract_until_end(buffer, length, pos, string, sizeof(string), is_array)) { + LogError("json_decode: couldn't extract until end at %d", pos); + return null; + } + + if (json_is_int(string)) { + int value = json_extract_int(string); + if (is_array) { + result.PushInt(value); + } else { + result.SetInt(key, value); + } + } else if (json_is_float(string)) { + float value = json_extract_float(string); + if (is_array) { + result.PushFloat(value); + } else { + result.SetFloat(key, value); + } + } else if (json_is_bool(string)) { + bool value = json_extract_bool(string); + if (is_array) { + result.PushBool(value); + } else { + result.SetBool(key, value); + } + } else if (json_is_null(string)) { + if (is_array) { + result.PushHandle(null); + } else { + result.SetHandle(key, null); + } + } + } + + if (!json_skip_whitespace(buffer, length, pos)) { + LogError("json_decode: buffer ended early at %d", pos); + return null; + } + } + + return result; +} + +/** + * Recursively cleans up JSON_Objects and any objects referenced within. + * + * @param obj JSON_Object to clean up. + */ +void json_cleanup(JSON_Object obj) { + char key[JSON_BUFFER_SIZE]; + bool is_array = obj.IsArray; + StringMapSnapshot snap = obj.Snapshot(); + for (int i = 0; i < snap.Length; ++i) { + snap.GetKey(i, key, sizeof(key)); + if (json_is_meta_key(key)) continue; + + JSON_CELL_TYPE type = obj.GetKeyType(key); + if (type != Type_Object) continue; + + JSON_Object nested_obj = obj.GetObject(key); + if (nested_obj != null) { + nested_obj.Cleanup(); + delete nested_obj; + } + } + + obj.Clear(); + delete snap; + + if (is_array) { + obj.SetValue(JSON_ARRAY_INDEX_KEY, 0); + } +} diff --git a/scripting/include/json/decode_helpers.inc b/scripting/include/json/decode_helpers.inc index c982181..5d4f8af 100644 --- a/scripting/include/json/decode_helpers.inc +++ b/scripting/include/json/decode_helpers.inc @@ -1,312 +1,312 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * sm-json - * Provides a pure SourcePawn implementation of JSON encoding and decoding. - * https://github.com/clugg/sm-json - * - * sm-json (C)2018 James D. (clug) - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - */ - -#if defined _json_decode_helpers_included - #endinput -#endif -#define _json_decode_helpers_included - -#include - -/** - * @section Analysing format of incoming JSON cells. - */ - -/** - * Checks whether the character at the given - * position in the buffer is whitespace. - * - * @param buffer String buffer of data. - * @param pos Position to check in buffer. - * @return True if buffer[pos] is whitespace, false otherwise. - */ -stock bool json_is_whitespace(const char[] buffer, int &pos) { - return buffer[pos] == ' ' || buffer[pos] == '\t' || - buffer[pos] == '\r' || buffer[pos] == '\n'; -} - -/** - * Checks whether the character at the beginning - * of the buffer is the start of a string. - * - * @param buffer String buffer of data. - * @return True if buffer[0] is the start of a string, false otherwise. - */ -stock bool json_is_string(const char[] buffer) { - return buffer[0] == '"'; -} - -/** - * Checks whether the buffer provided contains an int. - * - * @param buffer String buffer of data. - * @return True if buffer contains an int, false otherwise. - */ -stock bool json_is_int(const char[] buffer) { - int length = strlen(buffer); - if (buffer[0] != '+' && buffer[0] != '-' && !IsCharNumeric(buffer[0])) { - return false; - } - - for (int i = 0; i < length; ++i) { - if (!IsCharNumeric(buffer[i])) return false; - } - - return true; -} - -/** - * Checks whether the buffer provided contains a float. - * - * @param buffer String buffer of data. - * @return True if buffer contains a float, false otherwise. - */ -stock bool json_is_float(const char[] buffer) { - bool decimal = false; - int length = strlen(buffer); - if (buffer[0] != '+' && buffer[0] != '-' && buffer[0] != '.' && !IsCharNumeric(buffer[0])) { - return false; - } - - for (int i = 0; i < length; ++i) { - if (buffer[i] == '.') { - if (decimal) { - return false; - } - - decimal = true; - } else if (!IsCharNumeric(buffer[i])) { - return false; - } - } - - return true; -} - -/** - * Checks whether the buffer provided contains a bool. - * - * @param buffer String buffer of data. - * @return True if buffer contains a bool, false otherwise. - */ -stock bool json_is_bool(const char[] buffer) { - return StrEqual(buffer, "true") || - StrEqual(buffer, "false"); -} - -/** - * Checks whether the buffer provided contains null. - * - * @param buffer String buffer of data. - * @return True if buffer contains null, false otherwise. - */ -stock bool json_is_null(const char[] buffer) { - return StrEqual(buffer, "null"); -} - -/** - * Checks whether the character at the beginning - * of the buffer is the start of an object. - * - * @param buffer String buffer of data. - * @return True if buffer[0] is the start of an object, false otherwise. - */ -stock bool json_is_object(const char[] buffer) { - return buffer[0] == '{'; -} - -/** - * Checks whether the character at the beginning - * of the buffer is the end of an object. - * - * @param buffer String buffer of data. - * @return True if buffer[0] is the end of an object, false otherwise. - */ -stock bool json_is_object_end(const char[] buffer) { - return buffer[0] == '}'; -} - -/** - * Checks whether the character at the beginning - * of the buffer is the start of an array. - * - * @param buffer String buffer of data. - * @return True if buffer[0] is the start of an array, false otherwise. - */ -stock bool json_is_array(const char[] buffer) { - return buffer[0] == '['; -} - -/** - * Checks whether the character at the beginning - * of the buffer is the start of an array. - * - * @param buffer String buffer of data. - * @return True if buffer[0] is the start of an array, false otherwise. - */ -stock bool json_is_array_end(const char[] buffer) { - return buffer[0] == ']'; -} - -/** - * Checks whether the character at the given position in the buffer - * is considered a valid 'end point' for some data, such as a - * colon (indicating a key), a comma (indicating a new element), - * or the end of an object or array. - * - * @param buffer String buffer of data. - * @param pos Position to check in buffer. - * @return True if buffer[pos] is a valid data end point, false otherwise. - */ -stock bool json_is_at_end(const char[] buffer, int &pos, bool is_array) { - return buffer[pos] == ',' || - (!is_array && buffer[pos] == ':') || - json_is_object_end(buffer[pos]) || - json_is_array_end(buffer[pos]); -} - -/** - * Moves the position until it reaches a non-whitespace - * character or the end of the buffer's maximum size. - * - * @param buffer String buffer of data. - * @param maxlen Maximum size of string buffer. - * @param pos Position to increment. - * @return True if pos is not at the end of the buffer, false otherwise. - */ -stock bool json_skip_whitespace(const char[] buffer, int maxlen, int &pos) { - while (json_is_whitespace(buffer, pos) && pos < maxlen) { - ++pos; - } - - return pos < maxlen; -} - -/** - * Extracts a JSON cell from the buffer until - * a valid end point is reached. - * - * @param buffer String buffer of data. - * @param maxlen Maximum size of string buffer. - * @param pos Position to increment. - * @param output String buffer to store output. - * @param output_maxlen Maximum size of output string buffer. - * @param is_array Whether the decoder is currently processing an array. - * @return True if pos is not at the end of the buffer, false otherwise. - */ -stock bool json_extract_until_end(const char[] buffer, int maxlen, int &pos, char[] output, int output_maxlen, bool is_array) { - // extracts a string from current pos until a valid 'end point' - strcopy(output, output_maxlen, ""); - - int start = pos; - while (!json_is_whitespace(buffer, pos) && !json_is_at_end(buffer, pos, is_array) && pos < maxlen) { - ++pos; - } - int end = pos - 1; - - // skip trailing whitespace - json_skip_whitespace(buffer, maxlen, pos); - - if (!json_is_at_end(buffer, pos, is_array)) return false; - strcopy(output, end - start + 2, buffer[start]); - - return pos < maxlen; -} - - -/** - * Extracts a JSON string from the buffer until - * a valid end point is reached. - * - * @param buffer String buffer of data. - * @param maxlen Maximum size of string buffer. - * @param pos Position to increment. - * @param output String buffer to store output. - * @param output_maxlen Maximum size of output string buffer. - * @param is_array Whether the decoder is currently processing an array. - * @return True if pos is not at the end of the buffer, false otherwise. - */ -stock bool json_extract_string(const char[] buffer, int maxlen, int &pos, char[] output, int output_maxlen, bool is_array) { - // extracts a string which needs to be quote-escaped - strcopy(output, output_maxlen, ""); - - ++pos; - int start = pos; - while (!(buffer[pos] == '"' && buffer[pos - 1] != '\\') && pos < maxlen) { - ++pos; - } - int end = pos - 1; - - // jump 1 ahead since we ended on " instead of an ending char - ++pos; - - // skip trailing whitespace - json_skip_whitespace(buffer, maxlen, pos); - - if (!json_is_at_end(buffer, pos, is_array)) return false; - // copy only from start with length end - start + 2 (+2 for NULL terminator and something else) - strcopy(output, end - start + 2, buffer[start]); - json_unescape_string(output, maxlen); - - return pos < maxlen; -} - -/** - * Extracts an int from the buffer. - * - * @param buffer String buffer of data. - * @return Int value of the buffer. - */ -stock int json_extract_int(const char[] buffer) { - return StringToInt(buffer); -} - -/** - * Extracts a float from the buffer. - * - * @param buffer String buffer of data. - * @return Float value of the buffer. - */ -stock float json_extract_float(const char[] buffer) { - return StringToFloat(buffer); -} - -/** - * Extracts a bool from the buffer. - * - * @param buffer String buffer of data. - * @return Bool value of the buffer. - */ -stock bool json_extract_bool(const char[] buffer) { - return StrEqual(buffer, "true"); -} +/** + * vim: set ts=4 : + * ============================================================================= + * sm-json + * Provides a pure SourcePawn implementation of JSON encoding and decoding. + * https://github.com/clugg/sm-json + * + * sm-json (C)2018 James D. (clug) + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + */ + +#if defined _json_decode_helpers_included + #endinput +#endif +#define _json_decode_helpers_included + +#include + +/** + * @section Analysing format of incoming JSON cells. + */ + +/** + * Checks whether the character at the given + * position in the buffer is whitespace. + * + * @param buffer String buffer of data. + * @param pos Position to check in buffer. + * @return True if buffer[pos] is whitespace, false otherwise. + */ +stock bool json_is_whitespace(const char[] buffer, int &pos) { + return buffer[pos] == ' ' || buffer[pos] == '\t' || + buffer[pos] == '\r' || buffer[pos] == '\n'; +} + +/** + * Checks whether the character at the beginning + * of the buffer is the start of a string. + * + * @param buffer String buffer of data. + * @return True if buffer[0] is the start of a string, false otherwise. + */ +stock bool json_is_string(const char[] buffer) { + return buffer[0] == '"'; +} + +/** + * Checks whether the buffer provided contains an int. + * + * @param buffer String buffer of data. + * @return True if buffer contains an int, false otherwise. + */ +stock bool json_is_int(const char[] buffer) { + int length = strlen(buffer); + if (buffer[0] != '+' && buffer[0] != '-' && !IsCharNumeric(buffer[0])) { + return false; + } + + for (int i = 0; i < length; ++i) { + if (!IsCharNumeric(buffer[i])) return false; + } + + return true; +} + +/** + * Checks whether the buffer provided contains a float. + * + * @param buffer String buffer of data. + * @return True if buffer contains a float, false otherwise. + */ +stock bool json_is_float(const char[] buffer) { + bool decimal = false; + int length = strlen(buffer); + if (buffer[0] != '+' && buffer[0] != '-' && buffer[0] != '.' && !IsCharNumeric(buffer[0])) { + return false; + } + + for (int i = 0; i < length; ++i) { + if (buffer[i] == '.') { + if (decimal) { + return false; + } + + decimal = true; + } else if (!IsCharNumeric(buffer[i])) { + return false; + } + } + + return true; +} + +/** + * Checks whether the buffer provided contains a bool. + * + * @param buffer String buffer of data. + * @return True if buffer contains a bool, false otherwise. + */ +stock bool json_is_bool(const char[] buffer) { + return StrEqual(buffer, "true") || + StrEqual(buffer, "false"); +} + +/** + * Checks whether the buffer provided contains null. + * + * @param buffer String buffer of data. + * @return True if buffer contains null, false otherwise. + */ +stock bool json_is_null(const char[] buffer) { + return StrEqual(buffer, "null"); +} + +/** + * Checks whether the character at the beginning + * of the buffer is the start of an object. + * + * @param buffer String buffer of data. + * @return True if buffer[0] is the start of an object, false otherwise. + */ +stock bool json_is_object(const char[] buffer) { + return buffer[0] == '{'; +} + +/** + * Checks whether the character at the beginning + * of the buffer is the end of an object. + * + * @param buffer String buffer of data. + * @return True if buffer[0] is the end of an object, false otherwise. + */ +stock bool json_is_object_end(const char[] buffer) { + return buffer[0] == '}'; +} + +/** + * Checks whether the character at the beginning + * of the buffer is the start of an array. + * + * @param buffer String buffer of data. + * @return True if buffer[0] is the start of an array, false otherwise. + */ +stock bool json_is_array(const char[] buffer) { + return buffer[0] == '['; +} + +/** + * Checks whether the character at the beginning + * of the buffer is the start of an array. + * + * @param buffer String buffer of data. + * @return True if buffer[0] is the start of an array, false otherwise. + */ +stock bool json_is_array_end(const char[] buffer) { + return buffer[0] == ']'; +} + +/** + * Checks whether the character at the given position in the buffer + * is considered a valid 'end point' for some data, such as a + * colon (indicating a key), a comma (indicating a new element), + * or the end of an object or array. + * + * @param buffer String buffer of data. + * @param pos Position to check in buffer. + * @return True if buffer[pos] is a valid data end point, false otherwise. + */ +stock bool json_is_at_end(const char[] buffer, int &pos, bool is_array) { + return buffer[pos] == ',' || + (!is_array && buffer[pos] == ':') || + json_is_object_end(buffer[pos]) || + json_is_array_end(buffer[pos]); +} + +/** + * Moves the position until it reaches a non-whitespace + * character or the end of the buffer's maximum size. + * + * @param buffer String buffer of data. + * @param maxlen Maximum size of string buffer. + * @param pos Position to increment. + * @return True if pos is not at the end of the buffer, false otherwise. + */ +stock bool json_skip_whitespace(const char[] buffer, int maxlen, int &pos) { + while (json_is_whitespace(buffer, pos) && pos < maxlen) { + ++pos; + } + + return pos < maxlen; +} + +/** + * Extracts a JSON cell from the buffer until + * a valid end point is reached. + * + * @param buffer String buffer of data. + * @param maxlen Maximum size of string buffer. + * @param pos Position to increment. + * @param output String buffer to store output. + * @param output_maxlen Maximum size of output string buffer. + * @param is_array Whether the decoder is currently processing an array. + * @return True if pos is not at the end of the buffer, false otherwise. + */ +stock bool json_extract_until_end(const char[] buffer, int maxlen, int &pos, char[] output, int output_maxlen, bool is_array) { + // extracts a string from current pos until a valid 'end point' + strcopy(output, output_maxlen, ""); + + int start = pos; + while (!json_is_whitespace(buffer, pos) && !json_is_at_end(buffer, pos, is_array) && pos < maxlen) { + ++pos; + } + int end = pos - 1; + + // skip trailing whitespace + json_skip_whitespace(buffer, maxlen, pos); + + if (!json_is_at_end(buffer, pos, is_array)) return false; + strcopy(output, end - start + 2, buffer[start]); + + return pos < maxlen; +} + + +/** + * Extracts a JSON string from the buffer until + * a valid end point is reached. + * + * @param buffer String buffer of data. + * @param maxlen Maximum size of string buffer. + * @param pos Position to increment. + * @param output String buffer to store output. + * @param output_maxlen Maximum size of output string buffer. + * @param is_array Whether the decoder is currently processing an array. + * @return True if pos is not at the end of the buffer, false otherwise. + */ +stock bool json_extract_string(const char[] buffer, int maxlen, int &pos, char[] output, int output_maxlen, bool is_array) { + // extracts a string which needs to be quote-escaped + strcopy(output, output_maxlen, ""); + + ++pos; + int start = pos; + while (!(buffer[pos] == '"' && buffer[pos - 1] != '\\') && pos < maxlen) { + ++pos; + } + int end = pos - 1; + + // jump 1 ahead since we ended on " instead of an ending char + ++pos; + + // skip trailing whitespace + json_skip_whitespace(buffer, maxlen, pos); + + if (!json_is_at_end(buffer, pos, is_array)) return false; + // copy only from start with length end - start + 2 (+2 for NULL terminator and something else) + strcopy(output, end - start + 2, buffer[start]); + json_unescape_string(output, maxlen); + + return pos < maxlen; +} + +/** + * Extracts an int from the buffer. + * + * @param buffer String buffer of data. + * @return Int value of the buffer. + */ +stock int json_extract_int(const char[] buffer) { + return StringToInt(buffer); +} + +/** + * Extracts a float from the buffer. + * + * @param buffer String buffer of data. + * @return Float value of the buffer. + */ +stock float json_extract_float(const char[] buffer) { + return StringToFloat(buffer); +} + +/** + * Extracts a bool from the buffer. + * + * @param buffer String buffer of data. + * @return Bool value of the buffer. + */ +stock bool json_extract_bool(const char[] buffer) { + return StrEqual(buffer, "true"); +} diff --git a/scripting/include/json/object.inc b/scripting/include/json/object.inc index 64dd349..fe583c8 100644 --- a/scripting/include/json/object.inc +++ b/scripting/include/json/object.inc @@ -1,714 +1,714 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * sm-json - * Provides a pure SourcePawn implementation of JSON encoding and decoding. - * https://github.com/clugg/sm-json - * - * sm-json (C)2018 James D. (clug) - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - */ - -#if defined _json_object_included - #endinput -#endif -#define _json_object_included - -#include -#include -#include -#include - -methodmap JSON_Object < StringMap { - /** - * Creates a new JSON_Object. - * - * @param is_array Should the object created be an array? [optional, default: false] - * @return A new JSON_Object. - */ - public JSON_Object(bool is_array = false) { - StringMap obj = CreateTrie(); - if (is_array) { - obj.SetValue(JSON_ARRAY_INDEX_KEY, 0); - } - return view_as(obj); - } - - /** - * Checks whether the object has a key. - * - * @param key Key to check existence of. - * @return True if the key exists, false otherwise. - */ - public bool HasKey(const char[] key) { - int int_value; - char str_value[1]; - - return this.GetValue(key, int_value) || - this.GetString(key, str_value, sizeof(str_value)); - } - - /** - * @section Array helpers. - */ - - /** - * Whether the current object is an array. - */ - property bool IsArray { - public get() { - return this.HasKey(JSON_ARRAY_INDEX_KEY); - } - } - - /** - * The current index of the object if it is an array, or -1 otherwise. - */ - property int CurrentIndex { - public get() { - if (!this.IsArray) return -1; - - int result; - return (this.GetValue(JSON_ARRAY_INDEX_KEY, result)) ? result : -1; - } - } - - /** - * The number of items in the object if it is an array, - * or the number of keys (including meta-keys) otherwise. - */ - property int Length { - public get() { - StringMapSnapshot snap = this.Snapshot(); - int length = (this.IsArray) ? this.CurrentIndex : snap.Length; - delete snap; - return length; - } - } - - /** - * Increments the current index of the object. - * - * @return True on success, false if the current object is not an array. - */ - public bool IncrementIndex() { - int current = this.CurrentIndex; - if (current == -1) return false; - - return this.SetValue(JSON_ARRAY_INDEX_KEY, current + 1); - } - - /** - * Gets the string representation of an array index. - * - * @param output String buffer to store output. - * @param maxlen Maximum size of string buffer. - * @param key Key to get string for. [optional, default: current index] - * @returns True on success, false otherwise. - */ - public int GetIndexString(char[] output, int maxlen, int key = -1) { - key = (key == -1) ? this.CurrentIndex : key; - if (key == -1) return false; - - return IntToString(key, output, maxlen); - } - - /** - * Removes an item from the object by index. - * - * @param index Index of object to remove. - * @returns True on success, false if the current object - * is not an array or the index does not exist. - */ - public bool RemoveIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.Remove(key); - } - - /** - * @section Internal getters. - */ - - /** - * Gets the cell type stored at a key. - * - * @param key Key to get value type for. - * @return Value type for key provided, or Type_Invalid if it does not exist. - */ - public JSON_CELL_TYPE GetKeyType(const char[] key) { - int maxlen = strlen(key) + strlen(JSON_META_TYPE_KEY) + 1; - char[] type_key = new char[maxlen]; - Format(type_key, maxlen, "%s%s", key, JSON_META_TYPE_KEY); - - JSON_CELL_TYPE type; - return (this.GetValue(type_key, type)) ? type : Type_Invalid; - } - - /** - * Gets the cell type stored at an index. - * - * @param index Index to get value type for. - * @return Value type for index provided, or Type_Invalid if it does not exist. - */ - public JSON_CELL_TYPE GetKeyTypeIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return Type_Invalid; - - return this.GetKeyType(key); - } - - /** - * Gets the length of the string stored at a key. - * - * @param key Key to get string length for. - * @return Length of string at key provided, or -1 if it is not a string/does not exist. - */ - public int GetKeyLength(const char[] key) { - int maxlen = strlen(key) + strlen(JSON_META_LENGTH_KEY) + 1; - char[] length_key = new char[maxlen]; - Format(length_key, maxlen, "%s%s", key, JSON_META_LENGTH_KEY); - - int length; - return (this.GetValue(length_key, length)) ? length : -1; - } - - /** - * Gets the length of the string stored at an index. - * - * @param index Index to get string length for. - * @return Length of string at index provided, or -1 if it is not a string/does not exist. - */ - public int GetKeyLengthIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return -1; - - return this.GetKeyLength(key); - } - - /** - * Gets whether the key should be hidden from encoding. - * - * @param key Key to get hidden state for. - * @return Whether or not the key should be hidden. - */ - public bool GetKeyHidden(const char[] key) { - int maxlen = strlen(key) + strlen(JSON_META_HIDDEN_KEY) + 1; - char[] length_key = new char[maxlen]; - Format(length_key, maxlen, "%s%s", key, JSON_META_HIDDEN_KEY); - - bool hidden; - return (this.GetValue(length_key, hidden)) ? hidden : false; - } - - /** - * Gets whether the index should be hidden from encoding. - * - * @param index Index to get hidden state for. - * @return Whether or not the index should be hidden. - */ - public bool GetKeyHiddenIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.GetKeyHidden(key); - } - - /** - * @section Internal setters. - */ - - /** - * Sets the cell type stored at a key. - * - * @param key Key to set value type for. - * @param type Type to set key to. - * @return True on success, false otherwise. - */ - public bool SetKeyType(const char[] key, JSON_CELL_TYPE type) { - int maxlen = strlen(key) + strlen(JSON_META_TYPE_KEY) + 1; - char[] type_key = new char[maxlen]; - Format(type_key, maxlen, "%s%s", key, JSON_META_TYPE_KEY); - - return this.SetValue(type_key, type); - } - - /** - * Sets the cell type stored at an index. - * - * @param index Index to set value type for. - * @param type Type to set index to. - * @return True on success, false otherwise. - */ - public bool SetKeyTypeIndexed(int index, JSON_CELL_TYPE value) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetKeyType(key, value); - } - - /** - * Sets the length of the string stored at a key. - * - * @param key Key to set string length for. - * @param length Length to set string to. - * @return True on success, false otherwise. - */ - public bool SetKeyLength(const char[] key, int length) { - int maxlen = strlen(key) + strlen(JSON_META_LENGTH_KEY) + 1; - char[] length_key = new char[maxlen]; - Format(length_key, maxlen, "%s%s", key, JSON_META_LENGTH_KEY); - - return this.SetValue(length_key, length); - } - - /** - * Sets the length of the string stored at an index. - * - * @param index Index to set string length for. - * @param length Length to set string to. - * @return True on success, false otherwise. - */ - public bool SetKeyLengthIndexed(int index, int length) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetKeyLength(key, length); - } - - /** - * Sets whether the key should be hidden from encoding. - * - * @param key Key to set hidden state for. - * @param hidden Wheter or not the key should be hidden. - * @return True on success, false otherwise. - */ - public bool SetKeyHidden(const char[] key, bool hidden) { - int maxlen = strlen(key) + strlen(JSON_META_HIDDEN_KEY) + 1; - char[] hidden_key = new char[maxlen]; - Format(hidden_key, maxlen, "%s%s", key, JSON_META_HIDDEN_KEY); - - return this.SetValue(hidden_key, hidden); - } - - /** - * Sets whether the index should be hidden from encoding. - * - * @param index Index to set hidden state for. - * @param hidden Wheter or not the index should be hidden. - * @return True on success, false otherwise. - */ - public bool SetKeyHiddenIndexed(int index, bool hidden) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetKeyHidden(key, hidden); - } - - /** - * @section Object getters. - */ - - /** - * Retrieves the int stored at a key. - * - * @param key Key to retrieve int value for. - * @returns Value stored at key. - */ - public int GetInt(const char[] key) { - int value; - return (this.GetValue(key, value)) ? value : -1; - } - - /** - * Retrieves the int stored at an index. - * - * @param index Index to retrieve int value for. - * @returns Value stored at index. - */ - public int GetIntIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return -1; - - return this.GetInt(key); - } - - /** - * Retrieves the float stored at a key. - * - * @param key Key to retrieve float value for. - * @returns Value stored at key. - */ - public float GetFloat(const char[] key) { - float value; - return (this.GetValue(key, value)) ? value : -1.0; - } - - /** - * Retrieves the float stored at an index. - * - * @param index Index to retrieve float value for. - * @returns Value stored at index. - */ - public float GetFloatIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return -0.0; - - return this.GetFloat(key); - } - - /** - * Retrieves the bool stored at a key. - * - * @param key Key to retrieve bool value for. - * @returns Value stored at key. - */ - public bool GetBool(const char[] key) { - bool value; - return (this.GetValue(key, value)) ? value : false; - } - - /** - * Retrieves the bool stored at an index. - * - * @param index Index to retrieve bool value for. - * @returns Value stored at index. - */ - public bool GetBoolIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.GetBool(key); - } - - /** - * Retrieves the handle stored at a key. - * - * @param key Key to retrieve handle value for. - * @returns Value stored at key. - */ - public Handle GetHandle(const char[] key) { - Handle value; - return (this.GetValue(key, value)) ? value : null; - } - - /** - * Retrieves the handle stored at an index. - * - * @param index Index to retrieve handle value for. - * @returns Value stored at index. - */ - public Handle GetHandleIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return null; - - return this.GetHandle(key); - } - - /** - * Retrieves the object stored at a key. - * - * @param key Key to retrieve object value for. - * @returns Value stored at key. - */ - public JSON_Object GetObject(const char[] key) { - return view_as(this.GetHandle(key)); - } - - /** - * Retrieves the object stored at an index. - * - * @param index Index to retrieve object value for. - * @returns Value stored at index. - */ - public JSON_Object GetObjectIndexed(int index) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return null; - - return this.GetObject(key); - } - - /** - * @section Object setters. - */ - - /** - * Sets the string stored at a key. - * - * @param key Key to set to string value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetString(const char[] key, const char[] value, bool replace = true) { - return this.SetString(key, value, replace) && - this.SetKeyType(key, Type_String) && - this.SetKeyLength(key, strlen(value)); - } - - /** - * Sets the string stored at an index. - * - * @param index Index to set to string value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetStringIndexed(int index, const char[] value, bool replace = true) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetString(key, value, replace); - } - - /** - * Sets the int stored at a key. - * - * @param key Key to set to int value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetInt(const char[] key, int value, bool replace = true) { - return this.SetValue(key, value, replace) && - this.SetKeyType(key, Type_Int); - } - - /** - * Sets the int stored at an index. - * - * @param index Index to set to int value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetIntIndexed(int index, int value, bool replace = true) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetInt(key, value, replace); - } - - /** - * Sets the float stored at a key. - * - * @param key Key to set to float value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetFloat(const char[] key, float value, bool replace = true) { - return this.SetValue(key, value, replace) && - this.SetKeyType(key, Type_Float); - } - - /** - * Sets the float stored at an index. - * - * @param index Index to set to float value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetFloatIndexed(int index, float value, bool replace = true) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetFloat(key, value, replace); - } - - /** - * Sets the bool stored at a key. - * - * @param key Key to set to bool value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetBool(const char[] key, bool value, bool replace = true) { - return this.SetValue(key, value, replace) && - this.SetKeyType(key, Type_Bool); - } - - /** - * Sets the bool stored at an index. - * - * @param index Index to set to bool value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetBoolIndexed(int index, bool value, bool replace = true) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetBool(key, value, replace); - } - - /** - * Sets the handle stored at a key. - * - * @param key Key to set to handle value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetHandle(const char[] key, Handle value = null, bool replace = true) { - return this.SetValue(key, value, replace) && - this.SetKeyType(key, Type_Null); - } - - /** - * Sets the handle stored at an index. - * - * @param index Index to set to handle value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetHandleIndexed(int index, Handle value = null, bool replace = true) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetHandle(key, value, replace); - } - - /** - * Sets the object stored at a key. - * - * @param key Key to set to object value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetObject(const char[] key, JSON_Object value, bool replace = true) { - return this.SetValue(key, value, replace) && - this.SetKeyType(key, Type_Object); - } - - /** - * Sets the object stored at an index. - * - * @param index Index to set to object value. - * @param value Value to set. - * @returns True on success, false otherwise. - */ - public bool SetObjectIndexed(int index, JSON_Object value, bool replace = true) { - char key[JSON_INDEX_BUFFER_LENGTH]; - if (!this.GetIndexString(key, sizeof(key), index)) return false; - - return this.SetObject(key, value, replace); - } - - /** - * @section Array setters. - */ - - /** - * Pushes a string to the end of the array. - * - * @param value Value to push. - * @retusn True on success, false otherwise. - */ - public bool PushString(const char[] value) { - return this.SetStringIndexed(this.CurrentIndex, value) && - this.IncrementIndex(); - } - - /** - * Pushes an int to the end of the array. - * - * @param value Value to push. - * @retusn True on success, false otherwise. - */ - public bool PushInt(int value) { - return this.SetIntIndexed(this.CurrentIndex, value) && - this.IncrementIndex(); - } - - /** - * Pushes a float to the end of the array. - * - * @param value Value to push. - * @retusn True on success, false otherwise. - */ - public bool PushFloat(float value) { - return this.SetFloatIndexed(this.CurrentIndex, value) && - this.IncrementIndex(); - } - - /** - * Pushes a bool to the end of the array. - * - * @param value Value to push. - * @retusn True on success, false otherwise. - */ - public bool PushBool(bool value) { - return this.SetBoolIndexed(this.CurrentIndex, value) && - this.IncrementIndex(); - } - - /** - * Pushes a handle to the end of the array. - * - * @param value Value to push. - * @retusn True on success, false otherwise. - */ - public bool PushHandle(Handle value = null) { - return this.SetHandleIndexed(this.CurrentIndex, value) && - this.IncrementIndex(); - } - - /** - * Pushes an object to the end of the array. - * - * @param value Value to push. - * @retusn True on success, false otherwise. - */ - public bool PushObject(JSON_Object value) { - return this.SetObjectIndexed(this.CurrentIndex, value) && - this.IncrementIndex(); - } - - /** - * @section Generic. - */ - - /** - * Encodes the object into its string representation. - * - * @param output String buffer to store output. - * @param maxlen Maximum size of string buffer. - */ - public void Encode(char[] output, int maxlen) { - json_encode(this, output, maxlen); - } - - /** - * Decodes a JSON string into this object. - * - * @param buffer Buffer to decode. - */ - public void Decode(const char[] buffer) { - json_decode(buffer, this); - } - - /** - * Recursively cleans up the object and any objects referenced within. - */ - public void Cleanup() { - json_cleanup(this); - } -}; +/** + * vim: set ts=4 : + * ============================================================================= + * sm-json + * Provides a pure SourcePawn implementation of JSON encoding and decoding. + * https://github.com/clugg/sm-json + * + * sm-json (C)2018 James D. (clug) + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + */ + +#if defined _json_object_included + #endinput +#endif +#define _json_object_included + +#include +#include +#include +#include + +methodmap JSON_Object < StringMap { + /** + * Creates a new JSON_Object. + * + * @param is_array Should the object created be an array? [optional, default: false] + * @return A new JSON_Object. + */ + public JSON_Object(bool is_array = false) { + StringMap obj = CreateTrie(); + if (is_array) { + obj.SetValue(JSON_ARRAY_INDEX_KEY, 0); + } + return view_as(obj); + } + + /** + * Checks whether the object has a key. + * + * @param key Key to check existence of. + * @return True if the key exists, false otherwise. + */ + public bool HasKey(const char[] key) { + int int_value; + char str_value[1]; + + return this.GetValue(key, int_value) || + this.GetString(key, str_value, sizeof(str_value)); + } + + /** + * @section Array helpers. + */ + + /** + * Whether the current object is an array. + */ + property bool IsArray { + public get() { + return this.HasKey(JSON_ARRAY_INDEX_KEY); + } + } + + /** + * The current index of the object if it is an array, or -1 otherwise. + */ + property int CurrentIndex { + public get() { + if (!this.IsArray) return -1; + + int result; + return (this.GetValue(JSON_ARRAY_INDEX_KEY, result)) ? result : -1; + } + } + + /** + * The number of items in the object if it is an array, + * or the number of keys (including meta-keys) otherwise. + */ + property int Length { + public get() { + StringMapSnapshot snap = this.Snapshot(); + int length = (this.IsArray) ? this.CurrentIndex : snap.Length; + delete snap; + return length; + } + } + + /** + * Increments the current index of the object. + * + * @return True on success, false if the current object is not an array. + */ + public bool IncrementIndex() { + int current = this.CurrentIndex; + if (current == -1) return false; + + return this.SetValue(JSON_ARRAY_INDEX_KEY, current + 1); + } + + /** + * Gets the string representation of an array index. + * + * @param output String buffer to store output. + * @param maxlen Maximum size of string buffer. + * @param key Key to get string for. [optional, default: current index] + * @returns True on success, false otherwise. + */ + public int GetIndexString(char[] output, int maxlen, int key = -1) { + key = (key == -1) ? this.CurrentIndex : key; + if (key == -1) return false; + + return IntToString(key, output, maxlen); + } + + /** + * Removes an item from the object by index. + * + * @param index Index of object to remove. + * @returns True on success, false if the current object + * is not an array or the index does not exist. + */ + public bool RemoveIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.Remove(key); + } + + /** + * @section Internal getters. + */ + + /** + * Gets the cell type stored at a key. + * + * @param key Key to get value type for. + * @return Value type for key provided, or Type_Invalid if it does not exist. + */ + public JSON_CELL_TYPE GetKeyType(const char[] key) { + int maxlen = strlen(key) + strlen(JSON_META_TYPE_KEY) + 1; + char[] type_key = new char[maxlen]; + Format(type_key, maxlen, "%s%s", key, JSON_META_TYPE_KEY); + + JSON_CELL_TYPE type; + return (this.GetValue(type_key, type)) ? type : Type_Invalid; + } + + /** + * Gets the cell type stored at an index. + * + * @param index Index to get value type for. + * @return Value type for index provided, or Type_Invalid if it does not exist. + */ + public JSON_CELL_TYPE GetKeyTypeIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return Type_Invalid; + + return this.GetKeyType(key); + } + + /** + * Gets the length of the string stored at a key. + * + * @param key Key to get string length for. + * @return Length of string at key provided, or -1 if it is not a string/does not exist. + */ + public int GetKeyLength(const char[] key) { + int maxlen = strlen(key) + strlen(JSON_META_LENGTH_KEY) + 1; + char[] length_key = new char[maxlen]; + Format(length_key, maxlen, "%s%s", key, JSON_META_LENGTH_KEY); + + int length; + return (this.GetValue(length_key, length)) ? length : -1; + } + + /** + * Gets the length of the string stored at an index. + * + * @param index Index to get string length for. + * @return Length of string at index provided, or -1 if it is not a string/does not exist. + */ + public int GetKeyLengthIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return -1; + + return this.GetKeyLength(key); + } + + /** + * Gets whether the key should be hidden from encoding. + * + * @param key Key to get hidden state for. + * @return Whether or not the key should be hidden. + */ + public bool GetKeyHidden(const char[] key) { + int maxlen = strlen(key) + strlen(JSON_META_HIDDEN_KEY) + 1; + char[] length_key = new char[maxlen]; + Format(length_key, maxlen, "%s%s", key, JSON_META_HIDDEN_KEY); + + bool hidden; + return (this.GetValue(length_key, hidden)) ? hidden : false; + } + + /** + * Gets whether the index should be hidden from encoding. + * + * @param index Index to get hidden state for. + * @return Whether or not the index should be hidden. + */ + public bool GetKeyHiddenIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.GetKeyHidden(key); + } + + /** + * @section Internal setters. + */ + + /** + * Sets the cell type stored at a key. + * + * @param key Key to set value type for. + * @param type Type to set key to. + * @return True on success, false otherwise. + */ + public bool SetKeyType(const char[] key, JSON_CELL_TYPE type) { + int maxlen = strlen(key) + strlen(JSON_META_TYPE_KEY) + 1; + char[] type_key = new char[maxlen]; + Format(type_key, maxlen, "%s%s", key, JSON_META_TYPE_KEY); + + return this.SetValue(type_key, type); + } + + /** + * Sets the cell type stored at an index. + * + * @param index Index to set value type for. + * @param type Type to set index to. + * @return True on success, false otherwise. + */ + public bool SetKeyTypeIndexed(int index, JSON_CELL_TYPE value) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetKeyType(key, value); + } + + /** + * Sets the length of the string stored at a key. + * + * @param key Key to set string length for. + * @param length Length to set string to. + * @return True on success, false otherwise. + */ + public bool SetKeyLength(const char[] key, int length) { + int maxlen = strlen(key) + strlen(JSON_META_LENGTH_KEY) + 1; + char[] length_key = new char[maxlen]; + Format(length_key, maxlen, "%s%s", key, JSON_META_LENGTH_KEY); + + return this.SetValue(length_key, length); + } + + /** + * Sets the length of the string stored at an index. + * + * @param index Index to set string length for. + * @param length Length to set string to. + * @return True on success, false otherwise. + */ + public bool SetKeyLengthIndexed(int index, int length) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetKeyLength(key, length); + } + + /** + * Sets whether the key should be hidden from encoding. + * + * @param key Key to set hidden state for. + * @param hidden Wheter or not the key should be hidden. + * @return True on success, false otherwise. + */ + public bool SetKeyHidden(const char[] key, bool hidden) { + int maxlen = strlen(key) + strlen(JSON_META_HIDDEN_KEY) + 1; + char[] hidden_key = new char[maxlen]; + Format(hidden_key, maxlen, "%s%s", key, JSON_META_HIDDEN_KEY); + + return this.SetValue(hidden_key, hidden); + } + + /** + * Sets whether the index should be hidden from encoding. + * + * @param index Index to set hidden state for. + * @param hidden Wheter or not the index should be hidden. + * @return True on success, false otherwise. + */ + public bool SetKeyHiddenIndexed(int index, bool hidden) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetKeyHidden(key, hidden); + } + + /** + * @section Object getters. + */ + + /** + * Retrieves the int stored at a key. + * + * @param key Key to retrieve int value for. + * @returns Value stored at key. + */ + public int GetInt(const char[] key) { + int value; + return (this.GetValue(key, value)) ? value : -1; + } + + /** + * Retrieves the int stored at an index. + * + * @param index Index to retrieve int value for. + * @returns Value stored at index. + */ + public int GetIntIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return -1; + + return this.GetInt(key); + } + + /** + * Retrieves the float stored at a key. + * + * @param key Key to retrieve float value for. + * @returns Value stored at key. + */ + public float GetFloat(const char[] key) { + float value; + return (this.GetValue(key, value)) ? value : -1.0; + } + + /** + * Retrieves the float stored at an index. + * + * @param index Index to retrieve float value for. + * @returns Value stored at index. + */ + public float GetFloatIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return -0.0; + + return this.GetFloat(key); + } + + /** + * Retrieves the bool stored at a key. + * + * @param key Key to retrieve bool value for. + * @returns Value stored at key. + */ + public bool GetBool(const char[] key) { + bool value; + return (this.GetValue(key, value)) ? value : false; + } + + /** + * Retrieves the bool stored at an index. + * + * @param index Index to retrieve bool value for. + * @returns Value stored at index. + */ + public bool GetBoolIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.GetBool(key); + } + + /** + * Retrieves the handle stored at a key. + * + * @param key Key to retrieve handle value for. + * @returns Value stored at key. + */ + public Handle GetHandle(const char[] key) { + Handle value; + return (this.GetValue(key, value)) ? value : null; + } + + /** + * Retrieves the handle stored at an index. + * + * @param index Index to retrieve handle value for. + * @returns Value stored at index. + */ + public Handle GetHandleIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return null; + + return this.GetHandle(key); + } + + /** + * Retrieves the object stored at a key. + * + * @param key Key to retrieve object value for. + * @returns Value stored at key. + */ + public JSON_Object GetObject(const char[] key) { + return view_as(this.GetHandle(key)); + } + + /** + * Retrieves the object stored at an index. + * + * @param index Index to retrieve object value for. + * @returns Value stored at index. + */ + public JSON_Object GetObjectIndexed(int index) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return null; + + return this.GetObject(key); + } + + /** + * @section Object setters. + */ + + /** + * Sets the string stored at a key. + * + * @param key Key to set to string value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetString(const char[] key, const char[] value, bool replace = true) { + return this.SetString(key, value, replace) && + this.SetKeyType(key, Type_String) && + this.SetKeyLength(key, strlen(value)); + } + + /** + * Sets the string stored at an index. + * + * @param index Index to set to string value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetStringIndexed(int index, const char[] value, bool replace = true) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetString(key, value, replace); + } + + /** + * Sets the int stored at a key. + * + * @param key Key to set to int value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetInt(const char[] key, int value, bool replace = true) { + return this.SetValue(key, value, replace) && + this.SetKeyType(key, Type_Int); + } + + /** + * Sets the int stored at an index. + * + * @param index Index to set to int value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetIntIndexed(int index, int value, bool replace = true) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetInt(key, value, replace); + } + + /** + * Sets the float stored at a key. + * + * @param key Key to set to float value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetFloat(const char[] key, float value, bool replace = true) { + return this.SetValue(key, value, replace) && + this.SetKeyType(key, Type_Float); + } + + /** + * Sets the float stored at an index. + * + * @param index Index to set to float value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetFloatIndexed(int index, float value, bool replace = true) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetFloat(key, value, replace); + } + + /** + * Sets the bool stored at a key. + * + * @param key Key to set to bool value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetBool(const char[] key, bool value, bool replace = true) { + return this.SetValue(key, value, replace) && + this.SetKeyType(key, Type_Bool); + } + + /** + * Sets the bool stored at an index. + * + * @param index Index to set to bool value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetBoolIndexed(int index, bool value, bool replace = true) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetBool(key, value, replace); + } + + /** + * Sets the handle stored at a key. + * + * @param key Key to set to handle value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetHandle(const char[] key, Handle value = null, bool replace = true) { + return this.SetValue(key, value, replace) && + this.SetKeyType(key, Type_Null); + } + + /** + * Sets the handle stored at an index. + * + * @param index Index to set to handle value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetHandleIndexed(int index, Handle value = null, bool replace = true) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetHandle(key, value, replace); + } + + /** + * Sets the object stored at a key. + * + * @param key Key to set to object value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetObject(const char[] key, JSON_Object value, bool replace = true) { + return this.SetValue(key, value, replace) && + this.SetKeyType(key, Type_Object); + } + + /** + * Sets the object stored at an index. + * + * @param index Index to set to object value. + * @param value Value to set. + * @returns True on success, false otherwise. + */ + public bool SetObjectIndexed(int index, JSON_Object value, bool replace = true) { + char key[JSON_INDEX_BUFFER_LENGTH]; + if (!this.GetIndexString(key, sizeof(key), index)) return false; + + return this.SetObject(key, value, replace); + } + + /** + * @section Array setters. + */ + + /** + * Pushes a string to the end of the array. + * + * @param value Value to push. + * @retusn True on success, false otherwise. + */ + public bool PushString(const char[] value) { + return this.SetStringIndexed(this.CurrentIndex, value) && + this.IncrementIndex(); + } + + /** + * Pushes an int to the end of the array. + * + * @param value Value to push. + * @retusn True on success, false otherwise. + */ + public bool PushInt(int value) { + return this.SetIntIndexed(this.CurrentIndex, value) && + this.IncrementIndex(); + } + + /** + * Pushes a float to the end of the array. + * + * @param value Value to push. + * @retusn True on success, false otherwise. + */ + public bool PushFloat(float value) { + return this.SetFloatIndexed(this.CurrentIndex, value) && + this.IncrementIndex(); + } + + /** + * Pushes a bool to the end of the array. + * + * @param value Value to push. + * @retusn True on success, false otherwise. + */ + public bool PushBool(bool value) { + return this.SetBoolIndexed(this.CurrentIndex, value) && + this.IncrementIndex(); + } + + /** + * Pushes a handle to the end of the array. + * + * @param value Value to push. + * @retusn True on success, false otherwise. + */ + public bool PushHandle(Handle value = null) { + return this.SetHandleIndexed(this.CurrentIndex, value) && + this.IncrementIndex(); + } + + /** + * Pushes an object to the end of the array. + * + * @param value Value to push. + * @retusn True on success, false otherwise. + */ + public bool PushObject(JSON_Object value) { + return this.SetObjectIndexed(this.CurrentIndex, value) && + this.IncrementIndex(); + } + + /** + * @section Generic. + */ + + /** + * Encodes the object into its string representation. + * + * @param output String buffer to store output. + * @param maxlen Maximum size of string buffer. + */ + public void Encode(char[] output, int maxlen) { + json_encode(this, output, maxlen); + } + + /** + * Decodes a JSON string into this object. + * + * @param buffer Buffer to decode. + */ + public void Decode(const char[] buffer) { + json_decode(buffer, this); + } + + /** + * Recursively cleans up the object and any objects referenced within. + */ + public void Cleanup() { + json_cleanup(this); + } +}; diff --git a/scripting/include/socket.inc b/scripting/include/socket.inc index bd0dd79..a9d1041 100644 --- a/scripting/include/socket.inc +++ b/scripting/include/socket.inc @@ -540,7 +540,7 @@ methodmap Socket < Handle */ public void Connect(SocketConnectCB cfunc, SocketReceiveCB rfunc, SocketDisconnectCB dfunc, const char[] hostname, int port) { - SocketConnect(view_as(this), cfunc, rfunc, dfunc, hostname, port); + SocketConnect(this, cfunc, rfunc, dfunc, hostname, port); } /** @@ -614,7 +614,7 @@ methodmap Socket < Handle */ public int SetOption(SocketOption option, int value) { - return SocketSetOption(view_as(this), option, value); + return SocketSetOption(this, option, value); } /** diff --git a/scripting/include/sourcecomms.inc b/scripting/include/sourcecomms.inc index 8929b3d..fe92325 100644 --- a/scripting/include/sourcecomms.inc +++ b/scripting/include/sourcecomms.inc @@ -1,128 +1,127 @@ -// ************************************************************************* -// This file is part of SourceBans++. -// -// Copyright (C) 2014-2016 SourceBans++ Dev Team -// -// SourceBans++ is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, per version 3 of the License. -// -// SourceBans++ is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with SourceBans++. If not, see . -// -// This file based off work(s) covered by the following copyright(s): -// -// SourceComms 0.9.266 -// Copyright (C) 2013-2014 Alexandr Duplishchev -// Licensed under GNU GPL version 3, or later. -// Page: - -// -// ************************************************************************* - -#if defined _sourcecomms_included -#endinput -#endif -#define _sourcecomms_included - -/** - * @section Int definitions for punishments types. - */ - -#define TYPE_MUTE 1 /**< Voice Mute */ -#define TYPE_GAG 2 /**< Gag (text chat) */ -#define TYPE_SILENCE 3 /**< Silence (mute + gag) */ -#define TYPE_UNMUTE 4 /**< Voice Unmute*/ -#define TYPE_UNGAG 5 /**< Ungag*/ -#define TYPE_UNSILENCE 6 /**< Unsilence */ -#define TYPE_TEMP_UNMUTE 14 /**< Temp mute removed */ -#define TYPE_TEMP_UNGAG 15 /**< Temp gag removed */ -#define TYPE_TEMP_UNSILENCE 16 /**< Temp silence removed */ - -/* Punishments types */ -enum bType { - bNot = 0, // Player chat or voice is not blocked - bSess, // ... blocked for player session (until reconnect) - bTime, // ... blocked for some time - bPerm // ... permanently blocked -} - -/** - * Sets a client's mute state. - * - * @param client Client index. - * @param muteState True to mute client, false to unmute. - * -------------------------------------Parameters below this line are used only for muteState=true------------------------------------- - * ----------------------------------for muteState=false these parameters are ignored (saveToDB=false)---------------------------------- - * @param muteLength Length of punishment in minutes. Value < 0 muting client for session. Permanent (0) is not allowed at this time. - * @param saveToDB If true, punishment will be saved in database. - * @param reason Reason for punishment. - * @return True if this caused a change in mute state, false otherwise. - */ -native bool SourceComms_SetClientMute(int client, bool muteState, int muteLength = -1, bool saveToDB = false, const char[] reason = "Muted through natives"); - -/** - * Sets a client's gag state. - * - * @param client Client index. - * @param gagState True to gag client, false to ungag. - * --------------------------------------Parameters below this line are used only for gagState=true-------------------------------------- - * -----------------------------------for gagState=false these parameters are ignored (saveToDB=false)----------------------------------- - * @param gagLength Length of punishment in minutes. Value < 0 gagging client for session. Permanent (0) is not allowed at this time. - * @param saveToDB If true, punishment will be saved in database. - * @param reason Reason for punishment. - * @return True if this caused a change in gag state, false otherwise. - */ -native bool SourceComms_SetClientGag(int client, bool gagState, int gagLength = -1, bool saveToDB = false, const char[] reason = "Gagged through natives"); - -/** - * Returns the client's mute type - * - * @param client The client index of the player to check mute status - * @return The client's current mute type index (see enum bType in the begin). - */ -native bType SourceComms_GetClientMuteType(int client); - - -/** - * Returns the client's gag type - * - * @param client The client index of the player to check gag status - * @return The client's current gag type index (see enum bType in the begin). - */ -native bType SourceComms_GetClientGagType(int client); - -/** - * Called when added communication block for player. - * - * @param client The client index of the admin who is blocking the client. - * @param target The client index of the player to blocked. - * @param time The time to blocked the player for (in minutes, 0 = permanent). - * @param type The type of block. See section "Int definitions for punishments types". - * @param reason The reason to block the player. - */ -forward void SourceComms_OnBlockAdded(int client, int target, int time, bType type, char[] reason); - -public SharedPlugin __pl_sourcecomms = -{ - name = "sourcecomms++", - file = "sbpp_comms.smx", - #if defined REQUIRE_PLUGIN - required = 1 - #else - required = 0 - #endif -}; - -public void __pl_sourcecomms_SetNTVOptional() -{ - MarkNativeAsOptional("SourceComms_SetClientMute"); - MarkNativeAsOptional("SourceComms_SetClientGag"); - MarkNativeAsOptional("SourceComms_GetClientMuteType"); - MarkNativeAsOptional("SourceComms_GetClientGagType"); - -} +// ************************************************************************* +// This file is part of SourceBans++. +// +// Copyright (C) 2014-2016 SourceBans++ Dev Team +// +// SourceBans++ is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, per version 3 of the License. +// +// SourceBans++ is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SourceBans++. If not, see . +// +// This file based off work(s) covered by the following copyright(s): +// +// SourceComms 0.9.266 +// Copyright (C) 2013-2014 Alexandr Duplishchev +// Licensed under GNU GPL version 3, or later. +// Page: - +// +// ************************************************************************* + +#if defined _sourcecomms_included +#endinput +#endif +#define _sourcecomms_included + +/** + * @section Int definitions for punishments types. + */ + +#define TYPE_MUTE 1 /**< Voice Mute */ +#define TYPE_GAG 2 /**< Gag (text chat) */ +#define TYPE_SILENCE 3 /**< Silence (mute + gag) */ +#define TYPE_UNMUTE 4 /**< Voice Unmute*/ +#define TYPE_UNGAG 5 /**< Ungag*/ +#define TYPE_UNSILENCE 6 /**< Unsilence */ +#define TYPE_TEMP_UNMUTE 14 /**< Temp mute removed */ +#define TYPE_TEMP_UNGAG 15 /**< Temp gag removed */ +#define TYPE_TEMP_UNSILENCE 16 /**< Temp silence removed */ + +/* Punishments types */ +enum bType { + bNot = 0, // Player chat or voice is not blocked + bSess, // ... blocked for player session (until reconnect) + bTime, // ... blocked for some time + bPerm // ... permanently blocked +} + +/** + * Sets a client's mute state. + * + * @param client Client index. + * @param muteState True to mute client, false to unmute. + * -------------------------------------Parameters below this line are used only for muteState=true------------------------------------- + * ----------------------------------for muteState=false these parameters are ignored (saveToDB=false)---------------------------------- + * @param muteLength Length of punishment in minutes. Value < 0 muting client for session. Permanent (0) is not allowed at this time. + * @param saveToDB If true, punishment will be saved in database. + * @param reason Reason for punishment. + * @return True if this caused a change in mute state, false otherwise. + */ +native bool SourceComms_SetClientMute(int client, bool muteState, int muteLength = -1, bool saveToDB = false, const char[] reason = "Muted through natives"); + +/** + * Sets a client's gag state. + * + * @param client Client index. + * @param gagState True to gag client, false to ungag. + * --------------------------------------Parameters below this line are used only for gagState=true-------------------------------------- + * -----------------------------------for gagState=false these parameters are ignored (saveToDB=false)----------------------------------- + * @param gagLength Length of punishment in minutes. Value < 0 gagging client for session. Permanent (0) is not allowed at this time. + * @param saveToDB If true, punishment will be saved in database. + * @param reason Reason for punishment. + * @return True if this caused a change in gag state, false otherwise. + */ +native bool SourceComms_SetClientGag(int client, bool gagState, int gagLength = -1, bool saveToDB = false, const char[] reason = "Gagged through natives"); + +/** + * Returns the client's mute type + * + * @param client The client index of the player to check mute status + * @return The client's current mute type index (see enum bType in the begin). + */ +native bType SourceComms_GetClientMuteType(int client); + + +/** + * Returns the client's gag type + * + * @param client The client index of the player to check gag status + * @return The client's current gag type index (see enum bType in the begin). + */ +native bType SourceComms_GetClientGagType(int client); + +/** + * Called when added communication block for player. + * + * @param client The client index of the admin who is blocking the client. + * @param target The client index of the player to blocked. + * @param time The time to blocked the player for (in minutes, 0 = permanent). + * @param type The type of block. See section "Int definitions for punishments types". + * @param reason The reason to block the player. + */ +forward void SourceComms_OnBlockAdded(int client, int target, int time, bType type, char[] reason); + +public SharedPlugin __pl_sourcecomms = +{ + name = "sourcecomms++", + file = "sbpp_comms.smx", + #if defined REQUIRE_PLUGIN + required = 1 + #else + required = 0 + #endif +}; + +public void __pl_sourcecomms_SetNTVOptional() +{ + MarkNativeAsOptional("SourceComms_SetClientMute"); + MarkNativeAsOptional("SourceComms_SetClientGag"); + MarkNativeAsOptional("SourceComms_GetClientMuteType"); + MarkNativeAsOptional("SourceComms_GetClientGagType"); +} diff --git a/scripting/ngs_admin_toolkit.sp b/scripting/ngs_admin_toolkit.sp index 907c928..b147661 100644 --- a/scripting/ngs_admin_toolkit.sp +++ b/scripting/ngs_admin_toolkit.sp @@ -1,535 +1,535 @@ -/** -* TheXeon -* ngs_admin_toolkit.sp -* -* Files: -* addons/sourcemod/plugins/ngs_admin_toolkit.smx -* -* Dependencies: -* sourcemod.inc, sdktools.inc, sdkhooks.inc, tf2_stocks.inc, tf2.inc, -* multicolors.inc, clientprefs.inc, basecomm.inc, sourcecomms.inc, -* ngsutils.inc, ngsupdater.inc -*/ - -#pragma newdecls required -#pragma semicolon 1 - -#define LIBRARY_ADDED_FUNC OnLibAdded -#define LIBRARY_REMOVED_FUNC OnLibRemoved -#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" -#define RELOAD_ON_UPDATE 1 - -#include -#include -#include -#include -#include -#include -#include -#undef REQUIRE_PLUGIN -#include -#include -#define REQUIRE_PLUGIN -#include -#include - -bool basecommExists = false; -bool sourcecommsExists = false; -bool muteNonAdminsEnabled = false; -bool isPlayerNameBanned[MAXPLAYERS + 1]; - -Cookie nameBannedCookie = null; - -//--------------------// - -public Plugin myinfo = { - name = "[NGS] Admin Tools", - author = "TheXeon", - description = "Admin commands for NGS people.", - version = "1.2.6", - url = "https://neogenesisnetwork.net" -} - -public void OnPluginStart() -{ - RegAdminCmd("sm_forcerespawn", CommandForceRespawn, ADMFLAG_GENERIC, "Usage: sm_forcerespawn <#userid|name>"); - RegAdminCmd("sm_changeteam", CommandChangeTeam, ADMFLAG_GENERIC, "Usage: sm_changeteam <#userid|name> (1 = Spec / 2 = Red / 3 = Blue)"); - RegAdminCmd("sm_sethealth", CommandSetHealth, ADMFLAG_GENERIC, "Usage: sm_sethealth <#userid|name> "); - RegAdminCmd("sm_bamall", CommandBamboozleAll, ADMFLAG_GENERIC, "Usage: sm_bamall <#userid|name>"); - RegAdminCmd("sm_mutenonadmins", CommandMuteNonAdmins, ADMFLAG_GENERIC, "Usage: sm_mutenonadmins"); - RegAdminCmd("sm_unmutenonadmins", CommandUnmuteNonAdmins, ADMFLAG_GENERIC, "Usage: sm_unmutenonadmins"); - RegAdminCmd("sm_nameban", CommandNameBan, ADMFLAG_GENERIC, "Usage: sm_nameban <#userid|name>"); - RegAdminCmd("sm_nameunban", CommandNameUnban, ADMFLAG_GENERIC, "Usage: sm_nameunban <#userid|name>"); - RegAdminCmd("sm_getlookingpos", CommandGetLookingPosition, ADMFLAG_GENERIC, "Usage: sm_getlookingpos"); - RegAdminCmd("sm_checkcommandaccess", CommandCheckCommandAccess, ADMFLAG_ROOT, "Usage: sm_checkcommandaccess <#userid|name> "); - RegAdminCmd("sm_getclientinfo", CommandGetClientInfo, ADMFLAG_ROOT, "Usage: sm_getclientinfo <#userid|name> "); - RegAdminCmd("sm_queryclientconvar", CommandQueryClientConVar, ADMFLAG_ROOT, "Usage: sm_queryclientconvar <#userid|name> "); - - - LoadTranslations("common.phrases"); - - nameBannedCookie = new Cookie("NameBanned", "Is the player name-banned?", CookieAccess_Private); - - for (int i = MaxClients; i > 0; --i) - { - if (!AreClientCookiesCached(i)) - { - continue; - } - OnClientCookiesCached(i); - } -} - -public void OnLibAdded(const char[] name) -{ - if (StrEqual(name, "basecomm")) - basecommExists = true; - if (StrEqual(name, "sourcecomms")) - sourcecommsExists = true; -} - -public void OnLibRemoved(const char[] name) -{ - if (StrEqual(name, "basecomm")) - basecommExists = false; - if (StrEqual(name, "sourcecomms")) - sourcecommsExists = false; -} - -public void OnClientCookiesCached(int client) -{ - char sValue[8]; - nameBannedCookie.GetValue(client, sValue, sizeof(sValue)); - - isPlayerNameBanned[client] = (sValue[0] != '\0' && StringToInt(sValue)); -} - -public void OnClientPostAdminCheck(int client) -{ - if (muteNonAdminsEnabled && !CheckCommandAccess(client, "sm_admin", ADMFLAG_GENERIC)) - SetClientListeningFlags(client, VOICE_MUTED); - - if (AreClientCookiesCached(client) && isPlayerNameBanned[client] && CommandExists("sm_rename")) - { - int userid = GetClientUserId(client); - ServerCommand("sm_rename #%d IHaveANameNow#%d", userid, userid); - if (CommandExists("sm_namelock")) - ServerCommand("sm_namelock #%d 1", userid); - } -} - -public Action CommandNameBan(int client, int args) -{ - if (args < 1) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_nameban <#userid|name>"); - return Plugin_Handled; - } - - char arg1[MAX_BUFFER_LENGTH]; - GetCmdArg(1, arg1, sizeof(arg1)); - - int target = FindTarget(client, arg1, false, false); - if (target == -1) return Plugin_Handled; - - if (isPlayerNameBanned[target]) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} That player has already been name banned. Use sm_nameunban to unban them."); - return Plugin_Handled; - } - - if (CommandExists("sm_rename")) - { - int userid = GetClientUserId(target); - ServerCommand("sm_rename #%d IHaveANameNow#%d", userid, userid); - if (CommandExists("sm_namelock")) - ServerCommand("sm_namelock #%d 1", userid); - nameBannedCookie.SetValue(target, "1"); - } - - LogAction(client, target, "%N banned %N's name!", client, target); - return Plugin_Handled; -} - -public Action CommandNameUnban(int client, int args) -{ - if (args < 1) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_nameunban <#userid|name>"); - return Plugin_Handled; - } - - char arg1[MAX_BUFFER_LENGTH]; - GetCmdArg(1, arg1, sizeof(arg1)); - - int target = FindTarget(client, arg1, false, false); - if (target == -1) return Plugin_Handled; - - if (!isPlayerNameBanned[target]) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} That player has not been name banned. Use sm_nameban to ban them."); - return Plugin_Handled; - } - - if (CommandExists("sm_namelock")) - { - int userid = GetClientUserId(target); - ServerCommand("sm_namelock #%d 0", userid); - nameBannedCookie.SetValue(target, "0"); - CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Your name has been unlocked, feel free to change it."); - } - - LogAction(client, target, "%N unbanned %N's name!", client, target); - return Plugin_Handled; -} - -public Action CommandForceRespawn(int client, int args) -{ - if (args < 1) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_forcerespawn [target]"); - return Plugin_Handled; - } - char arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MAXPLAYERS, - COMMAND_FILTER_ALIVE, - target_name, - sizeof(target_name), - tn_is_ml)) <= 0) - { - ReplyToTargetError(client, target_count); - return Plugin_Handled; - } - - for (int i = 0; i < target_count; i++) - { - TF2_RespawnPlayer(target_list[i]); - LogAction(client, target_list[i], "\"%L\" respawned \"%L\"!", client, target_list[i]); - } - - if (tn_is_ml) - { - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Respawned %t!", target_name); - } - else - { - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Respawned %s!", target_name); - } - return Plugin_Handled; -} - -public Action CommandGetLookingPosition(int client, int args) -{ - if (!IsValidClient(client) || !IsPlayerAlive(client)) return Plugin_Handled; - - float start[3], angle[3], end[3]; - GetClientEyePosition(client, start); - GetClientEyeAngles(client, angle); - TR_TraceRayFilter(start, angle, MASK_SOLID, RayType_Infinite, TraceEntityFilterPlayer, client); - if (TR_DidHit()) - { - TR_GetEndPosition(end); - } - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Position you are looking at is x = %f, y = %f, z = %f.", end[0], end[1], end[2]); - return Plugin_Handled; -} - - -public bool TraceEntityFilterPlayer(int entity, int contentsMask, any data) -{ - return entity > MaxClients; -} - -public Action CommandChangeTeam(int client, int args) -{ - if (args < 2) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_changeteam [name] "); - } - - char arg1[MAX_NAME_LENGTH], arg2[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - GetCmdArg(2, arg2, sizeof(arg2)); - int Team; - - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MAXPLAYERS, - 0, - target_name, - sizeof(target_name), - tn_is_ml)) <= 0) - { - ReplyToTargetError(client, target_count); - return Plugin_Handled; - } - - int argteam = StringToInt(arg2); - if (argteam < 4 && argteam > 0) - { - Team = argteam; - } - else - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Please choose a team!"); - return Plugin_Handled; - } - - for (int i = 0; i < target_count; i++) - { - ChangeClientTeam(target_list[i], Team); - LogAction(client, target_list[i], "\"%L\" moved \"%L\" to team %d.", client, target_list[i], Team); - } - - if (tn_is_ml) - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Moved %t to team %d!", target_name, Team); - else - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Moved %s to team %d!", target_name, Team); - return Plugin_Handled; -} - -public Action CommandSetHealth(int client, int args) -{ - char arg1[MAX_TARGET_LENGTH], arg2[10], mod[32]; - int iHealth; - - GetGameFolderName(mod, sizeof(mod)); - - if (args < 2) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_sethealth <#userid|name> "); - return Plugin_Handled; - } - else - { - GetCmdArg(1, arg1, sizeof(arg1)); - GetCmdArg(2, arg2, sizeof(arg2)); - iHealth = StringToInt(arg2); - } - - if (iHealth < 0) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Health must be greater than zero."); - return Plugin_Handled; - } - - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MAXPLAYERS, - COMMAND_FILTER_ALIVE, - target_name, - sizeof(target_name), - tn_is_ml)) <= 0) - { - ReplyToTargetError(client, target_count); - return Plugin_Handled; - } - - for (int i = 0; i < target_count; i++) - { - if (StrEqual(mod, "tf", false)) - { - if (iHealth == 0) - FakeClientCommand(target_list[i], "explode"); - else - { - SetEntProp(target_list[i], Prop_Data, "m_iMaxHealth", iHealth); - SetEntityHealth(target_list[i], iHealth); - } - } - - else - { - if (iHealth == 0) - SetEntityHealth(target_list[i], 1); - else - SetEntityHealth(target_list[i], iHealth); - } - - LogAction(client, target_list[i], "\"%L\" set \"%L\"'s health to %i", client, target_list[i], iHealth); - } - - if (tn_is_ml) - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Set {LIGHTGREEN}%t{DEFAULT}'s health to {LIGHTGREEN}%d{DEFAULT}.", target_name, iHealth); - else - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Set {LIGHTGREEN}%s{DEFAULT}'s health to {LIGHTGREEN}%d{DEFAULT}.", target_name, iHealth); - - return Plugin_Handled; - -} - -public Action CommandBamboozleAll(int client, int args) -{ - if (args < 1) return Plugin_Handled; - char arg1[MAX_BUFFER_LENGTH], playerName[MAX_NAME_LENGTH]; - GetCmdArg(1, arg1, sizeof(arg1)); - - int target = FindTarget(client, arg1, false, false); - if (target == -1) return Plugin_Handled; - GetClientName(target, playerName, sizeof(playerName)); - - SetHudTextParams(-1.0, 0.1, 3.0, 255, 0, 0, 255, 1, 1.0, 1.0, 1.0); - for (int i = 1; i <= MaxClients; i++) - { - if (IsValidClient(i)) - { - EmitSoundToClient(i, "vo/demoman_specialcompleted11.mp3"); - EmitSoundToClient(i, "vo/demoman_specialcompleted11.mp3"); - Handle hHudText = CreateHudSynchronizer(); - ShowSyncHudText(i, hHudText, "BAMBOOZLED"); - delete hHudText; - LogAction(target, i, "\"%s\" bamboozled \"%L\"!", playerName, i); - } - } - - CPrintToChatAll("{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%s{DEFAULT} just {RED}B{ORANGE}A{YELLOW}M{GREEN}B{BLUE}O{PURPLE}O{MAGENTA}Z{BLACK}L{WHITE}E{GREEN}D{DEFAULT} {LIGHTGREEN}EVERYONE{DEFAULT}!", playerName); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} FEEL THE {BLACK}B{BLUE}A{YELLOW}M{GREEN}B{ORANGE}O{PURPLE}O{MAGENTA}Z{RED}L{WHITE}E{DEFAULT}!"); - return Plugin_Handled; -} - -public Action CommandMuteNonAdmins(int client, int args) -{ - if (muteNonAdminsEnabled) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Nonadmins are already muted. Use sm_unmutenonadmins to unmute."); - return Plugin_Handled; - } - for (int i = 1; i <= MaxClients; i++) - { - if (IsValidClient(i) && !CheckCommandAccess(i, "sm_admin", ADMFLAG_GENERIC)) - { - SetClientListeningFlags(i, VOICE_MUTED); - } - } - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Muted all nonadmins!"); - LogAction(client, -1, "Muted all nonadmins!"); - muteNonAdminsEnabled = true; - return Plugin_Handled; -} - -public Action CommandUnmuteNonAdmins(int client, int args) -{ - if (!muteNonAdminsEnabled) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Nonadmins aren\'t muted. Use sm_mutenonadmins to mute."); - return Plugin_Handled; - } - for (int i = 1; i <= MaxClients; i++) - { - if (IsValidClient(i) && ((sourcecommsExists && SourceComms_GetClientMuteType(i) == bNot) || (basecommExists && !BaseComm_IsClientMuted(i)))) - { - SetClientListeningFlags(i, VOICE_NORMAL); - } - } - CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Unmuted all nonadmins!"); - LogAction(client, -1, "Unmuted all nonadmins!"); - muteNonAdminsEnabled = false; - return Plugin_Handled; -} - -public Action CommandCheckCommandAccess(int client, int args) -{ - if (args < 1) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_checkcommandaccess <#userid|name> "); - return Plugin_Handled; - } - - char arg1[MAX_BUFFER_LENGTH], arg2[MAX_BUFFER_LENGTH]; - GetCmdArg(1, arg1, sizeof(arg1)); - GetCmdArg(2, arg2, sizeof(arg2)); - int target = FindTarget(client, arg1, true); - if (!IsValidClient(target)) return Plugin_Handled; - - AdminId admin = GetUserAdmin(target); - if (CheckCommandAccess(target, arg2, ADMFLAG_ROOT)) - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} has CheckCommandAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); - else - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} doesn\'t have CheckCommandAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); - if (CheckAccess(admin, arg2, ADMFLAG_ROOT)) - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} has CheckAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); - else - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} doesn\'t have CheckAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); - return Plugin_Handled; -} - -public Action CommandGetClientInfo(int client, int args) -{ - if (args < 1) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_getclientinfo <#userid|name> "); - return Plugin_Handled; - } - - char arg1[MAX_BUFFER_LENGTH], arg2[MAX_BUFFER_LENGTH]; - GetCmdArg(1, arg1, sizeof(arg1)); - GetCmdArg(2, arg2, sizeof(arg2)); - int target = FindTarget(client, arg1, true); - if (!IsValidClient(target)) return Plugin_Handled; - - char varString[MAX_BUFFER_LENGTH]; - - if (GetClientInfo(target, arg2, varString, sizeof(varString))) - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s value for {YELLOW}%s{DEFAULT} is {OLIVE}%s{DEFAULT}!", target, arg2, varString); - else - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Could not get client info of {LIGHTGREEN}%N{DEFAULT}!", target); - return Plugin_Handled; -} - -public Action CommandQueryClientConVar(int client, int args) -{ - if (args < 1) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_queryclientconvar <#userid|name> "); - return Plugin_Handled; - } - - char arg1[MAX_BUFFER_LENGTH], arg2[MAX_BUFFER_LENGTH]; - GetCmdArg(1, arg1, sizeof(arg1)); - GetCmdArg(2, arg2, sizeof(arg2)); - int target = FindTarget(client, arg1, true); - if (!IsValidClient(target)) return Plugin_Handled; - - QueryClientConVar(target, arg2, ClientConVar, client); - return Plugin_Handled; -} - -void ClientConVar(QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value) -{ - if (cookie == QUERYCOOKIE_FAILED) - { - CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s query was invalid!", client); - return; - } - switch (result) - { - case ConVarQuery_Okay: - CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s value for {YELLOW}%s{DEFAULT} is {OLIVE}%s{DEFAULT}!", client, cvarName, cvarValue); - case ConVarQuery_Protected: - CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s value for {YELLOW}%s{DEFAULT} is {PURPLE}PROTECTED{DEFAULT}!", client, cvarName); - default: - CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} Invalid ConVar or ConVar not found for {LIGHTGREEN}%N{DEFAULT}!", client); - } -} +/** +* TheXeon +* ngs_admin_toolkit.sp +* +* Files: +* addons/sourcemod/plugins/ngs_admin_toolkit.smx +* +* Dependencies: +* sourcemod.inc, sdktools.inc, sdkhooks.inc, tf2_stocks.inc, tf2.inc, +* multicolors.inc, clientprefs.inc, basecomm.inc, sourcecomms.inc, +* ngsutils.inc, ngsupdater.inc +*/ + +#pragma newdecls required +#pragma semicolon 1 + +#define LIBRARY_ADDED_FUNC OnLibAdded +#define LIBRARY_REMOVED_FUNC OnLibRemoved +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 + +#include +#include +#include +#include +#include +#include +#include +#undef REQUIRE_PLUGIN +#include +#include +#define REQUIRE_PLUGIN +#include +#include + +bool basecommExists = false; +bool sourcecommsExists = false; +bool muteNonAdminsEnabled = false; +bool isPlayerNameBanned[MAXPLAYERS + 1]; + +Cookie nameBannedCookie = null; + +//--------------------// + +public Plugin myinfo = { + name = "[NGS] Admin Tools", + author = "TheXeon", + description = "Admin commands for NGS people.", + version = "1.2.6", + url = "https://neogenesisnetwork.net" +} + +public void OnPluginStart() +{ + RegAdminCmd("sm_forcerespawn", CommandForceRespawn, ADMFLAG_GENERIC, "Usage: sm_forcerespawn <#userid|name>"); + RegAdminCmd("sm_changeteam", CommandChangeTeam, ADMFLAG_GENERIC, "Usage: sm_changeteam <#userid|name> (1 = Spec / 2 = Red / 3 = Blue)"); + RegAdminCmd("sm_sethealth", CommandSetHealth, ADMFLAG_GENERIC, "Usage: sm_sethealth <#userid|name> "); + RegAdminCmd("sm_bamall", CommandBamboozleAll, ADMFLAG_GENERIC, "Usage: sm_bamall <#userid|name>"); + RegAdminCmd("sm_mutenonadmins", CommandMuteNonAdmins, ADMFLAG_GENERIC, "Usage: sm_mutenonadmins"); + RegAdminCmd("sm_unmutenonadmins", CommandUnmuteNonAdmins, ADMFLAG_GENERIC, "Usage: sm_unmutenonadmins"); + RegAdminCmd("sm_nameban", CommandNameBan, ADMFLAG_GENERIC, "Usage: sm_nameban <#userid|name>"); + RegAdminCmd("sm_nameunban", CommandNameUnban, ADMFLAG_GENERIC, "Usage: sm_nameunban <#userid|name>"); + RegAdminCmd("sm_getlookingpos", CommandGetLookingPosition, ADMFLAG_GENERIC, "Usage: sm_getlookingpos"); + RegAdminCmd("sm_checkcommandaccess", CommandCheckCommandAccess, ADMFLAG_ROOT, "Usage: sm_checkcommandaccess <#userid|name> "); + RegAdminCmd("sm_getclientinfo", CommandGetClientInfo, ADMFLAG_ROOT, "Usage: sm_getclientinfo <#userid|name> "); + RegAdminCmd("sm_queryclientconvar", CommandQueryClientConVar, ADMFLAG_ROOT, "Usage: sm_queryclientconvar <#userid|name> "); + + + LoadTranslations("common.phrases"); + + nameBannedCookie = new Cookie("NameBanned", "Is the player name-banned?", CookieAccess_Private); + + for (int i = MaxClients; i > 0; --i) + { + if (!AreClientCookiesCached(i)) + { + continue; + } + OnClientCookiesCached(i); + } +} + +public void OnLibAdded(const char[] name) +{ + if (StrEqual(name, "basecomm")) + basecommExists = true; + if (StrEqual(name, "sourcecomms")) + sourcecommsExists = true; +} + +public void OnLibRemoved(const char[] name) +{ + if (StrEqual(name, "basecomm")) + basecommExists = false; + if (StrEqual(name, "sourcecomms")) + sourcecommsExists = false; +} + +public void OnClientCookiesCached(int client) +{ + char sValue[8]; + nameBannedCookie.GetValue(client, sValue, sizeof(sValue)); + + isPlayerNameBanned[client] = (sValue[0] != '\0' && StringToInt(sValue)); +} + +public void OnClientPostAdminCheck(int client) +{ + if (muteNonAdminsEnabled && !CheckCommandAccess(client, "sm_admin", ADMFLAG_GENERIC)) + SetClientListeningFlags(client, VOICE_MUTED); + + if (AreClientCookiesCached(client) && isPlayerNameBanned[client] && CommandExists("sm_rename")) + { + int userid = GetClientUserId(client); + ServerCommand("sm_rename #%d IHaveANameNow#%d", userid, userid); + if (CommandExists("sm_namelock")) + ServerCommand("sm_namelock #%d 1", userid); + } +} + +public Action CommandNameBan(int client, int args) +{ + if (args < 1) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_nameban <#userid|name>"); + return Plugin_Handled; + } + + char arg1[MAX_BUFFER_LENGTH]; + GetCmdArg(1, arg1, sizeof(arg1)); + + int target = FindTarget(client, arg1, false, false); + if (target == -1) return Plugin_Handled; + + if (isPlayerNameBanned[target]) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} That player has already been name banned. Use sm_nameunban to unban them."); + return Plugin_Handled; + } + + if (CommandExists("sm_rename")) + { + int userid = GetClientUserId(target); + ServerCommand("sm_rename #%d IHaveANameNow#%d", userid, userid); + if (CommandExists("sm_namelock")) + ServerCommand("sm_namelock #%d 1", userid); + nameBannedCookie.SetValue(target, "1"); + } + + LogAction(client, target, "%N banned %N's name!", client, target); + return Plugin_Handled; +} + +public Action CommandNameUnban(int client, int args) +{ + if (args < 1) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_nameunban <#userid|name>"); + return Plugin_Handled; + } + + char arg1[MAX_BUFFER_LENGTH]; + GetCmdArg(1, arg1, sizeof(arg1)); + + int target = FindTarget(client, arg1, false, false); + if (target == -1) return Plugin_Handled; + + if (!isPlayerNameBanned[target]) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} That player has not been name banned. Use sm_nameban to ban them."); + return Plugin_Handled; + } + + if (CommandExists("sm_namelock")) + { + int userid = GetClientUserId(target); + ServerCommand("sm_namelock #%d 0", userid); + nameBannedCookie.SetValue(target, "0"); + CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Your name has been unlocked, feel free to change it."); + } + + LogAction(client, target, "%N unbanned %N's name!", client, target); + return Plugin_Handled; +} + +public Action CommandForceRespawn(int client, int args) +{ + if (args < 1) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_forcerespawn [target]"); + return Plugin_Handled; + } + char arg1[32]; + GetCmdArg(1, arg1, sizeof(arg1)); + + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + MAXPLAYERS, + COMMAND_FILTER_ALIVE, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + for (int i = 0; i < target_count; i++) + { + TF2_RespawnPlayer(target_list[i]); + LogAction(client, target_list[i], "\"%L\" respawned \"%L\"!", client, target_list[i]); + } + + if (tn_is_ml) + { + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Respawned %t!", target_name); + } + else + { + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Respawned %s!", target_name); + } + return Plugin_Handled; +} + +public Action CommandGetLookingPosition(int client, int args) +{ + if (!IsValidClient(client) || !IsPlayerAlive(client)) return Plugin_Handled; + + float start[3], angle[3], end[3]; + GetClientEyePosition(client, start); + GetClientEyeAngles(client, angle); + TR_TraceRayFilter(start, angle, MASK_SOLID, RayType_Infinite, TraceEntityFilterPlayer, client); + if (TR_DidHit()) + { + TR_GetEndPosition(end); + } + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Position you are looking at is x = %f, y = %f, z = %f.", end[0], end[1], end[2]); + return Plugin_Handled; +} + + +public bool TraceEntityFilterPlayer(int entity, int contentsMask, any data) +{ + return entity > MaxClients; +} + +public Action CommandChangeTeam(int client, int args) +{ + if (args < 2) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_changeteam [name] "); + } + + char arg1[MAX_NAME_LENGTH], arg2[32]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + int Team; + + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + MAXPLAYERS, + 0, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + int argteam = StringToInt(arg2); + if (argteam < 4 && argteam > 0) + { + Team = argteam; + } + else + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Please choose a team!"); + return Plugin_Handled; + } + + for (int i = 0; i < target_count; i++) + { + ChangeClientTeam(target_list[i], Team); + LogAction(client, target_list[i], "\"%L\" moved \"%L\" to team %d.", client, target_list[i], Team); + } + + if (tn_is_ml) + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Moved %t to team %d!", target_name, Team); + else + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Moved %s to team %d!", target_name, Team); + return Plugin_Handled; +} + +public Action CommandSetHealth(int client, int args) +{ + char arg1[MAX_TARGET_LENGTH], arg2[10], mod[32]; + int iHealth; + + GetGameFolderName(mod, sizeof(mod)); + + if (args < 2) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_sethealth <#userid|name> "); + return Plugin_Handled; + } + else + { + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + iHealth = StringToInt(arg2); + } + + if (iHealth < 0) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Health must be greater than zero."); + return Plugin_Handled; + } + + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + MAXPLAYERS, + COMMAND_FILTER_ALIVE, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + for (int i = 0; i < target_count; i++) + { + if (StrEqual(mod, "tf", false)) + { + if (iHealth == 0) + FakeClientCommand(target_list[i], "explode"); + else + { + SetEntProp(target_list[i], Prop_Data, "m_iMaxHealth", iHealth); + SetEntityHealth(target_list[i], iHealth); + } + } + + else + { + if (iHealth == 0) + SetEntityHealth(target_list[i], 1); + else + SetEntityHealth(target_list[i], iHealth); + } + + LogAction(client, target_list[i], "\"%L\" set \"%L\"'s health to %i", client, target_list[i], iHealth); + } + + if (tn_is_ml) + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Set {LIGHTGREEN}%t{DEFAULT}'s health to {LIGHTGREEN}%d{DEFAULT}.", target_name, iHealth); + else + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Set {LIGHTGREEN}%s{DEFAULT}'s health to {LIGHTGREEN}%d{DEFAULT}.", target_name, iHealth); + + return Plugin_Handled; + +} + +public Action CommandBamboozleAll(int client, int args) +{ + if (args < 1) return Plugin_Handled; + char arg1[MAX_BUFFER_LENGTH], playerName[MAX_NAME_LENGTH]; + GetCmdArg(1, arg1, sizeof(arg1)); + + int target = FindTarget(client, arg1, false, false); + if (target == -1) return Plugin_Handled; + GetClientName(target, playerName, sizeof(playerName)); + + SetHudTextParams(-1.0, 0.1, 3.0, 255, 0, 0, 255, 1, 1.0, 1.0, 1.0); + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i)) + { + EmitSoundToClient(i, "vo/demoman_specialcompleted11.mp3"); + EmitSoundToClient(i, "vo/demoman_specialcompleted11.mp3"); + Handle hHudText = CreateHudSynchronizer(); + ShowSyncHudText(i, hHudText, "BAMBOOZLED"); + delete hHudText; + LogAction(target, i, "\"%s\" bamboozled \"%L\"!", playerName, i); + } + } + + CPrintToChatAll("{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%s{DEFAULT} just {RED}B{ORANGE}A{YELLOW}M{GREEN}B{BLUE}O{PURPLE}O{MAGENTA}Z{BLACK}L{WHITE}E{GREEN}D{DEFAULT} {LIGHTGREEN}EVERYONE{DEFAULT}!", playerName); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} FEEL THE {BLACK}B{BLUE}A{YELLOW}M{GREEN}B{ORANGE}O{PURPLE}O{MAGENTA}Z{RED}L{WHITE}E{DEFAULT}!"); + return Plugin_Handled; +} + +public Action CommandMuteNonAdmins(int client, int args) +{ + if (muteNonAdminsEnabled) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Nonadmins are already muted. Use sm_unmutenonadmins to unmute."); + return Plugin_Handled; + } + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && !CheckCommandAccess(i, "sm_admin", ADMFLAG_GENERIC)) + { + SetClientListeningFlags(i, VOICE_MUTED); + } + } + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Muted all nonadmins!"); + LogAction(client, -1, "Muted all nonadmins!"); + muteNonAdminsEnabled = true; + return Plugin_Handled; +} + +public Action CommandUnmuteNonAdmins(int client, int args) +{ + if (!muteNonAdminsEnabled) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Nonadmins aren\'t muted. Use sm_mutenonadmins to mute."); + return Plugin_Handled; + } + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && ((sourcecommsExists && SourceComms_GetClientMuteType(i) == bNot) || (basecommExists && !BaseComm_IsClientMuted(i)))) + { + SetClientListeningFlags(i, VOICE_NORMAL); + } + } + CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Unmuted all nonadmins!"); + LogAction(client, -1, "Unmuted all nonadmins!"); + muteNonAdminsEnabled = false; + return Plugin_Handled; +} + +public Action CommandCheckCommandAccess(int client, int args) +{ + if (args < 1) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_checkcommandaccess <#userid|name> "); + return Plugin_Handled; + } + + char arg1[MAX_BUFFER_LENGTH], arg2[MAX_BUFFER_LENGTH]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + int target = FindTarget(client, arg1, true); + if (!IsValidClient(target)) return Plugin_Handled; + + AdminId admin = GetUserAdmin(target); + if (CheckCommandAccess(target, arg2, ADMFLAG_ROOT)) + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} has CheckCommandAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); + else + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} doesn\'t have CheckCommandAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); + if (CheckAccess(admin, arg2, ADMFLAG_ROOT)) + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} has CheckAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); + else + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT} doesn\'t have CheckAccess access to {OLIVE}%s{DEFAULT}!", target, arg2); + return Plugin_Handled; +} + +public Action CommandGetClientInfo(int client, int args) +{ + if (args < 1) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_getclientinfo <#userid|name> "); + return Plugin_Handled; + } + + char arg1[MAX_BUFFER_LENGTH], arg2[MAX_BUFFER_LENGTH]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + int target = FindTarget(client, arg1, true); + if (!IsValidClient(target)) return Plugin_Handled; + + char varString[MAX_BUFFER_LENGTH]; + + if (GetClientInfo(target, arg2, varString, sizeof(varString))) + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s value for {YELLOW}%s{DEFAULT} is {OLIVE}%s{DEFAULT}!", target, arg2, varString); + else + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Could not get client info of {LIGHTGREEN}%N{DEFAULT}!", target); + return Plugin_Handled; +} + +public Action CommandQueryClientConVar(int client, int args) +{ + if (args < 1) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_queryclientconvar <#userid|name> "); + return Plugin_Handled; + } + + char arg1[MAX_BUFFER_LENGTH], arg2[MAX_BUFFER_LENGTH]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + int target = FindTarget(client, arg1, true); + if (!IsValidClient(target)) return Plugin_Handled; + + QueryClientConVar(target, arg2, ClientConVar, client); + return Plugin_Handled; +} + +void ClientConVar(QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value) +{ + if (cookie == QUERYCOOKIE_FAILED) + { + CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s query was invalid!", client); + return; + } + switch (result) + { + case ConVarQuery_Okay: + CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s value for {YELLOW}%s{DEFAULT} is {OLIVE}%s{DEFAULT}!", client, cvarName, cvarValue); + case ConVarQuery_Protected: + CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} {LIGHTGREEN}%N{DEFAULT}\'s value for {YELLOW}%s{DEFAULT} is {PURPLE}PROTECTED{DEFAULT}!", client, cvarName); + default: + CReplyToCommand(value, "{GREEN}[SM]{DEFAULT} Invalid ConVar or ConVar not found for {LIGHTGREEN}%N{DEFAULT}!", client); + } +} diff --git a/scripting/ngs_adminlist.sp b/scripting/ngs_adminlist.sp index a89c822..e9c426a 100644 --- a/scripting/ngs_adminlist.sp +++ b/scripting/ngs_adminlist.sp @@ -1,181 +1,181 @@ -/** -* TheXeon -* ngs_adminlist.sp -* -* Files: -* addons/sourcemod/plugins/ngs_adminlist.smx -* cfg/sourcemod/plugin.ngs_adminlist.cfg -* -* Dependencies: -* sourcemod.inc, ngsutils.inc, ngsupdater.inc, multicolors.inc -*/ -#pragma newdecls required -#pragma semicolon 1 - -#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" -#define RELOAD_ON_UPDATE 1 - -#include -#include -#include -#include - -ConVar AdminListEnabled; - -public Plugin myinfo = { - name = "[NGS] Admin List", - author = "Fredd / TheXeon", - description = "Prints admins and donors to clients.", - version = "1.0.5", - url = "https://www.neogenesisnetwork.net" -} - -public void OnPluginStart() -{ - AdminListEnabled = CreateConVar("sm_ngsadminlist_on", "1", "Turns the admin list feature on and off."); - - RegConsoleCmd("sm_administrators", CommandListAdmins, "List admins to chat."); - RegConsoleCmd("sm_admins", CommandListAdmins, "List admins to chat."); - RegConsoleCmd("sm_listadmins", CommandListAdmins, "List admins to chat."); - RegConsoleCmd("sm_donors", CommandListDonors, "List donors to chat."); - RegConsoleCmd("sm_listdonors", CommandListDonors, "List donors to chat."); - RegConsoleCmd("sm_donators", CommandListDonors, "List donors to chat."); - RegConsoleCmd("sm_djs", CommandListDJs, "List DJs in chat."); - RegConsoleCmd("sm_staff", CommandListStaff, "List all staff in chat."); - RegConsoleCmd("sm_liststaff", CommandListStaff, "List all staff in chat."); - RegConsoleCmd("sm_stafflist", CommandListStaff, "List all staff in chat."); - - AutoExecConfig(); -} - -public Action CommandListAdmins(int client, int args) -{ - if (AdminListEnabled.BoolValue) - { - char adminNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; - int count = 0; - for(int i = 1 ; i <= MaxClients; i++) - { - if (IsValidClient(i) && CheckCommandAccess(i, "sm_ngsstaff_administra_override", ADMFLAG_ROOT)) - { - GetClientName(i, adminNames[count], sizeof(adminNames[])); - count++; - } - } - if (count > 0) - { - char buffer[1024]; - ImplodeStrings(adminNames, count, ", ", buffer, sizeof(buffer)); - CReplyToCommand(client, "{GREEN}[SM] Administrators online: {CYAN}%s.", buffer); - } - else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no admins online. Use !calladmin to call an admin over."); - } - return Plugin_Handled; -} - -public Action CommandListDonors(int client, int args) -{ - if (AdminListEnabled.BoolValue) - { - char DonorNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; - int count = 0; - for(int i = 1 ; i <= MaxClients; i++) - { - if (IsValidClient(i) && CheckCommandAccess(i, "sm_ngsextra_donor_override", ADMFLAG_ROOT) && !CheckCommandAccess(i, "sm_ngsstaff_override", ADMFLAG_ROOT)) - { - GetClientName(i, DonorNames[count], sizeof(DonorNames[])); - count++; - } - } - if (count > 0) - { - char buffer[1024]; - ImplodeStrings(DonorNames, count, ", ", buffer, sizeof(buffer)); - CReplyToCommand(client, "{GREEN}[SM] Donors online: {ORANGE}%s.", buffer); - } - else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no donors online."); - } - return Plugin_Handled; -} - -public Action CommandListDJs(int client, int args) -{ - if (AdminListEnabled.BoolValue) - { - char DJNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; - int count = 0; - for(int i = 1 ; i <= MaxClients; i++) - { - if (IsValidClient(i) && CheckCommandAccess(i, "sm_ngsother_dj_override", ADMFLAG_ROOT) && !CheckCommandAccess(i, "sm_ngsstaff_override", ADMFLAG_ROOT)) - { - GetClientName(i, DJNames[count], sizeof(DJNames[])); - count++; - } - } - if (count > 0) - { - char buffer[1024]; - ImplodeStrings(DJNames, count, ", ", buffer, sizeof(buffer)); - CReplyToCommand(client, "{GREEN}[SM] DJs online: {PURPLE}%s.", buffer); - } - else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no DJs online."); - } - return Plugin_Handled; -} - -public Action CommandListStaff(int client, int args) -{ - if (AdminListEnabled.BoolValue) - { - char adminNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1], marketerNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1], - developerNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; - int adminListCount = 0, commAdvCount = 0, commManCount = 0, devCount = 0; - for(int i = 1 ; i <= MaxClients; i++) - { - if (IsValidClient(i)) - { - if (CheckCommandAccess(i, "sm_ngsstaff_dev_override", ADMFLAG_ROOT)) - { - GetClientName(i, developerNames[devCount], sizeof(developerNames[])); - devCount++; - continue; - } - else if (CheckCommandAccess(i, "sm_ngsstaff_administra_override", ADMFLAG_ROOT)) - { - GetClientName(i, adminNames[adminListCount], sizeof(adminNames[])); - adminListCount++; - continue; - } - else if (CheckCommandAccess(i, "sm_ngsstaff_marketer_override", ADMFLAG_ROOT)) - { - GetClientName(i, marketerNames[commAdvCount], sizeof(marketerNames[])); - commAdvCount++; - continue; - } - } - } - if (adminListCount > 0 || commAdvCount > 0 || commManCount > 0 || devCount > 0) - { - if (adminListCount > 0) - { - char buffer[1024]; - ImplodeStrings(adminNames, adminListCount, ", ", buffer, sizeof(buffer)); - CReplyToCommand(client, "{GREEN}[SM] Administration online: {CYAN}%s.", buffer); - } - if (commManCount > 0) - { - char buffer[1024]; - ImplodeStrings(marketerNames, commManCount, ", ", buffer, sizeof(buffer)); - CReplyToCommand(client, "{GREEN}[SM] Marketers online: {CRIMSON}%s.", buffer); - } - if (devCount > 0) - { - char buffer[1024]; - ImplodeStrings(developerNames, devCount, ", ", buffer, sizeof(buffer)); - CReplyToCommand(client, "{GREEN}[SM] Developers online: {MAGENTA}%s.", buffer); - } - } - else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no staff online. If you need an admin, call one with !calladmin."); - } - return Plugin_Handled; -} +/** +* TheXeon +* ngs_adminlist.sp +* +* Files: +* addons/sourcemod/plugins/ngs_adminlist.smx +* cfg/sourcemod/plugin.ngs_adminlist.cfg +* +* Dependencies: +* sourcemod.inc, ngsutils.inc, ngsupdater.inc, multicolors.inc +*/ +#pragma newdecls required +#pragma semicolon 1 + +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 + +#include +#include +#include +#include + +ConVar AdminListEnabled; + +public Plugin myinfo = { + name = "[NGS] Admin List", + author = "Fredd / TheXeon", + description = "Prints admins and donors to clients.", + version = "1.0.5", + url = "https://www.neogenesisnetwork.net" +} + +public void OnPluginStart() +{ + AdminListEnabled = CreateConVar("sm_ngsadminlist_on", "1", "Turns the admin list feature on and off."); + + RegConsoleCmd("sm_administrators", CommandListAdmins, "List admins to chat."); + RegConsoleCmd("sm_admins", CommandListAdmins, "List admins to chat."); + RegConsoleCmd("sm_listadmins", CommandListAdmins, "List admins to chat."); + RegConsoleCmd("sm_donors", CommandListDonors, "List donors to chat."); + RegConsoleCmd("sm_listdonors", CommandListDonors, "List donors to chat."); + RegConsoleCmd("sm_donators", CommandListDonors, "List donors to chat."); + RegConsoleCmd("sm_djs", CommandListDJs, "List DJs in chat."); + RegConsoleCmd("sm_staff", CommandListStaff, "List all staff in chat."); + RegConsoleCmd("sm_liststaff", CommandListStaff, "List all staff in chat."); + RegConsoleCmd("sm_stafflist", CommandListStaff, "List all staff in chat."); + + AutoExecConfig(); +} + +public Action CommandListAdmins(int client, int args) +{ + if (AdminListEnabled.BoolValue) + { + char adminNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; + int count = 0; + for(int i = 1 ; i <= MaxClients; i++) + { + if (IsValidClient(i) && CheckCommandAccess(i, "sm_ngsstaff_administra_override", ADMFLAG_ROOT)) + { + GetClientName(i, adminNames[count], sizeof(adminNames[])); + count++; + } + } + if (count > 0) + { + char buffer[1024]; + ImplodeStrings(adminNames, count, ", ", buffer, sizeof(buffer)); + CReplyToCommand(client, "{GREEN}[SM] Administrators online: {CYAN}%s.", buffer); + } + else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no admins online. Use !calladmin to call an admin over."); + } + return Plugin_Handled; +} + +public Action CommandListDonors(int client, int args) +{ + if (AdminListEnabled.BoolValue) + { + char DonorNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; + int count = 0; + for(int i = 1 ; i <= MaxClients; i++) + { + if (IsValidClient(i) && CheckCommandAccess(i, "sm_ngsextra_donor_override", ADMFLAG_ROOT) && !CheckCommandAccess(i, "sm_ngsstaff_override", ADMFLAG_ROOT)) + { + GetClientName(i, DonorNames[count], sizeof(DonorNames[])); + count++; + } + } + if (count > 0) + { + char buffer[1024]; + ImplodeStrings(DonorNames, count, ", ", buffer, sizeof(buffer)); + CReplyToCommand(client, "{GREEN}[SM] Donors online: {ORANGE}%s.", buffer); + } + else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no donors online."); + } + return Plugin_Handled; +} + +public Action CommandListDJs(int client, int args) +{ + if (AdminListEnabled.BoolValue) + { + char DJNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; + int count = 0; + for(int i = 1 ; i <= MaxClients; i++) + { + if (IsValidClient(i) && CheckCommandAccess(i, "sm_ngsother_dj_override", ADMFLAG_ROOT) && !CheckCommandAccess(i, "sm_ngsstaff_override", ADMFLAG_ROOT)) + { + GetClientName(i, DJNames[count], sizeof(DJNames[])); + count++; + } + } + if (count > 0) + { + char buffer[1024]; + ImplodeStrings(DJNames, count, ", ", buffer, sizeof(buffer)); + CReplyToCommand(client, "{GREEN}[SM] DJs online: {PURPLE}%s.", buffer); + } + else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no DJs online."); + } + return Plugin_Handled; +} + +public Action CommandListStaff(int client, int args) +{ + if (AdminListEnabled.BoolValue) + { + char adminNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1], marketerNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1], + developerNames[MAXPLAYERS + 1][MAX_NAME_LENGTH + 1]; + int adminListCount = 0, commAdvCount = 0, commManCount = 0, devCount = 0; + for(int i = 1 ; i <= MaxClients; i++) + { + if (IsValidClient(i)) + { + if (CheckCommandAccess(i, "sm_ngsstaff_dev_override", ADMFLAG_ROOT)) + { + GetClientName(i, developerNames[devCount], sizeof(developerNames[])); + devCount++; + continue; + } + else if (CheckCommandAccess(i, "sm_ngsstaff_administra_override", ADMFLAG_ROOT)) + { + GetClientName(i, adminNames[adminListCount], sizeof(adminNames[])); + adminListCount++; + continue; + } + else if (CheckCommandAccess(i, "sm_ngsstaff_marketer_override", ADMFLAG_ROOT)) + { + GetClientName(i, marketerNames[commAdvCount], sizeof(marketerNames[])); + commAdvCount++; + continue; + } + } + } + if (adminListCount > 0 || commAdvCount > 0 || commManCount > 0 || devCount > 0) + { + if (adminListCount > 0) + { + char buffer[1024]; + ImplodeStrings(adminNames, adminListCount, ", ", buffer, sizeof(buffer)); + CReplyToCommand(client, "{GREEN}[SM] Administration online: {CYAN}%s.", buffer); + } + if (commManCount > 0) + { + char buffer[1024]; + ImplodeStrings(marketerNames, commManCount, ", ", buffer, sizeof(buffer)); + CReplyToCommand(client, "{GREEN}[SM] Marketers online: {CRIMSON}%s.", buffer); + } + if (devCount > 0) + { + char buffer[1024]; + ImplodeStrings(developerNames, devCount, ", ", buffer, sizeof(buffer)); + CReplyToCommand(client, "{GREEN}[SM] Developers online: {MAGENTA}%s.", buffer); + } + } + else CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There are no staff online. If you need an admin, call one with !calladmin."); + } + return Plugin_Handled; +} diff --git a/scripting/ngs_celebrateunusual.sp b/scripting/ngs_celebrateunusual.sp index 6e35db3..7e27a1f 100644 --- a/scripting/ngs_celebrateunusual.sp +++ b/scripting/ngs_celebrateunusual.sp @@ -1,106 +1,106 @@ -/** -* TheXeon -* ngs_celebrateunusual.sp -* -* Files: -* addons/sourcemod/plugins/ngs_celebrateunusual.smx -* Optional: the sound file below -* sound/ngs/unusualcelebration/sf13_bcon_misc17.wav -* -* Dependencies: -* sourcemod.inc, ccc.inc, ngsutils.inc, ngsupdater.inc -*/ -#pragma newdecls required -#pragma semicolon 1 - -#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" -#define RELOAD_ON_UPDATE 1 - -#include -#include -#include -#include - -ConVar cvarSoundFile, cvarSoundVolume; -char soundFile[PLATFORM_MAX_PATH]; - -Handle hHudText; - -public Plugin myinfo = { - name = "[NGS] Celebrate Unusual", - author = "TheXeon", - description = "A bombastic celebration of achieving an unusual!", - version = "1.2.0", - url = "https://www.neogenesisnetwork.net" -} - -public void OnPluginStart() -{ - cvarSoundFile = CreateConVar("sm_celebrateunusual_file", "ngs/unusualcelebration/Sf13_bcon_misc17.wav", "The sound file relative to the sound folder played when someone gets an unusual."); - cvarSoundVolume = CreateConVar("sm_celebrateunusual_volume", "3.5", "The sound to play when someone gets an unusual.", FCVAR_NONE, true, 0.0, true, 5.0); - cvarSoundFile.AddChangeHook(OnSoundFileChanged); - - AutoExecConfig(true, "celebrateunusual.cfg"); - - HookEvent("item_found", OnItemFound); - LoadTranslations("common.phrases"); - - cvarSoundFile.GetString(soundFile, sizeof(soundFile)); - char path[PLATFORM_MAX_PATH]; - Format(path, sizeof(path), "sound/%s", soundFile); - if (FileExists(path)) - { - AddFileToDownloadsTable(path); - } - - if (GetEngineVersion() != Engine_TF2) - { - LogError("Attempting to run plugin on unsupported game!"); - } -} - -public void OnMapStart() -{ - PrecacheSound(soundFile); -} - -public void OnSoundFileChanged(ConVar convar, const char[] oldValue, const char[] newValue) -{ - char path[PLATFORM_MAX_PATH]; - Format(path, sizeof(path), "sound/%s", newValue); - if (FileExists(path)) - { - AddFileToDownloadsTable(path); - } - PrecacheSound(newValue); - strcopy(soundFile, sizeof(soundFile), newValue); -} - -public void OnItemFound(Event event, const char[] name, bool dontBroadcast) -{ - if(!event.GetBool("isFake") && event.GetInt("quality") == 5 && event.GetInt("method") == 4) - { - AnnounceUnbox(event.GetInt("player")); - } -} - -public void AnnounceUnbox(int player) -{ - if (!IsValidClient(player)) return; - delete hHudText; - hHudText = CreateHudSynchronizer(); - SetHudTextParams(-1.0, 0.1, 7.0, 255, 0, 0, 255, 1, 1.0, 1.0, 1.0); - - ShowSyncHudTextAll(hHudText, "%N just unboxed an Unusual!", player); - - delete hHudText; - float volume = cvarSoundVolume.FloatValue; - while (volume > 0.0) - { - if (volume < 1.0) - EmitSoundToAll(soundFile, _, _, _, SND_CHANGEVOL, volume); - else - EmitSoundToAll(soundFile); - volume--; - } +/** +* TheXeon +* ngs_celebrateunusual.sp +* +* Files: +* addons/sourcemod/plugins/ngs_celebrateunusual.smx +* Optional: the sound file below +* sound/ngs/unusualcelebration/sf13_bcon_misc17.wav +* +* Dependencies: +* sourcemod.inc, ccc.inc, ngsutils.inc, ngsupdater.inc +*/ +#pragma newdecls required +#pragma semicolon 1 + +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 + +#include +#include +#include +#include + +ConVar cvarSoundFile, cvarSoundVolume; +char soundFile[PLATFORM_MAX_PATH]; + +Handle hHudText; + +public Plugin myinfo = { + name = "[NGS] Celebrate Unusual", + author = "TheXeon", + description = "A bombastic celebration of achieving an unusual!", + version = "1.2.0", + url = "https://www.neogenesisnetwork.net" +} + +public void OnPluginStart() +{ + cvarSoundFile = CreateConVar("sm_celebrateunusual_file", "ngs/unusualcelebration/Sf13_bcon_misc17.wav", "The sound file relative to the sound folder played when someone gets an unusual."); + cvarSoundVolume = CreateConVar("sm_celebrateunusual_volume", "3.5", "The sound to play when someone gets an unusual.", FCVAR_NONE, true, 0.0, true, 5.0); + cvarSoundFile.AddChangeHook(OnSoundFileChanged); + + AutoExecConfig(true, "celebrateunusual.cfg"); + + HookEvent("item_found", OnItemFound); + LoadTranslations("common.phrases"); + + cvarSoundFile.GetString(soundFile, sizeof(soundFile)); + char path[PLATFORM_MAX_PATH]; + Format(path, sizeof(path), "sound/%s", soundFile); + if (FileExists(path)) + { + AddFileToDownloadsTable(path); + } + + if (GetEngineVersion() != Engine_TF2) + { + LogError("Attempting to run plugin on unsupported game!"); + } +} + +public void OnMapStart() +{ + PrecacheSound(soundFile); +} + +public void OnSoundFileChanged(ConVar convar, const char[] oldValue, const char[] newValue) +{ + char path[PLATFORM_MAX_PATH]; + Format(path, sizeof(path), "sound/%s", newValue); + if (FileExists(path)) + { + AddFileToDownloadsTable(path); + } + PrecacheSound(newValue); + strcopy(soundFile, sizeof(soundFile), newValue); +} + +public void OnItemFound(Event event, const char[] name, bool dontBroadcast) +{ + if(!event.GetBool("isFake") && event.GetInt("quality") == 5 && event.GetInt("method") == 4) + { + AnnounceUnbox(event.GetInt("player")); + } +} + +public void AnnounceUnbox(int player) +{ + if (!IsValidClient(player)) return; + delete hHudText; + hHudText = CreateHudSynchronizer(); + SetHudTextParams(-1.0, 0.1, 7.0, 255, 0, 0, 255, 1, 1.0, 1.0, 1.0); + + ShowSyncHudTextAll(hHudText, "%N just unboxed an Unusual!", player); + + delete hHudText; + float volume = cvarSoundVolume.FloatValue; + while (volume > 0.0) + { + if (volume < 1.0) + EmitSoundToAll(soundFile, _, _, _, SND_CHANGEVOL, volume); + else + EmitSoundToAll(soundFile); + volume--; + } } \ No newline at end of file diff --git a/scripting/ngs_donor_toolkit.sp b/scripting/ngs_donor_toolkit.sp index ac5f2c5..b8ce311 100644 --- a/scripting/ngs_donor_toolkit.sp +++ b/scripting/ngs_donor_toolkit.sp @@ -1,59 +1,59 @@ -/** -* TheXeon -* ngs_donor_toolkit.sp -* -* Files: -* addons/sourcemod/plugins/ngs_donor_toolkit.smx -* -* Dependencies: -* sourcemod.inc, tf2attributes.inc, multicolors.inc, ngsutils.inc, ngsupdater.inc -*/ -#pragma newdecls required -#pragma semicolon 1 - -#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" -#define RELOAD_ON_UPDATE 1 - -#include -#include -#include -#include -#include - -bool VoicesEnabled[MAXPLAYERS + 1]; - -public Plugin myinfo = { - name = "[NGS] Donor/VIP Tools", - author = "TheXeon", - description = "VIP commands for NGS people.", - version = "1.0.1", - url = "https://neogenesisnetwork.net" -} - -public void OnPluginStart() -{ - RegAdminCmd("sm_voices", CommandVoices, ADMFLAG_RESERVATION, "Usage: sm_voices"); - HookEvent("post_inventory_application", OnPostInventoryApplication); - LoadTranslations("common.phrases"); -} - -public void OnClientPutInServer(int client) -{ - VoicesEnabled[client] = false; -} - -public Action CommandVoices(int client, int args) -{ - if (!IsValidClient(client)) return Plugin_Handled; - VoicesEnabled[client] = !VoicesEnabled[client]; - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Halloween voices %s!", VoicesEnabled[client] ? "enabled" : "disabled"); - if (VoicesEnabled[client]) TF2Attrib_SetByName(client, "SPELL: Halloween voice modulation", 1.0); - else TF2Attrib_RemoveByName(client, "SPELL: Halloween voice modulation"); - return Plugin_Handled; -} - -public void OnPostInventoryApplication(Event hEvent, const char[] szName, bool bDontBroadcast) -{ - int client = GetClientOfUserId(hEvent.GetInt("userid")); - if (VoicesEnabled[client]) TF2Attrib_SetByName(client, "SPELL: Halloween voice modulation", 1.0); -} +/** +* TheXeon +* ngs_donor_toolkit.sp +* +* Files: +* addons/sourcemod/plugins/ngs_donor_toolkit.smx +* +* Dependencies: +* sourcemod.inc, tf2attributes.inc, multicolors.inc, ngsutils.inc, ngsupdater.inc +*/ +#pragma newdecls required +#pragma semicolon 1 + +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 + +#include +#include +#include +#include +#include + +bool VoicesEnabled[MAXPLAYERS + 1]; + +public Plugin myinfo = { + name = "[NGS] Donor/VIP Tools", + author = "TheXeon", + description = "VIP commands for NGS people.", + version = "1.0.1", + url = "https://neogenesisnetwork.net" +} + +public void OnPluginStart() +{ + RegAdminCmd("sm_voices", CommandVoices, ADMFLAG_RESERVATION, "Usage: sm_voices"); + HookEvent("post_inventory_application", OnPostInventoryApplication); + LoadTranslations("common.phrases"); +} + +public void OnClientPutInServer(int client) +{ + VoicesEnabled[client] = false; +} + +public Action CommandVoices(int client, int args) +{ + if (!IsValidClient(client)) return Plugin_Handled; + VoicesEnabled[client] = !VoicesEnabled[client]; + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Halloween voices %s!", VoicesEnabled[client] ? "enabled" : "disabled"); + if (VoicesEnabled[client]) TF2Attrib_SetByName(client, "SPELL: Halloween voice modulation", 1.0); + else TF2Attrib_RemoveByName(client, "SPELL: Halloween voice modulation"); + return Plugin_Handled; +} + +public void OnPostInventoryApplication(Event hEvent, const char[] szName, bool bDontBroadcast) +{ + int client = GetClientOfUserId(hEvent.GetInt("userid")); + if (VoicesEnabled[client]) TF2Attrib_SetByName(client, "SPELL: Halloween voice modulation", 1.0); +} diff --git a/scripting/ngs_freeduels.sp b/scripting/ngs_freeduels.sp index 43911cb..8925679 100644 --- a/scripting/ngs_freeduels.sp +++ b/scripting/ngs_freeduels.sp @@ -1,2120 +1,2120 @@ -/** -* TheXeon -* ngs_freeduels.sp -* -* Files: -* addons/sourcemod/plugins/ngs_freeduels.smx -* addons/sourcemod/translations/free_duels.phrases.txt -* addons/sourcemod/data/sqlite/duel.sq3 -* cfg/sourcemod/free_duels.cfg -* -* Dependencies: -* sdkhooks.inc, tf2_stocks.inc, tf2attributes.inc, multicolors.inc, -* free_duels.inc, friendly.inc, ngsutils.inc, ngsupdater.inc -*/ -#pragma newdecls required -#pragma semicolon 1 - -#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" -#define RELOAD_ON_UPDATE 1 - -#include -#include -#include -#include -#include -#include -#include -#include - -#define WEBSITE "https://www.neogenesisnetwork.net" -#define MAX_LINE_WIDTH 60 - -enum DuelData -{ - Challenger, - bool:Enabled, - Type, - Score, - PlayedTime, - kills, - Deads, - ClassRestrict, - GodMod, - bool:HeadShot, - TimeLeft, - CSprite, - SpriteParent, - bool:HideSprite, - bool:HealingAllowed -} - -int g_Duel[MAXPLAYERS+1][DuelData]; - -int victories[MAXPLAYERS+1] = {0, ...}; -int death[MAXPLAYERS+1] = {0, ...}; -int killsNbr[MAXPLAYERS+1] = {0, ...}; -int dueltotal[MAXPLAYERS+1] = {0, ...}; -float points[MAXPLAYERS+1] = {0.0, ...}; - -bool Abandon[MAXPLAYERS+1] = {false, ...}; -bool Equality[MAXPLAYERS+1] = {false, ...}; -bool Winner[MAXPLAYERS+1] = {false, ...}; -bool SQLite = false; -bool disableDuel[MAXPLAYERS + 1] = { false, ... }; - -ConVar c_EnableType[4]; -ConVar cvarEnabled; -ConVar c_Tag; -ConVar c_EnableClass; -ConVar c_EnableGodMod; -ConVar c_EnableHeadShot; -ConVar c_HeadShotFlag; -ConVar c_Immunity; -ConVar c_ClassRestriction; -ConVar c_GodModFlag; - -SmartDB db; - -char ClientSteamID[MAXPLAYERS+1][24]; -char ClientName[MAXPLAYERS+1][MAX_LINE_WIDTH]; - -static char DuelNames[4][16] = {"Disabled", "Normal", "Time left", "Amount of kills"}; -static char ClassNames[TFClassType][] = {"ANY", "Scout", "Sniper", "Soldier", "Demoman", "Medic", "Heavy", "Pyro", "Spy", "Engineer" }; -static char ClassRestricNames[TFClassType][] = {"", "scouts", "snipers", "soldiers", "demomen", "medics", "heavies", "pyros", "spies", "engineers" }; -static char TF_ClassNames[TFClassType][] = {"", "scout", "sniper", "soldier", "demoman", "medic", "heavyweapons", "pyro", "spy", "engineer" }; -static TimeLeftOptions[10] = {1, 2, 5, 10, 15, 20, 30, 45, 60, 120}; -static AmountOfKillOptions[12] = {1, 2, 3, 4, 5, 10, 15, 20, 50, 75, 100, 150}; - -int LimitPerClass[4][10]; -int RankTotal; -int Countdown = 600; - - -public Plugin myinfo = { - name = "[NGS] Free duels", - author = "Erreur 500 / TheXeon", - description = "Challenge other players", - version = "1.2.4", - url = "https://www.neogenesisnetwork.net" -} - -public void OnPluginStart() -{ - cvarEnabled = CreateConVar("duel_enabled", "1", "Enable or disable Free Duels ?", 0, true, 0.0, true, 1.0); - c_Tag = CreateConVar("duel_tag", "1", "Add 'duels' tags", 0, true, 0.0, true, 1.0); - c_Immunity = CreateConVar("duel_immunity", "0", "a or b or o or p or q or r or s or t or z for flag needed, 0 = no flag needed"); - c_ClassRestriction = CreateConVar("duel_classrestrict", "0", "1 = classrestrict by DJ Tsunami, 2 = Max Class (Class Limit) by Nican , 0 = none"); - c_EnableClass = CreateConVar("duel_class", "1", "0 = disable class restriction duel, 1 = enable", 0, true, 0.0, true, 1.0); - c_EnableType[1] = CreateConVar("duel_type1", "1", "0 = disable `normal` duel, 1 = enable", 0, true, 0.0, true, 1.0); - c_EnableType[2] = CreateConVar("duel_type2", "1", "0 = disable `time left` duel, 1 = enable", 0, true, 0.0, true, 1.0); - c_EnableType[3] = CreateConVar("duel_type3", "1", "0 = disable `amount of kills` duel, 1 = enable", 0, true, 0.0, true, 1.0); - c_EnableGodMod = CreateConVar("duel_godmod", "1", "0 = disable challenger godmod, 1 = enable", 0, true, 0.0, true, 1.0); - c_GodModFlag = CreateConVar("duel_godmod_flag", "0", "Flag needed to create godmod duel : a or b or o or p or q or r or s or t or z, 0 = no flag"); - c_EnableHeadShot = CreateConVar("duel_headshot", "1", "0 = disable head shot only (sniper), 1 = enable", 0, true, 0.0, true, 1.0); - c_HeadShotFlag = CreateConVar("duel_headshot_flag", "a", "Flag needed to create head shot duel : a or b or o or p or q or r or s or t or z, 0 = no flag"); - - if(cvarEnabled.BoolValue) - { - LogMessage("[0/5] Loading : Enabled"); - RegConsoleCmd("sm_duel", loadDuel, "Challenge player"); - RegConsoleCmd("sm_abort", AbortDuel, "Stop duel"); - RegConsoleCmd("sm_myduels", MyDuelStats, "Show your duels stats"); - RegConsoleCmd("sm_topduel", TopDuel, "Show top dueler"); - RegConsoleCmd("sm_noduelme", NoDuelMe, "Disables duel requests."); - RegConsoleCmd("sm_dontduelme", NoDuelMe, "Disables duel requests."); - - LogMessage("[1/5] Loading : Initialisation"); - Initialisation(); - AutoExecConfig(true, "free_duels"); - Connect(); - TranslationFileExists("free_duels.phrases", true, true); - LoadTranslations("common.phrases"); - - HookEvent("player_spawn", EventPlayerSpawn, EventHookMode_Pre); - HookEvent("player_death", EventPlayerDeath); - HookEvent("player_team", EventPlayerTeam, EventHookMode_Pre); - HookEvent("player_changeclass", EventPlayerchangeclass, EventHookMode_Pre); - HookEvent("player_builtobject", EventBuiltObject); - HookEvent("teamplay_round_win", EventRoundEnd, EventHookMode_PostNoCopy); - HookEvent("teamplay_flag_event", EventFlag); - HookEvent("controlpoint_starttouch", EventCPStartTouch); - HookEvent("controlpoint_endtouch", EventCPEndTouch); - HookEvent("player_sapped_object", EventSapped); - HookEvent("post_inventory_application", EventPostInventoryApplication); -// HookEvent("player_upgradedobject", EventUpgradedObject, EventHookMode_Pre); -// HookEvent("object_deflected", EventAirblast); - - for (int iClient = 1; iClient <= MaxClients; iClient++) - if (IsValidClient(iClient)) OnClientPutInServer(iClient); - - CreateTimer(1.0, Timer, INVALID_HANDLE, TIMER_REPEAT); - } - else - LogMessage("Loading : Free Duels disabled by CVar"); -} - -public void OnPluginEnd() -{ - for(int i = 1; i <= MaxClients ; i++) - { - if(g_Duel[i][Enabled]) - { - EndDuel(i, g_Duel[i][Type]); - g_Duel[i][Enabled] = false; - g_Duel[g_Duel[i][Challenger]][Enabled] = false; - } - } -} - -public void OnClientPutInServer(int client) -{ - SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); -} - -public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) -{ - CreateNative("IsPlayerInDuel", Native_IsPlayerInDuel); - CreateNative("IsDuelRestrictionClass", Native_IsDuelRestrictionClass); - CreateNative("GetDuelerID", Native_GetDuelerID); - - return APLRes_Success; -} - -void Initialisation() -{ - for (int i = 0; i < MAXPLAYERS + 1; i++) - { - g_Duel[i][Enabled] = false; - g_Duel[i][SpriteParent] = INVALID_ENT_REFERENCE; - g_Duel[i][CSprite] = INVALID_ENT_REFERENCE; - } -} - -public void OnClientConnected(int client) -{ - disableDuel[client] = false; -} - -public void OnConfigsExecuted() -{ - LogMessage("[4/5] Loading : Configs Executed"); - if(c_Tag.IntValue) - TagsCheck("Duels"); - - LogMessage("[5/5] Loading : Finished"); -} - -void TagsCheck(const char[] tag) -{ - ConVar hTags = FindConVar("sv_tags"); - char tags[255]; - hTags.GetString(tags, sizeof(tags)); - - if (!(StrContains(tags, tag, false) > -1)) - { - char newTags[255]; - Format(newTags, sizeof(newTags), "%s,%s", tags, tag); - hTags.SetString(newTags); - hTags.GetString(tags, sizeof(tags)); - } - delete hTags; -} - -public void OnMapStart() -{ - AddFileToDownloadsTable("materials/free_duel/RED_Target.vmt"); - AddFileToDownloadsTable("materials/free_duel/RED_Target.vtf"); - AddFileToDownloadsTable("materials/free_duel/BLU_Target.vmt"); - AddFileToDownloadsTable("materials/free_duel/BLU_Target.vtf"); - - PrecacheModel("models/player/medic_animations.mdl"); - PrecacheDecal("materials/free_duel/RED_Target.vmt", true); - PrecacheDecal("materials/free_duel/BLU_Target.vmt", true); -} - -void Connect() -{ - if (SQL_CheckConfig("duel")) - { - Database.Connect(Connected, "duel"); - } - else if (SQL_CheckConfig("default")) - { - Database.Connect(Connected); - } - else - { - ConnectToSQLite(); - } -} - -public void ConnectToSQLite() -{ - char error[255]; - SQLite = true; - - KeyValues kv = new KeyValues(""); - kv.SetString("driver", "sqlite"); - kv.SetString("database", "duel"); - db = view_as(SQL_ConnectCustom(kv, error, sizeof(error), false)); - delete kv; - - if (db == null) - LogMessage("Loading : Failed to connect: %s", error); - else - { - LogMessage("[2/5] Loading : Connected to SQLite Database"); - CreateDbSQLite(); - } -} - -public void Connected(Database hndl, const char[] error, any data) -{ - if (hndl == null) - { - LogError("Failed to connect! Error: %s", error); - LogMessage("Loading : Failed to connect! Falling back to SQLite!"); - ConnectToSQLite(); - return; - } - - LogMessage("Loading : Connected to MySQL Database[2/5]"); - hndl.Query(SQLErrorCheckCallback, "SET NAMES 'utf8'"); - db = view_as(hndl); - SQL_CreateTables(); -} - -void SQL_CreateTables() -{ - int len = 0; - char query[1000]; - len += Format(query[len], sizeof(query)-len, "CREATE TABLE IF NOT EXISTS `Duels_Stats` ("); - len += Format(query[len], sizeof(query)-len, "`Players` VARCHAR(30) NOT NULL,"); - len += Format(query[len], sizeof(query)-len, "`SteamID` VARCHAR(25) NOT NULL,"); - len += Format(query[len], sizeof(query)-len, "`Points` float(16,9) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`Victories` int(25) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`Duels` int(25) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`Kills` int(25) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`Deads` int(25) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`PlayTime` int(25) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`Abandoned` int(25) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`Equalities` int(25) NOT NULL default '0',"); - len += Format(query[len], sizeof(query)-len, "`Last_dueler` VARCHAR(30) NOT NULL,"); - len += Format(query[len], sizeof(query)-len, "`Last_dueler_SteamID` VARCHAR(25) NOT NULL,"); - len += Format(query[len], sizeof(query)-len, "`Etat` VARCHAR(25) NOT NULL,"); - len += Format(query[len], sizeof(query)-len, "PRIMARY KEY (`SteamID`)"); - len += Format(query[len], sizeof(query)-len, ") ENGINE=MyISAM DEFAULT CHARSET=utf8;"); - db.VoidQuery(query); - LogMessage("[?/5] Loading : Tables Created"); -} - -void CreateDbSQLite() -{ - int len = 0; - char query[10000]; - len += Format(query[len], sizeof(query)-len, "CREATE TABLE IF NOT EXISTS `Duels_Stats`"); - len += Format(query[len], sizeof(query)-len, " (`Players` TEXT, `SteamID` TEXT,"); - len += Format(query[len], sizeof(query)-len, " `Points` REAL DEFAULT 0,`Victories` INTEGER DEFAULT 0, `Duels` INTEGER DEFAULT 0,"); - len += Format(query[len], sizeof(query)-len, " `Kills` INTEGER DEFAULT 0, `Deads` INTEGER DEFAULT 0, `PlayTime` INTEGER DEFAULT 0,"); - len += Format(query[len], sizeof(query)-len, " `Abandoned` INTEGER DEFAULT 0, `Equalities` INTEGER DEFAULT 0,"); - len += Format(query[len], sizeof(query)-len, " `Last_dueler` TEXT, `Last_dueler_SteamID` TEXT, `Etat` TEXT"); - - len += Format(query[len], sizeof(query)-len, ");"); - db.VoidQuery(query); - LogMessage("[?/5] Loading : Tables Created"); -} - -public void SQLErrorCheckCallback(Database owner, DBResultSet hndl, const char[] error, any data) -{ - if (!StrEqual(error, "")) - { - LogError("Loading : SQL Error: %s", error); - LogMessage("Loading : SQL Error: %s", error); - } - delete hndl; -} - -public Action NoDuelMe(int client, int args) -{ - if (!IsValidClient(client)) return Plugin_Handled; - disableDuel[client] = !disableDuel[client]; - CReplyToCommand(client, "{CYAN}[Duel]{DEFAULT} You have %s duel requests.", (disableDuel[client]) ? "disabled" : "enabled"); - return Plugin_Handled; -} - -public Action loadDuel(int iClient, int Args) -{ - if (!IsValidClient(iClient)) - { - return Plugin_Handled; - } - - if (disableDuel[iClient]) - { - CReplyToCommand(iClient, "{CYAN}[Duel]{DEFAULT} You cannot send duel requests if you have disabled duel requests."); - return Plugin_Handled; - } - char FlagNeeded[2]; - c_Immunity.GetString(FlagNeeded, sizeof(FlagNeeded)); - - if(!isAdmin(iClient, FlagNeeded)) - return Plugin_Handled; - - char Argument1[256]; - GetCmdArgString(Argument1, sizeof(Argument1)); - - if(StrEqual ("",Argument1)) // No Args - CallPanel(iClient); - else - { - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - if((target_count = ProcessTargetString( - Argument1, - iClient, - target_list, - MAXPLAYERS, - COMMAND_FILTER_ALIVE, - target_name, - sizeof(target_name), - tn_is_ml)) <= 0) - { - ReplyToTargetError(iClient, target_count); - CallPanel(iClient); - return Plugin_Handled; - } - - for (int i = 0; i < target_count; i++) - { - if(isGoodSituation(iClient, target_list[i])) - { - if (disableDuel[target_list[i]]) - { - CReplyToCommand(iClient, "{CYAN}[Duel]{DEFAULT} That person has disabled duel requests!"); - continue; - } - if(!g_Duel[iClient][Type]) - { - LogAction(iClient, target_list[i], "%L challenged %L", iClient, target_list[i]); - CreateDuel(iClient, target_list[i]); - } - else - CPrintToChat(iClient,"%t", "WaitAnwser"); - } - } - } - return Plugin_Handled; -} - -public bool isAdmin(int iClient, char FlagNeeded[2]) -{ - if(StrEqual(FlagNeeded, "0")) - return true; - else - { - int flags = GetUserFlagBits(iClient); - if(flags == 0) - { - //PrintToChatAll("Flag : %s + %s", FlagNeeded[0], FlagNeeded[1]); - CPrintToChat(iClient,"%t", "NoFlag"); - return false; - } - else if((flags & ADMFLAG_ROOT) && StrEqual(FlagNeeded, "z")) - return true; - else if((flags & ADMFLAG_RESERVATION) && StrEqual(FlagNeeded, "a")) - return true; - else if((flags & ADMFLAG_GENERIC) && StrEqual(FlagNeeded, "b")) - return true; - else if((flags & ADMFLAG_CUSTOM1) && StrEqual(FlagNeeded, "o")) - return true; - else if((flags & ADMFLAG_CUSTOM2) && StrEqual(FlagNeeded, "p")) - return true; - else if((flags & ADMFLAG_CUSTOM3) && StrEqual(FlagNeeded, "q")) - return true; - else if((flags & ADMFLAG_CUSTOM4) && StrEqual(FlagNeeded, "r")) - return true; - else if((flags & ADMFLAG_CUSTOM5) && StrEqual(FlagNeeded, "s")) - return true; - else if((flags & ADMFLAG_CUSTOM6) && StrEqual(FlagNeeded, "t")) - return true; - else - { - //PrintToChatAll("FlagNO : %s + %s", FlagNeeded[0], FlagNeeded[1]); - CPrintToChat(iClient,"%t", "NoFlag"); - return false; - } - } -} - -void RemovePlayerBuilding(int iClient) -{ - int ObjEnt; - - while((ObjEnt = FindEntityByClassname(ObjEnt, "obj_sentrygun")) != -1) - { - if(GetEntPropEnt(ObjEnt, Prop_Send, "m_hBuilder") == iClient) - { - SetVariantInt(1000); - AcceptEntityInput(ObjEnt, "RemoveHealth"); - } - } - - while((ObjEnt = FindEntityByClassname(ObjEnt, "obj_dispenser")) != -1) - { - if(GetEntPropEnt(ObjEnt, Prop_Send, "m_hBuilder") == iClient) - { - SetVariantInt(1000); - AcceptEntityInput(ObjEnt, "RemoveHealth"); - } - } - - while((ObjEnt = FindEntityByClassname(ObjEnt, "obj_teleporter")) != -1) - { - if(GetEntPropEnt(ObjEnt, Prop_Send, "m_hBuilder") == iClient) - { - SetVariantInt(1000); - AcceptEntityInput(ObjEnt, "RemoveHealth"); - } - } -} - - -//------------------------------------------------------------------------------------------------------------------------ -// Event Zone -//------------------------------------------------------------------------------------------------------------------------ - - -public Action EventPlayerSpawn(Event hEvent, const char[] strName, bool bHidden) -{ - int iClient = GetClientOfUserId(hEvent.GetInt("userid")); - if(g_Duel[iClient][Enabled] && g_Duel[iClient][ClassRestrict] != 0 && TF2_GetPlayerClass(iClient) != view_as(g_Duel[iClient][ClassRestrict])) - { - TF2_SetPlayerClass(iClient, view_as(g_Duel[iClient][ClassRestrict]), false); - TF2_RespawnPlayer(iClient); - CPrintToChat(iClient, "%t", "ChangeClass"); - CPrintToChat(iClient, "%t", "Abort"); - } - - if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 1) - { - SetGodModColor(iClient); - SetEntProp(iClient, Prop_Send, "m_CollisionGroup", FindConVar("sm_friendly_noblock").IntValue); - } - else if (!g_Duel[iClient][GodMod] && !TF2Friendly_IsFriendly(iClient)) - SetEntProp(iClient, Prop_Send, "m_CollisionGroup", 5); -} - -public void EventPlayerDeath(Event hEvent, const char[] strName, bool bHidden) -{ - - int iClient = GetClientOfUserId(hEvent.GetInt("userid")); - int iKiller = GetClientOfUserId(hEvent.GetInt("attacker")); - int iAssister = GetClientOfUserId(hEvent.GetInt("assister")); - - if(hEvent.GetInt("death_flags") & TF_DEATHFLAG_DEADRINGER) - return; - - if(c_EnableHeadShot.BoolValue && g_Duel[iClient][HeadShot]) - { - if(hEvent.GetInt("customkill") != 1) - { - return; - } - } - - if (g_Duel[iKiller][Challenger] == iClient && g_Duel[iKiller][Enabled]) - { - g_Duel[iKiller][kills] += 1; - g_Duel[iClient][Deads] += 1; - - if(g_Duel[iKiller][Enabled] && g_Duel[iKiller][Type] != 3 ) - { - g_Duel[iKiller][Score] += 1; - CPrintToChat(iKiller, "%t", "Score", iKiller, g_Duel[iKiller][Score], iClient, g_Duel[iClient][Score]); - CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient], iKiller, g_Duel[iKiller][Score]); - } - else if(g_Duel[iKiller][Enabled] && g_Duel[iKiller][Type] == 3) - { - g_Duel[iKiller][Score] -= 1; - CPrintToChat(iKiller, "%t", "Score", iKiller, g_Duel[iKiller][Score], iClient, g_Duel[iClient][Score]); - CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient][Score], iKiller, g_Duel[iKiller][Score]); - - if(g_Duel[iKiller][Score] == 0) EndDuel(iKiller, g_Duel[iKiller][Type]); - } - } - else if(g_Duel[iAssister][Challenger] == iClient && g_Duel[iAssister][Enabled]) - { - g_Duel[iAssister][kills] += 1; - g_Duel[iClient][Deads] += 1; - if(g_Duel[iAssister][Enabled] && g_Duel[iAssister][Type] != 3 ) - { - g_Duel[iAssister][Score] += 1; - CPrintToChat(iAssister, "%t", "Score", iAssister, g_Duel[iAssister][Score], iClient, g_Duel[iClient][Score]); - CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient][Score], iAssister, g_Duel[iAssister][Score]); - } - else if(g_Duel[iAssister][Enabled] && g_Duel[iAssister][Type] == 3) - { - g_Duel[iAssister][Score] -= 1; - CPrintToChat(iAssister, "%t", "Score", iAssister, g_Duel[iAssister][Score], iClient, g_Duel[iClient][Score]); - CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient][Score], iAssister, g_Duel[iAssister][Score]); - - if(g_Duel[iAssister][Score] == 0) EndDuel(iAssister, g_Duel[iAssister][Type]); - } - } -} - -public Action EventPlayerTeam(Event hEvent, const char[] strName, bool bHidden) -{ - int iClient = GetClientOfUserId(hEvent.GetInt("userid")); - - if(g_Duel[iClient][Enabled]) - { - CPrintToChatAll("%t", "Victory", g_Duel[iClient][Challenger], iClient, "(Player changed team)"); - - Abandon[g_Duel[iClient][Challenger]] = false; - Abandon[iClient] = true; - Winner[g_Duel[iClient][Challenger]] = true; - Winner[iClient] = false; - - if(g_Duel[iClient][Challenger] !=0) - ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); - - if(iClient != 0) - ClientCommand(iClient, "playgamesound ui/duel_event.wav"); - - InitializeClientonDB(g_Duel[iClient][Challenger]); - InitializeClientonDB(iClient); - } -} - -public void EventPlayerchangeclass(Event event, const char[] name, bool bHidden) -{ - int iClient = GetClientOfUserId(event.GetInt("userid")); - if(g_Duel[iClient][Enabled] && g_Duel[iClient][ClassRestrict] != 0 && TF2_GetPlayerClass(iClient) != view_as(g_Duel[iClient][ClassRestrict])) - { - TF2_SetPlayerClass(iClient, view_as(g_Duel[iClient][ClassRestrict]), false); - TF2_RespawnPlayer(iClient); - CPrintToChat(iClient, "%t", "ChangeClass"); - CPrintToChat(iClient, "%t", "Abort"); - } -} - -public void EventRoundEnd(Event event, const char[] name, bool bHidden) -{ - for (int i = 1; i <= MaxClients ; i++) - { - if(g_Duel[i][Enabled]) - { - EndDuel(i, g_Duel[i][Type]); - g_Duel[i][Enabled] = false; - g_Duel[g_Duel[i][Challenger]][Enabled] = false; - } - } -} - -public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype) -{ - if (!IsValidClient(victim) || !IsValidClient(attacker)) return Plugin_Continue; - if(c_EnableGodMod.BoolValue) - { - // int damageAmount = event.GetInt("damageamount"); - - if(((g_Duel[victim][Challenger] != attacker) || (g_Duel[attacker][Challenger] != victim)) && - (victim != attacker) && ((g_Duel[victim][Enabled] && g_Duel[victim][GodMod] == 1 ) || - (g_Duel[attacker][Enabled] && g_Duel[attacker][GodMod] == 1))) - { - damage = 0.0; - return Plugin_Changed; - // SetEntityHealth(client, GetClientHealth(client) + damageAmount); - } - } - return Plugin_Continue; -} - -public void EventCPStartTouch(Event hEvent, const char[] strName, bool bHidden) -{ - int iClient = hEvent.GetInt("player"); - if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 1) - { - g_Duel[iClient][GodMod] = 2; // It's not because you are on GodMod you can take CP! - SetEntityRenderColor(iClient, 255, 255, 255, 255); - } -} - -public void EventCPEndTouch(Event hEvent, const char[] strName, bool bHidden) -{ - int iClient = hEvent.GetInt("player"); - if(!IsValidClient(iClient)) return; - - if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 2) - { - g_Duel[iClient][GodMod] = 1; // You're a good guy! - SetGodModColor(iClient); - } -} - -public void EventPostInventoryApplication(Event event, const char[] name, bool bHidden) -{ - int client = GetClientOfUserId(event.GetInt("userid")); - if (IsValidClient(client)) - { - if (g_Duel[client][Enabled] && !g_Duel[client][HealingAllowed]) - { - TF2Attrib_SetByName(client, "health from healers reduced", 0.0); - } - } -} - -public void EventFlag(Event hEvent, const char[] strName, bool bHidden) -{ - int iClient = hEvent.GetInt("player"); - int EventType = hEvent.GetInt("eventtype"); - - if(!IsValidClient(iClient)) return; - - if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 1 && (EventType == 1 || EventType == 3) ) - { - g_Duel[iClient][GodMod] = 2; // It's not because you are on GodMod you can take Flag! - SetEntityRenderColor(iClient, 255, 255, 255, 255); - } - else if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 2 && (EventType == 2 || EventType == 4) ) - { - g_Duel[iClient][GodMod] = 1; // You're a good guy! - SetGodModColor(iClient); - } -} - -public void EventBuiltObject(Event hEvent, const char[] strName, bool bHidden) -{ - int iClient = GetClientOfUserId(hEvent.GetInt("userid")); - int ObjEnt = hEvent.GetInt("index"); - - if(!IsValidClient(iClient)) return; - - SDKHook(ObjEnt, SDKHook_OnTakeDamage, BuildingTakeDamage); - - if(!g_Duel[iClient][Enabled]) return; - if(!g_Duel[iClient][GodMod]) return; - - CPrintToChat(iClient, "%t", "Don'tBuilt"); - SetVariantInt(1000); - AcceptEntityInput(ObjEnt, "RemoveHealth"); -} - -// Next few methods from ddhoward's friendly. He is a god. -public Action BuildingTakeDamage(int building, int &attacker, int &inflictor, float &damage, int &damagetype) -{ - int engie = GetEntPropEnt(building, Prop_Send, "m_hBuilder"); - char classname[64]; - if (!GetEntityClassname(building, classname, sizeof(classname))) - { - return Plugin_Continue; - } - if (!IsValidClient(attacker) || !IsValidClient(engie)) { - return Plugin_Continue; - } - - if (g_Duel[attacker][Enabled] && g_Duel[attacker][GodMod] == 1 && g_Duel[attacker][Challenger] != engie) - { - damage = 0.0; - return Plugin_Changed; - } - return Plugin_Continue; -} - -public void EventSapped(Event event, const char[] name, bool dontBroadcast) -{ - int spy = GetClientOfUserId(event.GetInt("userid")); - int sapper = event.GetInt("sapperid"); - int engie = GetClientOfUserId(event.GetInt("ownerid")); - if (g_Duel[spy][Enabled] && g_Duel[spy][GodMod] == 1) - { - if (g_Duel[spy][Challenger] != engie) - { - AcceptEntityInput(sapper, "Kill"); - } - else - { - SDKHook(sapper, SDKHook_OnTakeDamage, SapperTakeDamage); - } - } -} - -public Action SapperTakeDamage(int sapper, int &attacker, int &inflictor, float &damage, int &damagetype) -{ - int building = GetEntPropEnt(sapper, Prop_Send, "m_hBuiltOnEntity"); - int engie = GetEntPropEnt(building, Prop_Send, "m_hBuilder"); - if (!IsValidClient(attacker)) - { - return Plugin_Continue; - } - - if (g_Duel[engie][Enabled] && g_Duel[engie][GodMod] == 1 && g_Duel[engie][Challenger] != attacker) // I dont know how it could be true - { - damage = 0.0; - return Plugin_Changed; - } - return Plugin_Continue; -} - -public void OnGameFrame() -{ - float vecOrigin[3]; - - for(int iClient = 1; iClient <= MaxClients; iClient++ ) - if(IsValidClient(iClient) && g_Duel[iClient][Enabled]) - { - if(TF2_IsPlayerInCondition(iClient, TFCond_Cloaked)) // prevents showing during spells or plugin stuffs - { - if(!g_Duel[iClient][HideSprite]) - g_Duel[iClient][HideSprite] = true; - } - else - { - if(g_Duel[iClient][HideSprite]) - g_Duel[iClient][HideSprite] = false; - } - - GetClientEyePosition( iClient, vecOrigin ); - vecOrigin[2] += 25.0; - - if(EntRefToEntIndex(g_Duel[iClient][SpriteParent]) != INVALID_ENT_REFERENCE) - TeleportEntity(EntRefToEntIndex(g_Duel[iClient][SpriteParent]), vecOrigin, NULL_VECTOR, NULL_VECTOR); - } -} - - -//------------------------------------------------------------------------------------------------------------------------ -// !DUEL Menu -//------------------------------------------------------------------------------------------------------------------------ - - -public void CallPanel(int iClient) -{ - if(!g_Duel[iClient][Enabled]) - { - if(!g_Duel[iClient][Type]) - { - int iteam; - int Player[40]; - - if(GetClientTeam(iClient) == 2) iteam = 3; - else if(GetClientTeam(iClient) == 3) iteam = 2; - - if(iteam == 2 || iteam == 3) - { - int nbr = 0; - for(int i = 1; i <= MaxClients ; i++) // Create an array if valid players (players + bots) - { - Player[i-1] = 0; - if(IsValidClient(i) && GetClientTeam(i) == iteam && !g_Duel[i][Enabled] && g_Duel[i][Challenger] == 0) - { - Player[nbr] = i; - nbr++; - } - } - - if(nbr >= 1) // Player found, open menu - { - char Playername[MAX_LINE_WIDTH]; - char str_PlayerID[8]; - Menu menuPlayer = new Menu(DuelPanel1); - menuPlayer.SetTitle("Who should be challenged?"); - - for(int i = 0; i < nbr; i++) - { - GetClientName(Player[i], Playername, sizeof(Playername)); - IntToString(Player[i], str_PlayerID, sizeof(str_PlayerID)); - menuPlayer.AddItem(str_PlayerID, Playername); - } - - menuPlayer.ExitButton = true; - menuPlayer.Display(iClient, MENU_TIME_FOREVER); - - } - else - CPrintToChat(iClient,"%t", "NoFound"); - } - else - CPrintToChat(iClient,"%t", "Spectator"); - } - else - CPrintToChat(iClient,"%t", "WaitAnwser"); - } - else - CPrintToChat(iClient,"%t", "InDuel"); - return ; -} - -public int DuelPanel1(Menu menu, MenuAction action, int iClient, int args) -{ - if (action == MenuAction_End) - delete menu; - else if (action == MenuAction_Select) - { - char str_PlayerID[8]; - GetMenuItem(menu, args, str_PlayerID, sizeof(str_PlayerID)); - - CreateDuel(iClient, StringToInt(str_PlayerID)); - } -} - -void CreateDuel(int Player1, int Player2) -{ - if(isGoodSituation(Player1, Player2)) - { - g_Duel[Player1][Challenger] = Player2; - - GetSafeClientData(Player1); - GetSafeClientData(Player2); - - if(StrEqual(ClientSteamID[Player1], "INVALID")) - { - CPrintToChat(Player1, "Your SteamID isn't valid!"); - ResetPlayer(Player1); - ResetPlayer(Player2); - } - else if(StrEqual(ClientSteamID[Player2], "INVALID")) - { - CPrintToChat(Player1, "%N's SteamID isn't valid!", Player2); - ResetPlayer(Player1); - ResetPlayer(Player2); - } - else - { - g_Duel[Player1][Type] = 1; - g_Duel[Player1][TimeLeft] = 1; - g_Duel[Player1][Score] = 1; - g_Duel[Player1][HealingAllowed] = true; - - DuelOption(Player1); - } - } -} - -public void DuelOption(int Player1) -{ - char MenuItem[100]; - Panel menu = new Panel(); - - menu.SetTitle("Duel Options:"); - Format(MenuItem, sizeof(MenuItem), "Duel [%s]", DuelNames[g_Duel[Player1][Type]]); - menu.DrawItem(MenuItem); - - if(g_Duel[Player1][Type] == 2) - { - Format(MenuItem, sizeof(MenuItem), "Time [%i %s]", g_Duel[Player1][TimeLeft], g_Duel[Player1][TimeLeft] >1 ? "mins":"min"); - menu.DrawItem(MenuItem); - } - else if(g_Duel[Player1][Type] == 3) - { - Format(MenuItem, sizeof(MenuItem), "Amount [%i %s]", g_Duel[Player1][Score], g_Duel[Player1][Score] >1 ? "kills":"kill"); - menu.DrawItem(MenuItem); - } - else - menu.DrawText(" "); - - Format(MenuItem, sizeof(MenuItem), "Class restriction [%s]", ClassNames[g_Duel[Player1][ClassRestrict]]); - menu.DrawItem(MenuItem); - Format(MenuItem, sizeof(MenuItem), "Challenger protection [%s]", g_Duel[Player1][GodMod] ? "ON":"OFF"); - menu.DrawItem(MenuItem); - Format(MenuItem, sizeof(MenuItem), "Head shot only [%s]", g_Duel[Player1][HeadShot] ? "ON":"OFF"); - menu.DrawItem(MenuItem); - Format(MenuItem, sizeof(MenuItem), "Healing allowed [%s]", g_Duel[Player1][HealingAllowed] ? "ON":"OFF"); - menu.DrawItem(MenuItem); - menu.DrawText(" "); - menu.DrawItem("Rules"); - menu.DrawItem("Send duel"); - menu.DrawItem("Exit"); - - - menu.Send(Player1, DuelOptionAnswer, MENU_TIME_FOREVER); -} - -public int DuelOptionAnswer(Menu menu, MenuAction action, int Player1, int args) -{ - if (action == MenuAction_Cancel) - { - ResetPlayer(g_Duel[Player1][Challenger]); - ResetPlayer(Player1); - } - else if (action == MenuAction_End) - delete menu; - else if (action == MenuAction_Select) - { - bool AvailableClass[10] = {true,...}; - - // IF Class restriction Enable - if(c_ClassRestriction.IntValue > 0) - { - int PlayerPerClass[2][10]; - char CVARClassRed[35]; - char CVARClassBlue[35]; - - // Get Plugin restriction limit - if(c_ClassRestriction.IntValue == 2) //MaxClass Plugin - { - if(!StartReadingFromTable()) //error while reding file - { - c_ClassRestriction.IntValue = 0; - LogMessage("[Duel] Error while reading MaxClass config file. Now duel_classrestrict = 0 "); - } - } - else - { - for(int i=1;i<=9;i++) - { - if(c_ClassRestriction.IntValue == 1) //Class Restrict Plugin - { - Format(CVARClassRed, sizeof(CVARClassRed), "sm_classrestrict_red_%s", ClassRestricNames[i]); - Format(CVARClassBlue, sizeof(CVARClassBlue), "sm_classrestrict_blu_%s", ClassRestricNames[i]); - LimitPerClass[2][i] = FindConVar(CVARClassRed).IntValue; - LimitPerClass[3][i] = FindConVar(CVARClassBlue).IntValue; - } - else //Error in Cvar - { - LimitPerClass[2][i] = -1; - LimitPerClass[3][i] = -1; - } - } - } - - // Get current players class - for(int i=1;i<=9;i++) - { - PlayerPerClass[0][i] = 0; - PlayerPerClass[1][i] = 0; - } - for(int i = 1; i <= MaxClients; i++) - if(IsClientInGame(i)) - PlayerPerClass[GetClientTeam(i)%2][TF2_GetPlayerClass(i)] ++; - - if(IsClientInGame(Player1)) - PlayerPerClass[GetClientTeam(Player1)%2][TF2_GetPlayerClass(Player1)] --; - if(IsClientInGame(g_Duel[Player1][Challenger])) - PlayerPerClass[GetClientTeam(g_Duel[Player1][Challenger])%2][TF2_GetPlayerClass(g_Duel[Player1][Challenger])] --; - - // Check Class full and available - for( int i=1;i<=9;i++) - { - if( (LimitPerClass[2][i] < 0 && LimitPerClass[3][i] < 0) || (LimitPerClass[2][i] > PlayerPerClass[0][i] && LimitPerClass[3][i] > PlayerPerClass[1][i]) ) - AvailableClass[i] = true; - else - AvailableClass[i] = false; - } - } - - - // Process the information - - char FlagNeeded1[2]; - char FlagNeeded2[2]; - c_GodModFlag.GetString(FlagNeeded1, sizeof(FlagNeeded1)); - c_HeadShotFlag.GetString(FlagNeeded2, sizeof(FlagNeeded2)); - - - - if(args == 1) // Duel type - { - g_Duel[Player1][Type]++; - - if(g_Duel[Player1][Type] > 3) - g_Duel[Player1][Type] = 1; - } - else if(args == 2 && g_Duel[Player1][Type] == 2) // Time - { - int i; - while(TimeLeftOptions[i] != g_Duel[Player1][TimeLeft] && i < 10) i++; - - if(i == 9) i = 0; - else i++; - - g_Duel[Player1][TimeLeft] = TimeLeftOptions[i]; - } - else if(args == 2 && g_Duel[Player1][Type] == 3) // Amount - { - int i; - while(AmountOfKillOptions[i] != g_Duel[Player1][Score] && i < 12) i++; - - if(i == 11) i = 0; - else i++; - - g_Duel[Player1][Score] = AmountOfKillOptions[i]; - } - else if(args >= 2 && args < 9) - { - if(g_Duel[Player1][Type] == 1) - args++; - - if(args == 3) // Class Restriction - { - if(c_EnableClass.BoolValue) - { - do - { - if(g_Duel[Player1][ClassRestrict] == 2) // Only for sniper - g_Duel[Player1][HeadShot] = false; - - g_Duel[Player1][ClassRestrict] ++; - - if(g_Duel[Player1][ClassRestrict] >= 10) // Modulo 10 classes - g_Duel[Player1][ClassRestrict] = 0; - - } - while(!AvailableClass[g_Duel[Player1][ClassRestrict]]); - } - else - g_Duel[Player1][ClassRestrict] = 0; - } - else if(args == 4) // Challenger protection - { - if(c_EnableGodMod.BoolValue && isAdmin(Player1, FlagNeeded1)) - { - g_Duel[Player1][GodMod] = g_Duel[Player1][GodMod] ? 0 : 1; - g_Duel[Player1][HealingAllowed] = false; - } - else - { - g_Duel[Player1][GodMod] = 0; - } - } - else if(args == 5) // Head shot only - { - if(c_EnableHeadShot.BoolValue && g_Duel[Player1][ClassRestrict] == 2 && isAdmin(Player1, FlagNeeded2)) - g_Duel[Player1][HeadShot] = g_Duel[Player1][HeadShot] ? false : true; - else - g_Duel[Player1][HeadShot] = false; - } - else if(args == 6) // Disallow healing - { - g_Duel[Player1][HealingAllowed] = !g_Duel[Player1][HealingAllowed]; - } - else if(args == 7) // Click on rules - { - ShowMOTDPanel(Player1, "Free-Duels rules", WEBSITE, MOTDPANEL_TYPE_URL ); - } - else if(args == 8) // Click on send duel - { - if(!isGoodSituation(Player1, g_Duel[Player1][Challenger])) - return; - - if(IsClientInGame(g_Duel[Player1][Challenger])) - { - g_Duel[g_Duel[Player1][Challenger]][Challenger] = Player1; - g_Duel[g_Duel[Player1][Challenger]][Type] = g_Duel[Player1][Type]; - g_Duel[g_Duel[Player1][Challenger]][Score] = g_Duel[Player1][Score] = g_Duel[Player1][Type] < 3 ? 0:g_Duel[Player1][Score]; - g_Duel[g_Duel[Player1][Challenger]][ClassRestrict] = g_Duel[Player1][ClassRestrict]; - g_Duel[g_Duel[Player1][Challenger]][HealingAllowed] = g_Duel[Player1][HealingAllowed]; - g_Duel[g_Duel[Player1][Challenger]][GodMod] = g_Duel[Player1][GodMod]; - g_Duel[g_Duel[Player1][Challenger]][HeadShot] = g_Duel[Player1][HeadShot]; - g_Duel[g_Duel[Player1][Challenger]][TimeLeft] = g_Duel[Player1][TimeLeft] *= 60; - - - if(IsFakeClient(g_Duel[Player1][Challenger])) // Against BOT - LoadDuel(g_Duel[Player1][Challenger]); - else - ChallengerMenu(Player1, g_Duel[Player1][Challenger]); // Against Player - } - else - { - ResetPlayer(g_Duel[Player1][Challenger]); - ResetPlayer(Player1); - CPrintToChat(Player1, "%t", "NotInGame"); - } - return; - } - else if(args == 9) // Click on exit - { - ResetPlayer(g_Duel[Player1][Challenger]); - ResetPlayer(Player1); - return; - } - } - - if(IsValidClient(Player1)) - DuelOption(Player1); - } -} - -bool StartReadingFromTable() -{ - char file[PLATFORM_MAX_PATH]; - char config[PLATFORM_MAX_PATH]; - char mapname[32]; - int MaxClass[MAXPLAYERS][TFTeam + view_as(1)][TFClassType + view_as(1)]; - - FindConVar("sm_maxclass_config").GetString(config, sizeof(config)); - BuildPath(Path_SM, file, sizeof(file),"configs/%s", config); - - if (!FileExists(file)) - BuildPath(Path_SM, file, sizeof(file),"configs/%s", "MaxClass.txt"); - - if (!FileExists(file)) - return false; - - KeyValues kv = new KeyValues("MaxClassPlayers"); - kv.ImportFromFile(file); - - //Get in the first sub-key, first look for the map, then look for default - GetCurrentMap(mapname, sizeof(mapname)); - if (!kv.JumpToKey(mapname)) - { - // Check for map type! - SplitString(mapname, "_", mapname, sizeof(mapname)); - - if (!kv.JumpToKey(mapname)) - { - if (!kv.JumpToKey("default")) - { - delete kv; - return false; - } - } - } - - int MaxPlayers[TFClassType + view_as(1)], breakpoint, iStart, iEnd, i; - TFTeam a; - char buffer[64], start[32], end[32]; - int redblue[TFTeam]; - - //Reset all numbers to -1 - for (i=0; i<10; i++) - MaxPlayers[i] = -1; - - for (i=0; i<= MaxClients; i++) - for (a=TFTeam_Unassigned; a <= TFTeam_Blue; a++) - MaxClass[i][a] = MaxPlayers; - - if (!kv.GotoFirstSubKey()) - { - delete kv; - return false; - } - - do - { - kv.GetSectionName(buffer, sizeof(buffer)); - - //Collect all data - MaxPlayers[TFClass_Scout] = kv.GetNum(TF_ClassNames[TFClass_Scout], -1); - MaxPlayers[TFClass_Sniper] = kv.GetNum(TF_ClassNames[TFClass_Sniper], -1); - MaxPlayers[TFClass_Soldier] = kv.GetNum(TF_ClassNames[TFClass_Soldier], -1); - MaxPlayers[TFClass_DemoMan] = kv.GetNum(TF_ClassNames[TFClass_DemoMan], -1); - MaxPlayers[TFClass_Medic] = kv.GetNum(TF_ClassNames[TFClass_Medic], -1); - MaxPlayers[TFClass_Heavy] = kv.GetNum(TF_ClassNames[TFClass_Heavy], -1); - MaxPlayers[TFClass_Pyro] = kv.GetNum(TF_ClassNames[TFClass_Pyro], -1); - MaxPlayers[TFClass_Spy] = kv.GetNum(TF_ClassNames[TFClass_Spy], -1); - MaxPlayers[TFClass_Engineer] = kv.GetNum(TF_ClassNames[TFClass_Engineer], -1); - - if (MaxPlayers[TFClass_Engineer] == -1) - MaxPlayers[TFClass_Engineer] = kv.GetNum("engenner", -1); - - redblue[TFTeam_Red] = kv.GetNum("team2", 1); - redblue[TFTeam_Blue] = kv.GetNum("team3", 1); - - if (redblue[TFTeam_Red] == 1) - redblue[TFTeam_Red] = kv.GetNum("red", 1); - - if (redblue[TFTeam_Blue] == 1) - redblue[TFTeam_Blue] = kv.GetNum("blue", 1); - - if ((redblue[TFTeam_Red] + redblue[TFTeam_Blue]) == 0) - continue; - - //Just 1 number - if (StrContains(buffer,"-") == -1) - { - iStart = CheckBoundries(StringToInt(buffer)); - - for (a=TFTeam_Unassigned; a<= TFTeam_Blue; a++) - { - if (redblue[a] == 1) - MaxClass[iStart][a] = MaxPlayers; - } - //A range, like 1-5 - } - else - { - //Break the "1-5" into "1" and "5" - breakpoint = SplitString(buffer,"-",start,sizeof(buffer)); - strcopy(end,sizeof(end),buffer[breakpoint]); - TrimString(start); - TrimString(end); - - //make "1" and "5" into integers - //Check boundries, see if does not go out of the array limits - iStart = CheckBoundries(StringToInt(start)); - iEnd = CheckBoundries(StringToInt(end)); - - //Copy data to the global array for each one in the range - for (i= iStart; i<= iEnd;i++) - { - for (a=TFTeam_Unassigned; a<= TFTeam_Blue; a++) - { - if (redblue[a] == 1) - MaxClass[i][a] = MaxPlayers; - } - } - } - for(i = 1; i<10; i++) - { - LimitPerClass[2][i] = MaxClass[GetClientCount(true)][2][i]; - LimitPerClass[3][i] = MaxClass[GetClientCount(true)][1][i]; - } - } while (kv.GotoNextKey()); - - - delete kv; - return true; -} - -int CheckBoundries(int i) -{ - if (i < 0) - return 0; - else if (i > MAXPLAYERS) - return MAXPLAYERS; - else - return i; -} - - -//------------------------------------------------------------------------------------------------------------------------ -// Challenger Menu Answer -//------------------------------------------------------------------------------------------------------------------------ - - -public void ChallengerMenu(int Player1, int Player2) -{ - if(g_Duel[Player1][Type] == 1) - { - ClientCommand(Player1, "playgamesound ui/duel_challenge.wav"); - ClientCommand(g_Duel[Player1][Challenger], "playgamesound ui/duel_challenge.wav"); - - } - else if(g_Duel[Player1][Type] == 2 || g_Duel[Player1][Type] == 3) - { - ClientCommand(Player1, "playgamesound ui/duel_challenge_with_restriction.wav"); - ClientCommand(g_Duel[Player1][Challenger], "playgamesound ui/duel_challenge_with_restriction.wav"); - } - else - { - ResetPlayer(Player1); - ResetPlayer(Player2); - return; - } - - for(int i = 1; i<= MaxClients; i++) - if(IsValidClient(i) && i != g_Duel[Player1][Challenger]) - CPrintToChat(i, "%t", "Challenged", Player1, g_Duel[Player1][Challenger]); - - CPrintToChat(Player2, "%t", "You!", Player1, g_Duel[Player1][Type]); - - - char MenuItem[100]; - char MenuTitle[100]; - Panel menu = new Panel(); - - Format(MenuTitle, sizeof(MenuTitle), "%N challenged you!", Player1); - menu.SetTitle(MenuTitle); - if(g_Duel[Player1][Type] == 1) - Format(MenuItem, sizeof(MenuItem), "Type: Normal"); - else if(g_Duel[Player1][Type] == 2) - Format(MenuItem, sizeof(MenuItem), "Type: Time left [%i %s]", g_Duel[Player1][TimeLeft], g_Duel[Player1][TimeLeft] >1 ? "mins":"min"); - else if(g_Duel[Player1][Type] == 3) - Format(MenuItem, sizeof(MenuItem), "Type: Amount of kills [%i %s]", g_Duel[Player1][Score], g_Duel[Player1][Score] >1 ? "kills":"kill"); - menu.DrawText(MenuItem); - menu.DrawText(" "); - Format(MenuItem, sizeof(MenuItem), "Class restriction [%s]", ClassNames[g_Duel[Player1][ClassRestrict]]); - menu.DrawText(MenuItem); - Format(MenuItem, sizeof(MenuItem), "Challenger protection [%s]", g_Duel[Player1][GodMod] ? "ON":"OFF"); - menu.DrawText(MenuItem); - Format(MenuItem, sizeof(MenuItem), "Head shot only [%s]", g_Duel[Player1][HeadShot] ? "ON":"OFF"); - menu.DrawText(MenuItem); - Format(MenuItem, sizeof(MenuItem), "Healing allowed [%s]", g_Duel[Player1][HealingAllowed] ? "ON":"OFF"); - menu.DrawText(MenuItem); - Format(MenuItem, sizeof(MenuItem), " "); - menu.DrawText(MenuItem); - - menu.DrawItem("Yes, I challenge"); - menu.DrawItem("No, I refuse"); - - - menu.Send(Player2, ChallengerMenuAnswer, 20); -} - -public int ChallengerMenuAnswer(Menu menu, MenuAction action, int Player2, int args) -{ - if (action == MenuAction_Cancel) - { - CPrintToChatAll("%t", "TooAfraid", Player2, g_Duel[Player2][Challenger]); - ResetPlayer(g_Duel[Player2][Challenger]); - ResetPlayer(Player2); - } - else if (action == MenuAction_End) - { - delete menu; - } - else if (action == MenuAction_Select) - { - if(args == 1) // ACCEPT THE DUEL - { - if(!isGoodSituation(Player2, g_Duel[Player2][Challenger])) - return; - - LoadDuel(Player2); // Load Duel - - } - else if(args == 2) // REFUSE THE DUEL - { - int Player1 = g_Duel[Player2][Challenger]; - int D_Type = g_Duel[Player2][Type]; - - ResetPlayer(Player1); - ResetPlayer(Player2); - - CPrintToChatAll("%t", "Refused", Player2, Player1); - - if(D_Type == 1) - { - ClientCommand(Player2, "playgamesound ui/duel_challenge_rejected.wav"); - ClientCommand(Player1, "playgamesound ui/duel_challenge_rejected.wav"); - } - else if(D_Type == 2 || D_Type == 3) - { - ClientCommand(Player2, "playgamesound ui/duel_challenge_rejected_with_restriction.wav"); - ClientCommand(Player1, "playgamesound ui/duel_challenge_rejected_with_restriction.wav"); - } - } - } -} - - -void LoadDuel(int Player2) -{ - if(!isGoodSituation(g_Duel[Player2][Challenger], Player2)) return; - - g_Duel[Player2][Enabled] = true; - g_Duel[g_Duel[Player2][Challenger]][Enabled] = true; - - if(g_Duel[Player2][ClassRestrict] != 0) // Load Classrestriction - { - if(view_as(g_Duel[Player2][ClassRestrict]) != view_as(TF2_GetPlayerClass(Player2))) // Player2 - { - TF2_SetPlayerClass(Player2, view_as(g_Duel[Player2][ClassRestrict]), false); - TF2_RespawnPlayer(Player2); - } - - if(view_as(g_Duel[Player2][ClassRestrict]) != view_as(TF2_GetPlayerClass(g_Duel[Player2][Challenger]))) // Player1 - { - TF2_SetPlayerClass(g_Duel[Player2][Challenger], view_as(g_Duel[Player2][ClassRestrict]), false); - TF2_RespawnPlayer(g_Duel[Player2][Challenger]); - } - } - - if (!g_Duel[Player2][HealingAllowed]) - { - TF2Attrib_SetByName(Player2, "health from healers reduced", 0.0); - } - - if(g_Duel[Player2][GodMod]) // Load Godmode - { - if(TF2_GetPlayerClass(Player2) == TFClass_Engineer) - RemovePlayerBuilding(Player2); - if(TF2_GetPlayerClass(g_Duel[Player2][Challenger]) == TFClass_Engineer) - RemovePlayerBuilding(g_Duel[Player2][Challenger]); - - SetGodModColor(Player2); - SetGodModColor(g_Duel[Player2][Challenger]); - TF2_RespawnPlayer(Player2); - TF2_RespawnPlayer(g_Duel[Player2][Challenger]); - } - - CreateChallengerParticle(Player2); - CreateChallengerParticle(g_Duel[Player2][Challenger]); - - if(g_Duel[Player2][Type] == 1) // Play Sound - { - ClientCommand(Player2, "playgamesound ui/duel_challenge_accepted.wav"); - ClientCommand(g_Duel[Player2][Challenger], "playgamesound ui/duel_challenge_accepted.wav"); - } - else if(g_Duel[Player2][Type] == 2 || g_Duel[Player2][Type] == 3) - { - ClientCommand(Player2, "playgamesound ui/duel_challenge_accepted_with_restriction.wav"); - ClientCommand(g_Duel[Player2][Challenger], "playgamesound ui/duel_challenge_accepted_with_restriction.wav"); - } - - CPrintToChatAll("%t", "Accepts", Player2, g_Duel[Player2][Challenger]); - CPrintToChat(Player2,"%t", "Abort"); - CPrintToChat(g_Duel[Player2][Challenger],"%t", "Abort"); -} - - -//------------------------------------------------------------------------------------------------------------------------ -// Option Functions -//------------------------------------------------------------------------------------------------------------------------ - - -void SetGodModColor(int client) -{ - int userid = GetClientUserId(client); - if (CommandExists("sm_colorize")) - { - ServerCommand("sm_colorize #%d normal", userid); - } - else SetEntityRenderColor(client, 255, 255, 255, 255); - - CreateTimer(0.4, OnSetGodModeColor, userid); -} - -public Action OnSetGodModeColor(Handle timer, any userid) -{ - int client = GetClientOfUserId(userid); - if (!IsValidClient(client) || !IsPlayerAlive(client) || !g_Duel[client][Enabled]) return Plugin_Stop; - if (TF2_GetClientTeam(client) == TFTeam_Red) - SetEntityRenderColor(client, 200, 0, 0, 255); - else - SetEntityRenderColor(client, 0, 0, 200, 255); - return Plugin_Continue; -} - - -void CreateChallengerParticle(int iClient) -{ - float vOrigin[3]; - GetClientAbsOrigin(iClient, vOrigin); - vOrigin[2] += 25; - - int parent = CreateEntityByName("prop_dynamic"); - char strParent[64]; - Format(strParent, sizeof(strParent), "prop%i", parent); - DispatchKeyValue(parent, "targetname", strParent); - DispatchKeyValue(parent, "renderfx","0"); - DispatchKeyValue(parent, "damagetoenablemotion","0"); - DispatchKeyValue(parent, "forcetoenablemotion","0"); - DispatchKeyValue(parent, "Damagetype","0"); - DispatchKeyValue(parent, "disablereceiveshadows","1"); - DispatchKeyValue(parent, "massScale","0"); - DispatchKeyValue(parent, "nodamageforces","0"); - DispatchKeyValue(parent, "shadowcastdist","0"); - DispatchKeyValue(parent, "disableshadows","1"); - DispatchKeyValue(parent, "spawnflags","1670"); - DispatchKeyValue(parent, "model","models/player/medic_animations.mdl"); - DispatchKeyValue(parent, "PerformanceMode","1"); - DispatchKeyValue(parent, "rendermode","10"); - DispatchKeyValue(parent, "physdamagescale","0"); - DispatchKeyValue(parent, "physicsmode","2"); - - DispatchSpawn(parent); - TeleportEntity(parent, vOrigin, NULL_VECTOR, NULL_VECTOR); - - int ent = CreateEntityByName("env_sprite"); - if(ent) - { - char StrEntityName[64]; - Format(StrEntityName, sizeof(StrEntityName), "ent_sprite_oriented_%i", ent); - - if(GetClientTeam(iClient) == 2) - DispatchKeyValue(ent, "model", "free_duel/RED_Target.vmt"); - else - DispatchKeyValue(ent, "model", "free_duel/BLU_Target.vmt"); - DispatchKeyValue(ent, "classname", "env_sprite"); - DispatchKeyValue(ent, "spawnflags", "1"); - DispatchKeyValue(ent, "scale", "0.1"); - DispatchKeyValue(ent, "rendermode", "1"); - DispatchKeyValue(ent, "rendercolor", "255 255 255"); - //DispatchKeyValue(ent, "targetname", StrEntityName); - DispatchKeyValue(ent, "parentname", strParent); - - DispatchSpawn(ent); - TeleportEntity(ent, vOrigin, NULL_VECTOR, NULL_VECTOR); - - SetVariantString(strParent); - AcceptEntityInput(ent, "SetParent"); - - g_Duel[iClient][CSprite] = EntIndexToEntRef(ent); - g_Duel[iClient][SpriteParent] = EntIndexToEntRef(parent); - SDKHook(ent, SDKHook_SetTransmit, Hook_SetTransmit); - } -} - -public Action Hook_SetTransmit(int entity, int iClient) -{ - if(EntRefToEntIndex(g_Duel[iClient][CSprite]) == entity && !g_Duel[iClient][HideSprite]) // Can see - return Plugin_Continue; - - if(EntRefToEntIndex(g_Duel[g_Duel[iClient][Challenger]][CSprite]) == entity && !g_Duel[g_Duel[iClient][Challenger]][HideSprite]) // Can see - return Plugin_Continue; - - return Plugin_Handled; -} - -public Action Timer(Handle timer) -{ - char FlagNeeded[2]; - c_Immunity.GetString(FlagNeeded, sizeof(FlagNeeded)); - Countdown--; - for(int t=1; t <= MaxClients; t++) - { - if(IsValidClient(t) && g_Duel[t][Enabled]) - { - HudMessageTime(t); - - g_Duel[t][PlayedTime] += 1; - - if(g_Duel[t][Type] == 2) - { - g_Duel[t][TimeLeft] -= 1; - if(g_Duel[t][TimeLeft] <= 0) - { - g_Duel[g_Duel[t][Challenger]][Enabled] = false; - EndDuel(t, g_Duel[t][Type]); - } - } - - if(Countdown <= 0 && isAdmin(t, FlagNeeded)) - CPrintToChat(t, "%t","!myduels"); - else if(Countdown == 450 && isAdmin(t, FlagNeeded)) - CPrintToChat(t, "%t","!topduel"); - } - } - if(Countdown <= 0) - Countdown = 900; -} - -void HudMessageTime(int iClient) -{ - SetHudTextParams(0.85, 0.0, 1.0, 39, 148, 0, 255, 1, 0.0, 0.0, 0.0); - - if(g_Duel[iClient][Type] == 1 || g_Duel[iClient][Type] == 3) ShowHudText(iClient, -1, "You : %i - Him: %i", g_Duel[iClient][Score], g_Duel[g_Duel[iClient][Challenger]][Score]); - else if(g_Duel[iClient][Type] == 2) ShowHudText(iClient, -1, "Time left : %i | You : %i - Him: %i", g_Duel[iClient][TimeLeft], g_Duel[iClient][Score], g_Duel[g_Duel[iClient][Challenger]][Score]); -} - -public void OnClientDisconnect(int iClient) -{ - if(!IsValidClient(iClient)) return; - - if(g_Duel[iClient][Enabled]) - { - CPrintToChatAll("%t","Victory", g_Duel[iClient][Challenger], iClient, "(Player disconnected)"); - - if(IsValidClient(g_Duel[iClient][Challenger])) - ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); - - Winner[g_Duel[iClient][Challenger]] = true; - Winner[iClient] = false; - Abandon[iClient] = true; - Abandon[g_Duel[iClient][Challenger]] = false; - - InitializeClientonDB(g_Duel[iClient][Challenger]); - InitializeClientonDB(iClient); - } -} - -public Action AbortDuel(int iClient, int Args) -{ - if(!IsValidClient(iClient)) return; - - if(g_Duel[iClient][Enabled]) - { - char reason[64]; - Format(reason, sizeof(reason), "(%N aborted)", iClient); - CPrintToChatAll("%t","Victory", g_Duel[iClient][Challenger], iClient, reason); - - Winner[g_Duel[iClient][Challenger]] = true; - Winner[iClient] = false; - Abandon[iClient] = true; - Abandon[g_Duel[iClient][Challenger]] = false; - - InitializeClientonDB(g_Duel[iClient][Challenger]); - InitializeClientonDB(iClient); - - if(g_Duel[iClient][Challenger] != 0) - { - ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); - TF2_RespawnPlayer(g_Duel[iClient][Challenger]); - } - if(iClient != 0) - { - ClientCommand(iClient, "playgamesound ui/duel_event.wav"); - TF2_RespawnPlayer(iClient); - } - } - else - CPrintToChat(iClient,"%t", "NotInDuel"); -} - - -//------------------------------------------------------------------------------------------------------------------------ -// Security functions -//------------------------------------------------------------------------------------------------------------------------ - -public bool isGoodSituation(int iClient, int Player2) -{ - if(!IsValidClient(iClient) || !IsValidClient(Player2)) - { - ResetPlayer(Player2); - ResetPlayer(iClient); - return false; - } - - if(g_Duel[Player2][Enabled]) // too late ! iClient Player2 already in duel ... - { - CPrintToChat(iClient,"%t", "IsInDuel", Player2); - ResetPlayer(iClient); - return false; - } - else if(g_Duel[iClient][Enabled]) // you are already in duel ... - { - CPrintToChat(iClient,"%t", "InDuel"); - ResetPlayer(iClient); - return false; - } - else if(GetClientTeam(iClient) != 2 && GetClientTeam(iClient) != 3) - { - CPrintToChat(iClient,"%t", "TeamError"); - ResetPlayer(iClient); - return false; - } - else if(GetClientTeam(Player2) != 2 && GetClientTeam(Player2) != 3) - { - CPrintToChat(iClient,"%t", "TeamError"); - ResetPlayer(Player2); - return false; - } - else if(GetClientTeam(iClient) == GetClientTeam(Player2)) - { - CPrintToChat(iClient,"%t", "TeamError"); - ResetPlayer(iClient); - ResetPlayer(Player2); - return false; - } - else - return true; -} - -void GetSafeClientData(int iClient) -{ - char PlayerInfo[MAX_LINE_WIDTH]; - - //Client Name - GetClientName(iClient, PlayerInfo, sizeof(PlayerInfo)); - - ReplaceString(PlayerInfo, sizeof(PlayerInfo), "", ""); - ReplaceString(PlayerInfo, sizeof(PlayerInfo), "<", "["); - ReplaceString(PlayerInfo, sizeof(PlayerInfo), ">", "]"); - ReplaceString(PlayerInfo, sizeof(PlayerInfo), ",", "."); - - db.Escape(PlayerInfo, ClientName[iClient], MAX_LINE_WIDTH); - - //Client SteamID - if(IsFakeClient(iClient)) - strcopy(PlayerInfo, MAX_LINE_WIDTH, "BOT"); - else - { - if (!GetClientAuthId(iClient, AuthId_Steam3, PlayerInfo, sizeof(PlayerInfo))) - { - strcopy(PlayerInfo, MAX_LINE_WIDTH, "INVALID"); - } - } - strcopy(ClientSteamID[iClient], 24, PlayerInfo); -} - - -//------------------------------------------------------------------------------------------------------------------------ -// Duel Stats -//------------------------------------------------------------------------------------------------------------------------ - - -public Action MyDuelStats(int iClient, int Args) -{ - if (!IsValidClient(iClient)) - { - return Plugin_Handled; - } - - char buffer[255]; - - Format(buffer, sizeof(buffer), "SELECT COUNT(*) FROM `Duels_Stats`"); - db.Query(T_Rank1, buffer, GetClientUserId(iClient)); - return Plugin_Handled; -} - -public void T_Rank1(Database dummy, DBResultSet hndl, const char[] error, any userid) -{ - if (hndl == null) - LogError("Query failed! %s", error); - else - { - int iClient = GetClientOfUserId(userid); - if(!IsValidClient(iClient)) return; - char buffer[255]; - - while (hndl.FetchRow()) - { - RankTotal = hndl.FetchInt(0); - Format(buffer, sizeof(buffer), "SELECT `Points`, `Victories`, `Duels`, `Kills`, `Deads` FROM `Duels_Stats` WHERE SteamID = '%s'", ClientSteamID[iClient]); - db.Query(T_Rank2, buffer, userid); - } - } -} - -public void T_Rank2(Database dummy, DBResultSet hndl, const char[] error, any userid) -{ - if (hndl == null) - LogError("Query failed! %s", error); - else - { - int iClient = GetClientOfUserId(userid); - if (!IsValidClient(iClient)) return; - char buffer[255]; - while (hndl.FetchRow()) - { - points[iClient] = hndl.FetchFloat(0); - victories[iClient] = hndl.FetchInt(1); - dueltotal[iClient] = hndl.FetchInt(2); - killsNbr[iClient] = hndl.FetchInt(3); - death[iClient] = hndl.FetchInt(4); - - Format(buffer, sizeof(buffer), "SELECT COUNT(*) FROM `Duels_Stats` WHERE `Points` > %i", victories); - db.Query(T_Rank3, buffer, userid); - } - } -} - -public void T_Rank3(Database dummy, DBResultSet hndl, const char[] error, any userid) -{ - if (hndl == null) - LogError("Query failed! %s", error); - else - { - int iClient = GetClientOfUserId(userid); - if (!IsValidClient(iClient)) return; - while (hndl.FetchRow()) - RankPanel(iClient, hndl.FetchInt(0)); - } -} - -void RankPanel(int iClient, int Rank) -{ - char value[MAX_LINE_WIDTH]; - char ClientID[MAX_LINE_WIDTH]; - Panel rnkpanel = new Panel(); - - GetClientName(iClient, ClientID, sizeof(ClientID) ); - rnkpanel.SetTitle("Your duels' stats:"); - Format(value, sizeof(value), "Name: %s", ClientID); - rnkpanel.DrawText(value); - Format(value, sizeof(value), "Rank: %i out of %i", Rank , RankTotal); - rnkpanel.DrawText(value); - Format(value, sizeof(value), "Points: %f" , points[iClient]); - rnkpanel.DrawText(value); - Format(value, sizeof(value), "Victories: %i" , victories[iClient]); - rnkpanel.DrawText(value); - Format(value, sizeof(value), "Duels total: %i" , dueltotal[iClient]); - rnkpanel.DrawText(value); - Format(value, sizeof(value), "Kills: %i" , killsNbr[iClient]); - rnkpanel.DrawText(value); - Format(value, sizeof(value), "Deaths: %i" , death[iClient]); - rnkpanel.DrawText(value); - rnkpanel.DrawItem("Close"); - rnkpanel.Send(iClient, RankPanelHandler, 15); -} - -public int RankPanelHandler(Menu menu, MenuAction action, int param1, int param2) -{ -} - -public Action TopDuel(int iClient, int Args) -{ - char buffer[255]; - Format(buffer, sizeof(buffer), "SELECT `Players`, `Points` FROM `Duels_Stats` ORDER BY `Points` DESC LIMIT 0,100"); - db.Query(T_ShowTopDuel, buffer, GetClientUserId(iClient)); - return Plugin_Handled; -} - -public void T_ShowTopDuel(Database dummy, DBResultSet hndl, const char[] error, any userid) -{ - if (hndl == null) - LogError("Query failed! %s", error); - else - { - int iClient = GetClientOfUserId(userid); - if (!IsValidClient(iClient)) return; - - Menu menu = new Menu(TopDuelPanel); - menu.SetTitle("Top Duel Menu:"); - - int i = 1; - while (hndl.FetchRow()) - { - char PlayerName[MAX_LINE_WIDTH]; - char line[MAX_LINE_WIDTH]; - hndl.FetchString(0, PlayerName , MAX_LINE_WIDTH); - - Format(line, sizeof(line), "%i : %s %f points", i, PlayerName, SQL_FetchFloat(hndl,1)); - menu.AddItem("i" , line); - i++; - } - menu.ExitButton = true; - menu.Display(iClient, MENU_TIME_FOREVER); - } - return; -} - -public int TopDuelPanel(Menu menu, MenuAction action, int param1, int param2) -{ - if (action == MenuAction_End) - delete menu; -} - - -//------------------------------------------------------------------------------------------------------------------------ -// When duel end -//------------------------------------------------------------------------------------------------------------------------ - - -bool EndDuel(int iClient, int DuelType) -{ - if(DuelType != 0) - { - if(DuelType == 1 || DuelType == 2) - { - if(g_Duel[iClient][Score] > g_Duel[g_Duel[iClient][Challenger]][Score]) - { - CPrintToChatAll("%t", "Victory", iClient, g_Duel[iClient][Challenger],""); - Winner[iClient] = true; - Winner[g_Duel[iClient][Challenger]] = false; - } - else if (g_Duel[iClient][Score] < g_Duel[g_Duel[iClient][Challenger]][Score]) - { - CPrintToChatAll("%t", "Victory", g_Duel[iClient][Challenger], iClient,""); - Winner[iClient] = false; - Winner[g_Duel[iClient][Challenger]] = true; - } - else - { - CPrintToChatAll("%t", "Equality", g_Duel[iClient][Challenger], iClient); - Equality[iClient] = true; - Winner[iClient] = true; - Equality[g_Duel[iClient][Challenger]] = true; - Winner[g_Duel[iClient][Challenger]] = true; - } - } - else if(DuelType == 3) - { - if(g_Duel[iClient][Score] > g_Duel[g_Duel[iClient][Challenger]][Score]) - { - CPrintToChatAll("%t", "Victory", g_Duel[iClient][Challenger], iClient,""); - Winner[iClient] = false; - Winner[g_Duel[iClient][Challenger]] = true; - } - else if (g_Duel[iClient][Score] < g_Duel[g_Duel[iClient][Challenger]][Score]) - { - CPrintToChatAll("%t", "Victory", iClient, g_Duel[iClient][Challenger],""); - Winner[iClient] = true; - Winner[g_Duel[iClient][Challenger]] = false; - } - else - { - CPrintToChatAll("%t", "Equality", g_Duel[iClient][Challenger], iClient); - Equality[iClient] = true; - Winner[iClient] = true; - Equality[g_Duel[iClient][Challenger]] = true; - Winner[g_Duel[iClient][Challenger]] = true; - } - } - - if(IsValidClient(g_Duel[iClient][Challenger])) - ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); - - if(IsValidClient(iClient)) - ClientCommand(iClient, "playgamesound ui/duel_event.wav"); - - InitializeClientonDB(g_Duel[iClient][Challenger]); - InitializeClientonDB(iClient); - - return true; - } - return false; -} - - -public void InitializeClientonDB(int iClient) -{ - if(iClient == 0) - { - ResetPlayer(iClient); - return; - } - char buffer[255]; - - Format(buffer, sizeof(buffer), "SELECT `Victories`,`Duels` FROM Duels_Stats WHERE STEAMID = '%s'", ClientSteamID[iClient]); - db.Query(T_UpdateClient, buffer, iClient); -} - -public void T_UpdateClient(Database dummy, DBResultSet hndl, const char[] error, any iClient) -{ - char etat[512]; - int CltPoint; - int Victory; - int Equal; - int Kill = g_Duel[iClient][kills]; - int Dead = g_Duel[iClient][Deads]; - int Abort = Abandon[iClient]; - int Tmer = g_Duel[iClient][PlayedTime]; - int Dueller = g_Duel[iClient][Challenger]; - - if(Equality[iClient]) - { - Format(etat, sizeof(etat), "Equality"); - CltPoint = 1; - Victory = 1; - Equal = 1; - } - else if(Winner[iClient]) - { - Format(etat, sizeof(etat), "Winner"); - CltPoint = 2; - Victory = 1; - Equal = 0; - } - else - { - Format(etat, sizeof(etat), "Loser"); - CltPoint = 0; - Victory = 0; - Equal = 0; - } - - - ResetPlayer(iClient); - - if (!hndl.RowCount) - { - char buffer[1500]; - if(!SQLite) - { - Format(buffer, sizeof(buffer), "INSERT INTO Duels_Stats (`Players`,`SteamID`,`Points`,`Victories`,`Duels`,`Kills`,`Deads`,`PlayTime`,`Abandoned`,`Equalities`,`Last_dueler`,`Last_dueler_SteamID`,`Etat`) VALUES ('%s','%s','%i','%i','1','%i','%i','%i','%i','%i','%s','%s','%s')", ClientName[iClient], ClientSteamID[iClient], CltPoint, Victory, Kill, Dead, Tmer, Abort, Equal, ClientName[Dueller], ClientSteamID[Dueller], etat); - db.Query(SQLErrorCheckCallback, buffer); - LogMessage("MySQL => %s First victory, and add on database.", ClientName[iClient]); - } - else - { - Format(buffer, sizeof(buffer), "INSERT INTO Duels_Stats VALUES('%s','%s','%i','%i','1','%i','%i','%i','%i','%i','%s','%s','%s');", ClientName[iClient], ClientSteamID[iClient], CltPoint, Victory, Kill, Dead, Tmer, Abort, Equal, ClientName[Dueller], ClientSteamID[Dueller], etat ); - db.Query(SQLErrorCheckCallback, buffer); - LogMessage("SQLite => %s First victory, and add on database.", ClientName[iClient]); - } - CPrintToChatAll("%t", Victory >1 ? "Victories" : "VictoryNbr", ClientName[iClient], Victory); - } - else - { - char buffer[1500]; - - while (hndl.FetchRow()) - { - int clientvictories = hndl.FetchInt(0); - int clientduels = hndl.FetchInt(1); - if(Victory == 1) - clientvictories += 1; - float clientpoints = ((clientvictories*1.0)/(clientduels+1)) + clientvictories; - - Format(buffer, sizeof(buffer), "UPDATE Duels_Stats SET Players = '%s', Points = %f, Victories = Victories +%i, Duels = Duels +1, Kills = Kills +%i, Deads = Deads +%i, PlayTime = PlayTime +%i, Abandoned = Abandoned +%i, Equalities = Equalities +%i, Last_dueler = '%s', Last_dueler_SteamID = '%s', Etat = '%s' WHERE SteamID = '%s'",ClientName[iClient], clientpoints, Victory, Kill, Dead, Tmer, Abort, Equal, ClientName[Dueller], ClientSteamID[Dueller], etat, ClientSteamID[iClient]); - db.Query(SQLErrorCheckCallback, buffer); - - CPrintToChatAll("%t", clientvictories >1 ? "Victories" : "VictoryNbr", ClientName[iClient], clientvictories); - LogMessage("MySQL => %s %d victories, and updated on database.", ClientName[iClient], clientvictories); - } - } -} - -void ResetPlayer(int iClient) -{ - if(IsValidClient(iClient)) - { - if (g_Duel[iClient][GodMod]) - { - if(CommandExists("sm_colorize")) - { - ServerCommand("sm_colorize #%d normal", GetClientUserId(iClient)); - } - else - { - SetEntityRenderColor(iClient, 255, 255, 255, 255); - } - } - - if (!g_Duel[iClient][HealingAllowed]) - { - TF2Attrib_RemoveByName(iClient, "health from healers reduced"); - } - } - g_Duel[iClient][Enabled] = false; - g_Duel[iClient][HeadShot] = false; - g_Duel[iClient][HealingAllowed] = true; - g_Duel[iClient][ClassRestrict] = 0; - g_Duel[iClient][kills] = 0; - g_Duel[iClient][Deads] = 0; - g_Duel[iClient][TimeLeft] = 0; - g_Duel[iClient][Score] = 0; - g_Duel[iClient][Challenger] = 0; - g_Duel[iClient][PlayedTime] = 0; - g_Duel[iClient][GodMod] = 0; - g_Duel[iClient][Type] = 0; - - Winner[iClient] = false; - Abandon[iClient] = false; - Equality[iClient] = false; - - if(IsValidEdict(EntRefToEntIndex(g_Duel[iClient][SpriteParent]))) - { - RemoveEdict(EntRefToEntIndex(g_Duel[iClient][SpriteParent])); - g_Duel[iClient][SpriteParent] = INVALID_ENT_REFERENCE; - } - - if(IsValidEdict(EntRefToEntIndex(g_Duel[iClient][CSprite]))) - { - RemoveEdict(EntRefToEntIndex(g_Duel[iClient][CSprite])); - g_Duel[iClient][CSprite] = INVALID_ENT_REFERENCE; - } -} - - -//------------------------------------------------------------------------------------------------------------------------ -// Native Functions -//------------------------------------------------------------------------------------------------------------------------ - - -public int Native_IsPlayerInDuel(Handle plugin, int numParams) -{ - int iClient = GetNativeCell(1); - - if(!IsValidClient(iClient)) return false; - - if(g_Duel[iClient][Enabled]) - return true; - else - return false; -} - -public int Native_IsDuelRestrictionClass(Handle plugin, int numParams) -{ - int iClient = GetNativeCell(1); - - if(!IsValidClient(iClient)) return false; - - if(g_Duel[iClient][ClassRestrict] != 0) - return true; - else - return false; -} - -public int Native_GetDuelerID(Handle plugin, int numParams) -{ - if(!IsValidClient(GetNativeCell(1))) return -1; - return g_Duel[GetNativeCell(1)][Challenger]; -} +/** +* TheXeon +* ngs_freeduels.sp +* +* Files: +* addons/sourcemod/plugins/ngs_freeduels.smx +* addons/sourcemod/translations/free_duels.phrases.txt +* addons/sourcemod/data/sqlite/duel.sq3 +* cfg/sourcemod/free_duels.cfg +* +* Dependencies: +* sdkhooks.inc, tf2_stocks.inc, tf2attributes.inc, multicolors.inc, +* free_duels.inc, friendly.inc, ngsutils.inc, ngsupdater.inc +*/ +#pragma newdecls required +#pragma semicolon 1 + +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define WEBSITE "https://www.neogenesisnetwork.net" +#define MAX_LINE_WIDTH 60 + +enum DuelData +{ + Challenger, + bool:Enabled, + Type, + Score, + PlayedTime, + kills, + Deads, + ClassRestrict, + GodMod, + bool:HeadShot, + TimeLeft, + CSprite, + SpriteParent, + bool:HideSprite, + bool:HealingAllowed +} + +int g_Duel[MAXPLAYERS+1][DuelData]; + +int victories[MAXPLAYERS+1] = {0, ...}; +int death[MAXPLAYERS+1] = {0, ...}; +int killsNbr[MAXPLAYERS+1] = {0, ...}; +int dueltotal[MAXPLAYERS+1] = {0, ...}; +float points[MAXPLAYERS+1] = {0.0, ...}; + +bool Abandon[MAXPLAYERS+1] = {false, ...}; +bool Equality[MAXPLAYERS+1] = {false, ...}; +bool Winner[MAXPLAYERS+1] = {false, ...}; +bool SQLite = false; +bool disableDuel[MAXPLAYERS + 1] = { false, ... }; + +ConVar c_EnableType[4]; +ConVar cvarEnabled; +ConVar c_Tag; +ConVar c_EnableClass; +ConVar c_EnableGodMod; +ConVar c_EnableHeadShot; +ConVar c_HeadShotFlag; +ConVar c_Immunity; +ConVar c_ClassRestriction; +ConVar c_GodModFlag; + +SmartDB db; + +char ClientSteamID[MAXPLAYERS+1][24]; +char ClientName[MAXPLAYERS+1][MAX_LINE_WIDTH]; + +static char DuelNames[4][16] = {"Disabled", "Normal", "Time left", "Amount of kills"}; +static char ClassNames[TFClassType][] = {"ANY", "Scout", "Sniper", "Soldier", "Demoman", "Medic", "Heavy", "Pyro", "Spy", "Engineer" }; +static char ClassRestricNames[TFClassType][] = {"", "scouts", "snipers", "soldiers", "demomen", "medics", "heavies", "pyros", "spies", "engineers" }; +static char TF_ClassNames[TFClassType][] = {"", "scout", "sniper", "soldier", "demoman", "medic", "heavyweapons", "pyro", "spy", "engineer" }; +static TimeLeftOptions[10] = {1, 2, 5, 10, 15, 20, 30, 45, 60, 120}; +static AmountOfKillOptions[12] = {1, 2, 3, 4, 5, 10, 15, 20, 50, 75, 100, 150}; + +int LimitPerClass[4][10]; +int RankTotal; +int Countdown = 600; + + +public Plugin myinfo = { + name = "[NGS] Free duels", + author = "Erreur 500 / TheXeon", + description = "Challenge other players", + version = "1.2.4", + url = "https://www.neogenesisnetwork.net" +} + +public void OnPluginStart() +{ + cvarEnabled = CreateConVar("duel_enabled", "1", "Enable or disable Free Duels ?", 0, true, 0.0, true, 1.0); + c_Tag = CreateConVar("duel_tag", "1", "Add 'duels' tags", 0, true, 0.0, true, 1.0); + c_Immunity = CreateConVar("duel_immunity", "0", "a or b or o or p or q or r or s or t or z for flag needed, 0 = no flag needed"); + c_ClassRestriction = CreateConVar("duel_classrestrict", "0", "1 = classrestrict by DJ Tsunami, 2 = Max Class (Class Limit) by Nican , 0 = none"); + c_EnableClass = CreateConVar("duel_class", "1", "0 = disable class restriction duel, 1 = enable", 0, true, 0.0, true, 1.0); + c_EnableType[1] = CreateConVar("duel_type1", "1", "0 = disable `normal` duel, 1 = enable", 0, true, 0.0, true, 1.0); + c_EnableType[2] = CreateConVar("duel_type2", "1", "0 = disable `time left` duel, 1 = enable", 0, true, 0.0, true, 1.0); + c_EnableType[3] = CreateConVar("duel_type3", "1", "0 = disable `amount of kills` duel, 1 = enable", 0, true, 0.0, true, 1.0); + c_EnableGodMod = CreateConVar("duel_godmod", "1", "0 = disable challenger godmod, 1 = enable", 0, true, 0.0, true, 1.0); + c_GodModFlag = CreateConVar("duel_godmod_flag", "0", "Flag needed to create godmod duel : a or b or o or p or q or r or s or t or z, 0 = no flag"); + c_EnableHeadShot = CreateConVar("duel_headshot", "1", "0 = disable head shot only (sniper), 1 = enable", 0, true, 0.0, true, 1.0); + c_HeadShotFlag = CreateConVar("duel_headshot_flag", "a", "Flag needed to create head shot duel : a or b or o or p or q or r or s or t or z, 0 = no flag"); + + if(cvarEnabled.BoolValue) + { + LogMessage("[0/5] Loading : Enabled"); + RegConsoleCmd("sm_duel", loadDuel, "Challenge player"); + RegConsoleCmd("sm_abort", AbortDuel, "Stop duel"); + RegConsoleCmd("sm_myduels", MyDuelStats, "Show your duels stats"); + RegConsoleCmd("sm_topduel", TopDuel, "Show top dueler"); + RegConsoleCmd("sm_noduelme", NoDuelMe, "Disables duel requests."); + RegConsoleCmd("sm_dontduelme", NoDuelMe, "Disables duel requests."); + + LogMessage("[1/5] Loading : Initialisation"); + Initialisation(); + AutoExecConfig(true, "free_duels"); + Connect(); + TranslationFileExists("free_duels.phrases", true, true); + LoadTranslations("common.phrases"); + + HookEvent("player_spawn", EventPlayerSpawn, EventHookMode_Pre); + HookEvent("player_death", EventPlayerDeath); + HookEvent("player_team", EventPlayerTeam, EventHookMode_Pre); + HookEvent("player_changeclass", EventPlayerchangeclass, EventHookMode_Pre); + HookEvent("player_builtobject", EventBuiltObject); + HookEvent("teamplay_round_win", EventRoundEnd, EventHookMode_PostNoCopy); + HookEvent("teamplay_flag_event", EventFlag); + HookEvent("controlpoint_starttouch", EventCPStartTouch); + HookEvent("controlpoint_endtouch", EventCPEndTouch); + HookEvent("player_sapped_object", EventSapped); + HookEvent("post_inventory_application", EventPostInventoryApplication); +// HookEvent("player_upgradedobject", EventUpgradedObject, EventHookMode_Pre); +// HookEvent("object_deflected", EventAirblast); + + for (int iClient = 1; iClient <= MaxClients; iClient++) + if (IsValidClient(iClient)) OnClientPutInServer(iClient); + + CreateTimer(1.0, Timer, INVALID_HANDLE, TIMER_REPEAT); + } + else + LogMessage("Loading : Free Duels disabled by CVar"); +} + +public void OnPluginEnd() +{ + for(int i = 1; i <= MaxClients ; i++) + { + if(g_Duel[i][Enabled]) + { + EndDuel(i, g_Duel[i][Type]); + g_Duel[i][Enabled] = false; + g_Duel[g_Duel[i][Challenger]][Enabled] = false; + } + } +} + +public void OnClientPutInServer(int client) +{ + SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + CreateNative("IsPlayerInDuel", Native_IsPlayerInDuel); + CreateNative("IsDuelRestrictionClass", Native_IsDuelRestrictionClass); + CreateNative("GetDuelerID", Native_GetDuelerID); + + return APLRes_Success; +} + +void Initialisation() +{ + for (int i = 0; i < MAXPLAYERS + 1; i++) + { + g_Duel[i][Enabled] = false; + g_Duel[i][SpriteParent] = INVALID_ENT_REFERENCE; + g_Duel[i][CSprite] = INVALID_ENT_REFERENCE; + } +} + +public void OnClientConnected(int client) +{ + disableDuel[client] = false; +} + +public void OnConfigsExecuted() +{ + LogMessage("[4/5] Loading : Configs Executed"); + if(c_Tag.IntValue) + TagsCheck("Duels"); + + LogMessage("[5/5] Loading : Finished"); +} + +void TagsCheck(const char[] tag) +{ + ConVar hTags = FindConVar("sv_tags"); + char tags[255]; + hTags.GetString(tags, sizeof(tags)); + + if (!(StrContains(tags, tag, false) > -1)) + { + char newTags[255]; + Format(newTags, sizeof(newTags), "%s,%s", tags, tag); + hTags.SetString(newTags); + hTags.GetString(tags, sizeof(tags)); + } + delete hTags; +} + +public void OnMapStart() +{ + AddFileToDownloadsTable("materials/free_duel/RED_Target.vmt"); + AddFileToDownloadsTable("materials/free_duel/RED_Target.vtf"); + AddFileToDownloadsTable("materials/free_duel/BLU_Target.vmt"); + AddFileToDownloadsTable("materials/free_duel/BLU_Target.vtf"); + + PrecacheModel("models/player/medic_animations.mdl"); + PrecacheDecal("materials/free_duel/RED_Target.vmt", true); + PrecacheDecal("materials/free_duel/BLU_Target.vmt", true); +} + +void Connect() +{ + if (SQL_CheckConfig("duel")) + { + Database.Connect(Connected, "duel"); + } + else if (SQL_CheckConfig("default")) + { + Database.Connect(Connected); + } + else + { + ConnectToSQLite(); + } +} + +public void ConnectToSQLite() +{ + char error[255]; + SQLite = true; + + KeyValues kv = new KeyValues(""); + kv.SetString("driver", "sqlite"); + kv.SetString("database", "duel"); + db = view_as(SQL_ConnectCustom(kv, error, sizeof(error), false)); + delete kv; + + if (db == null) + LogMessage("Loading : Failed to connect: %s", error); + else + { + LogMessage("[2/5] Loading : Connected to SQLite Database"); + CreateDbSQLite(); + } +} + +public void Connected(Database hndl, const char[] error, any data) +{ + if (hndl == null) + { + LogError("Failed to connect! Error: %s", error); + LogMessage("Loading : Failed to connect! Falling back to SQLite!"); + ConnectToSQLite(); + return; + } + + LogMessage("Loading : Connected to MySQL Database[2/5]"); + hndl.Query(SQLErrorCheckCallback, "SET NAMES 'utf8'"); + db = view_as(hndl); + SQL_CreateTables(); +} + +void SQL_CreateTables() +{ + int len = 0; + char query[1000]; + len += Format(query[len], sizeof(query)-len, "CREATE TABLE IF NOT EXISTS `Duels_Stats` ("); + len += Format(query[len], sizeof(query)-len, "`Players` VARCHAR(30) NOT NULL,"); + len += Format(query[len], sizeof(query)-len, "`SteamID` VARCHAR(25) NOT NULL,"); + len += Format(query[len], sizeof(query)-len, "`Points` float(16,9) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`Victories` int(25) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`Duels` int(25) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`Kills` int(25) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`Deads` int(25) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`PlayTime` int(25) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`Abandoned` int(25) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`Equalities` int(25) NOT NULL default '0',"); + len += Format(query[len], sizeof(query)-len, "`Last_dueler` VARCHAR(30) NOT NULL,"); + len += Format(query[len], sizeof(query)-len, "`Last_dueler_SteamID` VARCHAR(25) NOT NULL,"); + len += Format(query[len], sizeof(query)-len, "`Etat` VARCHAR(25) NOT NULL,"); + len += Format(query[len], sizeof(query)-len, "PRIMARY KEY (`SteamID`)"); + len += Format(query[len], sizeof(query)-len, ") ENGINE=MyISAM DEFAULT CHARSET=utf8;"); + db.VoidQuery(query); + LogMessage("[?/5] Loading : Tables Created"); +} + +void CreateDbSQLite() +{ + int len = 0; + char query[10000]; + len += Format(query[len], sizeof(query)-len, "CREATE TABLE IF NOT EXISTS `Duels_Stats`"); + len += Format(query[len], sizeof(query)-len, " (`Players` TEXT, `SteamID` TEXT,"); + len += Format(query[len], sizeof(query)-len, " `Points` REAL DEFAULT 0,`Victories` INTEGER DEFAULT 0, `Duels` INTEGER DEFAULT 0,"); + len += Format(query[len], sizeof(query)-len, " `Kills` INTEGER DEFAULT 0, `Deads` INTEGER DEFAULT 0, `PlayTime` INTEGER DEFAULT 0,"); + len += Format(query[len], sizeof(query)-len, " `Abandoned` INTEGER DEFAULT 0, `Equalities` INTEGER DEFAULT 0,"); + len += Format(query[len], sizeof(query)-len, " `Last_dueler` TEXT, `Last_dueler_SteamID` TEXT, `Etat` TEXT"); + + len += Format(query[len], sizeof(query)-len, ");"); + db.VoidQuery(query); + LogMessage("[?/5] Loading : Tables Created"); +} + +public void SQLErrorCheckCallback(Database owner, DBResultSet hndl, const char[] error, any data) +{ + if (!StrEqual(error, "")) + { + LogError("Loading : SQL Error: %s", error); + LogMessage("Loading : SQL Error: %s", error); + } + delete hndl; +} + +public Action NoDuelMe(int client, int args) +{ + if (!IsValidClient(client)) return Plugin_Handled; + disableDuel[client] = !disableDuel[client]; + CReplyToCommand(client, "{CYAN}[Duel]{DEFAULT} You have %s duel requests.", (disableDuel[client]) ? "disabled" : "enabled"); + return Plugin_Handled; +} + +public Action loadDuel(int iClient, int Args) +{ + if (!IsValidClient(iClient)) + { + return Plugin_Handled; + } + + if (disableDuel[iClient]) + { + CReplyToCommand(iClient, "{CYAN}[Duel]{DEFAULT} You cannot send duel requests if you have disabled duel requests."); + return Plugin_Handled; + } + char FlagNeeded[2]; + c_Immunity.GetString(FlagNeeded, sizeof(FlagNeeded)); + + if(!isAdmin(iClient, FlagNeeded)) + return Plugin_Handled; + + char Argument1[256]; + GetCmdArgString(Argument1, sizeof(Argument1)); + + if(StrEqual ("",Argument1)) // No Args + CallPanel(iClient); + else + { + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if((target_count = ProcessTargetString( + Argument1, + iClient, + target_list, + MAXPLAYERS, + COMMAND_FILTER_ALIVE, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0) + { + ReplyToTargetError(iClient, target_count); + CallPanel(iClient); + return Plugin_Handled; + } + + for (int i = 0; i < target_count; i++) + { + if(isGoodSituation(iClient, target_list[i])) + { + if (disableDuel[target_list[i]]) + { + CReplyToCommand(iClient, "{CYAN}[Duel]{DEFAULT} That person has disabled duel requests!"); + continue; + } + if(!g_Duel[iClient][Type]) + { + LogAction(iClient, target_list[i], "%L challenged %L", iClient, target_list[i]); + CreateDuel(iClient, target_list[i]); + } + else + CPrintToChat(iClient,"%t", "WaitAnwser"); + } + } + } + return Plugin_Handled; +} + +public bool isAdmin(int iClient, char FlagNeeded[2]) +{ + if(StrEqual(FlagNeeded, "0")) + return true; + else + { + int flags = GetUserFlagBits(iClient); + if(flags == 0) + { + //PrintToChatAll("Flag : %s + %s", FlagNeeded[0], FlagNeeded[1]); + CPrintToChat(iClient,"%t", "NoFlag"); + return false; + } + else if((flags & ADMFLAG_ROOT) && StrEqual(FlagNeeded, "z")) + return true; + else if((flags & ADMFLAG_RESERVATION) && StrEqual(FlagNeeded, "a")) + return true; + else if((flags & ADMFLAG_GENERIC) && StrEqual(FlagNeeded, "b")) + return true; + else if((flags & ADMFLAG_CUSTOM1) && StrEqual(FlagNeeded, "o")) + return true; + else if((flags & ADMFLAG_CUSTOM2) && StrEqual(FlagNeeded, "p")) + return true; + else if((flags & ADMFLAG_CUSTOM3) && StrEqual(FlagNeeded, "q")) + return true; + else if((flags & ADMFLAG_CUSTOM4) && StrEqual(FlagNeeded, "r")) + return true; + else if((flags & ADMFLAG_CUSTOM5) && StrEqual(FlagNeeded, "s")) + return true; + else if((flags & ADMFLAG_CUSTOM6) && StrEqual(FlagNeeded, "t")) + return true; + else + { + //PrintToChatAll("FlagNO : %s + %s", FlagNeeded[0], FlagNeeded[1]); + CPrintToChat(iClient,"%t", "NoFlag"); + return false; + } + } +} + +void RemovePlayerBuilding(int iClient) +{ + int ObjEnt; + + while((ObjEnt = FindEntityByClassname(ObjEnt, "obj_sentrygun")) != -1) + { + if(GetEntPropEnt(ObjEnt, Prop_Send, "m_hBuilder") == iClient) + { + SetVariantInt(1000); + AcceptEntityInput(ObjEnt, "RemoveHealth"); + } + } + + while((ObjEnt = FindEntityByClassname(ObjEnt, "obj_dispenser")) != -1) + { + if(GetEntPropEnt(ObjEnt, Prop_Send, "m_hBuilder") == iClient) + { + SetVariantInt(1000); + AcceptEntityInput(ObjEnt, "RemoveHealth"); + } + } + + while((ObjEnt = FindEntityByClassname(ObjEnt, "obj_teleporter")) != -1) + { + if(GetEntPropEnt(ObjEnt, Prop_Send, "m_hBuilder") == iClient) + { + SetVariantInt(1000); + AcceptEntityInput(ObjEnt, "RemoveHealth"); + } + } +} + + +//------------------------------------------------------------------------------------------------------------------------ +// Event Zone +//------------------------------------------------------------------------------------------------------------------------ + + +public Action EventPlayerSpawn(Event hEvent, const char[] strName, bool bHidden) +{ + int iClient = GetClientOfUserId(hEvent.GetInt("userid")); + if(g_Duel[iClient][Enabled] && g_Duel[iClient][ClassRestrict] != 0 && TF2_GetPlayerClass(iClient) != view_as(g_Duel[iClient][ClassRestrict])) + { + TF2_SetPlayerClass(iClient, view_as(g_Duel[iClient][ClassRestrict]), false); + TF2_RespawnPlayer(iClient); + CPrintToChat(iClient, "%t", "ChangeClass"); + CPrintToChat(iClient, "%t", "Abort"); + } + + if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 1) + { + SetGodModColor(iClient); + SetEntProp(iClient, Prop_Send, "m_CollisionGroup", FindConVar("sm_friendly_noblock").IntValue); + } + else if (!g_Duel[iClient][GodMod] && !TF2Friendly_IsFriendly(iClient)) + SetEntProp(iClient, Prop_Send, "m_CollisionGroup", 5); +} + +public void EventPlayerDeath(Event hEvent, const char[] strName, bool bHidden) +{ + + int iClient = GetClientOfUserId(hEvent.GetInt("userid")); + int iKiller = GetClientOfUserId(hEvent.GetInt("attacker")); + int iAssister = GetClientOfUserId(hEvent.GetInt("assister")); + + if(hEvent.GetInt("death_flags") & TF_DEATHFLAG_DEADRINGER) + return; + + if(c_EnableHeadShot.BoolValue && g_Duel[iClient][HeadShot]) + { + if(hEvent.GetInt("customkill") != 1) + { + return; + } + } + + if (g_Duel[iKiller][Challenger] == iClient && g_Duel[iKiller][Enabled]) + { + g_Duel[iKiller][kills] += 1; + g_Duel[iClient][Deads] += 1; + + if(g_Duel[iKiller][Enabled] && g_Duel[iKiller][Type] != 3 ) + { + g_Duel[iKiller][Score] += 1; + CPrintToChat(iKiller, "%t", "Score", iKiller, g_Duel[iKiller][Score], iClient, g_Duel[iClient][Score]); + CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient], iKiller, g_Duel[iKiller][Score]); + } + else if(g_Duel[iKiller][Enabled] && g_Duel[iKiller][Type] == 3) + { + g_Duel[iKiller][Score] -= 1; + CPrintToChat(iKiller, "%t", "Score", iKiller, g_Duel[iKiller][Score], iClient, g_Duel[iClient][Score]); + CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient][Score], iKiller, g_Duel[iKiller][Score]); + + if(g_Duel[iKiller][Score] == 0) EndDuel(iKiller, g_Duel[iKiller][Type]); + } + } + else if(g_Duel[iAssister][Challenger] == iClient && g_Duel[iAssister][Enabled]) + { + g_Duel[iAssister][kills] += 1; + g_Duel[iClient][Deads] += 1; + if(g_Duel[iAssister][Enabled] && g_Duel[iAssister][Type] != 3 ) + { + g_Duel[iAssister][Score] += 1; + CPrintToChat(iAssister, "%t", "Score", iAssister, g_Duel[iAssister][Score], iClient, g_Duel[iClient][Score]); + CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient][Score], iAssister, g_Duel[iAssister][Score]); + } + else if(g_Duel[iAssister][Enabled] && g_Duel[iAssister][Type] == 3) + { + g_Duel[iAssister][Score] -= 1; + CPrintToChat(iAssister, "%t", "Score", iAssister, g_Duel[iAssister][Score], iClient, g_Duel[iClient][Score]); + CPrintToChat(iClient, "%t", "Score", iClient, g_Duel[iClient][Score], iAssister, g_Duel[iAssister][Score]); + + if(g_Duel[iAssister][Score] == 0) EndDuel(iAssister, g_Duel[iAssister][Type]); + } + } +} + +public Action EventPlayerTeam(Event hEvent, const char[] strName, bool bHidden) +{ + int iClient = GetClientOfUserId(hEvent.GetInt("userid")); + + if(g_Duel[iClient][Enabled]) + { + CPrintToChatAll("%t", "Victory", g_Duel[iClient][Challenger], iClient, "(Player changed team)"); + + Abandon[g_Duel[iClient][Challenger]] = false; + Abandon[iClient] = true; + Winner[g_Duel[iClient][Challenger]] = true; + Winner[iClient] = false; + + if(g_Duel[iClient][Challenger] !=0) + ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); + + if(iClient != 0) + ClientCommand(iClient, "playgamesound ui/duel_event.wav"); + + InitializeClientonDB(g_Duel[iClient][Challenger]); + InitializeClientonDB(iClient); + } +} + +public void EventPlayerchangeclass(Event event, const char[] name, bool bHidden) +{ + int iClient = GetClientOfUserId(event.GetInt("userid")); + if(g_Duel[iClient][Enabled] && g_Duel[iClient][ClassRestrict] != 0 && TF2_GetPlayerClass(iClient) != view_as(g_Duel[iClient][ClassRestrict])) + { + TF2_SetPlayerClass(iClient, view_as(g_Duel[iClient][ClassRestrict]), false); + TF2_RespawnPlayer(iClient); + CPrintToChat(iClient, "%t", "ChangeClass"); + CPrintToChat(iClient, "%t", "Abort"); + } +} + +public void EventRoundEnd(Event event, const char[] name, bool bHidden) +{ + for (int i = 1; i <= MaxClients ; i++) + { + if(g_Duel[i][Enabled]) + { + EndDuel(i, g_Duel[i][Type]); + g_Duel[i][Enabled] = false; + g_Duel[g_Duel[i][Challenger]][Enabled] = false; + } + } +} + +public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype) +{ + if (!IsValidClient(victim) || !IsValidClient(attacker)) return Plugin_Continue; + if(c_EnableGodMod.BoolValue) + { + // int damageAmount = event.GetInt("damageamount"); + + if(((g_Duel[victim][Challenger] != attacker) || (g_Duel[attacker][Challenger] != victim)) && + (victim != attacker) && ((g_Duel[victim][Enabled] && g_Duel[victim][GodMod] == 1 ) || + (g_Duel[attacker][Enabled] && g_Duel[attacker][GodMod] == 1))) + { + damage = 0.0; + return Plugin_Changed; + // SetEntityHealth(client, GetClientHealth(client) + damageAmount); + } + } + return Plugin_Continue; +} + +public void EventCPStartTouch(Event hEvent, const char[] strName, bool bHidden) +{ + int iClient = hEvent.GetInt("player"); + if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 1) + { + g_Duel[iClient][GodMod] = 2; // It's not because you are on GodMod you can take CP! + SetEntityRenderColor(iClient, 255, 255, 255, 255); + } +} + +public void EventCPEndTouch(Event hEvent, const char[] strName, bool bHidden) +{ + int iClient = hEvent.GetInt("player"); + if(!IsValidClient(iClient)) return; + + if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 2) + { + g_Duel[iClient][GodMod] = 1; // You're a good guy! + SetGodModColor(iClient); + } +} + +public void EventPostInventoryApplication(Event event, const char[] name, bool bHidden) +{ + int client = GetClientOfUserId(event.GetInt("userid")); + if (IsValidClient(client)) + { + if (g_Duel[client][Enabled] && !g_Duel[client][HealingAllowed]) + { + TF2Attrib_SetByName(client, "health from healers reduced", 0.0); + } + } +} + +public void EventFlag(Event hEvent, const char[] strName, bool bHidden) +{ + int iClient = hEvent.GetInt("player"); + int EventType = hEvent.GetInt("eventtype"); + + if(!IsValidClient(iClient)) return; + + if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 1 && (EventType == 1 || EventType == 3) ) + { + g_Duel[iClient][GodMod] = 2; // It's not because you are on GodMod you can take Flag! + SetEntityRenderColor(iClient, 255, 255, 255, 255); + } + else if(g_Duel[iClient][Enabled] && g_Duel[iClient][GodMod] == 2 && (EventType == 2 || EventType == 4) ) + { + g_Duel[iClient][GodMod] = 1; // You're a good guy! + SetGodModColor(iClient); + } +} + +public void EventBuiltObject(Event hEvent, const char[] strName, bool bHidden) +{ + int iClient = GetClientOfUserId(hEvent.GetInt("userid")); + int ObjEnt = hEvent.GetInt("index"); + + if(!IsValidClient(iClient)) return; + + SDKHook(ObjEnt, SDKHook_OnTakeDamage, BuildingTakeDamage); + + if(!g_Duel[iClient][Enabled]) return; + if(!g_Duel[iClient][GodMod]) return; + + CPrintToChat(iClient, "%t", "Don'tBuilt"); + SetVariantInt(1000); + AcceptEntityInput(ObjEnt, "RemoveHealth"); +} + +// Next few methods from ddhoward's friendly. He is a god. +public Action BuildingTakeDamage(int building, int &attacker, int &inflictor, float &damage, int &damagetype) +{ + int engie = GetEntPropEnt(building, Prop_Send, "m_hBuilder"); + char classname[64]; + if (!GetEntityClassname(building, classname, sizeof(classname))) + { + return Plugin_Continue; + } + if (!IsValidClient(attacker) || !IsValidClient(engie)) { + return Plugin_Continue; + } + + if (g_Duel[attacker][Enabled] && g_Duel[attacker][GodMod] == 1 && g_Duel[attacker][Challenger] != engie) + { + damage = 0.0; + return Plugin_Changed; + } + return Plugin_Continue; +} + +public void EventSapped(Event event, const char[] name, bool dontBroadcast) +{ + int spy = GetClientOfUserId(event.GetInt("userid")); + int sapper = event.GetInt("sapperid"); + int engie = GetClientOfUserId(event.GetInt("ownerid")); + if (g_Duel[spy][Enabled] && g_Duel[spy][GodMod] == 1) + { + if (g_Duel[spy][Challenger] != engie) + { + AcceptEntityInput(sapper, "Kill"); + } + else + { + SDKHook(sapper, SDKHook_OnTakeDamage, SapperTakeDamage); + } + } +} + +public Action SapperTakeDamage(int sapper, int &attacker, int &inflictor, float &damage, int &damagetype) +{ + int building = GetEntPropEnt(sapper, Prop_Send, "m_hBuiltOnEntity"); + int engie = GetEntPropEnt(building, Prop_Send, "m_hBuilder"); + if (!IsValidClient(attacker)) + { + return Plugin_Continue; + } + + if (g_Duel[engie][Enabled] && g_Duel[engie][GodMod] == 1 && g_Duel[engie][Challenger] != attacker) // I dont know how it could be true + { + damage = 0.0; + return Plugin_Changed; + } + return Plugin_Continue; +} + +public void OnGameFrame() +{ + float vecOrigin[3]; + + for(int iClient = 1; iClient <= MaxClients; iClient++ ) + if(IsValidClient(iClient) && g_Duel[iClient][Enabled]) + { + if(TF2_IsPlayerInCondition(iClient, TFCond_Cloaked)) // prevents showing during spells or plugin stuffs + { + if(!g_Duel[iClient][HideSprite]) + g_Duel[iClient][HideSprite] = true; + } + else + { + if(g_Duel[iClient][HideSprite]) + g_Duel[iClient][HideSprite] = false; + } + + GetClientEyePosition( iClient, vecOrigin ); + vecOrigin[2] += 25.0; + + if(EntRefToEntIndex(g_Duel[iClient][SpriteParent]) != INVALID_ENT_REFERENCE) + TeleportEntity(EntRefToEntIndex(g_Duel[iClient][SpriteParent]), vecOrigin, NULL_VECTOR, NULL_VECTOR); + } +} + + +//------------------------------------------------------------------------------------------------------------------------ +// !DUEL Menu +//------------------------------------------------------------------------------------------------------------------------ + + +public void CallPanel(int iClient) +{ + if(!g_Duel[iClient][Enabled]) + { + if(!g_Duel[iClient][Type]) + { + int iteam; + int Player[40]; + + if(GetClientTeam(iClient) == 2) iteam = 3; + else if(GetClientTeam(iClient) == 3) iteam = 2; + + if(iteam == 2 || iteam == 3) + { + int nbr = 0; + for(int i = 1; i <= MaxClients ; i++) // Create an array if valid players (players + bots) + { + Player[i-1] = 0; + if(IsValidClient(i) && GetClientTeam(i) == iteam && !g_Duel[i][Enabled] && g_Duel[i][Challenger] == 0) + { + Player[nbr] = i; + nbr++; + } + } + + if(nbr >= 1) // Player found, open menu + { + char Playername[MAX_LINE_WIDTH]; + char str_PlayerID[8]; + Menu menuPlayer = new Menu(DuelPanel1); + menuPlayer.SetTitle("Who should be challenged?"); + + for(int i = 0; i < nbr; i++) + { + GetClientName(Player[i], Playername, sizeof(Playername)); + IntToString(Player[i], str_PlayerID, sizeof(str_PlayerID)); + menuPlayer.AddItem(str_PlayerID, Playername); + } + + menuPlayer.ExitButton = true; + menuPlayer.Display(iClient, MENU_TIME_FOREVER); + + } + else + CPrintToChat(iClient,"%t", "NoFound"); + } + else + CPrintToChat(iClient,"%t", "Spectator"); + } + else + CPrintToChat(iClient,"%t", "WaitAnwser"); + } + else + CPrintToChat(iClient,"%t", "InDuel"); + return ; +} + +public int DuelPanel1(Menu menu, MenuAction action, int iClient, int args) +{ + if (action == MenuAction_End) + delete menu; + else if (action == MenuAction_Select) + { + char str_PlayerID[8]; + GetMenuItem(menu, args, str_PlayerID, sizeof(str_PlayerID)); + + CreateDuel(iClient, StringToInt(str_PlayerID)); + } +} + +void CreateDuel(int Player1, int Player2) +{ + if(isGoodSituation(Player1, Player2)) + { + g_Duel[Player1][Challenger] = Player2; + + GetSafeClientData(Player1); + GetSafeClientData(Player2); + + if(StrEqual(ClientSteamID[Player1], "INVALID")) + { + CPrintToChat(Player1, "Your SteamID isn't valid!"); + ResetPlayer(Player1); + ResetPlayer(Player2); + } + else if(StrEqual(ClientSteamID[Player2], "INVALID")) + { + CPrintToChat(Player1, "%N's SteamID isn't valid!", Player2); + ResetPlayer(Player1); + ResetPlayer(Player2); + } + else + { + g_Duel[Player1][Type] = 1; + g_Duel[Player1][TimeLeft] = 1; + g_Duel[Player1][Score] = 1; + g_Duel[Player1][HealingAllowed] = true; + + DuelOption(Player1); + } + } +} + +public void DuelOption(int Player1) +{ + char MenuItem[100]; + Panel menu = new Panel(); + + menu.SetTitle("Duel Options:"); + Format(MenuItem, sizeof(MenuItem), "Duel [%s]", DuelNames[g_Duel[Player1][Type]]); + menu.DrawItem(MenuItem); + + if(g_Duel[Player1][Type] == 2) + { + Format(MenuItem, sizeof(MenuItem), "Time [%i %s]", g_Duel[Player1][TimeLeft], g_Duel[Player1][TimeLeft] >1 ? "mins":"min"); + menu.DrawItem(MenuItem); + } + else if(g_Duel[Player1][Type] == 3) + { + Format(MenuItem, sizeof(MenuItem), "Amount [%i %s]", g_Duel[Player1][Score], g_Duel[Player1][Score] >1 ? "kills":"kill"); + menu.DrawItem(MenuItem); + } + else + menu.DrawText(" "); + + Format(MenuItem, sizeof(MenuItem), "Class restriction [%s]", ClassNames[g_Duel[Player1][ClassRestrict]]); + menu.DrawItem(MenuItem); + Format(MenuItem, sizeof(MenuItem), "Challenger protection [%s]", g_Duel[Player1][GodMod] ? "ON":"OFF"); + menu.DrawItem(MenuItem); + Format(MenuItem, sizeof(MenuItem), "Head shot only [%s]", g_Duel[Player1][HeadShot] ? "ON":"OFF"); + menu.DrawItem(MenuItem); + Format(MenuItem, sizeof(MenuItem), "Healing allowed [%s]", g_Duel[Player1][HealingAllowed] ? "ON":"OFF"); + menu.DrawItem(MenuItem); + menu.DrawText(" "); + menu.DrawItem("Rules"); + menu.DrawItem("Send duel"); + menu.DrawItem("Exit"); + + + menu.Send(Player1, DuelOptionAnswer, MENU_TIME_FOREVER); +} + +public int DuelOptionAnswer(Menu menu, MenuAction action, int Player1, int args) +{ + if (action == MenuAction_Cancel) + { + ResetPlayer(g_Duel[Player1][Challenger]); + ResetPlayer(Player1); + } + else if (action == MenuAction_End) + delete menu; + else if (action == MenuAction_Select) + { + bool AvailableClass[10] = {true,...}; + + // IF Class restriction Enable + if(c_ClassRestriction.IntValue > 0) + { + int PlayerPerClass[2][10]; + char CVARClassRed[35]; + char CVARClassBlue[35]; + + // Get Plugin restriction limit + if(c_ClassRestriction.IntValue == 2) //MaxClass Plugin + { + if(!StartReadingFromTable()) //error while reding file + { + c_ClassRestriction.IntValue = 0; + LogMessage("[Duel] Error while reading MaxClass config file. Now duel_classrestrict = 0 "); + } + } + else + { + for(int i=1;i<=9;i++) + { + if(c_ClassRestriction.IntValue == 1) //Class Restrict Plugin + { + Format(CVARClassRed, sizeof(CVARClassRed), "sm_classrestrict_red_%s", ClassRestricNames[i]); + Format(CVARClassBlue, sizeof(CVARClassBlue), "sm_classrestrict_blu_%s", ClassRestricNames[i]); + LimitPerClass[2][i] = FindConVar(CVARClassRed).IntValue; + LimitPerClass[3][i] = FindConVar(CVARClassBlue).IntValue; + } + else //Error in Cvar + { + LimitPerClass[2][i] = -1; + LimitPerClass[3][i] = -1; + } + } + } + + // Get current players class + for(int i=1;i<=9;i++) + { + PlayerPerClass[0][i] = 0; + PlayerPerClass[1][i] = 0; + } + for(int i = 1; i <= MaxClients; i++) + if(IsClientInGame(i)) + PlayerPerClass[GetClientTeam(i)%2][TF2_GetPlayerClass(i)] ++; + + if(IsClientInGame(Player1)) + PlayerPerClass[GetClientTeam(Player1)%2][TF2_GetPlayerClass(Player1)] --; + if(IsClientInGame(g_Duel[Player1][Challenger])) + PlayerPerClass[GetClientTeam(g_Duel[Player1][Challenger])%2][TF2_GetPlayerClass(g_Duel[Player1][Challenger])] --; + + // Check Class full and available + for( int i=1;i<=9;i++) + { + if( (LimitPerClass[2][i] < 0 && LimitPerClass[3][i] < 0) || (LimitPerClass[2][i] > PlayerPerClass[0][i] && LimitPerClass[3][i] > PlayerPerClass[1][i]) ) + AvailableClass[i] = true; + else + AvailableClass[i] = false; + } + } + + + // Process the information + + char FlagNeeded1[2]; + char FlagNeeded2[2]; + c_GodModFlag.GetString(FlagNeeded1, sizeof(FlagNeeded1)); + c_HeadShotFlag.GetString(FlagNeeded2, sizeof(FlagNeeded2)); + + + + if(args == 1) // Duel type + { + g_Duel[Player1][Type]++; + + if(g_Duel[Player1][Type] > 3) + g_Duel[Player1][Type] = 1; + } + else if(args == 2 && g_Duel[Player1][Type] == 2) // Time + { + int i; + while(TimeLeftOptions[i] != g_Duel[Player1][TimeLeft] && i < 10) i++; + + if(i == 9) i = 0; + else i++; + + g_Duel[Player1][TimeLeft] = TimeLeftOptions[i]; + } + else if(args == 2 && g_Duel[Player1][Type] == 3) // Amount + { + int i; + while(AmountOfKillOptions[i] != g_Duel[Player1][Score] && i < 12) i++; + + if(i == 11) i = 0; + else i++; + + g_Duel[Player1][Score] = AmountOfKillOptions[i]; + } + else if(args >= 2 && args < 9) + { + if(g_Duel[Player1][Type] == 1) + args++; + + if(args == 3) // Class Restriction + { + if(c_EnableClass.BoolValue) + { + do + { + if(g_Duel[Player1][ClassRestrict] == 2) // Only for sniper + g_Duel[Player1][HeadShot] = false; + + g_Duel[Player1][ClassRestrict] ++; + + if(g_Duel[Player1][ClassRestrict] >= 10) // Modulo 10 classes + g_Duel[Player1][ClassRestrict] = 0; + + } + while(!AvailableClass[g_Duel[Player1][ClassRestrict]]); + } + else + g_Duel[Player1][ClassRestrict] = 0; + } + else if(args == 4) // Challenger protection + { + if(c_EnableGodMod.BoolValue && isAdmin(Player1, FlagNeeded1)) + { + g_Duel[Player1][GodMod] = g_Duel[Player1][GodMod] ? 0 : 1; + g_Duel[Player1][HealingAllowed] = false; + } + else + { + g_Duel[Player1][GodMod] = 0; + } + } + else if(args == 5) // Head shot only + { + if(c_EnableHeadShot.BoolValue && g_Duel[Player1][ClassRestrict] == 2 && isAdmin(Player1, FlagNeeded2)) + g_Duel[Player1][HeadShot] = g_Duel[Player1][HeadShot] ? false : true; + else + g_Duel[Player1][HeadShot] = false; + } + else if(args == 6) // Disallow healing + { + g_Duel[Player1][HealingAllowed] = !g_Duel[Player1][HealingAllowed]; + } + else if(args == 7) // Click on rules + { + ShowMOTDPanel(Player1, "Free-Duels rules", WEBSITE, MOTDPANEL_TYPE_URL ); + } + else if(args == 8) // Click on send duel + { + if(!isGoodSituation(Player1, g_Duel[Player1][Challenger])) + return; + + if(IsClientInGame(g_Duel[Player1][Challenger])) + { + g_Duel[g_Duel[Player1][Challenger]][Challenger] = Player1; + g_Duel[g_Duel[Player1][Challenger]][Type] = g_Duel[Player1][Type]; + g_Duel[g_Duel[Player1][Challenger]][Score] = g_Duel[Player1][Score] = g_Duel[Player1][Type] < 3 ? 0:g_Duel[Player1][Score]; + g_Duel[g_Duel[Player1][Challenger]][ClassRestrict] = g_Duel[Player1][ClassRestrict]; + g_Duel[g_Duel[Player1][Challenger]][HealingAllowed] = g_Duel[Player1][HealingAllowed]; + g_Duel[g_Duel[Player1][Challenger]][GodMod] = g_Duel[Player1][GodMod]; + g_Duel[g_Duel[Player1][Challenger]][HeadShot] = g_Duel[Player1][HeadShot]; + g_Duel[g_Duel[Player1][Challenger]][TimeLeft] = g_Duel[Player1][TimeLeft] *= 60; + + + if(IsFakeClient(g_Duel[Player1][Challenger])) // Against BOT + LoadDuel(g_Duel[Player1][Challenger]); + else + ChallengerMenu(Player1, g_Duel[Player1][Challenger]); // Against Player + } + else + { + ResetPlayer(g_Duel[Player1][Challenger]); + ResetPlayer(Player1); + CPrintToChat(Player1, "%t", "NotInGame"); + } + return; + } + else if(args == 9) // Click on exit + { + ResetPlayer(g_Duel[Player1][Challenger]); + ResetPlayer(Player1); + return; + } + } + + if(IsValidClient(Player1)) + DuelOption(Player1); + } +} + +bool StartReadingFromTable() +{ + char file[PLATFORM_MAX_PATH]; + char config[PLATFORM_MAX_PATH]; + char mapname[32]; + int MaxClass[MAXPLAYERS][TFTeam + view_as(1)][TFClassType + view_as(1)]; + + FindConVar("sm_maxclass_config").GetString(config, sizeof(config)); + BuildPath(Path_SM, file, sizeof(file),"configs/%s", config); + + if (!FileExists(file)) + BuildPath(Path_SM, file, sizeof(file),"configs/%s", "MaxClass.txt"); + + if (!FileExists(file)) + return false; + + KeyValues kv = new KeyValues("MaxClassPlayers"); + kv.ImportFromFile(file); + + //Get in the first sub-key, first look for the map, then look for default + GetCurrentMap(mapname, sizeof(mapname)); + if (!kv.JumpToKey(mapname)) + { + // Check for map type! + SplitString(mapname, "_", mapname, sizeof(mapname)); + + if (!kv.JumpToKey(mapname)) + { + if (!kv.JumpToKey("default")) + { + delete kv; + return false; + } + } + } + + int MaxPlayers[TFClassType + view_as(1)], breakpoint, iStart, iEnd, i; + TFTeam a; + char buffer[64], start[32], end[32]; + int redblue[TFTeam]; + + //Reset all numbers to -1 + for (i=0; i<10; i++) + MaxPlayers[i] = -1; + + for (i=0; i<= MaxClients; i++) + for (a=TFTeam_Unassigned; a <= TFTeam_Blue; a++) + MaxClass[i][a] = MaxPlayers; + + if (!kv.GotoFirstSubKey()) + { + delete kv; + return false; + } + + do + { + kv.GetSectionName(buffer, sizeof(buffer)); + + //Collect all data + MaxPlayers[TFClass_Scout] = kv.GetNum(TF_ClassNames[TFClass_Scout], -1); + MaxPlayers[TFClass_Sniper] = kv.GetNum(TF_ClassNames[TFClass_Sniper], -1); + MaxPlayers[TFClass_Soldier] = kv.GetNum(TF_ClassNames[TFClass_Soldier], -1); + MaxPlayers[TFClass_DemoMan] = kv.GetNum(TF_ClassNames[TFClass_DemoMan], -1); + MaxPlayers[TFClass_Medic] = kv.GetNum(TF_ClassNames[TFClass_Medic], -1); + MaxPlayers[TFClass_Heavy] = kv.GetNum(TF_ClassNames[TFClass_Heavy], -1); + MaxPlayers[TFClass_Pyro] = kv.GetNum(TF_ClassNames[TFClass_Pyro], -1); + MaxPlayers[TFClass_Spy] = kv.GetNum(TF_ClassNames[TFClass_Spy], -1); + MaxPlayers[TFClass_Engineer] = kv.GetNum(TF_ClassNames[TFClass_Engineer], -1); + + if (MaxPlayers[TFClass_Engineer] == -1) + MaxPlayers[TFClass_Engineer] = kv.GetNum("engenner", -1); + + redblue[TFTeam_Red] = kv.GetNum("team2", 1); + redblue[TFTeam_Blue] = kv.GetNum("team3", 1); + + if (redblue[TFTeam_Red] == 1) + redblue[TFTeam_Red] = kv.GetNum("red", 1); + + if (redblue[TFTeam_Blue] == 1) + redblue[TFTeam_Blue] = kv.GetNum("blue", 1); + + if ((redblue[TFTeam_Red] + redblue[TFTeam_Blue]) == 0) + continue; + + //Just 1 number + if (StrContains(buffer,"-") == -1) + { + iStart = CheckBoundries(StringToInt(buffer)); + + for (a=TFTeam_Unassigned; a<= TFTeam_Blue; a++) + { + if (redblue[a] == 1) + MaxClass[iStart][a] = MaxPlayers; + } + //A range, like 1-5 + } + else + { + //Break the "1-5" into "1" and "5" + breakpoint = SplitString(buffer,"-",start,sizeof(buffer)); + strcopy(end,sizeof(end),buffer[breakpoint]); + TrimString(start); + TrimString(end); + + //make "1" and "5" into integers + //Check boundries, see if does not go out of the array limits + iStart = CheckBoundries(StringToInt(start)); + iEnd = CheckBoundries(StringToInt(end)); + + //Copy data to the global array for each one in the range + for (i= iStart; i<= iEnd;i++) + { + for (a=TFTeam_Unassigned; a<= TFTeam_Blue; a++) + { + if (redblue[a] == 1) + MaxClass[i][a] = MaxPlayers; + } + } + } + for(i = 1; i<10; i++) + { + LimitPerClass[2][i] = MaxClass[GetClientCount(true)][2][i]; + LimitPerClass[3][i] = MaxClass[GetClientCount(true)][1][i]; + } + } while (kv.GotoNextKey()); + + + delete kv; + return true; +} + +int CheckBoundries(int i) +{ + if (i < 0) + return 0; + else if (i > MAXPLAYERS) + return MAXPLAYERS; + else + return i; +} + + +//------------------------------------------------------------------------------------------------------------------------ +// Challenger Menu Answer +//------------------------------------------------------------------------------------------------------------------------ + + +public void ChallengerMenu(int Player1, int Player2) +{ + if(g_Duel[Player1][Type] == 1) + { + ClientCommand(Player1, "playgamesound ui/duel_challenge.wav"); + ClientCommand(g_Duel[Player1][Challenger], "playgamesound ui/duel_challenge.wav"); + + } + else if(g_Duel[Player1][Type] == 2 || g_Duel[Player1][Type] == 3) + { + ClientCommand(Player1, "playgamesound ui/duel_challenge_with_restriction.wav"); + ClientCommand(g_Duel[Player1][Challenger], "playgamesound ui/duel_challenge_with_restriction.wav"); + } + else + { + ResetPlayer(Player1); + ResetPlayer(Player2); + return; + } + + for(int i = 1; i<= MaxClients; i++) + if(IsValidClient(i) && i != g_Duel[Player1][Challenger]) + CPrintToChat(i, "%t", "Challenged", Player1, g_Duel[Player1][Challenger]); + + CPrintToChat(Player2, "%t", "You!", Player1, g_Duel[Player1][Type]); + + + char MenuItem[100]; + char MenuTitle[100]; + Panel menu = new Panel(); + + Format(MenuTitle, sizeof(MenuTitle), "%N challenged you!", Player1); + menu.SetTitle(MenuTitle); + if(g_Duel[Player1][Type] == 1) + Format(MenuItem, sizeof(MenuItem), "Type: Normal"); + else if(g_Duel[Player1][Type] == 2) + Format(MenuItem, sizeof(MenuItem), "Type: Time left [%i %s]", g_Duel[Player1][TimeLeft], g_Duel[Player1][TimeLeft] >1 ? "mins":"min"); + else if(g_Duel[Player1][Type] == 3) + Format(MenuItem, sizeof(MenuItem), "Type: Amount of kills [%i %s]", g_Duel[Player1][Score], g_Duel[Player1][Score] >1 ? "kills":"kill"); + menu.DrawText(MenuItem); + menu.DrawText(" "); + Format(MenuItem, sizeof(MenuItem), "Class restriction [%s]", ClassNames[g_Duel[Player1][ClassRestrict]]); + menu.DrawText(MenuItem); + Format(MenuItem, sizeof(MenuItem), "Challenger protection [%s]", g_Duel[Player1][GodMod] ? "ON":"OFF"); + menu.DrawText(MenuItem); + Format(MenuItem, sizeof(MenuItem), "Head shot only [%s]", g_Duel[Player1][HeadShot] ? "ON":"OFF"); + menu.DrawText(MenuItem); + Format(MenuItem, sizeof(MenuItem), "Healing allowed [%s]", g_Duel[Player1][HealingAllowed] ? "ON":"OFF"); + menu.DrawText(MenuItem); + Format(MenuItem, sizeof(MenuItem), " "); + menu.DrawText(MenuItem); + + menu.DrawItem("Yes, I challenge"); + menu.DrawItem("No, I refuse"); + + + menu.Send(Player2, ChallengerMenuAnswer, 20); +} + +public int ChallengerMenuAnswer(Menu menu, MenuAction action, int Player2, int args) +{ + if (action == MenuAction_Cancel) + { + CPrintToChatAll("%t", "TooAfraid", Player2, g_Duel[Player2][Challenger]); + ResetPlayer(g_Duel[Player2][Challenger]); + ResetPlayer(Player2); + } + else if (action == MenuAction_End) + { + delete menu; + } + else if (action == MenuAction_Select) + { + if(args == 1) // ACCEPT THE DUEL + { + if(!isGoodSituation(Player2, g_Duel[Player2][Challenger])) + return; + + LoadDuel(Player2); // Load Duel + + } + else if(args == 2) // REFUSE THE DUEL + { + int Player1 = g_Duel[Player2][Challenger]; + int D_Type = g_Duel[Player2][Type]; + + ResetPlayer(Player1); + ResetPlayer(Player2); + + CPrintToChatAll("%t", "Refused", Player2, Player1); + + if(D_Type == 1) + { + ClientCommand(Player2, "playgamesound ui/duel_challenge_rejected.wav"); + ClientCommand(Player1, "playgamesound ui/duel_challenge_rejected.wav"); + } + else if(D_Type == 2 || D_Type == 3) + { + ClientCommand(Player2, "playgamesound ui/duel_challenge_rejected_with_restriction.wav"); + ClientCommand(Player1, "playgamesound ui/duel_challenge_rejected_with_restriction.wav"); + } + } + } +} + + +void LoadDuel(int Player2) +{ + if(!isGoodSituation(g_Duel[Player2][Challenger], Player2)) return; + + g_Duel[Player2][Enabled] = true; + g_Duel[g_Duel[Player2][Challenger]][Enabled] = true; + + if(g_Duel[Player2][ClassRestrict] != 0) // Load Classrestriction + { + if(view_as(g_Duel[Player2][ClassRestrict]) != view_as(TF2_GetPlayerClass(Player2))) // Player2 + { + TF2_SetPlayerClass(Player2, view_as(g_Duel[Player2][ClassRestrict]), false); + TF2_RespawnPlayer(Player2); + } + + if(view_as(g_Duel[Player2][ClassRestrict]) != view_as(TF2_GetPlayerClass(g_Duel[Player2][Challenger]))) // Player1 + { + TF2_SetPlayerClass(g_Duel[Player2][Challenger], view_as(g_Duel[Player2][ClassRestrict]), false); + TF2_RespawnPlayer(g_Duel[Player2][Challenger]); + } + } + + if (!g_Duel[Player2][HealingAllowed]) + { + TF2Attrib_SetByName(Player2, "health from healers reduced", 0.0); + } + + if(g_Duel[Player2][GodMod]) // Load Godmode + { + if(TF2_GetPlayerClass(Player2) == TFClass_Engineer) + RemovePlayerBuilding(Player2); + if(TF2_GetPlayerClass(g_Duel[Player2][Challenger]) == TFClass_Engineer) + RemovePlayerBuilding(g_Duel[Player2][Challenger]); + + SetGodModColor(Player2); + SetGodModColor(g_Duel[Player2][Challenger]); + TF2_RespawnPlayer(Player2); + TF2_RespawnPlayer(g_Duel[Player2][Challenger]); + } + + CreateChallengerParticle(Player2); + CreateChallengerParticle(g_Duel[Player2][Challenger]); + + if(g_Duel[Player2][Type] == 1) // Play Sound + { + ClientCommand(Player2, "playgamesound ui/duel_challenge_accepted.wav"); + ClientCommand(g_Duel[Player2][Challenger], "playgamesound ui/duel_challenge_accepted.wav"); + } + else if(g_Duel[Player2][Type] == 2 || g_Duel[Player2][Type] == 3) + { + ClientCommand(Player2, "playgamesound ui/duel_challenge_accepted_with_restriction.wav"); + ClientCommand(g_Duel[Player2][Challenger], "playgamesound ui/duel_challenge_accepted_with_restriction.wav"); + } + + CPrintToChatAll("%t", "Accepts", Player2, g_Duel[Player2][Challenger]); + CPrintToChat(Player2,"%t", "Abort"); + CPrintToChat(g_Duel[Player2][Challenger],"%t", "Abort"); +} + + +//------------------------------------------------------------------------------------------------------------------------ +// Option Functions +//------------------------------------------------------------------------------------------------------------------------ + + +void SetGodModColor(int client) +{ + int userid = GetClientUserId(client); + if (CommandExists("sm_colorize")) + { + ServerCommand("sm_colorize #%d normal", userid); + } + else SetEntityRenderColor(client, 255, 255, 255, 255); + + CreateTimer(0.4, OnSetGodModeColor, userid); +} + +public Action OnSetGodModeColor(Handle timer, any userid) +{ + int client = GetClientOfUserId(userid); + if (!IsValidClient(client) || !IsPlayerAlive(client) || !g_Duel[client][Enabled]) return Plugin_Stop; + if (TF2_GetClientTeam(client) == TFTeam_Red) + SetEntityRenderColor(client, 200, 0, 0, 255); + else + SetEntityRenderColor(client, 0, 0, 200, 255); + return Plugin_Continue; +} + + +void CreateChallengerParticle(int iClient) +{ + float vOrigin[3]; + GetClientAbsOrigin(iClient, vOrigin); + vOrigin[2] += 25; + + int parent = CreateEntityByName("prop_dynamic"); + char strParent[64]; + Format(strParent, sizeof(strParent), "prop%i", parent); + DispatchKeyValue(parent, "targetname", strParent); + DispatchKeyValue(parent, "renderfx","0"); + DispatchKeyValue(parent, "damagetoenablemotion","0"); + DispatchKeyValue(parent, "forcetoenablemotion","0"); + DispatchKeyValue(parent, "Damagetype","0"); + DispatchKeyValue(parent, "disablereceiveshadows","1"); + DispatchKeyValue(parent, "massScale","0"); + DispatchKeyValue(parent, "nodamageforces","0"); + DispatchKeyValue(parent, "shadowcastdist","0"); + DispatchKeyValue(parent, "disableshadows","1"); + DispatchKeyValue(parent, "spawnflags","1670"); + DispatchKeyValue(parent, "model","models/player/medic_animations.mdl"); + DispatchKeyValue(parent, "PerformanceMode","1"); + DispatchKeyValue(parent, "rendermode","10"); + DispatchKeyValue(parent, "physdamagescale","0"); + DispatchKeyValue(parent, "physicsmode","2"); + + DispatchSpawn(parent); + TeleportEntity(parent, vOrigin, NULL_VECTOR, NULL_VECTOR); + + int ent = CreateEntityByName("env_sprite"); + if(ent) + { + char StrEntityName[64]; + Format(StrEntityName, sizeof(StrEntityName), "ent_sprite_oriented_%i", ent); + + if(GetClientTeam(iClient) == 2) + DispatchKeyValue(ent, "model", "free_duel/RED_Target.vmt"); + else + DispatchKeyValue(ent, "model", "free_duel/BLU_Target.vmt"); + DispatchKeyValue(ent, "classname", "env_sprite"); + DispatchKeyValue(ent, "spawnflags", "1"); + DispatchKeyValue(ent, "scale", "0.1"); + DispatchKeyValue(ent, "rendermode", "1"); + DispatchKeyValue(ent, "rendercolor", "255 255 255"); + //DispatchKeyValue(ent, "targetname", StrEntityName); + DispatchKeyValue(ent, "parentname", strParent); + + DispatchSpawn(ent); + TeleportEntity(ent, vOrigin, NULL_VECTOR, NULL_VECTOR); + + SetVariantString(strParent); + AcceptEntityInput(ent, "SetParent"); + + g_Duel[iClient][CSprite] = EntIndexToEntRef(ent); + g_Duel[iClient][SpriteParent] = EntIndexToEntRef(parent); + SDKHook(ent, SDKHook_SetTransmit, Hook_SetTransmit); + } +} + +public Action Hook_SetTransmit(int entity, int iClient) +{ + if(EntRefToEntIndex(g_Duel[iClient][CSprite]) == entity && !g_Duel[iClient][HideSprite]) // Can see + return Plugin_Continue; + + if(EntRefToEntIndex(g_Duel[g_Duel[iClient][Challenger]][CSprite]) == entity && !g_Duel[g_Duel[iClient][Challenger]][HideSprite]) // Can see + return Plugin_Continue; + + return Plugin_Handled; +} + +public Action Timer(Handle timer) +{ + char FlagNeeded[2]; + c_Immunity.GetString(FlagNeeded, sizeof(FlagNeeded)); + Countdown--; + for(int t=1; t <= MaxClients; t++) + { + if(IsValidClient(t) && g_Duel[t][Enabled]) + { + HudMessageTime(t); + + g_Duel[t][PlayedTime] += 1; + + if(g_Duel[t][Type] == 2) + { + g_Duel[t][TimeLeft] -= 1; + if(g_Duel[t][TimeLeft] <= 0) + { + g_Duel[g_Duel[t][Challenger]][Enabled] = false; + EndDuel(t, g_Duel[t][Type]); + } + } + + if(Countdown <= 0 && isAdmin(t, FlagNeeded)) + CPrintToChat(t, "%t","!myduels"); + else if(Countdown == 450 && isAdmin(t, FlagNeeded)) + CPrintToChat(t, "%t","!topduel"); + } + } + if(Countdown <= 0) + Countdown = 900; +} + +void HudMessageTime(int iClient) +{ + SetHudTextParams(0.85, 0.0, 1.0, 39, 148, 0, 255, 1, 0.0, 0.0, 0.0); + + if(g_Duel[iClient][Type] == 1 || g_Duel[iClient][Type] == 3) ShowHudText(iClient, -1, "You : %i - Him: %i", g_Duel[iClient][Score], g_Duel[g_Duel[iClient][Challenger]][Score]); + else if(g_Duel[iClient][Type] == 2) ShowHudText(iClient, -1, "Time left : %i | You : %i - Him: %i", g_Duel[iClient][TimeLeft], g_Duel[iClient][Score], g_Duel[g_Duel[iClient][Challenger]][Score]); +} + +public void OnClientDisconnect(int iClient) +{ + if(!IsValidClient(iClient)) return; + + if(g_Duel[iClient][Enabled]) + { + CPrintToChatAll("%t","Victory", g_Duel[iClient][Challenger], iClient, "(Player disconnected)"); + + if(IsValidClient(g_Duel[iClient][Challenger])) + ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); + + Winner[g_Duel[iClient][Challenger]] = true; + Winner[iClient] = false; + Abandon[iClient] = true; + Abandon[g_Duel[iClient][Challenger]] = false; + + InitializeClientonDB(g_Duel[iClient][Challenger]); + InitializeClientonDB(iClient); + } +} + +public Action AbortDuel(int iClient, int Args) +{ + if(!IsValidClient(iClient)) return; + + if(g_Duel[iClient][Enabled]) + { + char reason[64]; + Format(reason, sizeof(reason), "(%N aborted)", iClient); + CPrintToChatAll("%t","Victory", g_Duel[iClient][Challenger], iClient, reason); + + Winner[g_Duel[iClient][Challenger]] = true; + Winner[iClient] = false; + Abandon[iClient] = true; + Abandon[g_Duel[iClient][Challenger]] = false; + + InitializeClientonDB(g_Duel[iClient][Challenger]); + InitializeClientonDB(iClient); + + if(g_Duel[iClient][Challenger] != 0) + { + ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); + TF2_RespawnPlayer(g_Duel[iClient][Challenger]); + } + if(iClient != 0) + { + ClientCommand(iClient, "playgamesound ui/duel_event.wav"); + TF2_RespawnPlayer(iClient); + } + } + else + CPrintToChat(iClient,"%t", "NotInDuel"); +} + + +//------------------------------------------------------------------------------------------------------------------------ +// Security functions +//------------------------------------------------------------------------------------------------------------------------ + +public bool isGoodSituation(int iClient, int Player2) +{ + if(!IsValidClient(iClient) || !IsValidClient(Player2)) + { + ResetPlayer(Player2); + ResetPlayer(iClient); + return false; + } + + if(g_Duel[Player2][Enabled]) // too late ! iClient Player2 already in duel ... + { + CPrintToChat(iClient,"%t", "IsInDuel", Player2); + ResetPlayer(iClient); + return false; + } + else if(g_Duel[iClient][Enabled]) // you are already in duel ... + { + CPrintToChat(iClient,"%t", "InDuel"); + ResetPlayer(iClient); + return false; + } + else if(GetClientTeam(iClient) != 2 && GetClientTeam(iClient) != 3) + { + CPrintToChat(iClient,"%t", "TeamError"); + ResetPlayer(iClient); + return false; + } + else if(GetClientTeam(Player2) != 2 && GetClientTeam(Player2) != 3) + { + CPrintToChat(iClient,"%t", "TeamError"); + ResetPlayer(Player2); + return false; + } + else if(GetClientTeam(iClient) == GetClientTeam(Player2)) + { + CPrintToChat(iClient,"%t", "TeamError"); + ResetPlayer(iClient); + ResetPlayer(Player2); + return false; + } + else + return true; +} + +void GetSafeClientData(int iClient) +{ + char PlayerInfo[MAX_LINE_WIDTH]; + + //Client Name + GetClientName(iClient, PlayerInfo, sizeof(PlayerInfo)); + + ReplaceString(PlayerInfo, sizeof(PlayerInfo), "", ""); + ReplaceString(PlayerInfo, sizeof(PlayerInfo), "<", "["); + ReplaceString(PlayerInfo, sizeof(PlayerInfo), ">", "]"); + ReplaceString(PlayerInfo, sizeof(PlayerInfo), ",", "."); + + db.Escape(PlayerInfo, ClientName[iClient], MAX_LINE_WIDTH); + + //Client SteamID + if(IsFakeClient(iClient)) + strcopy(PlayerInfo, MAX_LINE_WIDTH, "BOT"); + else + { + if (!GetClientAuthId(iClient, AuthId_Steam3, PlayerInfo, sizeof(PlayerInfo))) + { + strcopy(PlayerInfo, MAX_LINE_WIDTH, "INVALID"); + } + } + strcopy(ClientSteamID[iClient], 24, PlayerInfo); +} + + +//------------------------------------------------------------------------------------------------------------------------ +// Duel Stats +//------------------------------------------------------------------------------------------------------------------------ + + +public Action MyDuelStats(int iClient, int Args) +{ + if (!IsValidClient(iClient)) + { + return Plugin_Handled; + } + + char buffer[255]; + + Format(buffer, sizeof(buffer), "SELECT COUNT(*) FROM `Duels_Stats`"); + db.Query(T_Rank1, buffer, GetClientUserId(iClient)); + return Plugin_Handled; +} + +public void T_Rank1(Database dummy, DBResultSet hndl, const char[] error, any userid) +{ + if (hndl == null) + LogError("Query failed! %s", error); + else + { + int iClient = GetClientOfUserId(userid); + if(!IsValidClient(iClient)) return; + char buffer[255]; + + while (hndl.FetchRow()) + { + RankTotal = hndl.FetchInt(0); + Format(buffer, sizeof(buffer), "SELECT `Points`, `Victories`, `Duels`, `Kills`, `Deads` FROM `Duels_Stats` WHERE SteamID = '%s'", ClientSteamID[iClient]); + db.Query(T_Rank2, buffer, userid); + } + } +} + +public void T_Rank2(Database dummy, DBResultSet hndl, const char[] error, any userid) +{ + if (hndl == null) + LogError("Query failed! %s", error); + else + { + int iClient = GetClientOfUserId(userid); + if (!IsValidClient(iClient)) return; + char buffer[255]; + while (hndl.FetchRow()) + { + points[iClient] = hndl.FetchFloat(0); + victories[iClient] = hndl.FetchInt(1); + dueltotal[iClient] = hndl.FetchInt(2); + killsNbr[iClient] = hndl.FetchInt(3); + death[iClient] = hndl.FetchInt(4); + + Format(buffer, sizeof(buffer), "SELECT COUNT(*) FROM `Duels_Stats` WHERE `Points` > %i", victories); + db.Query(T_Rank3, buffer, userid); + } + } +} + +public void T_Rank3(Database dummy, DBResultSet hndl, const char[] error, any userid) +{ + if (hndl == null) + LogError("Query failed! %s", error); + else + { + int iClient = GetClientOfUserId(userid); + if (!IsValidClient(iClient)) return; + while (hndl.FetchRow()) + RankPanel(iClient, hndl.FetchInt(0)); + } +} + +void RankPanel(int iClient, int Rank) +{ + char value[MAX_LINE_WIDTH]; + char ClientID[MAX_LINE_WIDTH]; + Panel rnkpanel = new Panel(); + + GetClientName(iClient, ClientID, sizeof(ClientID) ); + rnkpanel.SetTitle("Your duels' stats:"); + Format(value, sizeof(value), "Name: %s", ClientID); + rnkpanel.DrawText(value); + Format(value, sizeof(value), "Rank: %i out of %i", Rank , RankTotal); + rnkpanel.DrawText(value); + Format(value, sizeof(value), "Points: %f" , points[iClient]); + rnkpanel.DrawText(value); + Format(value, sizeof(value), "Victories: %i" , victories[iClient]); + rnkpanel.DrawText(value); + Format(value, sizeof(value), "Duels total: %i" , dueltotal[iClient]); + rnkpanel.DrawText(value); + Format(value, sizeof(value), "Kills: %i" , killsNbr[iClient]); + rnkpanel.DrawText(value); + Format(value, sizeof(value), "Deaths: %i" , death[iClient]); + rnkpanel.DrawText(value); + rnkpanel.DrawItem("Close"); + rnkpanel.Send(iClient, RankPanelHandler, 15); +} + +public int RankPanelHandler(Menu menu, MenuAction action, int param1, int param2) +{ +} + +public Action TopDuel(int iClient, int Args) +{ + char buffer[255]; + Format(buffer, sizeof(buffer), "SELECT `Players`, `Points` FROM `Duels_Stats` ORDER BY `Points` DESC LIMIT 0,100"); + db.Query(T_ShowTopDuel, buffer, GetClientUserId(iClient)); + return Plugin_Handled; +} + +public void T_ShowTopDuel(Database dummy, DBResultSet hndl, const char[] error, any userid) +{ + if (hndl == null) + LogError("Query failed! %s", error); + else + { + int iClient = GetClientOfUserId(userid); + if (!IsValidClient(iClient)) return; + + Menu menu = new Menu(TopDuelPanel); + menu.SetTitle("Top Duel Menu:"); + + int i = 1; + while (hndl.FetchRow()) + { + char PlayerName[MAX_LINE_WIDTH]; + char line[MAX_LINE_WIDTH]; + hndl.FetchString(0, PlayerName , MAX_LINE_WIDTH); + + Format(line, sizeof(line), "%i : %s %f points", i, PlayerName, SQL_FetchFloat(hndl,1)); + menu.AddItem("i" , line); + i++; + } + menu.ExitButton = true; + menu.Display(iClient, MENU_TIME_FOREVER); + } + return; +} + +public int TopDuelPanel(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_End) + delete menu; +} + + +//------------------------------------------------------------------------------------------------------------------------ +// When duel end +//------------------------------------------------------------------------------------------------------------------------ + + +bool EndDuel(int iClient, int DuelType) +{ + if(DuelType != 0) + { + if(DuelType == 1 || DuelType == 2) + { + if(g_Duel[iClient][Score] > g_Duel[g_Duel[iClient][Challenger]][Score]) + { + CPrintToChatAll("%t", "Victory", iClient, g_Duel[iClient][Challenger],""); + Winner[iClient] = true; + Winner[g_Duel[iClient][Challenger]] = false; + } + else if (g_Duel[iClient][Score] < g_Duel[g_Duel[iClient][Challenger]][Score]) + { + CPrintToChatAll("%t", "Victory", g_Duel[iClient][Challenger], iClient,""); + Winner[iClient] = false; + Winner[g_Duel[iClient][Challenger]] = true; + } + else + { + CPrintToChatAll("%t", "Equality", g_Duel[iClient][Challenger], iClient); + Equality[iClient] = true; + Winner[iClient] = true; + Equality[g_Duel[iClient][Challenger]] = true; + Winner[g_Duel[iClient][Challenger]] = true; + } + } + else if(DuelType == 3) + { + if(g_Duel[iClient][Score] > g_Duel[g_Duel[iClient][Challenger]][Score]) + { + CPrintToChatAll("%t", "Victory", g_Duel[iClient][Challenger], iClient,""); + Winner[iClient] = false; + Winner[g_Duel[iClient][Challenger]] = true; + } + else if (g_Duel[iClient][Score] < g_Duel[g_Duel[iClient][Challenger]][Score]) + { + CPrintToChatAll("%t", "Victory", iClient, g_Duel[iClient][Challenger],""); + Winner[iClient] = true; + Winner[g_Duel[iClient][Challenger]] = false; + } + else + { + CPrintToChatAll("%t", "Equality", g_Duel[iClient][Challenger], iClient); + Equality[iClient] = true; + Winner[iClient] = true; + Equality[g_Duel[iClient][Challenger]] = true; + Winner[g_Duel[iClient][Challenger]] = true; + } + } + + if(IsValidClient(g_Duel[iClient][Challenger])) + ClientCommand(g_Duel[iClient][Challenger], "playgamesound ui/duel_event.wav"); + + if(IsValidClient(iClient)) + ClientCommand(iClient, "playgamesound ui/duel_event.wav"); + + InitializeClientonDB(g_Duel[iClient][Challenger]); + InitializeClientonDB(iClient); + + return true; + } + return false; +} + + +public void InitializeClientonDB(int iClient) +{ + if(iClient == 0) + { + ResetPlayer(iClient); + return; + } + char buffer[255]; + + Format(buffer, sizeof(buffer), "SELECT `Victories`,`Duels` FROM Duels_Stats WHERE STEAMID = '%s'", ClientSteamID[iClient]); + db.Query(T_UpdateClient, buffer, iClient); +} + +public void T_UpdateClient(Database dummy, DBResultSet hndl, const char[] error, any iClient) +{ + char etat[512]; + int CltPoint; + int Victory; + int Equal; + int Kill = g_Duel[iClient][kills]; + int Dead = g_Duel[iClient][Deads]; + int Abort = Abandon[iClient]; + int Tmer = g_Duel[iClient][PlayedTime]; + int Dueller = g_Duel[iClient][Challenger]; + + if(Equality[iClient]) + { + Format(etat, sizeof(etat), "Equality"); + CltPoint = 1; + Victory = 1; + Equal = 1; + } + else if(Winner[iClient]) + { + Format(etat, sizeof(etat), "Winner"); + CltPoint = 2; + Victory = 1; + Equal = 0; + } + else + { + Format(etat, sizeof(etat), "Loser"); + CltPoint = 0; + Victory = 0; + Equal = 0; + } + + + ResetPlayer(iClient); + + if (!hndl.RowCount) + { + char buffer[1500]; + if(!SQLite) + { + Format(buffer, sizeof(buffer), "INSERT INTO Duels_Stats (`Players`,`SteamID`,`Points`,`Victories`,`Duels`,`Kills`,`Deads`,`PlayTime`,`Abandoned`,`Equalities`,`Last_dueler`,`Last_dueler_SteamID`,`Etat`) VALUES ('%s','%s','%i','%i','1','%i','%i','%i','%i','%i','%s','%s','%s')", ClientName[iClient], ClientSteamID[iClient], CltPoint, Victory, Kill, Dead, Tmer, Abort, Equal, ClientName[Dueller], ClientSteamID[Dueller], etat); + db.Query(SQLErrorCheckCallback, buffer); + LogMessage("MySQL => %s First victory, and add on database.", ClientName[iClient]); + } + else + { + Format(buffer, sizeof(buffer), "INSERT INTO Duels_Stats VALUES('%s','%s','%i','%i','1','%i','%i','%i','%i','%i','%s','%s','%s');", ClientName[iClient], ClientSteamID[iClient], CltPoint, Victory, Kill, Dead, Tmer, Abort, Equal, ClientName[Dueller], ClientSteamID[Dueller], etat ); + db.Query(SQLErrorCheckCallback, buffer); + LogMessage("SQLite => %s First victory, and add on database.", ClientName[iClient]); + } + CPrintToChatAll("%t", Victory >1 ? "Victories" : "VictoryNbr", ClientName[iClient], Victory); + } + else + { + char buffer[1500]; + + while (hndl.FetchRow()) + { + int clientvictories = hndl.FetchInt(0); + int clientduels = hndl.FetchInt(1); + if(Victory == 1) + clientvictories += 1; + float clientpoints = ((clientvictories*1.0)/(clientduels+1)) + clientvictories; + + Format(buffer, sizeof(buffer), "UPDATE Duels_Stats SET Players = '%s', Points = %f, Victories = Victories +%i, Duels = Duels +1, Kills = Kills +%i, Deads = Deads +%i, PlayTime = PlayTime +%i, Abandoned = Abandoned +%i, Equalities = Equalities +%i, Last_dueler = '%s', Last_dueler_SteamID = '%s', Etat = '%s' WHERE SteamID = '%s'",ClientName[iClient], clientpoints, Victory, Kill, Dead, Tmer, Abort, Equal, ClientName[Dueller], ClientSteamID[Dueller], etat, ClientSteamID[iClient]); + db.Query(SQLErrorCheckCallback, buffer); + + CPrintToChatAll("%t", clientvictories >1 ? "Victories" : "VictoryNbr", ClientName[iClient], clientvictories); + LogMessage("MySQL => %s %d victories, and updated on database.", ClientName[iClient], clientvictories); + } + } +} + +void ResetPlayer(int iClient) +{ + if(IsValidClient(iClient)) + { + if (g_Duel[iClient][GodMod]) + { + if(CommandExists("sm_colorize")) + { + ServerCommand("sm_colorize #%d normal", GetClientUserId(iClient)); + } + else + { + SetEntityRenderColor(iClient, 255, 255, 255, 255); + } + } + + if (!g_Duel[iClient][HealingAllowed]) + { + TF2Attrib_RemoveByName(iClient, "health from healers reduced"); + } + } + g_Duel[iClient][Enabled] = false; + g_Duel[iClient][HeadShot] = false; + g_Duel[iClient][HealingAllowed] = true; + g_Duel[iClient][ClassRestrict] = 0; + g_Duel[iClient][kills] = 0; + g_Duel[iClient][Deads] = 0; + g_Duel[iClient][TimeLeft] = 0; + g_Duel[iClient][Score] = 0; + g_Duel[iClient][Challenger] = 0; + g_Duel[iClient][PlayedTime] = 0; + g_Duel[iClient][GodMod] = 0; + g_Duel[iClient][Type] = 0; + + Winner[iClient] = false; + Abandon[iClient] = false; + Equality[iClient] = false; + + if(IsValidEdict(EntRefToEntIndex(g_Duel[iClient][SpriteParent]))) + { + RemoveEdict(EntRefToEntIndex(g_Duel[iClient][SpriteParent])); + g_Duel[iClient][SpriteParent] = INVALID_ENT_REFERENCE; + } + + if(IsValidEdict(EntRefToEntIndex(g_Duel[iClient][CSprite]))) + { + RemoveEdict(EntRefToEntIndex(g_Duel[iClient][CSprite])); + g_Duel[iClient][CSprite] = INVALID_ENT_REFERENCE; + } +} + + +//------------------------------------------------------------------------------------------------------------------------ +// Native Functions +//------------------------------------------------------------------------------------------------------------------------ + + +public int Native_IsPlayerInDuel(Handle plugin, int numParams) +{ + int iClient = GetNativeCell(1); + + if(!IsValidClient(iClient)) return false; + + if(g_Duel[iClient][Enabled]) + return true; + else + return false; +} + +public int Native_IsDuelRestrictionClass(Handle plugin, int numParams) +{ + int iClient = GetNativeCell(1); + + if(!IsValidClient(iClient)) return false; + + if(g_Duel[iClient][ClassRestrict] != 0) + return true; + else + return false; +} + +public int Native_GetDuelerID(Handle plugin, int numParams) +{ + if(!IsValidClient(GetNativeCell(1))) return -1; + return g_Duel[GetNativeCell(1)][Challenger]; +} diff --git a/scripting/ngs_friendly.sp b/scripting/ngs_friendly.sp index 7d0b683..8511de7 100644 --- a/scripting/ngs_friendly.sp +++ b/scripting/ngs_friendly.sp @@ -360,20 +360,20 @@ public void OnPluginStart() LogError("Could not initialize call for CTFWeaponBase::WeaponReset. Plugin will not be able to reset weapons before switching!"); } } - CloseHandle(hConf); + delete hConf; } else { LogError("Could not read gamedata/friendly.txt. Plugin will not be able to reset weapons before switching!"); } for (int i = 1; i < MaxClients; i++) - { - if (!AreClientCookiesCached(i)) - { - continue; - } + { + if (!AreClientCookiesCached(i)) + { + continue; + } - OnClientCookiesCached(i); - } + OnClientCookiesCached(i); + } } public void OnClientCookiesCached(int client) @@ -1332,7 +1332,7 @@ public Action OnTakeDamage(int client, int &attacker, int &inflictor, float &dam } if ((IsFriendly[attacker] || IsFriendly[client]) && !IsAdmin[attacker]) { damage = 0.0; - return Plugin_Handled; + return Plugin_Changed; } return Plugin_Continue; } diff --git a/scripting/ngs_player_feedback.sp b/scripting/ngs_player_feedback.sp index d10a988..4a0ca73 100644 --- a/scripting/ngs_player_feedback.sp +++ b/scripting/ngs_player_feedback.sp @@ -13,7 +13,7 @@ #define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" #define RELOAD_ON_UPDATE 1 - + #include #include #include @@ -21,8 +21,8 @@ ConVar cvarPromptPercent, cvarRedirectAddress; -Cookie promptCookie; - +Cookie promptCookie; + int promptTimeStamps[MAXPLAYERS + 1], playerLifeCount[MAXPLAYERS + 1]; //--------------------// @@ -38,15 +38,15 @@ public Plugin myinfo = { public void OnPluginStart() { LoadTranslations("common.phrases"); - + AutoExecConfig_SetCreateDirectory(true); AutoExecConfig_SetFile("ngs_player_feedback"); - AutoExecConfig_SetCreateFile(true); - + AutoExecConfig_SetCreateFile(true); + bool appended; - cvarPromptPercent = AutoExecConfig_CreateConVarCheckAppend(appended, "ngs_feedback_prompt_percent", "0.25", "Percent to use to determine how many people should be prompted."); - cvarRedirectAddress = AutoExecConfig_CreateConVarCheckAppend(appended, "ngs_feedback_prompt_address", "neogenesisnetwork.net:29015", "What address to use to redirect people."); - AutoExecConfig_ExecAndClean(appended); + cvarPromptPercent = AutoExecConfig_CreateConVarCheckAppend(appended, "ngs_feedback_prompt_percent", "0.25", "Percent to use to determine how many people should be prompted."); + cvarRedirectAddress = AutoExecConfig_CreateConVarCheckAppend(appended, "ngs_feedback_prompt_address", "neogenesisnetwork.net:29015", "What address to use to redirect people."); + AutoExecConfig_ExecAndClean(appended); promptCookie = new Cookie("ServerJoinFeedbackPrompt", "Timestamp of last prompt check.", CookieAccess_Private); @@ -60,23 +60,23 @@ public void OnPluginStart() } OnClientCookiesCached(i); } -} - -public void OnClientPutInServer(int client) -{ - promptTimeStamps[client] = 0; - playerLifeCount[client] = 0; -} - -public void OnClientDisconnect(int client) -{ - promptTimeStamps[client] = 0; - playerLifeCount[client] = 0; +} + +public void OnClientPutInServer(int client) +{ + promptTimeStamps[client] = 0; + playerLifeCount[client] = 0; +} + +public void OnClientDisconnect(int client) +{ + promptTimeStamps[client] = 0; + playerLifeCount[client] = 0; } public void OnClientCookiesCached(int client) { - char sValue[32]; + char sValue[32]; promptCookie.GetValue(client, sValue, sizeof(sValue)); promptTimeStamps[client] = (sValue[0] != '\0') ? StringToInt(sValue) : 0; @@ -93,67 +93,67 @@ public void OnClientPostAdminCheck(int client) public void OnPlayerSpawn(Event event, const char[] name, bool dontBroadcast) { int client = GetClientOfUserId(event.GetInt("userid")); - if (!IsValidClient(client)) return; - - if (playerLifeCount[client] < 3) - { - playerLifeCount[client]++; - return; - } - - int currenttime = GetTime(); - char timestamp[64]; - IntToString(currenttime, timestamp, sizeof(timestamp)); - if (isValidCandidate(client, currenttime)) - { - Menu menu = new Menu(PromptMenuHandler); - menu.SetTitle("We are working on a new map and\nyou have been chosen to help beta-test it!\nWould you like to join?"); - menu.AddItem("yes", "Yes!"); - menu.AddItem("no", "No, don't show me again for 3 days."); - menu.ExitButton = false; - menu.Display(client, MENU_TIME_FOREVER); - } - - promptTimeStamps[client] = currenttime; + if (!IsValidClient(client)) return; + + if (playerLifeCount[client] < 3) + { + playerLifeCount[client]++; + return; + } + + int currenttime = GetTime(); + char timestamp[64]; + IntToString(currenttime, timestamp, sizeof(timestamp)); + if (isValidCandidate(client, currenttime)) + { + Menu menu = new Menu(PromptMenuHandler); + menu.SetTitle("We are working on a new map and\nyou have been chosen to help beta-test it!\nWould you like to join?"); + menu.AddItem("yes", "Yes!"); + menu.AddItem("no", "No, don't show me again for 3 days."); + menu.ExitButton = false; + menu.Display(client, MENU_TIME_FOREVER); + } + + promptTimeStamps[client] = currenttime; promptCookie.SetValue(client, timestamp); -} - -public bool isValidCandidate(int client, int time) -{ - return (time - promptTimeStamps[client] > 259200) && - ((GetRandomFloat() <= cvarPromptPercent.FloatValue) || - CheckCommandAccess(client, "sm_ngsextra_donor_override", ADMFLAG_RESERVATION)); -} - -public int PromptMenuHandler(Menu menu, MenuAction action, int param1, int param2) -{ - switch (action) - { - case MenuAction_End: - { - delete menu; - } - case MenuAction_Select: - { - char info[16]; - if (menu.GetItem(param2, info, sizeof(info))) - { - if (StrEqual(info, "yes")) - { - Menu menu2 = new Menu(PromptMenuHandler); - menu2.SetTitle("Would you like to be redirected there now?"); - menu2.AddItem("yesredirect", "Yes!"); - menu2.AddItem("no", "No, don't show me again for 3 days."); - menu2.ExitButton = false; - menu2.Display(param1, MENU_TIME_FOREVER); - } - else if (StrEqual(info, "yesredirect")) - { - char serverip[128]; - cvarRedirectAddress.GetString(serverip, sizeof(serverip)); - ClientCommand(param1, "redirect %s", serverip); - } - } - } - } +} + +public bool isValidCandidate(int client, int time) +{ + return (time - promptTimeStamps[client] > 259200) && + ((GetRandomFloat() <= cvarPromptPercent.FloatValue) || + CheckCommandAccess(client, "sm_ngsextra_donor_override", ADMFLAG_RESERVATION)); +} + +public int PromptMenuHandler(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + { + delete menu; + } + case MenuAction_Select: + { + char info[16]; + if (menu.GetItem(param2, info, sizeof(info))) + { + if (StrEqual(info, "yes")) + { + Menu menu2 = new Menu(PromptMenuHandler); + menu2.SetTitle("Would you like to be redirected there now?"); + menu2.AddItem("yesredirect", "Yes!"); + menu2.AddItem("no", "No, don't show me again for 3 days."); + menu2.ExitButton = false; + menu2.Display(param1, MENU_TIME_FOREVER); + } + else if (StrEqual(info, "yesredirect")) + { + char serverip[128]; + cvarRedirectAddress.GetString(serverip, sizeof(serverip)); + ClientCommand(param1, "redirect %s", serverip); + } + } + } + } } \ No newline at end of file diff --git a/updater/ngs_freeduels.txt b/updater/ngs_freeduels.txt index 857aae9..2e30447 100644 --- a/updater/ngs_freeduels.txt +++ b/updater/ngs_freeduels.txt @@ -1,21 +1,21 @@ -"Updater" -{ - "Information" - { - "Version" - { - "Latest" "1.2.4" - } - - "Notes" "Add a disallow healing option! Works mostly :)" - "Notes" "Use new syntax where applicable." - } - - "Files" - { - "Plugin" "Path_SM/plugins/ngs_freeduels.smx" - "Plugin" "Path_SM/translations/free_duels.phrases.txt" - - "Source" "Path_SM/scripting/ngs_freeduels.sp" - } +"Updater" +{ + "Information" + { + "Version" + { + "Latest" "1.2.4" + } + + "Notes" "Add a disallow healing option! Works mostly :)" + "Notes" "Use new syntax where applicable." + } + + "Files" + { + "Plugin" "Path_SM/plugins/ngs_freeduels.smx" + "Plugin" "Path_SM/translations/free_duels.phrases.txt" + + "Source" "Path_SM/scripting/ngs_freeduels.sp" + } } \ No newline at end of file From 35f132638471267f1e1cced65bc46793b1fdfa2b Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:14:29 -0800 Subject: [PATCH 05/29] More line endings! --- scripting/ngs_fixes.sp | 272 +++++++++---------- scripting/ngs_truedemocracy.sp | 472 ++++++++++++++++----------------- 2 files changed, 372 insertions(+), 372 deletions(-) diff --git a/scripting/ngs_fixes.sp b/scripting/ngs_fixes.sp index 2e7b865..194e0b7 100644 --- a/scripting/ngs_fixes.sp +++ b/scripting/ngs_fixes.sp @@ -1,137 +1,137 @@ -/** -* TheXeon -* ngs_fixes.sp -* -* Files: -* addons/sourcemod/plugins/ngs_fixes.smx -* cfg/sourcemod/ngs_fixes.cfg -* -* Dependencies: -* basecomm.inc, ngsutils.inc, ngsupdater.inc -*/ -#pragma newdecls required -#pragma semicolon 1 - -#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" -#define RELOAD_ON_UPDATE 1 - -#include -#include -#include - -ConVar cvarDisableDoveSpawn, cvarDisableNonAuthedSpam, cvarDisableVoiceMenuSpam; -bool allowVoiceMenuSpam; -SMTimer authClientTimer[MAXPLAYERS + 1]; -SMTimer voiceMenuTimer[MAXPLAYERS + 1]; - -public Plugin myinfo = { - name = "[NGS] Game Fixes", - author = "TheXeon", - description = "Small plugin including changes for NGS server.", - version = "1.0.4", - url = "https://www.neogenesisnetwork.net/" -} - -public void OnPluginStart() -{ - AutoExecConfig_SetCreateDirectory(true); - AutoExecConfig_SetFile("ngs_fixes"); - AutoExecConfig_SetCreateFile(true); - bool appended; - cvarDisableNonAuthedSpam = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsfixes_disable_authspam", "1", "Should players be kicked if they don\'t auth?"); - cvarDisableVoiceMenuSpam = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsfixes_disable_voicespam", "1", "Should we limit the voicemenu spam on the server?"); - cvarDisableVoiceMenuSpam.AddChangeHook(OnVoiceMenuSpamChanged); - if (GetEngineVersion() == Engine_TF2) - { - cvarDisableDoveSpawn = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsfixes_disable_doves", "1", "Should the plugin disable dove spawning?"); - HookUserMessage(GetUserMessageId("SpawnFlyingBird"), UserMsg_SpawnBird, true); - } - AutoExecConfig_ExecAndClean(appended); - - AddCommandListener(CmdVoiceMenu, "voicemenu"); -} - -public void OnConfigsExecuted() -{ - char voicemenuspam[8]; - cvarDisableVoiceMenuSpam.GetString(voicemenuspam, sizeof(voicemenuspam)); - allowVoiceMenuSpam = !(view_as(StringToInt(voicemenuspam))); -} - -public void OnVoiceMenuSpamChanged(ConVar convar, const char[] oldValue, const char[] newValue) -{ - allowVoiceMenuSpam = !convar.BoolValue; -} - -public Action UserMsg_SpawnBird(UserMsg msg_id, BfRead bf, const int[] players, int playersNum, bool reliable, bool init) -{ - if (!cvarDisableDoveSpawn.BoolValue) return Plugin_Continue; - return Plugin_Stop; -} - -public void OnClientConnected(int client) -{ - if (cvarDisableNonAuthedSpam.BoolValue && !IsFakeClient(client)) - authClientTimer[client] = new SMTimer(2.0, AuthCheckTimer, GetClientUserId(client), TIMER_REPEAT); -} - -public Action CmdVoiceMenu(int client, const char[] command, int argc) -{ - if (allowVoiceMenuSpam) return Plugin_Continue; - if (voiceMenuTimer[client] != null) - { - return Plugin_Handled; - } - else - { - char CmdString[4]; - GetCmdArgString(CmdString, sizeof(CmdString)); - if (StrEqual(CmdString, "0 0")) - voiceMenuTimer[client] = new SMTimer(0.5, OnVoiceMenuTimer, GetClientUserId(client)); - else - voiceMenuTimer[client] = new SMTimer(0.1, OnVoiceMenuTimer, GetClientUserId(client)); - return Plugin_Continue; - } -} - -public Action OnVoiceMenuTimer(Handle timer, any userid) -{ - int client = GetClientOfUserId(userid); - if (client == 0) return; - voiceMenuTimer[client] = null; -} - -public Action AuthCheckTimer(Handle timer, int userid) -{ - int client = GetClientOfUserId(userid); - if (client == 0) - { - authClientTimer[client] = null; - return Plugin_Stop; - } - if (!IsClientInGame(client)) return Plugin_Continue; - char auth[24]; - if (!GetClientAuthId(client, AuthId_Engine, auth, sizeof(auth))) - { - if (IsPlayerAlive(client)) - { - ChangeClientTeam(client, 1); - PrintToChat(client, "Your client has not been authed, please reconnect."); - } - BaseComm_SetClientGag(client, true); - BaseComm_SetClientMute(client, true); - ServerCommand("namelockid %d 1", userid); - } - else - { - authClientTimer[client] = null; - return Plugin_Stop; - } - return Plugin_Continue; -} - -public void OnClientDisconnect(int client) -{ - delete authClientTimer[client]; - delete voiceMenuTimer[client]; +/** +* TheXeon +* ngs_fixes.sp +* +* Files: +* addons/sourcemod/plugins/ngs_fixes.smx +* cfg/sourcemod/ngs_fixes.cfg +* +* Dependencies: +* basecomm.inc, ngsutils.inc, ngsupdater.inc +*/ +#pragma newdecls required +#pragma semicolon 1 + +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 + +#include +#include +#include + +ConVar cvarDisableDoveSpawn, cvarDisableNonAuthedSpam, cvarDisableVoiceMenuSpam; +bool allowVoiceMenuSpam; +SMTimer authClientTimer[MAXPLAYERS + 1]; +SMTimer voiceMenuTimer[MAXPLAYERS + 1]; + +public Plugin myinfo = { + name = "[NGS] Game Fixes", + author = "TheXeon", + description = "Small plugin including changes for NGS server.", + version = "1.0.4", + url = "https://www.neogenesisnetwork.net/" +} + +public void OnPluginStart() +{ + AutoExecConfig_SetCreateDirectory(true); + AutoExecConfig_SetFile("ngs_fixes"); + AutoExecConfig_SetCreateFile(true); + bool appended; + cvarDisableNonAuthedSpam = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsfixes_disable_authspam", "1", "Should players be kicked if they don\'t auth?"); + cvarDisableVoiceMenuSpam = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsfixes_disable_voicespam", "1", "Should we limit the voicemenu spam on the server?"); + cvarDisableVoiceMenuSpam.AddChangeHook(OnVoiceMenuSpamChanged); + if (GetEngineVersion() == Engine_TF2) + { + cvarDisableDoveSpawn = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsfixes_disable_doves", "1", "Should the plugin disable dove spawning?"); + HookUserMessage(GetUserMessageId("SpawnFlyingBird"), UserMsg_SpawnBird, true); + } + AutoExecConfig_ExecAndClean(appended); + + AddCommandListener(CmdVoiceMenu, "voicemenu"); +} + +public void OnConfigsExecuted() +{ + char voicemenuspam[8]; + cvarDisableVoiceMenuSpam.GetString(voicemenuspam, sizeof(voicemenuspam)); + allowVoiceMenuSpam = !(view_as(StringToInt(voicemenuspam))); +} + +public void OnVoiceMenuSpamChanged(ConVar convar, const char[] oldValue, const char[] newValue) +{ + allowVoiceMenuSpam = !convar.BoolValue; +} + +public Action UserMsg_SpawnBird(UserMsg msg_id, BfRead bf, const int[] players, int playersNum, bool reliable, bool init) +{ + if (!cvarDisableDoveSpawn.BoolValue) return Plugin_Continue; + return Plugin_Stop; +} + +public void OnClientConnected(int client) +{ + if (cvarDisableNonAuthedSpam.BoolValue && !IsFakeClient(client)) + authClientTimer[client] = new SMTimer(2.0, AuthCheckTimer, GetClientUserId(client), TIMER_REPEAT); +} + +public Action CmdVoiceMenu(int client, const char[] command, int argc) +{ + if (allowVoiceMenuSpam) return Plugin_Continue; + if (voiceMenuTimer[client] != null) + { + return Plugin_Handled; + } + else + { + char CmdString[4]; + GetCmdArgString(CmdString, sizeof(CmdString)); + if (StrEqual(CmdString, "0 0")) + voiceMenuTimer[client] = new SMTimer(0.5, OnVoiceMenuTimer, GetClientUserId(client)); + else + voiceMenuTimer[client] = new SMTimer(0.1, OnVoiceMenuTimer, GetClientUserId(client)); + return Plugin_Continue; + } +} + +public Action OnVoiceMenuTimer(Handle timer, any userid) +{ + int client = GetClientOfUserId(userid); + if (client == 0) return; + voiceMenuTimer[client] = null; +} + +public Action AuthCheckTimer(Handle timer, int userid) +{ + int client = GetClientOfUserId(userid); + if (client == 0) + { + authClientTimer[client] = null; + return Plugin_Stop; + } + if (!IsClientInGame(client)) return Plugin_Continue; + char auth[24]; + if (!GetClientAuthId(client, AuthId_Engine, auth, sizeof(auth))) + { + if (IsPlayerAlive(client)) + { + ChangeClientTeam(client, 1); + PrintToChat(client, "Your client has not been authed, please reconnect."); + } + BaseComm_SetClientGag(client, true); + BaseComm_SetClientMute(client, true); + ServerCommand("namelockid %d 1", userid); + } + else + { + authClientTimer[client] = null; + return Plugin_Stop; + } + return Plugin_Continue; +} + +public void OnClientDisconnect(int client) +{ + delete authClientTimer[client]; + delete voiceMenuTimer[client]; } \ No newline at end of file diff --git a/scripting/ngs_truedemocracy.sp b/scripting/ngs_truedemocracy.sp index 3b30732..2efb312 100644 --- a/scripting/ngs_truedemocracy.sp +++ b/scripting/ngs_truedemocracy.sp @@ -1,237 +1,237 @@ -#pragma semicolon 1 -#pragma newdecls required - -#include -#include -#include -#include - -#define PLUGIN_VERSION "1.0.0" - -// ConVar BleedChance; -Menu voteMenu[MAXPLAYERS + 1]; - -bool voteEnabled; - -int results[MAXPLAYERS + 1]; -int resultCount[5] = {0, 0, 0, 0, 0}; - -int numOptions = 0; - -char question[1024], options[5][2][48], baseoptions[5][48]; - -public Plugin myinfo = { - name = "[NGS] True Democracy", - author = "TheXeon", - description = "True democracy through smart votes.", - version = PLUGIN_VERSION, - url = "https://www.neogenesisnetwork.net/" -}; - -public void OnPluginStart( ) -{ - CreateConVar("sm_truedemocracy_version", PLUGIN_VERSION, "True democracy randomized vote version"); - - RegAdminCmd("sm_rvote", CommandRandomVote, ADMFLAG_VOTE, "Creates a randomized vote."); - RegAdminCmd("sm_rvoteresults", CommandRandomVoteResults, ADMFLAG_VOTE, "Prints vote results."); - RegAdminCmd("sm_rvoteend", CommandRandomVoteEnd, ADMFLAG_VOTE, "Ends a vote."); - RegAdminCmd("sm_rvoteclear", CommandRandomVoteClear, ADMFLAG_VOTE, "Clears results of last vote."); - - RegConsoleCmd("sm_rrevote", CommandRandomVoteRevote, "Revote on a randomized vote!"); - - LoadTranslations("common.phrases"); -} - -public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) -{ - CreateNative("TrueDemocracy_StartVote", Native_StartRandomizedVote); - return APLRes_Success; -} - -public Action CommandRandomVote(int client, int args) -{ - if (voteEnabled) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There is already a vote going on!"); - return Plugin_Handled; - } - if (args < 3) - { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Please provide a question and two options!"); - return Plugin_Handled; - } - voteEnabled = true; - numOptions = args - 1; - - ClearVoteResults(); - - GetCmdArg(1, question, sizeof(question)); - for (int i = 2; i <= numOptions + 1; i++) - { - int place = i - 2; - GetCmdArg(i, options[place][0], 48); - strcopy(baseoptions[place], 48, options[place][0]); - Format(options[place][1], 48, "option%d", (place + 1)); - } - DisplayRandomVoteToAll(30.0); - return Plugin_Handled; -} - -void DisplayRandomVoteToAll(float time) -{ - char voteTitle[64]; - Format(voteTitle, sizeof(voteTitle), "%s (random options)", question); - for (int i = 1; i <= MaxClients; i++) - { - if (!IsValidClient(i)) continue; - PrepareVoteMenu(i, voteTitle); - voteMenu[i].Display(i, 30); - } - CreateTimer(time, OnVoteTimerEnd); -} - -public void RandomizeOptions() -{ - for (int j = 0; j < numOptions; j++) - { - int randPos = GetRandomInt(0, numOptions - 1); - char tmpQuestion[48], tmpOption[48]; - strcopy(tmpQuestion, 48, options[j][0]); - strcopy(tmpOption, 48, options[j][1]); - strcopy(options[j][0], 48, options[randPos][0]); - strcopy(options[j][1], 48, options[randPos][1]); - strcopy(options[randPos][0], 48, tmpQuestion); - strcopy(options[randPos][1], 48, tmpOption); - } -} - -public int Native_StartRandomizedVote(Handle plugin, int numParams) -{ - if (voteEnabled) - return ThrowNativeError(1, "There is currently a vote already happening!"); - if (numParams < 4) // at least question, two options, and a time - return ThrowNativeError(2, "There are not enough options in this vote!"); - voteEnabled = true; - GetNativeString(1, question, sizeof(question)); - numOptions = numParams - 2; - for (int i = 2; i <= numParams - 1; i++) - { - int place = i - 2; - GetNativeString(i, options[place][0], 48); - strcopy(baseoptions[place], 48, options[place][0]); - Format(options[place][1], 48, "option%d", (place + 1)); - } - DisplayRandomVoteToAll(GetNativeCell(numParams)); -} - -public Action OnVoteTimerEnd(Handle timer, any data) -{ - ServerCommand("sm_rvoteend"); - ServerCommand("sm_rvoteresults"); -} - -public Action CommandRandomVoteResults(int client, int args) -{ - CountVoteResults(); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} === Vote results ==="); - for (int i = 0; i < numOptions; i++) - { - CPrintToChatAll("{CRIMSON}%d.{DEFAULT} {YELLOW}%s{DEFAULT}: %d.", i + 1, baseoptions[i], resultCount[i]); - } - return Plugin_Handled; -} - -public Action CommandRandomVoteEnd(int client, int args) -{ - voteEnabled = false; - CPrintToChatAll("{GREEN}[SM]{DEFAULT} Vote has ended."); - return Plugin_Handled; -} - -public Action CommandRandomVoteRevote(int client, int args) -{ - if (!IsValidClient(client) || !voteEnabled) return Plugin_Handled; - char voteTitle[64]; - Format(voteTitle, sizeof(voteTitle), "%s (random options)", question); - PrepareVoteMenu(client, voteTitle); - voteMenu[client].Display(client, 30); - return Plugin_Handled; -} - -public Action CommandRandomVoteClear(int client, int args) -{ - ClearVoteResults(); - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Vote results cleared."); - return Plugin_Handled; -} - -public int RandomizedVoteMenuHandler(Menu menu, MenuAction action, int param1, int param2) -{ - switch(action) - { - case MenuAction_Select: - { - if (!voteEnabled) return 0; - char info[32], displayBuffer[48]; - menu.GetItem(param2, info, sizeof(info), _, displayBuffer, sizeof(displayBuffer)); - int place = info[6] - 48; - CPrintToChat(param1, "{GREEN}[SM]{DEFAULT} Vote for {OLIVE}%s{DEFAULT} counted! Use {YELLOW}!rrevote{DEFAULT} to revote!", displayBuffer); -// CPrintToChatAdmins(ADMFLAG_ROOT, "%N chose %s", param1, info); -// CPrintToChatAdmins(ADMFLAG_ROOT, "%N set to place info[6] - 48 is %d", param1, place); - results[param1] = place; - } - case MenuAction_Cancel: - PrintToServer("Client %d's menu was cancelled for reason %d", param1, param2); - case MenuAction_End: - delete menu; - } - - return 0; -} - -void PrepareVoteMenu(int client, char[] title) -{ -// if (voteMenu[client] != null) return; commenting this out but I'm not sure it'll leak - voteMenu[client] = new Menu(RandomizedVoteMenuHandler); - voteMenu[client].SetTitle(title); - RandomizeOptions(); - for (int k = 0; k < numOptions; k++) - { - voteMenu[client].AddItem(options[k][1], options[k][0]); - } - voteMenu[client].ExitButton = false; -} - -void CountVoteResults() -{ - for (int i = 1; i <= MaxClients; i++) - { - int result = results[i]; - if (result == 0) continue; - resultCount[result - 1]++; - } -} - -void ClearVoteResults() -{ - for (int i = 1; i <= MaxClients; i++) - { - results[i] = 0; - } - for (int i = 0; i < 5; i++) - { - resultCount[i] = 0; - } -} - -stock bool IsValidClient(int client, bool aliveTest=false, bool botTest=true, bool rangeTest=true, - bool ingameTest=true) -{ - if (client > 4096) client = EntRefToEntIndex(client); - if (rangeTest && (client < 1 || client > MaxClients)) return false; - if (ingameTest && !IsClientInGame(client)) return false; - if (botTest && IsFakeClient(client)) return false; - if (GetEntProp(client, Prop_Send, "m_bIsCoaching")) return false; - if (aliveTest && !IsPlayerAlive(client)) return false; - return true; +#pragma semicolon 1 +#pragma newdecls required + +#include +#include +#include +#include + +#define PLUGIN_VERSION "1.0.0" + +// ConVar BleedChance; +Menu voteMenu[MAXPLAYERS + 1]; + +bool voteEnabled; + +int results[MAXPLAYERS + 1]; +int resultCount[5] = {0, 0, 0, 0, 0}; + +int numOptions = 0; + +char question[1024], options[5][2][48], baseoptions[5][48]; + +public Plugin myinfo = { + name = "[NGS] True Democracy", + author = "TheXeon", + description = "True democracy through smart votes.", + version = PLUGIN_VERSION, + url = "https://www.neogenesisnetwork.net/" +}; + +public void OnPluginStart( ) +{ + CreateConVar("sm_truedemocracy_version", PLUGIN_VERSION, "True democracy randomized vote version"); + + RegAdminCmd("sm_rvote", CommandRandomVote, ADMFLAG_VOTE, "Creates a randomized vote."); + RegAdminCmd("sm_rvoteresults", CommandRandomVoteResults, ADMFLAG_VOTE, "Prints vote results."); + RegAdminCmd("sm_rvoteend", CommandRandomVoteEnd, ADMFLAG_VOTE, "Ends a vote."); + RegAdminCmd("sm_rvoteclear", CommandRandomVoteClear, ADMFLAG_VOTE, "Clears results of last vote."); + + RegConsoleCmd("sm_rrevote", CommandRandomVoteRevote, "Revote on a randomized vote!"); + + LoadTranslations("common.phrases"); +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + CreateNative("TrueDemocracy_StartVote", Native_StartRandomizedVote); + return APLRes_Success; +} + +public Action CommandRandomVote(int client, int args) +{ + if (voteEnabled) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There is already a vote going on!"); + return Plugin_Handled; + } + if (args < 3) + { + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Please provide a question and two options!"); + return Plugin_Handled; + } + voteEnabled = true; + numOptions = args - 1; + + ClearVoteResults(); + + GetCmdArg(1, question, sizeof(question)); + for (int i = 2; i <= numOptions + 1; i++) + { + int place = i - 2; + GetCmdArg(i, options[place][0], 48); + strcopy(baseoptions[place], 48, options[place][0]); + Format(options[place][1], 48, "option%d", (place + 1)); + } + DisplayRandomVoteToAll(30.0); + return Plugin_Handled; +} + +void DisplayRandomVoteToAll(float time) +{ + char voteTitle[64]; + Format(voteTitle, sizeof(voteTitle), "%s (random options)", question); + for (int i = 1; i <= MaxClients; i++) + { + if (!IsValidClient(i)) continue; + PrepareVoteMenu(i, voteTitle); + voteMenu[i].Display(i, 30); + } + CreateTimer(time, OnVoteTimerEnd); +} + +public void RandomizeOptions() +{ + for (int j = 0; j < numOptions; j++) + { + int randPos = GetRandomInt(0, numOptions - 1); + char tmpQuestion[48], tmpOption[48]; + strcopy(tmpQuestion, 48, options[j][0]); + strcopy(tmpOption, 48, options[j][1]); + strcopy(options[j][0], 48, options[randPos][0]); + strcopy(options[j][1], 48, options[randPos][1]); + strcopy(options[randPos][0], 48, tmpQuestion); + strcopy(options[randPos][1], 48, tmpOption); + } +} + +public int Native_StartRandomizedVote(Handle plugin, int numParams) +{ + if (voteEnabled) + return ThrowNativeError(1, "There is currently a vote already happening!"); + if (numParams < 4) // at least question, two options, and a time + return ThrowNativeError(2, "There are not enough options in this vote!"); + voteEnabled = true; + GetNativeString(1, question, sizeof(question)); + numOptions = numParams - 2; + for (int i = 2; i <= numParams - 1; i++) + { + int place = i - 2; + GetNativeString(i, options[place][0], 48); + strcopy(baseoptions[place], 48, options[place][0]); + Format(options[place][1], 48, "option%d", (place + 1)); + } + DisplayRandomVoteToAll(GetNativeCell(numParams)); +} + +public Action OnVoteTimerEnd(Handle timer, any data) +{ + ServerCommand("sm_rvoteend"); + ServerCommand("sm_rvoteresults"); +} + +public Action CommandRandomVoteResults(int client, int args) +{ + CountVoteResults(); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} === Vote results ==="); + for (int i = 0; i < numOptions; i++) + { + CPrintToChatAll("{CRIMSON}%d.{DEFAULT} {YELLOW}%s{DEFAULT}: %d.", i + 1, baseoptions[i], resultCount[i]); + } + return Plugin_Handled; +} + +public Action CommandRandomVoteEnd(int client, int args) +{ + voteEnabled = false; + CPrintToChatAll("{GREEN}[SM]{DEFAULT} Vote has ended."); + return Plugin_Handled; +} + +public Action CommandRandomVoteRevote(int client, int args) +{ + if (!IsValidClient(client) || !voteEnabled) return Plugin_Handled; + char voteTitle[64]; + Format(voteTitle, sizeof(voteTitle), "%s (random options)", question); + PrepareVoteMenu(client, voteTitle); + voteMenu[client].Display(client, 30); + return Plugin_Handled; +} + +public Action CommandRandomVoteClear(int client, int args) +{ + ClearVoteResults(); + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Vote results cleared."); + return Plugin_Handled; +} + +public int RandomizedVoteMenuHandler(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select: + { + if (!voteEnabled) return 0; + char info[32], displayBuffer[48]; + menu.GetItem(param2, info, sizeof(info), _, displayBuffer, sizeof(displayBuffer)); + int place = info[6] - 48; + CPrintToChat(param1, "{GREEN}[SM]{DEFAULT} Vote for {OLIVE}%s{DEFAULT} counted! Use {YELLOW}!rrevote{DEFAULT} to revote!", displayBuffer); +// CPrintToChatAdmins(ADMFLAG_ROOT, "%N chose %s", param1, info); +// CPrintToChatAdmins(ADMFLAG_ROOT, "%N set to place info[6] - 48 is %d", param1, place); + results[param1] = place; + } + case MenuAction_Cancel: + PrintToServer("Client %d's menu was cancelled for reason %d", param1, param2); + case MenuAction_End: + delete menu; + } + + return 0; +} + +void PrepareVoteMenu(int client, char[] title) +{ +// if (voteMenu[client] != null) return; commenting this out but I'm not sure it'll leak + voteMenu[client] = new Menu(RandomizedVoteMenuHandler); + voteMenu[client].SetTitle(title); + RandomizeOptions(); + for (int k = 0; k < numOptions; k++) + { + voteMenu[client].AddItem(options[k][1], options[k][0]); + } + voteMenu[client].ExitButton = false; +} + +void CountVoteResults() +{ + for (int i = 1; i <= MaxClients; i++) + { + int result = results[i]; + if (result == 0) continue; + resultCount[result - 1]++; + } +} + +void ClearVoteResults() +{ + for (int i = 1; i <= MaxClients; i++) + { + results[i] = 0; + } + for (int i = 0; i < 5; i++) + { + resultCount[i] = 0; + } +} + +stock bool IsValidClient(int client, bool aliveTest=false, bool botTest=true, bool rangeTest=true, + bool ingameTest=true) +{ + if (client > 4096) client = EntRefToEntIndex(client); + if (rangeTest && (client < 1 || client > MaxClients)) return false; + if (ingameTest && !IsClientInGame(client)) return false; + if (botTest && IsFakeClient(client)) return false; + if (GetEntProp(client, Prop_Send, "m_bIsCoaching")) return false; + if (aliveTest && !IsPlayerAlive(client)) return false; + return true; } \ No newline at end of file From 2cfab0afad23c0c35fa9edd8248133f97b72e112 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:36:57 -0800 Subject: [PATCH 06/29] GitIgnore Includes --- .gitignore | 85 ++++++++++++++++++------------------ scripting/include/.gitignore | 70 +++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 43 deletions(-) create mode 100644 scripting/include/.gitignore diff --git a/.gitignore b/.gitignore index 9db6807..6bc9e46 100644 --- a/.gitignore +++ b/.gitignore @@ -1,44 +1,43 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.out -*.app -*.sh -*.dat -*.exe - -# Editor Extras -.vscode/ - -# Folders -smac/ -scripting/compiled - -# Debug Filetypes -scripting/*.smx -scripting/*/*.smx -*.inc +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.out +*.app +*.sh +*.dat +*.exe + +# Editor Extras +.vscode/ + +# Folders +smac/ +scripting/compiled + +# Debug Filetypes +scripting/*.smx +scripting/*/*.smx scripting/spcomp \ No newline at end of file diff --git a/scripting/include/.gitignore b/scripting/include/.gitignore new file mode 100644 index 0000000..25fed29 --- /dev/null +++ b/scripting/include/.gitignore @@ -0,0 +1,70 @@ +# Ignore miscellaneous includes +admin.inc +adminmenu.inc +adt_array.inc +adt.inc +adt_stack.inc +adt_trie.inc +banning.inc +basecomm.inc +bitbuffer.inc +clientprefs.inc +clients.inc +commandfilters.inc +commandline.inc +console.inc +convars.inc +core.inc +cstrike.inc +datapack.inc +dbi.inc +entity.inc +entity_prop_stocks.inc +events.inc +files.inc +float.inc +functions.inc +geoip.inc +halflife.inc +handles.inc +helpers.inc +keyvalues.inc +lang.inc +logging.inc +mapchooser.inc +menus.inc +nextmap.inc +profiler.inc +protobuf.inc +regex.inc +scriptstuff.sh +sdkhooks.inc +sdktools_client.inc +sdktools_engine.inc +sdktools_entinput.inc +sdktools_entoutput.inc +sdktools_functions.inc +sdktools_gamerules.inc +sdktools_hooks.inc +sdktools.inc +sdktools_sound.inc +sdktools_stocks.inc +sdktools_stringtables.inc +sdktools_tempents.inc +sdktools_tempents_stocks.inc +sdktools_trace.inc +sdktools_variant_t.inc +sdktools_voice.inc +sorting.inc +sourcemod.inc +string.inc +testing.inc +textparse.inc +tf2.inc +tf2_stocks.inc +timers.inc +topmenus.inc +usermessages.inc +vector.inc +version.inc +version_auto.inc \ No newline at end of file From dcd5a55cd512e7d21a5482b01bbba73de9ce1ea8 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:45:44 -0800 Subject: [PATCH 07/29] Remove SM includes from tracking --- scripting/include/admin.inc | 775 ------------ scripting/include/adminmenu.inc | 152 --- scripting/include/adt.inc | 40 - scripting/include/adt_array.inc | 455 ------- scripting/include/adt_stack.inc | 240 ---- scripting/include/adt_trie.inc | 317 ----- scripting/include/banning.inc | 156 --- scripting/include/basecomm.inc | 109 -- scripting/include/bitbuffer.inc | 470 ------- scripting/include/clientprefs.inc | 282 ----- scripting/include/clients.inc | 811 ------------ scripting/include/commandfilters.inc | 161 --- scripting/include/commandline.inc | 86 -- scripting/include/console.inc | 668 ---------- scripting/include/convars.inc | 498 -------- scripting/include/core.inc | 317 ----- scripting/include/cstrike.inc | 458 ------- scripting/include/datapack.inc | 225 ---- scripting/include/dbi.inc | 1066 ---------------- scripting/include/entity.inc | 759 ----------- scripting/include/entity_prop_stocks.inc | 594 --------- scripting/include/events.inc | 340 ----- scripting/include/files.inc | 618 --------- scripting/include/float.inc | 436 ------- scripting/include/functions.inc | 541 -------- scripting/include/geoip.inc | 102 -- scripting/include/halflife.inc | 706 ----------- scripting/include/handles.inc | 97 -- scripting/include/helpers.inc | 279 ---- scripting/include/keyvalues.inc | 707 ----------- scripting/include/lang.inc | 134 -- scripting/include/logging.inc | 135 -- scripting/include/mapchooser.inc | 159 --- scripting/include/menus.inc | 1121 ----------------- scripting/include/nextmap.inc | 82 -- scripting/include/profiler.inc | 97 -- scripting/include/protobuf.inc | 572 --------- scripting/include/regex.inc | 275 ---- scripting/include/sdkhooks.inc | 412 ------ scripting/include/sdktools.inc | 229 ---- scripting/include/sdktools_client.inc | 50 - scripting/include/sdktools_engine.inc | 66 - scripting/include/sdktools_entinput.inc | 51 - scripting/include/sdktools_entoutput.inc | 108 -- scripting/include/sdktools_functions.inc | 352 ------ scripting/include/sdktools_gamerules.inc | 197 --- scripting/include/sdktools_hooks.inc | 96 -- scripting/include/sdktools_sound.inc | 725 ----------- scripting/include/sdktools_stocks.inc | 75 -- scripting/include/sdktools_stringtables.inc | 180 --- scripting/include/sdktools_tempents.inc | 232 ---- .../include/sdktools_tempents_stocks.inc | 443 ------- scripting/include/sdktools_trace.inc | 368 ------ scripting/include/sdktools_variant_t.inc | 93 -- scripting/include/sdktools_voice.inc | 122 -- scripting/include/sorting.inc | 169 --- scripting/include/sourcemod.inc | 681 ---------- scripting/include/string.inc | 548 -------- scripting/include/testing.inc | 72 -- scripting/include/textparse.inc | 243 ---- scripting/include/tf2.inc | 493 -------- scripting/include/tf2_stocks.inc | 637 ---------- scripting/include/timers.inc | 209 --- scripting/include/topmenus.inc | 434 ------- scripting/include/usermessages.inc | 257 ---- scripting/include/vector.inc | 179 --- scripting/include/version.inc | 49 - scripting/include/version_auto.inc | 15 - 68 files changed, 22825 deletions(-) delete mode 100644 scripting/include/admin.inc delete mode 100644 scripting/include/adminmenu.inc delete mode 100644 scripting/include/adt.inc delete mode 100644 scripting/include/adt_array.inc delete mode 100644 scripting/include/adt_stack.inc delete mode 100644 scripting/include/adt_trie.inc delete mode 100644 scripting/include/banning.inc delete mode 100644 scripting/include/basecomm.inc delete mode 100644 scripting/include/bitbuffer.inc delete mode 100644 scripting/include/clientprefs.inc delete mode 100644 scripting/include/clients.inc delete mode 100644 scripting/include/commandfilters.inc delete mode 100644 scripting/include/commandline.inc delete mode 100644 scripting/include/console.inc delete mode 100644 scripting/include/convars.inc delete mode 100644 scripting/include/core.inc delete mode 100644 scripting/include/cstrike.inc delete mode 100644 scripting/include/datapack.inc delete mode 100644 scripting/include/dbi.inc delete mode 100644 scripting/include/entity.inc delete mode 100644 scripting/include/entity_prop_stocks.inc delete mode 100644 scripting/include/events.inc delete mode 100644 scripting/include/files.inc delete mode 100644 scripting/include/float.inc delete mode 100644 scripting/include/functions.inc delete mode 100644 scripting/include/geoip.inc delete mode 100644 scripting/include/halflife.inc delete mode 100644 scripting/include/handles.inc delete mode 100644 scripting/include/helpers.inc delete mode 100644 scripting/include/keyvalues.inc delete mode 100644 scripting/include/lang.inc delete mode 100644 scripting/include/logging.inc delete mode 100644 scripting/include/mapchooser.inc delete mode 100644 scripting/include/menus.inc delete mode 100644 scripting/include/nextmap.inc delete mode 100644 scripting/include/profiler.inc delete mode 100644 scripting/include/protobuf.inc delete mode 100644 scripting/include/regex.inc delete mode 100644 scripting/include/sdkhooks.inc delete mode 100644 scripting/include/sdktools.inc delete mode 100644 scripting/include/sdktools_client.inc delete mode 100644 scripting/include/sdktools_engine.inc delete mode 100644 scripting/include/sdktools_entinput.inc delete mode 100644 scripting/include/sdktools_entoutput.inc delete mode 100644 scripting/include/sdktools_functions.inc delete mode 100644 scripting/include/sdktools_gamerules.inc delete mode 100644 scripting/include/sdktools_hooks.inc delete mode 100644 scripting/include/sdktools_sound.inc delete mode 100644 scripting/include/sdktools_stocks.inc delete mode 100644 scripting/include/sdktools_stringtables.inc delete mode 100644 scripting/include/sdktools_tempents.inc delete mode 100644 scripting/include/sdktools_tempents_stocks.inc delete mode 100644 scripting/include/sdktools_trace.inc delete mode 100644 scripting/include/sdktools_variant_t.inc delete mode 100644 scripting/include/sdktools_voice.inc delete mode 100644 scripting/include/sorting.inc delete mode 100644 scripting/include/sourcemod.inc delete mode 100644 scripting/include/string.inc delete mode 100644 scripting/include/testing.inc delete mode 100644 scripting/include/textparse.inc delete mode 100644 scripting/include/tf2.inc delete mode 100644 scripting/include/tf2_stocks.inc delete mode 100644 scripting/include/timers.inc delete mode 100644 scripting/include/topmenus.inc delete mode 100644 scripting/include/usermessages.inc delete mode 100644 scripting/include/vector.inc delete mode 100644 scripting/include/version.inc delete mode 100644 scripting/include/version_auto.inc diff --git a/scripting/include/admin.inc b/scripting/include/admin.inc deleted file mode 100644 index 17d2c99..0000000 --- a/scripting/include/admin.inc +++ /dev/null @@ -1,775 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _admin_included - #endinput -#endif -#define _admin_included - -/** - * Access levels (flags) for admins. - */ -enum AdminFlag -{ - Admin_Reservation = 0, /**< Reserved slot */ - Admin_Generic, /**< Generic admin abilities */ - Admin_Kick, /**< Kick another user */ - Admin_Ban, /**< Ban another user */ - Admin_Unban, /**< Unban another user */ - Admin_Slay, /**< Slay/kill/damage another user */ - Admin_Changemap, /**< Change the map */ - Admin_Convars, /**< Change basic convars */ - Admin_Config, /**< Change configuration */ - Admin_Chat, /**< Special chat privileges */ - Admin_Vote, /**< Special vote privileges */ - Admin_Password, /**< Set a server password */ - Admin_RCON, /**< Use RCON */ - Admin_Cheats, /**< Change sv_cheats and use its commands */ - Admin_Root, /**< All access by default */ - Admin_Custom1, /**< First custom flag type */ - Admin_Custom2, /**< Second custom flag type */ - Admin_Custom3, /**< Third custom flag type */ - Admin_Custom4, /**< Fourth custom flag type */ - Admin_Custom5, /**< Fifth custom flag type */ - Admin_Custom6, /**< Sixth custom flag type */ - /* --- */ -}; - -#define AdminFlags_TOTAL 21 /**< Total number of admin flags */ - -/** - * @section Bitwise values definitions for admin flags. - */ -#define ADMFLAG_RESERVATION (1<<0) /**< Convenience macro for Admin_Reservation as a FlagBit */ -#define ADMFLAG_GENERIC (1<<1) /**< Convenience macro for Admin_Generic as a FlagBit */ -#define ADMFLAG_KICK (1<<2) /**< Convenience macro for Admin_Kick as a FlagBit */ -#define ADMFLAG_BAN (1<<3) /**< Convenience macro for Admin_Ban as a FlagBit */ -#define ADMFLAG_UNBAN (1<<4) /**< Convenience macro for Admin_Unban as a FlagBit */ -#define ADMFLAG_SLAY (1<<5) /**< Convenience macro for Admin_Slay as a FlagBit */ -#define ADMFLAG_CHANGEMAP (1<<6) /**< Convenience macro for Admin_Changemap as a FlagBit */ -#define ADMFLAG_CONVARS (1<<7) /**< Convenience macro for Admin_Convars as a FlagBit */ -#define ADMFLAG_CONFIG (1<<8) /**< Convenience macro for Admin_Config as a FlagBit */ -#define ADMFLAG_CHAT (1<<9) /**< Convenience macro for Admin_Chat as a FlagBit */ -#define ADMFLAG_VOTE (1<<10) /**< Convenience macro for Admin_Vote as a FlagBit */ -#define ADMFLAG_PASSWORD (1<<11) /**< Convenience macro for Admin_Password as a FlagBit */ -#define ADMFLAG_RCON (1<<12) /**< Convenience macro for Admin_RCON as a FlagBit */ -#define ADMFLAG_CHEATS (1<<13) /**< Convenience macro for Admin_Cheats as a FlagBit */ -#define ADMFLAG_ROOT (1<<14) /**< Convenience macro for Admin_Root as a FlagBit */ -#define ADMFLAG_CUSTOM1 (1<<15) /**< Convenience macro for Admin_Custom1 as a FlagBit */ -#define ADMFLAG_CUSTOM2 (1<<16) /**< Convenience macro for Admin_Custom2 as a FlagBit */ -#define ADMFLAG_CUSTOM3 (1<<17) /**< Convenience macro for Admin_Custom3 as a FlagBit */ -#define ADMFLAG_CUSTOM4 (1<<18) /**< Convenience macro for Admin_Custom4 as a FlagBit */ -#define ADMFLAG_CUSTOM5 (1<<19) /**< Convenience macro for Admin_Custom5 as a FlagBit */ -#define ADMFLAG_CUSTOM6 (1<<20) /**< Convenience macro for Admin_Custom6 as a FlagBit */ - -/** - * @endsection - */ - -/** - * @section Hardcoded authentication methods - */ -#define AUTHMETHOD_STEAM "steam" /**< SteamID based authentication */ -#define AUTHMETHOD_IP "ip" /**< IP based authentication */ -#define AUTHMETHOD_NAME "name" /**< Name based authentication */ - -/** - * @endsection - */ - -/** - * Access override types. - */ -enum OverrideType -{ - Override_Command = 1, /**< Command */ - Override_CommandGroup, /**< Command group */ -}; - -/** - * Access override rules. - */ -enum OverrideRule -{ - Command_Deny = 0, - Command_Allow = 1, -}; - -/** - * DEPRECATED, do not use. - */ -enum ImmunityType -{ - Immunity_Default = 1, /**< Deprecated. */ - Immunity_Global, /**< Deprecated. */ -}; - -/** - * Identifies a unique entry in the group permissions cache. These are not Handles. - */ -enum GroupId -{ - INVALID_GROUP_ID = -1, /**< An invalid/non-existent group */ -}; - -/** - * Identifies a unique entry in the admin permissions cache. These are not Handles. - */ -enum AdminId -{ - INVALID_ADMIN_ID = -1, /**< An invalid/non-existent admin */ -}; - -/** - * Methods of computing access permissions. - */ -enum AdmAccessMode -{ - Access_Real, /**< Access the user has inherently */ - Access_Effective, /**< Access the user has from their groups */ -}; - -/** - * Represents the various cache regions. - */ -enum AdminCachePart -{ - AdminCache_Overrides = 0, /**< Global overrides */ - AdminCache_Groups = 1, /**< All groups (automatically invalidates admins too) */ - AdminCache_Admins = 2, /**< All admins */ -}; - -methodmap AdminId { - // Retrieves an admin's user name as made with CreateAdmin(). - // - // @note This function can return UTF-8 strings, and will safely chop UTF-8 strings. - // - // @param name String buffer to store name. - // @param maxlength Maximum size of string buffer. - // @return Number of bytes written. - public native void GetUsername(char[] name, int maxlength); - - // Binds an admin to an identity for fast lookup later on. The bind must be unique. - // - // @param authMethod Auth method to use, predefined or from RegisterAuthIdentType(). - // @param ident String containing the arbitrary, unique identity. - // @return True on success, false if the auth method was not found, - // ident was already taken, or ident invalid for auth method. - public native bool BindIdentity(const char[] authMethod, const char[] ident); - - // Sets whether or not a flag is enabled on an admin. - // - // @param flag Admin flag to use. - // @param enabled True to enable, false to disable. - public native void SetFlag(AdminFlag flag, bool enabled); - - // Returns whether or not a flag is enabled on an admin. - // - // @param flag Admin flag to use. - // @param mode Access mode to check. - // @return True if enabled, false otherwise. - public native bool HasFlag(AdminFlag flag, AdmAccessMode mode=Access_Effective); - - // Returns the bitstring of access flags on an admin. - // - // @param mode Access mode to use. - // @return A bitstring containing which flags are enabled. - public native int GetFlags(AdmAccessMode mode); - - // Adds a group to an admin's inherited group list. Any flags the group has - // will be added to the admin's effective flags. - // - // @param gid GroupId index of the group. - // @return True on success, false on invalid input or duplicate membership. - public native bool InheritGroup(GroupId gid); - - // Returns group information from an admin. - // - // @param index Group number to retrieve, from 0 to N-1, where N - // is the value of the GroupCount property. - // @param name Buffer to store the group's name. - // Note: This will safely chop UTF-8 strings. - // @param maxlength Maximum size of the output name buffer. - // @return A GroupId index and a name pointer, or - // INVALID_GROUP_ID and NULL if an error occurred. - public native GroupId GetGroup(int index, const char[] name, int maxlength); - - // Sets a password on an admin. - // - // @param password String containing the password. - public native void SetPassword(const char[] password); - - // Gets an admin's password. - // - // @param buffer Optional buffer to store the admin's password. - // @param maxlength Maximum size of the output name buffer. - // Note: This will safely chop UTF-8 strings. - // @return True if there was a password set, false otherwise. - public native bool GetPassword(char[] buffer="", int maxlength=0); - - // Tests whether one admin can target another. - // - // The heuristics for this check are as follows: - // 0. If the targeting AdminId is INVALID_ADMIN_ID, targeting fails. - // 1. If the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds. - // 2. If the targeted AdminId is the same as the targeting AdminId, - // (self) targeting succeeds. - // 3. If the targeting admin is root, targeting succeeds. - // 4. If the targeted admin has access higher (as interpreted by - // (sm_immunity_mode) than the targeting admin, then targeting fails. - // 5. If the targeted admin has specific immunity from the - // targeting admin via group immunities, targeting fails. - // 6. Targeting succeeds. - // - // @param target Target admin (may be INVALID_ADMIN_ID). - // @return True if targetable, false if immune. - public native bool CanTarget(AdminId other); - - // The number of groups of which this admin is a member. - property int GroupCount { - public native get(); - } - - // Immunity level used for targetting. - property int ImmunityLevel { - public native get(); - public native set(int level); - } -} - -methodmap GroupId { - // Gets whether or not a flag is enabled on a group's flag set. - // - // @param flag Admin flag to retrieve. - // @return True if enabled, false otherwise, - public native bool HasFlag(AdminFlag flag); - - // Adds or removes a flag from a group's flag set. - // - // @param flag Admin flag to toggle. - // @param enabled True to set the flag, false to unset/disable. - public native void SetFlag(AdminFlag flag, bool enabled); - - // Returns the flag set that is added to users from this group. - // - // @return Bitstring containing the flags enabled. - public native int GetFlags(); - - // Returns a group that this group is immune to given an index. - // - // @param number Index from 0 to N-1, from GroupImmunitiesCount. - // @return GroupId that this group is immune to, or INVALID_GROUP_ID on failure. - public native GroupId GetGroupImmunity(int index); - - // Adds immunity to a specific group. - // - // @param other Group id to receive immunity to. - public native void AddGroupImmunity(GroupId other); - - // Retrieves a group-specific command override. - // - // @param name String containing command name (case sensitive). - // @param type Override type (specific command or group). - // @param rule Optional pointer to store allow/deny setting. - // @return True if an override exists, false otherwise. - public native bool GetCommandOverride(const char[] name, OverrideType type, OverrideRule &rule); - - // Adds a group-specific override type. - // - // @param name String containing command name (case sensitive). - // @param type Override type (specific command or group). - // @param rule Override allow/deny setting. - public native void AddCommandOverride(const char[] name, OverrideType type, OverrideRule rule); - - // Number of specific group immunities - property int GroupImmunitiesCount { - public native get(); - } - - // Immunity level used for targetting. - property int ImmunityLevel { - public native get(); - public native set(int level); - } -} - -/** - * Called when part of the cache needs to be rebuilt. - * - * @param part Part of the admin cache to rebuild. - */ -forward void OnRebuildAdminCache(AdminCachePart part); - -/** - * Tells the admin system to dump a portion of the cache. - * - * @param part Part of the cache to dump. Specifying groups also dumps admins. - * @param rebuild If true, the rebuild forwards will fire. - */ -native void DumpAdminCache(AdminCachePart part, bool rebuild); - -/** - * Adds a global command flag override. Any command registered with this name - * will assume the new flag. This is applied retroactively as well. - * - * @param cmd String containing command name (case sensitive). - * @param type Override type (specific command or group). - * @param flags New admin flag. - */ -native void AddCommandOverride(const char[] cmd, OverrideType type, int flags); - -/** - * Returns a command override. - * - * @param cmd String containing command name (case sensitive). - * @param type Override type (specific command or group). - * @param flags By-reference cell to store the flag (undefined if not found). - * @return True if there is an override, false otherwise. - */ -native bool GetCommandOverride(const char[] cmd, OverrideType type, int &flags); - -/** - * Unsets a command override. - * - * @param cmd String containing command name (case sensitive). - * @param type Override type (specific command or group). - */ -native void UnsetCommandOverride(const char[] cmd, OverrideType type); - -/** - * Adds a new group. Name must be unique. - * - * @param group_name String containing the group name. - * @return A new group id, INVALID_GROUP_ID if it already exists. - */ -native GroupId CreateAdmGroup(const char[] group_name); - -/** - * Finds a group by name. - * - * @param group_name String containing the group name. - * @return A group id, or INVALID_GROUP_ID if not found. - */ -native GroupId FindAdmGroup(const char[] group_name); - -/** - * Adds or removes a flag from a group's flag set. - * @note These are called "add flags" because they add to a user's flags. - * - * @param id Group id. - * @param flag Admin flag to toggle. - * @param enabled True to set the flag, false to unset/disable. - */ -native void SetAdmGroupAddFlag(GroupId id, AdminFlag flag, bool enabled); - -/** - * Gets the set value of an add flag on a group's flag set. - * @note These are called "add flags" because they add to a user's flags. - * - * @param id Group id. - * @param flag Admin flag to retrieve. - * @return True if enabled, false otherwise, - */ -native bool GetAdmGroupAddFlag(GroupId id, AdminFlag flag); - -/** - * Returns the flag set that is added to a user from their group. - * @note These are called "add flags" because they add to a user's flags. - * - * @param id GroupId of the group. - * @return Bitstring containing the flags enabled. - */ -native int GetAdmGroupAddFlags(GroupId id); - -/** - * @deprecated Functionality removed. - */ -#pragma deprecated Use SetAdmGroupImmunityLevel() instead. -native void SetAdmGroupImmunity(GroupId id, ImmunityType type, bool enabled); - -/** - * @deprecated Functionality removed. - */ -#pragma deprecated Use GetAdmGroupImmunityLevel() instead. -native bool GetAdmGroupImmunity(GroupId id, ImmunityType type); - -/** - * Adds immunity to a specific group. - * - * @param id Group id. - * @param other_id Group id to receive immunity to. - */ -native void SetAdmGroupImmuneFrom(GroupId id, GroupId other_id); - -/** - * Returns the number of specific group immunities. - * - * @param id Group id. - * @return Number of group immunities. - */ -native int GetAdmGroupImmuneCount(GroupId id); - -/** - * Returns a group that this group is immune to given an index. - * - * @param id Group id. - * @param number Index from 0 to N-1, from GetAdmGroupImmuneCount(). - * @return GroupId that this group is immune to, or INVALID_GROUP_ID on failure. - */ -native GroupId GetAdmGroupImmuneFrom(GroupId id, int number); - -/** - * Adds a group-specific override type. - * - * @param id Group id. - * @param name String containing command name (case sensitive). - * @param type Override type (specific command or group). - * @param rule Override allow/deny setting. - */ -native void AddAdmGroupCmdOverride(GroupId id, const char[] name, OverrideType type, OverrideRule rule); - -/** - * Retrieves a group-specific command override. - * - * @param id Group id. - * @param name String containing command name (case sensitive). - * @param type Override type (specific command or group). - * @param rule Optional pointer to store allow/deny setting. - * @return True if an override exists, false otherwise. - */ -native bool GetAdmGroupCmdOverride(GroupId id, const char[] name, OverrideType type, OverrideRule &rule); - -/** - * Registers an authentication identity type. You normally never need to call this except for - * very specific systems. - * - * @param name Codename to use for your authentication type. - */ -native void RegisterAuthIdentType(const char[] name); - -/** - * Creates a new admin entry in the permissions cache. - * - * @param name Name for this entry (does not have to be unique). - * Specify an empty string for an anonymous admin. - */ -native AdminId CreateAdmin(const char[] name=""); - -/** - * Retrieves an admin's user name as made with CreateAdmin(). - * - * @note This function can return UTF-8 strings, and will safely chop UTF-8 strings. - * - * @param id AdminId of the admin. - * @param name String buffer to store name. - * @param maxlength Maximum size of string buffer. - * @return Number of bytes written. - */ -native int GetAdminUsername(AdminId id, char[] name, int maxlength); - -/** - * Binds an admin to an identity for fast lookup later on. The bind must be unique. - * - * @param id AdminId of the admin. - * @param auth Auth method to use, predefined or from RegisterAuthIdentType(). - * @param ident String containing the arbitrary, unique identity. - * @return True on success, false if the auth method was not found, - * ident was already taken, or ident invalid for auth method. - */ -native bool BindAdminIdentity(AdminId id, const char[] auth, const char[] ident); - -/** - * Sets whether or not a flag is enabled on an admin. - * - * @param id AdminId index of the admin. - * @param flag Admin flag to use. - * @param enabled True to enable, false to disable. - */ -native void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled); - -/** - * Returns whether or not a flag is enabled on an admin. - * - * @param id AdminId index of the admin. - * @param flag Admin flag to use. - * @param mode Access mode to check. - * @return True if enabled, false otherwise. - */ -native bool GetAdminFlag(AdminId id, AdminFlag flag, AdmAccessMode mode=Access_Effective); - -/** - * Returns the bitstring of access flags on an admin. - * - * @param id AdminId index of the admin. - * @param mode Access mode to use. - * @return A bitstring containing which flags are enabled. - */ -native int GetAdminFlags(AdminId id, AdmAccessMode mode); - -/** - * Adds a group to an admin's inherited group list. Any flags the group has - * will be added to the admin's effective flags. - * - * @param id AdminId index of the admin. - * @param gid GroupId index of the group. - * @return True on success, false on invalid input or duplicate membership. - */ -native bool AdminInheritGroup(AdminId id, GroupId gid); - -/** - * Returns the number of groups this admin is a member of. - * - * @param id AdminId index of the admin. - * @return Number of groups this admin is a member of. - */ -native int GetAdminGroupCount(AdminId id); - -/** - * Returns group information from an admin. - * - * @param id AdminId index of the admin. - * @param index Group number to retrieve, from 0 to N-1, where N - * is the value of GetAdminGroupCount(id). - * @param name Buffer to store the group's name. - * Note: This will safely chop UTF-8 strings. - * @param maxlength Maximum size of the output name buffer. - * @return A GroupId index and a name pointer, or - * INVALID_GROUP_ID and NULL if an error occurred. - */ -native GroupId GetAdminGroup(AdminId id, int index, const char[] name, int maxlength); - -/** - * Sets a password on an admin. - * - * @param id AdminId index of the admin. - * @param password String containing the password. - */ -native void SetAdminPassword(AdminId id, const char[] password); - -/** - * Gets an admin's password. - * - * @param id AdminId index of the admin. - * @param buffer Optional buffer to store the admin's password. - * @param maxlength Maximum size of the output name buffer. - * Note: This will safely chop UTF-8 strings. - * @return True if there was a password set, false otherwise. - */ -native bool GetAdminPassword(AdminId id, char[] buffer="", int maxlength=0); - -/** - * Attempts to find an admin by an auth method and an identity. - * - * @param auth Auth method to try. - * @param identity Identity string to look up. - * @return An AdminId index if found, INVALID_ADMIN_ID otherwise. - */ -native AdminId FindAdminByIdentity(const char[] auth, const char[] identity); - -/** - * Removes an admin entry from the cache. - * - * @note This will remove any bindings to a specific user. - * - * @param id AdminId index to remove/invalidate. - * @return True on success, false otherwise. - */ -native bool RemoveAdmin(AdminId id); - -/** - * Converts a flag bit string to a bit array. - * - * @param bits Bit string containing the flags. - * @param array Array to write the flags to. Enabled flags will be 'true'. - * @param maxSize Maximum number of flags the array can store. - * @return Number of flags written. - */ -native int FlagBitsToBitArray(int bits, bool[] array, int maxSize); - -/** - * Converts a flag array to a bit string. - * - * @param array Array containing true or false for each AdminFlag. - * @param maxSize Maximum size of the flag array. - * @return A bit string composed of the array bits. - */ -native int FlagBitArrayToBits(const bool[] array, int maxSize); - -/** - * Converts an array of flags to bits. - * - * @param array Array containing flags that are enabled. - * @param numFlags Number of flags in the array. - * @return A bit string composed of the array flags. - */ -native int FlagArrayToBits(const AdminFlag[] array, int numFlags); - -/** - * Converts a bit string to an array of flags. - * - * @param bits Bit string containing the flags. - * @param array Output array to write flags. - * @param maxSize Maximum size of the flag array. - * @return Number of flags written. - */ -native int FlagBitsToArray(int bits, AdminFlag[] array, int maxSize); - -/** - * Finds a flag by its string name. - * - * @param name Flag name (like "kick"), case sensitive. - * @param flag Variable to store flag in. - * @return True on success, false if not found. - */ -native bool FindFlagByName(const char[] name, AdminFlag &flag); - -/** - * Finds a flag by a given character. - * - * @param c Flag ASCII character/token. - * @param flag Variable to store flag in. - * @return True on success, false if not found. - */ -native bool FindFlagByChar(int c, AdminFlag &flag); - -/** - * Finds the flag char for a given admin flag. - * - * @param flag Flag to look up. - * @param c Variable to store flag char. - * @return True on success, false if not found. - */ -native bool FindFlagChar(AdminFlag flag, int &c); - -/** - * Converts a string of flag characters to a bit string. - * - * @param flags Flag ASCII string. - * @param numchars Optional variable to store the number of bytes read. - * @return Bit string of ADMFLAG values. - */ -native int ReadFlagString(const char[] flags, int &numchars=0); - -/** - * Tests whether one admin can target another. - * - * The heuristics for this check are as follows: - * 0. If the targeting AdminId is INVALID_ADMIN_ID, targeting fails. - * 1. If the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds. - * 2. If the targeted AdminId is the same as the targeting AdminId, - * (self) targeting succeeds. - * 3. If the targeting admin is root, targeting succeeds. - * 4. If the targeted admin has access higher (as interpreted by - * (sm_immunity_mode) than the targeting admin, then targeting fails. - * 5. If the targeted admin has specific immunity from the - * targeting admin via group immunities, targeting fails. - * 6. Targeting succeeds. - * - * @param admin Admin doing the targetting (may be INVALID_ADMIN_ID). - * @param target Target admin (may be INVALID_ADMIN_ID). - * @return True if targetable, false if immune. - */ -native bool CanAdminTarget(AdminId admin, AdminId target); - -/** - * Creates an admin auth method. This does not need to be called more than once - * per method, ever. - * - * @param method Name of the authentication method. - * @return True on success, false on failure. - */ -native bool CreateAuthMethod(const char[] method); - -/** - * Sets a group's immunity level. - * - * @param gid Group Id. - * @param level Immunity level value. - * @return Old immunity level value. - */ -native int SetAdmGroupImmunityLevel(GroupId gid, int level); - -/** - * Gets a group's immunity level (defaults to 0). - * - * @param gid Group Id. - * @return Immunity level value. - */ -native int GetAdmGroupImmunityLevel(GroupId gid); - -/** - * Sets an admin's immunity level. - * - * @param id Admin Id. - * @param level Immunity level value. - * @return Old immunity level value. - */ -native int SetAdminImmunityLevel(AdminId id, int level); - -/** - * Gets an admin's immunity level. - * - * @param id Admin Id. - * @return Immunity level value. - */ -native int GetAdminImmunityLevel(AdminId id); - -/** - * Converts a flag to its single bit. - * - * @param flag Flag to convert. - * @return Bit representation of the flag. - */ -stock int FlagToBit(AdminFlag flag) -{ - return (1 << view_as(flag)); -} - -/** - * Converts a bit to an AdminFlag. - * - * @param bit Bit to convert. - * @param flag Stores the converted flag by reference. - * @return True on success, false otherwise. - */ -stock bool BitToFlag(int bit, AdminFlag &flag) -{ - AdminFlag array[1]; - - if (FlagBitsToArray(bit, array, 1)) - { - flag = array[0]; - return true; - } - - return false; -} diff --git a/scripting/include/adminmenu.inc b/scripting/include/adminmenu.inc deleted file mode 100644 index a3cb617..0000000 --- a/scripting/include/adminmenu.inc +++ /dev/null @@ -1,152 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _adminmenu_included - #endinput -#endif -#define _adminmenu_included - -/* Decide whether topmenus should be required */ -#if !defined REQUIRE_PLUGIN - #if defined REQUIRE_EXTENSIONS - #define TEMP_REQUIRE_EXTENSIONS - #undef REQUIRE_EXTENSIONS - #endif -#endif - -#include - -/* Restore old REQUIRE_EXTENSIONS value if necessary */ -#if defined TEMP_REQUIRE_EXTENSIONS - #define REQUIRE_EXTENSIONS - #undef TEMP_REQUIRE_EXTENSIONS -#endif - -/** Category for player commands. */ -#define ADMINMENU_PLAYERCOMMANDS "PlayerCommands" -/** Category for server commands. */ -#define ADMINMENU_SERVERCOMMANDS "ServerCommands" -/** Category for voting commands. */ -#define ADMINMENU_VOTINGCOMMANDS "VotingCommands" - -/** - * Called when the admin menu is created and 3rd party plugins can grab - * the Handle or add categories. - * - * @param topmenu Handle to the admin menu's TopMenu. - */ -forward void OnAdminMenuCreated(Handle topmenu); - -/** - * Called when the admin menu is ready to have items added. - * - * @param topmenu Handle to the admin menu's TopMenu. - */ -forward void OnAdminMenuReady(Handle topmenu); - -/** - * Retrieves the Handle to the admin top menu. - * - * @return Handle to the admin menu's TopMenu, - * or INVALID_HANDLE if not created yet. - */ -native TopMenu GetAdminTopMenu(); - -/** - * Adds targets to an admin menu. - * - * Each client is displayed as: name (userid) - * Each item contains the userid as a string for its info. - * - * @param menu Menu Handle. - * @param source_client Source client, or 0 to ignore immunity. - * @param in_game_only True to only select in-game players. - * @param alive_only True to only select alive players. - * @return Number of clients added. - */ -native int AddTargetsToMenu(Handle menu, - int source_client, - bool in_game_only=true, - bool alive_only=false); - -/** - * Adds targets to an admin menu. - * - * Each client is displayed as: name (userid) - * Each item contains the userid as a string for its info. - * - * @param menu Menu Handle. - * @param source_client Source client, or 0 to ignore immunity. - * @param flags COMMAND_FILTER flags from commandfilters.inc. - * @return Number of clients added. - */ -native int AddTargetsToMenu2(Handle menu, int source_client, int flags); - -/** - * Re-displays the admin menu to a client after selecting an item. - * Auto-aborts if the Handle is invalid. - * - * @param topmenu TopMenu Handle. - * @param client Client index. - * @return True on success, false on failure. - */ -stock bool RedisplayAdminMenu(Handle topmenu, int client) -{ - if (topmenu == INVALID_HANDLE) - { - return false; - } - - return DisplayTopMenu(topmenu, client, TopMenuPosition_LastCategory); -} - -/* DO NOT EDIT BELOW THIS LINE */ - -public SharedPlugin __pl_adminmenu = -{ - name = "adminmenu", - file = "adminmenu.smx", -#if defined REQUIRE_PLUGIN - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_PLUGIN -public void __pl_adminmenu_SetNTVOptional() -{ - MarkNativeAsOptional("GetAdminTopMenu"); - MarkNativeAsOptional("AddTargetsToMenu"); - MarkNativeAsOptional("AddTargetsToMenu2"); -} -#endif diff --git a/scripting/include/adt.inc b/scripting/include/adt.inc deleted file mode 100644 index 1727fc9..0000000 --- a/scripting/include/adt.inc +++ /dev/null @@ -1,40 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _adt_included - #endinput -#endif -#define _adt_included - -#include -#include -#include diff --git a/scripting/include/adt_array.inc b/scripting/include/adt_array.inc deleted file mode 100644 index 043898d..0000000 --- a/scripting/include/adt_array.inc +++ /dev/null @@ -1,455 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _adt_array_included - #endinput -#endif -#define _adt_array_included - -/** - * Given a maximum string size (including the null terminator), - * returns the number of cells required to fit that string. - * - * @param size Number of bytes. - * @return Minimum number of cells required to fit the byte count. - */ -stock int ByteCountToCells(int size) -{ - if (!size) - return 1; - return (size + 3) / 4; -} - -methodmap ArrayList < Handle { - // Creates a dynamic global cell array. While slower than a normal array, - // it can be used globally AND dynamically, which is otherwise impossible. - // - // The contents of the array are uniform; i.e. storing a string at index X - // and then retrieving it as an integer is NOT the same as StringToInt()! - // The "blocksize" determines how many cells each array slot has; it cannot - // be changed after creation. - // - // @param blocksize The number of cells each member of the array can - // hold. For example, 32 cells is equivalent to: - // new Array[X][32] - // @param startsize Initial size of the array. Note that data will - // NOT be auto-initialized. - // @return New Handle to the array object. - public native ArrayList(int blocksize=1, int startsize=0); - - // Clears an array of all entries. This is the same as Resize(0). - public native void Clear(); - - // Clones an array, returning a new handle with the same size and data. - // This should NOT be confused with CloneHandle. This is a completely new - // handle with the same data but no relation to the original. It should - // closed when no longer needed. - // - // @return New handle to the cloned array object - public native ArrayList Clone(); - - // Resizes an array. If the size is smaller than the current size, the - // array is truncated. If the size is larger than the current size, - // the data at the additional indexes will not be initialized. - // - // @param newsize New size. - public native void Resize(int newsize); - - // Pushes a value onto the end of an array, adding a new index. - // - // This may safely be used even if the array has a blocksize greater - // than 1. - // - // @param value Value to push. - // @return Index of the new entry. - // @error Invalid Handle or out of memory. - // - public native int Push(any value); - - // Pushes a string onto the end of an array, truncating it if it is too big. - // - // @param value String to push. - // @return Index of the new entry. - public native int PushString(const char[] value); - - // Pushes an array of cells onto the end of an array. The cells - // are pushed as a block (i.e. the entire array sits at the index), - // rather than pushing each cell individually. - // - // @param values Block of values to copy. - // @param size If not set, the number of elements copied from the array - // will be equal to the blocksize. If set higher than the - // blocksize, the operation will be truncated. - // @return Index of the new entry. - public native int PushArray(const any[] values, int size=-1); - - // Retrieves a cell value from an array. - // - // @param index Index in the array. - // @param block Optionally specify which block to read from - // (useful if the blocksize > 0). - // @param asChar Optionally read as a byte instead of a cell. - // @return Value read. - // @error Invalid index. - public native any Get(int index, int block=0, bool asChar=false); - - // Retrieves a string value from an array. - // - // @param index Index in the array. - // @param buffer Buffer to copy to. - // @param maxlength Maximum size of the buffer. - // @return Number of characters copied. - // @error Invalid index. - public native int GetString(int index, char[] buffer, int maxlength); - - // Retrieves an array of cells from an array. - // - // @param index Index in the array. - // @param buffer Buffer to store the array in. - // @param size If not set, assumes the buffer size is equal to the - // blocksize. Otherwise, the size passed is used. - // @return Number of cells copied. - // @error Invalid index. - public native int GetArray(int index, any[] buffer, int size=-1); - - // Sets a cell value in an array. - // - // @param index Index in the array. - // @param value Cell value to set. - // @param block Optionally specify which block to write to - // (useful if the blocksize > 0). - // @param asChar Optionally set as a byte instead of a cell. - // @error Invalid index, or invalid block. - public native void Set(int index, any value, int block=0, bool asChar=false); - - // Sets a string value in an array. - // - // @param index Index in the array. - // @param value String value to set. - // @return Number of characters copied. - // @error Invalid index. - public native void SetString(int index, const char[] value); - - // Sets an array of cells in an array. - // - // @param index Index in the array. - // @param values Array to copy. - // @param size If not set, assumes the buffer size is equal to the - // blocksize. Otherwise, the size passed is used. - // @return Number of cells copied. - // @error Invalid index. - public native void SetArray(int index, const any[] values, int size=-1); - - // Shifts an array up. All array contents after and including the given - // index are shifted up by one, and the given index is then "free." - // After shifting, the contents of the given index is undefined. - // - // @param index Index in the array to shift up from. - // @error Invalid index. - public native void ShiftUp(int index); - - // Removes an array index, shifting the entire array down from that position - // on. For example, if item 8 of 10 is removed, the last 3 items will then be - // (6,7,8) instead of (7,8,9), and all indexes before 8 will remain unchanged. - // - // @param index Index in the array to remove at. - // @error Invalid index. - public native void Erase(int index); - - // Swaps two items in the array. - // - // @param index1 First index. - // @param index2 Second index. - // @error Invalid index. - public native void SwapAt(int index1, int index2); - - // Returns the index for the first occurrence of the provided string. If - // the string cannot be located, -1 will be returned. - // - // @param item String to search for - // @return Array index, or -1 on failure - public native int FindString(const char[] item); - - // Returns the index for the first occurrence of the provided value. If the - // value cannot be located, -1 will be returned. - // - // @param item Value to search for - // @param block Optionally which block to search in - // @return Array index, or -1 on failure - // @error Invalid block index - public native int FindValue(any item, int block=0); - - // Retrieve the size of the array. - property int Length { - public native get(); - } - - // Retrieve the blocksize the array was created with. - property int BlockSize { - public native get(); - } -}; - -/** - * Creates a dynamic global cell array. While slower than a normal array, - * it can be used globally AND dynamically, which is otherwise impossible. - * - * The contents of the array are uniform; i.e. storing a string at index X - * and then retrieving it as an integer is NOT the same as StringToInt()! - * The "blocksize" determines how many cells each array slot has; it cannot - * be changed after creation. - * - * @param blocksize The number of cells each member of the array can - * hold. For example, 32 cells is equivalent to: - * new Array[X][32] - * @param startsize Initial size of the array. Note that data will - * NOT be auto-initialized. - * @return New Handle to the array object. - */ -native ArrayList CreateArray(int blocksize=1, int startsize=0); - -/** - * Clears an array of all entries. This is the same as ResizeArray(0). - * - * @param array Array Handle. - * @error Invalid Handle. - */ -native void ClearArray(Handle array); - -/** - * Clones an array, returning a new handle with the same size and data. This should NOT - * be confused with CloneHandle. This is a completely new handle with the same data but - * no relation to the original. You MUST close it. - * - * @param array Array handle to be cloned - * @return New handle to the cloned array object - * @error Invalid Handle - */ -native Handle CloneArray(Handle array); - -/** - * Resizes an array. If the size is smaller than the current size, - * the array is truncated. If the size is larger than the current size, - * the data at the additional indexes will not be initialized. - * - * @param array Array Handle. - * @param newsize New size. - * @error Invalid Handle or out of memory. - */ -native void ResizeArray(Handle array, int newsize); - -/** - * Returns the array size. - * - * @param array Array Handle. - * @return Number of elements in the array. - * @error Invalid Handle. - */ -native int GetArraySize(Handle array); - -/** - * Pushes a value onto the end of an array, adding a new index. - * - * This may safely be used even if the array has a blocksize - * greater than 1. - * - * @param array Array Handle. - * @param value Value to push. - * @return Index of the new entry. - * @error Invalid Handle or out of memory. - */ -native int PushArrayCell(Handle array, any value); - -/** - * Pushes a string onto the end of an array, truncating it - * if it is too big. - * - * @param array Array Handle. - * @param value String to push. - * @return Index of the new entry. - * @error Invalid Handle or out of memory. - */ -native int PushArrayString(Handle array, const char[] value); - -/** - * Pushes an array of cells onto the end of an array. The cells - * are pushed as a block (i.e. the entire array sits at the index), - * rather than pushing each cell individually. - * - * @param array Array Handle. - * @param values Block of values to copy. - * @param size If not set, the number of elements copied from the array - * will be equal to the blocksize. If set higher than the - * blocksize, the operation will be truncated. - * @return Index of the new entry. - * @error Invalid Handle or out of memory. - */ -native int PushArrayArray(Handle array, const any[] values, int size=-1); - -/** - * Retrieves a cell value from an array. - * - * @param array Array Handle. - * @param index Index in the array. - * @param block Optionally specify which block to read from - * (useful if the blocksize > 0). - * @param asChar Optionally read as a byte instead of a cell. - * @return Value read. - * @error Invalid Handle, invalid index, or invalid block. - */ -native any GetArrayCell(Handle array, int index, int block=0, bool asChar=false); - -/** - * Retrieves a string value from an array. - * - * @param array Array Handle. - * @param index Index in the array. - * @param buffer Buffer to copy to. - * @param maxlength Maximum size of the buffer. - * @return Number of characters copied. - * @error Invalid Handle or invalid index. - */ -native int GetArrayString(Handle array, int index, char[] buffer, int maxlength); - -/** - * Retrieves an array of cells from an array. - * - * @param array Array Handle. - * @param index Index in the array. - * @param buffer Buffer to store the array in. - * @param size If not set, assumes the buffer size is equal to the - * blocksize. Otherwise, the size passed is used. - * @return Number of cells copied. - * @error Invalid Handle or invalid index. - */ -native int GetArrayArray(Handle array, int index, any[] buffer, int size=-1); - -/** - * Sets a cell value in an array. - * - * @param array Array Handle. - * @param index Index in the array. - * @param value Cell value to set. - * @param block Optionally specify which block to write to - * (useful if the blocksize > 0). - * @param asChar Optionally set as a byte instead of a cell. - * @error Invalid Handle, invalid index, or invalid block. - */ -native void SetArrayCell(Handle array, int index, any value, int block=0, bool asChar=false); - -/** - * Sets a string value in an array. - * - * @param array Array Handle. - * @param index Index in the array. - * @param value String value to set. - * @return Number of characters copied. - * @error Invalid Handle or invalid index. - */ -native int SetArrayString(Handle array, int index, const char[] value); - -/** - * Sets an array of cells in an array. - * - * @param array Array Handle. - * @param index Index in the array. - * @param values Array to copy. - * @param size If not set, assumes the buffer size is equal to the - * blocksize. Otherwise, the size passed is used. - * @return Number of cells copied. - * @error Invalid Handle or invalid index. - */ -native int SetArrayArray(Handle array, int index, const any[] values, int size=-1); - -/** - * Shifts an array up. All array contents after and including the given - * index are shifted up by one, and the given index is then "free." - * After shifting, the contents of the given index is undefined. - * - * @param array Array Handle. - * @param index Index in the array to shift up from. - * @error Invalid Handle or invalid index. - */ -native void ShiftArrayUp(Handle array, int index); - -/** - * Removes an array index, shifting the entire array down from that position - * on. For example, if item 8 of 10 is removed, the last 3 items will then be - * (6,7,8) instead of (7,8,9), and all indexes before 8 will remain unchanged. - * - * @param array Array Handle. - * @param index Index in the array to remove at. - * @error Invalid Handle or invalid index. - */ -native void RemoveFromArray(Handle array, int index); - -/** - * Swaps two items in the array. - * - * @param array Array Handle. - * @param index1 First index. - * @param index2 Second index. - * @error Invalid Handle or invalid index. - */ -native void SwapArrayItems(Handle array, int index1, int index2); - -/** - * Returns the index for the first occurrence of the provided string. If the string - * cannot be located, -1 will be returned. - * - * @param array Array Handle. - * @param item String to search for - * @return Array index, or -1 on failure - * @error Invalid Handle - */ -native int FindStringInArray(Handle array, const char[] item); - -/** - * Returns the index for the first occurrence of the provided value. If the value - * cannot be located, -1 will be returned. - * - * @param array Array Handle. - * @param item Value to search for - * @param block Optionally which block to search in - * @return Array index, or -1 on failure - * @error Invalid Handle or invalid block - */ -native int FindValueInArray(Handle array, any item, int block=0); - -/** - * Returns the blocksize the array was created with. - * - * @param array Array Handle. - * @return The blocksize of the array. - * @error Invalid Handle - */ -native int GetArrayBlockSize(Handle array); diff --git a/scripting/include/adt_stack.inc b/scripting/include/adt_stack.inc deleted file mode 100644 index b841a0a..0000000 --- a/scripting/include/adt_stack.inc +++ /dev/null @@ -1,240 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _adt_stack_included - #endinput -#endif -#define _adt_stack_included - -methodmap ArrayStack < Handle -{ - // Creates a stack structure. A stack is a LIFO (last in, first out) - // vector (array) of items. It has O(1) insertion and O(1) removal. - // - // Stacks have two operations: Push (adding an item) and Pop (removes - // items in reverse-push order). - // - // The contents of the stack are uniform; i.e. storing a string and then - // retrieving it as an integer is NOT the same as StringToInt()! - // - // The "blocksize" determines how many cells each slot has; it cannot - // be changed after creation. - // - // @param blocksize The number of cells each entry in the stack can - // hold. For example, 32 cells is equivalent to: - // new Array[X][32] - public native ArrayStack(int blocksize=1); - - // Pushes a value onto the end of the stack, adding a new index. - // - // This may safely be used even if the stack has a blocksize - // greater than 1. - // - // @param value Value to push. - public native void Push(any value); - - // Pushes a copy of a string onto the end of a stack, truncating it if it - // is too big. - // - // @param value String to push. - public native void PushString(const char[] value); - - // Pushes a copy of an array of cells onto the end of a stack. The cells - // are pushed as a block (i.e. the entire array takes up one stack slot), - // rather than pushing each cell individually. - // - // @param stack Stack Handle. - // @param values Block of values to copy. - // @param size If not set, the number of elements copied from the array - // will be equal to the blocksize. If set higher than the - // blocksize, the operation will be truncated. - public native void PushArray(const any[] values, int size=-1); - - // Pops a cell value from a stack. - // - // @param block Optionally specify which block to read from - // (useful if the blocksize > 0). - // @param asChar Optionally read as a byte instead of a cell. - // @return True on success, false if the stack is empty. - // @error The stack is empty. - public native any Pop(int block=0, bool asChar=false); - - // Pops a string value from a stack. - // - // @param buffer Buffer to store string. - // @param maxlength Maximum size of the buffer. - // @oaram written Number of characters written to buffer, not including - // the null terminator. - // @error The stack is empty. - public native void PopString(char[] buffer, int maxlength, int &written = 0); - - // Pops an array of cells from a stack. - // - // @param buffer Buffer to store the array in. - // @param size If not set, assumes the buffer size is equal to the - // blocksize. Otherwise, the size passed is used. - // @error The stack is empty. - public native void PopArray(any[] buffer, int size=-1); - - // Returns true if the stack is empty, false otherwise. - property bool Empty { - public native get(); - } - - // Retrieve the blocksize the stack was created with. - property int BlockSize { - public native get(); - } -}; - -/** - * Creates a stack structure. A stack is a LIFO (last in, first out) - * vector (array) of items. It has O(1) insertion and O(1) removal. - * - * Stacks have two operations: Push (adding an item) and Pop (removes - * items in reverse-push order). - * - * The contents of the stack are uniform; i.e. storing a string and then - * retrieving it as an integer is NOT the same as StringToInt()! - * - * The "blocksize" determines how many cells each slot has; it cannot - * be changed after creation. - * - * @param blocksize The number of cells each entry in the stack can - * hold. For example, 32 cells is equivalent to: - * new Array[X][32] - * @return New stack Handle. - */ -native ArrayStack CreateStack(int blocksize=1); - -/** - * Pushes a value onto the end of the stack, adding a new index. - * - * This may safely be used even if the stack has a blocksize - * greater than 1. - * - * @param stack Stack Handle. - * @param value Value to push. - * @error Invalid Handle or out of memory. - */ -native void PushStackCell(Handle stack, any value); - -/** - * Pushes a copy of a string onto the end of a stack, truncating it if it is - * too big. - * - * @param stack Stack Handle. - * @param value String to push. - * @error Invalid Handle or out of memory. - */ -native void PushStackString(Handle stack, const char[] value); - -/** - * Pushes a copy of an array of cells onto the end of a stack. The cells - * are pushed as a block (i.e. the entire array takes up one stack slot), - * rather than pushing each cell individually. - * - * @param stack Stack Handle. - * @param values Block of values to copy. - * @param size If not set, the number of elements copied from the array - * will be equal to the blocksize. If set higher than the - * blocksize, the operation will be truncated. - * @error Invalid Handle or out of memory. - */ -native void PushStackArray(Handle stack, const any[] values, int size=-1); - -/** - * Pops a cell value from a stack. - * - * @param stack Stack Handle. - * @param value Variable to store the value. - * @param block Optionally specify which block to read from - * (useful if the blocksize > 0). - * @param asChar Optionally read as a byte instead of a cell. - * @return True on success, false if the stack is empty. - * @error Invalid Handle. - */ -native bool PopStackCell(Handle stack, any &value, int block=0, bool asChar=false); - -/** - * Pops a string value from a stack. - * - * @param stack Stack Handle. - * @param buffer Buffer to store string. - * @param maxlength Maximum size of the buffer. - * @return True on success, false if the stack is empty. - * @error Invalid Handle. - */ -native bool PopStackString(Handle stack, char[] buffer, int maxlength, int &written=0); - -/** - * Pops an array of cells from a stack. - * - * @param stack Stack Handle. - * @param buffer Buffer to store the array in. - * @param size If not set, assumes the buffer size is equal to the - * blocksize. Otherwise, the size passed is used. - * @return True on success, false if the stack is empty. - * @error Invalid Handle. - */ -native bool PopStackArray(Handle stack, any[] buffer, int size=-1); - -/** - * Checks if a stack is empty. - * - * @param stack Stack Handle. - * @return True if empty, false if not empty. - * @error Invalid Handle. - */ -native bool IsStackEmpty(Handle stack); - -/** - * Pops a value off a stack, ignoring it completely. - * - * @param stack Stack Handle. - * @return True if something was popped, false otherwise. - * @error Invalid Handle. - */ -stock bool PopStack(Handle stack) -{ - int value; - return PopStackCell(stack, value); -} - -/** - * Returns the blocksize the stack was created with. - * - * @param stack Stack Handle. - * @return The blocksize of the stack. - * @error Invalid Handle - */ -native int GetStackBlockSize(Handle stack); diff --git a/scripting/include/adt_trie.inc b/scripting/include/adt_trie.inc deleted file mode 100644 index 44548ab..0000000 --- a/scripting/include/adt_trie.inc +++ /dev/null @@ -1,317 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _adt_trie_included - #endinput -#endif -#define _adt_trie_included - -/* Object-oriented wrapper for maps. */ -methodmap StringMap < Handle -{ - // Creates a hash map. A hash map is a container that can map strings (called - // "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map - // are unique. That is, there is at most one entry in the map for a given key. - // - // Insertion, deletion, and lookup in a hash map are all considered to be fast - // operations, amortized to O(1), or constant time. - // - // The word "Trie" in this API is historical. As of SourceMod 1.6, tries have - // been internally replaced with hash tables, which have O(1) insertion time - // instead of O(n). - // - // The StringMap must be freed via delete or CloseHandle(). - public native StringMap(); - - // Sets a value in a hash map, either inserting a new entry or replacing an old one. - // - // @param key Key string. - // @param value Value to store at this key. - // @param replace If false, operation will fail if the key is already set. - // @return True on success, false on failure. - public native bool SetValue(const char[] key, any value, bool replace=true); - - // Sets an array value in a Map, either inserting a new entry or replacing an old one. - // - // @param key Key string. - // @param array Array to store. - // @param num_items Number of items in the array. - // @param replace If false, operation will fail if the key is already set. - // @return True on success, false on failure. - public native bool SetArray(const char[] key, const any[] array, int num_items, bool replace=true); - - // Sets a string value in a Map, either inserting a new entry or replacing an old one. - // - // @param key Key string. - // @param value String to store. - // @param replace If false, operation will fail if the key is already set. - // @return True on success, false on failure. - public native bool SetString(const char[] key, const char[] value, bool replace=true); - - // Retrieves a value in a Map. - // - // @param key Key string. - // @param value Variable to store value. - // @return True on success. False if the key is not set, or the key is set - // as an array or string (not a value). - public native bool GetValue(const char[] key, any &value); - - // Retrieves an array in a Map. - // - // @param map Map Handle. - // @param key Key string. - // @param array Buffer to store array. - // @param max_size Maximum size of array buffer. - // @param size Optional parameter to store the number of elements written to the buffer. - // @return True on success. False if the key is not set, or the key is set - // as a value or string (not an array). - public native bool GetArray(const char[] key, any[] array, int max_size, int &size=0); - - // Retrieves a string in a Map. - // - // @param key Key string. - // @param value Buffer to store value. - // @param max_size Maximum size of string buffer. - // @param size Optional parameter to store the number of bytes written to the buffer. - // @return True on success. False if the key is not set, or the key is set - // as a value or array (not a string). - public native bool GetString(const char[] key, char[] value, int max_size, int &size=0); - - // Removes a key entry from a Map. - // - // @param key Key string. - // @return True on success, false if the value was never set. - public native bool Remove(const char[] key); - - // Clears all entries from a Map. - public native void Clear(); - - // Create a snapshot of the map's keys. See StringMapSnapshot. - public native StringMapSnapshot Snapshot(); - - // Retrieves the number of elements in a map. - property int Size { - public native get(); - } -}; - -// A StringMapSnapshot is created via StringMap.Snapshot(). It captures the -// keys on a map so they can be read. Snapshots must be freed with delete or -// CloseHandle(). -methodmap StringMapSnapshot < Handle -{ - // Returns the number of keys in the map snapshot. - property int Length { - public native get(); - } - - // Returns the buffer size required to store a given key. That is, it - // returns the length of the key plus one. - // - // @param index Key index (starting from 0). - // @return Buffer size required to store the key string. - // @error Index out of range. - public native int KeyBufferSize(int index); - - // Retrieves the key string of a given key in a map snapshot. - // - // @param index Key index (starting from 0). - // @param buffer String buffer. - // @param maxlength Maximum buffer length. - // @return Number of bytes written to the buffer. - // @error Index out of range. - public native int GetKey(int index, char[] buffer, int maxlength); -}; - -/** - * Creates a hash map. A hash map is a container that can map strings (called - * "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map - * are unique. That is, there is at most one entry in the map for a given key. - * - * Insertion, deletion, and lookup in a hash map are all considered to be fast - * operations, amortized to O(1), or constant time. - * - * The word "Trie" in this API is historical. As of SourceMod 1.6, tries have - * been internally replaced with hash tables, which have O(1) insertion time - * instead of O(n). - * - * @return New Map Handle, which must be freed via CloseHandle(). - */ -native StringMap CreateTrie(); - -/** - * Sets a value in a hash map, either inserting a new entry or replacing an old one. - * - * @param map Map Handle. - * @param key Key string. - * @param value Value to store at this key. - * @param replace If false, operation will fail if the key is already set. - * @return True on success, false on failure. - * @error Invalid Handle. - */ -native bool SetTrieValue(Handle map, const char[] key, any value, bool replace=true); - -/** - * Sets an array value in a Map, either inserting a new entry or replacing an old one. - * - * @param map Map Handle. - * @param key Key string. - * @param array Array to store. - * @param num_items Number of items in the array. - * @param replace If false, operation will fail if the key is already set. - * @return True on success, false on failure. - * @error Invalid Handle. - */ -native bool SetTrieArray(Handle map, const char[] key, const any[] array, int num_items, bool replace=true); - -/** - * Sets a string value in a Map, either inserting a new entry or replacing an old one. - * - * @param map Map Handle. - * @param key Key string. - * @param value String to store. - * @param replace If false, operation will fail if the key is already set. - * @return True on success, false on failure. - * @error Invalid Handle. - */ -native bool SetTrieString(Handle map, const char[] key, const char[] value, bool replace=true); - -/** - * Retrieves a value in a Map. - * - * @param map Map Handle. - * @param key Key string. - * @param value Variable to store value. - * @return True on success. False if the key is not set, or the key is set - * as an array or string (not a value). - * @error Invalid Handle. - */ -native bool GetTrieValue(Handle map, const char[] key, any &value); - -/** - * Retrieves an array in a Map. - * - * @param map Map Handle. - * @param key Key string. - * @param array Buffer to store array. - * @param max_size Maximum size of array buffer. - * @param size Optional parameter to store the number of elements written to the buffer. - * @return True on success. False if the key is not set, or the key is set - * as a value or string (not an array). - * @error Invalid Handle. - */ -native bool GetTrieArray(Handle map, const char[] key, any[] array, int max_size, int &size=0); - -/** - * Retrieves a string in a Map. - * - * @param map Map Handle. - * @param key Key string. - * @param value Buffer to store value. - * @param max_size Maximum size of string buffer. - * @param size Optional parameter to store the number of bytes written to the buffer. - * @return True on success. False if the key is not set, or the key is set - * as a value or array (not a string). - * @error Invalid Handle. - */ -native bool GetTrieString(Handle map, const char[] key, char[] value, int max_size, int &size=0); - -/** - * Removes a key entry from a Map. - * - * @param map Map Handle. - * @param key Key string. - * @return True on success, false if the value was never set. - * @error Invalid Handle. - */ -native bool RemoveFromTrie(Handle map, const char[] key); - -/** - * Clears all entries from a Map. - * - * @param map Map Handle. - * @error Invalid Handle. - */ -native void ClearTrie(Handle map); - -/** - * Retrieves the number of elements in a map. - * - * @param map Map Handle. - * @return Number of elements in the trie. - * @error Invalid Handle. - */ -native int GetTrieSize(Handle map); - -/** - * Creates a snapshot of all keys in the map. If the map is changed after this - * call, the changes are not reflected in the snapshot. Keys are not sorted. - * - * @param map Map Handle. - * @return New Map Snapshot Handle, which must be closed via CloseHandle(). - * @error Invalid Handle. - */ -native Handle CreateTrieSnapshot(Handle map); - -/** - * Returns the number of keys in a map snapshot. Note that this may be - * different from the size of the map, since the map can change after the - * snapshot of its keys was taken. - * - * @param snapshot Map snapshot. - * @return Number of keys. - * @error Invalid Handle. - */ -native int TrieSnapshotLength(Handle snapshot); - -/** - * Returns the buffer size required to store a given key. That is, it returns - * the length of the key plus one. - * - * @param snapshot Map snapshot. - * @param index Key index (starting from 0). - * @return Buffer size required to store the key string. - * @error Invalid Handle or index out of range. - */ -native int TrieSnapshotKeyBufferSize(Handle snapshot, int index); - -/** - * Retrieves the key string of a given key in a map snapshot. - * - * @param snapshot Map snapshot. - * @param index Key index (starting from 0). - * @param buffer String buffer. - * @param maxlength Maximum buffer length. - * @return Number of bytes written to the buffer. - * @error Invalid Handle or index out of range. - */ -native int GetTrieSnapshotKey(Handle snapshot, int index, char[] buffer, int maxlength); diff --git a/scripting/include/banning.inc b/scripting/include/banning.inc deleted file mode 100644 index 424753e..0000000 --- a/scripting/include/banning.inc +++ /dev/null @@ -1,156 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _banning_included - #endinput -#endif -#define _banning_included - -#define BANFLAG_AUTO (1<<0) /**< Auto-detects whether to ban by steamid or IP */ -#define BANFLAG_IP (1<<1) /**< Always ban by IP address */ -#define BANFLAG_AUTHID (1<<2) /**< Always ban by authstring (for BanIdentity) if possible */ -#define BANFLAG_NOKICK (1<<3) /**< Does not kick the client */ - -/** - * Called for calls to BanClient() with a non-empty command. - * - * @param client Client being banned. - * @param time Time the client is being banned for (0 = permanent). - * @param flags One if AUTHID or IP will be enabled. If AUTO is also - * enabled, it means Core autodetected which to use. - * @param reason Reason passed via BanClient(). - * @param kick_message Kick message passed via BanClient(). - * @param command Command string to identify the ban source. - * @param source Source value passed via BanClient(). - * @return Plugin_Handled to block the actual server banning. - * Kicking will still occur. - */ -forward Action OnBanClient(int client, - int time, - int flags, - const char[] reason, - const char[] kick_message, - const char[] command, - any source); - -/** - * Called for calls to BanIdentity() with a non-empty command. - * - * @param identity Identity string being banned (authstring or ip). - * @param time Time the client is being banned for (0 = permanent). - * @param flags Ban flags (only IP or AUTHID are valid here). - * @param reason Reason passed via BanIdentity(). - * @param command Command string to identify the ban source. - * @param source Source value passed via BanIdentity(). - * @return Plugin_Handled to block the actual server banning. - */ -forward Action OnBanIdentity(const char[] identity, - int time, - int flags, - const char[] reason, - const char[] command, - any source); - -/** - * Called for calls to RemoveBan() with a non-empty command. - * - * @param identity Identity string being banned (authstring or ip). - * @param flags Ban flags (only IP or AUTHID are valid here). - * @param command Command string to identify the ban source. - * @param source Source value passed via BanIdentity(). - * @return Plugin_Handled to block the actual unbanning. - */ -forward Action OnRemoveBan(const char[] identity, - int flags, - const char[] command, - any source); - -/** - * Bans a client. - * - * @param client Client being banned. - * @param time Time (in minutes) to ban (0 = permanent). - * @param flags Flags for controlling the ban mechanism. If AUTHID - * is set and no AUTHID is available, the ban will fail - * unless AUTO is also flagged. - * @param reason Reason to ban the client for. - * @param kick_message Message to display to the user when kicking. - * @param command Command string to identify the source. If this is left - * empty, then the OnBanClient forward will not be called. - * @param source A source value that could be interpreted as a player - * index of any sort (not actually checked by Core). - * @return True on success, false on failure. - * @error Invalid client index or client not in game. - */ -native bool BanClient(int client, - int time, - int flags, - const char[] reason, - const char[] kick_message="", - const char[] command="", - any source=0); - -/** - * Bans an identity (either an IP address or auth string). - * - * @param identity String to ban (ip or authstring). - * @param time Time to ban for (0 = permanent). - * @param flags Flags (only IP and AUTHID are valid flags here). - * @param reason Ban reason string. - * @param command Command string to identify the source. If this is left - * empty, then the OnBanIdentity forward will not be called. - * @param source A source value that could be interpreted as a player - * index of any sort (not actually checked by Core). - * @return True on success, false on failure. - */ -native bool BanIdentity(const char[] identity, - int time, - int flags, - const char[] reason, - const char[] command="", - any source=0); - -/** - * Removes a ban that was written to the server (either in memory or on disk). - * - * @param identity String to unban (ip or authstring). - * @param flags Flags (only IP and AUTHID are valid flags here). - * @param command Command string to identify the source. If this is left - * empty, then OnRemoveBan will not be called. - * @param source A source value that could be interpreted as a player - * index of any sort (not actually checked by Core). - * @return True on success, false on failure. - */ -native bool RemoveBan(const char[] identity, - int flags, - const char[] command="", - any source=0); diff --git a/scripting/include/basecomm.inc b/scripting/include/basecomm.inc deleted file mode 100644 index 54545c8..0000000 --- a/scripting/include/basecomm.inc +++ /dev/null @@ -1,109 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _basecomm_included - #endinput -#endif -#define _basecomm_included - -/** - * Called when a client is muted or unmuted - * - * @param client Client index - * @param muteState True if client was muted, false otherwise - */ - forward void BaseComm_OnClientMute(int client, bool muteState); - - /** - * Called when a client is gagged or ungagged - * - * @param client Client index - * @param gagState True if client was gaged, false otherwise - */ - forward void BaseComm_OnClientGag(int client, bool gagState); - -/** - * Returns whether or not a client is gagged - * - * @param client Client index. - * @return True if client is gagged, false otherwise. - */ -native bool BaseComm_IsClientGagged(int client); - -/** - * Returns whether or not a client is muted - * - * @param client Client index. - * @return True if client is muted, false otherwise. - */ -native bool BaseComm_IsClientMuted(int client); - -/** - * Sets a client's gag state - * - * @param client Client index. - * @param gagState True to gag client, false to ungag. - * @return True if this caused a change in gag state, false otherwise. - */ -native bool BaseComm_SetClientGag(int client, bool gagState); - -/** - * Sets a client's mute state - * - * @param client Client index. - * @param muteState True to mute client, false to unmute. - * @return True if this caused a change in mute state, false otherwise. - */ -native bool BaseComm_SetClientMute(int client, bool muteState); - -/* DO NOT EDIT BELOW THIS LINE */ - -public SharedPlugin __pl_basecomm = -{ - name = "basecomm", - file = "basecomm.smx", -#if defined REQUIRE_PLUGIN - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_PLUGIN -public void __pl_basecomm_SetNTVOptional() -{ - MarkNativeAsOptional("BaseComm_IsClientGagged"); - MarkNativeAsOptional("BaseComm_IsClientMuted"); - MarkNativeAsOptional("BaseComm_SetClientGag"); - MarkNativeAsOptional("BaseComm_SetClientMute"); -} -#endif diff --git a/scripting/include/bitbuffer.inc b/scripting/include/bitbuffer.inc deleted file mode 100644 index 1de58a5..0000000 --- a/scripting/include/bitbuffer.inc +++ /dev/null @@ -1,470 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _bitbuffer_included - #endinput -#endif -#define _bitbuffer_included - -methodmap BfWrite < Handle -{ - // Writes a single bit to a writable bitbuffer (bf_write). - // - // @param bit Bit to write (true for 1, false for 0). - public native void WriteBool(bool bit); - - // Writes a byte to a writable bitbuffer (bf_write). - // - // @param byte Byte to write (value will be written as 8bit). - public native void WriteByte(int byte); - - // Writes a byte to a writable bitbuffer (bf_write). - // - // @param chr Character to write. - public native void WriteChar(int chr); - - // Writes a 16bit integer to a writable bitbuffer (bf_write). - // - // @param num Integer to write (value will be written as 16bit). - public native void WriteShort(int num); - - // Writes a 16bit unsigned integer to a writable bitbuffer (bf_write). - // - // @param num Integer to write (value will be written as 16bit). - public native void WriteWord(int num); - - // Writes a normal integer to a writable bitbuffer (bf_write). - // - // @param num Integer to write (value will be written as 32bit). - public native void WriteNum(int num); - - // Writes a floating point number to a writable bitbuffer (bf_write). - // - // @param num Number to write. - public native void WriteFloat(float num); - - // Writes a string to a writable bitbuffer (bf_write). - // - // @param string Text string to write. - public native void WriteString(const char[] string); - - // Writes an entity to a writable bitbuffer (bf_write). - // - // @param ent Entity index to write. - public native void WriteEntity(int ent); - - // Writes a bit angle to a writable bitbuffer (bf_write). - // - // @param angle Angle to write. - // @param numBits Optional number of bits to use. - public native void WriteAngle(float angle, int numBits=8); - - // Writes a coordinate to a writable bitbuffer (bf_write). - // - // @param coord Coordinate to write. - public native void WriteCoord(float coord); - - // Writes a 3D vector of coordinates to a writable bitbuffer (bf_write). - // - // @param coord Coordinate array to write. - public native void WriteVecCoord(float coord[3]); - - // Writes a 3D normal vector to a writable bitbuffer (bf_write). - // - // @param vec Vector to write. - public native void WriteVecNormal(float vec[3]); - - // Writes a 3D angle vector to a writable bitbuffer (bf_write). - // - // @param angles Angle vector to write. - public native void WriteAngles(float angles[3]); -}; - -methodmap BfRead < Handle -{ - // Reads a single bit from a readable bitbuffer (bf_read). - // - // @return Bit value read. - public native bool ReadBool(); - - // Reads a byte from a readable bitbuffer (bf_read). - // - // @return Byte value read (read as 8bit). - public native int ReadByte(); - - // Reads a character from a readable bitbuffer (bf_read). - // - // @return Character value read. - public native int ReadChar(); - - // Reads a 16bit integer from a readable bitbuffer (bf_read). - // - // @param bf bf_read handle to read from. - // @return Integer value read (read as 16bit). - public native int ReadShort(); - - // Reads a 16bit unsigned integer from a readable bitbuffer (bf_read). - // - // @param bf bf_read handle to read from. - // @return Integer value read (read as 16bit). - public native int ReadWord(); - - // Reads a normal integer to a readable bitbuffer (bf_read). - // - // @return Integer value read (read as 32bit). - public native int ReadNum(); - - // Reads a floating point number from a readable bitbuffer (bf_read). - // - // @return Floating point value read. - public native float ReadFloat(); - - // Reads a string from a readable bitbuffer (bf_read). - // - // @param buffer Destination string buffer. - // @param maxlength Maximum length of output string buffer. - // @param line If true the buffer will be copied until it reaches a '\n' or a null terminator. - // @return Number of bytes written to the buffer. If the bitbuffer stream overflowed, - // that is, had no terminator before the end of the stream, then a negative - // number will be returned equal to the number of characters written to the - // buffer minus 1. The buffer will be null terminated regardless of the - // return value. - public native int ReadString(char[] buffer, int maxlength, bool line=false); - - // Reads an entity from a readable bitbuffer (bf_read). - // - // @return Entity index read. - public native int ReadEntity(); - - // Reads a bit angle from a readable bitbuffer (bf_read). - // - // @param numBits Optional number of bits to use. - // @return Angle read. - public native float ReadAngle(int numBits=8); - - // Reads a coordinate from a readable bitbuffer (bf_read). - // - // @return Coordinate read. - public native float ReadCoord(); - - // Reads a 3D vector of coordinates from a readable bitbuffer (bf_read). - // - // @param coord Destination coordinate array. - public native void ReadVecCoord(float coord[3]); - - // Reads a 3D normal vector from a readable bitbuffer (bf_read). - // - // @param vec Destination vector array. - public native void ReadVecNormal(float vec[3]); - - // Reads a 3D angle vector from a readable bitbuffer (bf_read). - // - // @param angles Destination angle vector. - public native void ReadAngles(float angles[3]); - - // Returns the number of bytes left in a readable bitbuffer (bf_read). - property int BytesLeft { - public native get(); - } -}; - -/** - * Writes a single bit to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param bit Bit to write (true for 1, false for 0). - * @error Invalid or incorrect Handle. - */ -native void BfWriteBool(Handle bf, bool bit); - -/** - * Writes a byte to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param byte Byte to write (value will be written as 8bit). - * @error Invalid or incorrect Handle. - */ -native void BfWriteByte(Handle bf, int byte); - -/** - * Writes a byte to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param chr Character to write. - * @error Invalid or incorrect Handle. - */ -native void BfWriteChar(Handle bf, int chr); - -/** - * Writes a 16bit integer to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param num Integer to write (value will be written as 16bit). - * @error Invalid or incorrect Handle. - */ -native void BfWriteShort(Handle bf, int num); - -/** - * Writes a 16bit unsigned integer to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param num Integer to write (value will be written as 16bit). - * @error Invalid or incorrect Handle. - */ -native void BfWriteWord(Handle bf, int num); - -/** - * Writes a normal integer to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param num Integer to write (value will be written as 32bit). - * @error Invalid or incorrect Handle. - */ -native void BfWriteNum(Handle bf, int num); - -/** - * Writes a floating point number to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param num Number to write. - * @error Invalid or incorrect Handle. - */ -native void BfWriteFloat(Handle bf, float num); - -/** - * Writes a string to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param string Text string to write. - * @error Invalid or incorrect Handle. - */ -native void BfWriteString(Handle bf, const char[] string); - -/** - * Writes an entity to a writable bitbuffer (bf_write). - * @note This is a wrapper around BfWriteShort(). - * - * @param bf bf_write handle to write to. - * @param ent Entity index to write. - * @error Invalid or incorrect Handle, or invalid entity. - */ -native void BfWriteEntity(Handle bf, int ent); - -/** - * Writes a bit angle to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param angle Angle to write. - * @param numBits Optional number of bits to use. - * @error Invalid or incorrect Handle. - */ -native void BfWriteAngle(Handle bf, float angle, int numBits=8); - -/** - * Writes a coordinate to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param coord Coordinate to write. - * @error Invalid or incorrect Handle. - */ -native void BfWriteCoord(Handle bf, float coord); - -/** - * Writes a 3D vector of coordinates to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param coord Coordinate array to write. - * @error Invalid or incorrect Handle. - */ -native void BfWriteVecCoord(Handle bf, float coord[3]); - -/** - * Writes a 3D normal vector to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param vec Vector to write. - * @error Invalid or incorrect Handle. - */ -native void BfWriteVecNormal(Handle bf, float vec[3]); - -/** - * Writes a 3D angle vector to a writable bitbuffer (bf_write). - * - * @param bf bf_write handle to write to. - * @param angles Angle vector to write. - * @error Invalid or incorrect Handle. - */ -native void BfWriteAngles(Handle bf, float angles[3]); - -/** - * Reads a single bit from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Bit value read. - * @error Invalid or incorrect Handle. - */ -native bool BfReadBool(Handle bf); - -/** - * Reads a byte from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Byte value read (read as 8bit). - * @error Invalid or incorrect Handle. - */ -native int BfReadByte(Handle bf); - -/** - * Reads a character from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Character value read. - * @error Invalid or incorrect Handle. - */ -native int BfReadChar(Handle bf); - -/** - * Reads a 16bit integer from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Integer value read (read as 16bit). - * @error Invalid or incorrect Handle. - */ -native int BfReadShort(Handle bf); - -/** - * Reads a 16bit unsigned integer from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Integer value read (read as 16bit). - * @error Invalid or incorrect Handle. - */ -native int BfReadWord(Handle bf); - -/** - * Reads a normal integer to a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Integer value read (read as 32bit). - * @error Invalid or incorrect Handle. - */ -native int BfReadNum(Handle bf); - -/** - * Reads a floating point number from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Floating point value read. - * @error Invalid or incorrect Handle. - */ -native float BfReadFloat(Handle bf); - -/** - * Reads a string from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @param buffer Destination string buffer. - * @param maxlength Maximum length of output string buffer. - * @param line If true the buffer will be copied until it reaches a '\n' or a null terminator. - * @return Number of bytes written to the buffer. If the bitbuffer stream overflowed, - * that is, had no terminator before the end of the stream, then a negative - * number will be returned equal to the number of characters written to the - * buffer minus 1. The buffer will be null terminated regardless of the - * return value. - * @error Invalid or incorrect Handle. - */ -native int BfReadString(Handle bf, char[] buffer, int maxlength, bool line=false); - -/** - * Reads an entity from a readable bitbuffer (bf_read). - * @note This is a wrapper around BfReadShort(). - * - * @param bf bf_read handle to read from. - * @return Entity index read. - * @error Invalid or incorrect Handle. - */ -native int BfReadEntity(Handle bf); - -/** - * Reads a bit angle from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @param numBits Optional number of bits to use. - * @return Angle read. - * @error Invalid or incorrect Handle. - */ -native float BfReadAngle(Handle bf, int numBits=8); - -/** - * Reads a coordinate from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Coordinate read. - * @error Invalid or incorrect Handle. - */ -native float BfReadCoord(Handle bf); - -/** - * Reads a 3D vector of coordinates from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @param coord Destination coordinate array. - * @error Invalid or incorrect Handle. - */ -native void BfReadVecCoord(Handle bf, float coord[3]); - -/** - * Reads a 3D normal vector from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @param vec Destination vector array. - * @error Invalid or incorrect Handle. - */ -native void BfReadVecNormal(Handle bf, float vec[3]); - -/** - * Reads a 3D angle vector from a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @param angles Destination angle vector. - * @error Invalid or incorrect Handle. - */ -native void BfReadAngles(Handle bf, float angles[3]); - -/** - * Returns the number of bytes left in a readable bitbuffer (bf_read). - * - * @param bf bf_read handle to read from. - * @return Number of bytes left unread. - * @error Invalid or incorrect Handle. - */ -native int BfGetNumBytesLeft(Handle bf); diff --git a/scripting/include/clientprefs.inc b/scripting/include/clientprefs.inc deleted file mode 100644 index bdd6e53..0000000 --- a/scripting/include/clientprefs.inc +++ /dev/null @@ -1,282 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _clientprefs_included - #endinput -#endif -#define _clientprefs_included - -/** - * Cookie access types for client viewing - */ -enum CookieAccess -{ - CookieAccess_Public, /**< Visible and Changeable by users */ - CookieAccess_Protected, /**< Read only to users */ - CookieAccess_Private, /**< Completely hidden cookie */ -}; - -/** - * Cookie Prefab menu types - */ -enum CookieMenu -{ - CookieMenu_YesNo, /**< Yes/No menu with "yes"/"no" results saved into the cookie */ - CookieMenu_YesNo_Int, /**< Yes/No menu with 1/0 saved into the cookie */ - CookieMenu_OnOff, /**< On/Off menu with "on"/"off" results saved into the cookie */ - CookieMenu_OnOff_Int, /**< On/Off menu with 1/0 saved into the cookie */ -}; - -enum CookieMenuAction -{ - /** - * An option is being drawn for a menu. - * - * INPUT : Client index and data if available. - * OUTPUT: Buffer for rendering, maxlength of buffer. - */ - CookieMenuAction_DisplayOption = 0, - - /** - * A menu option has been selected. - * - * INPUT : Client index and any data if available. - */ - CookieMenuAction_SelectOption = 1, -}; - -/** - * Note: - * - * A successful return value/result on any client prefs native only guarantees that the local cache has been updated. - * Database connection problems can still prevent the data from being permanently saved. Connection problems will be logged as - * errors by the clientprefs extension. - */ - -/** - * Creates a new Client preference cookie. - * - * Handles returned by RegClientCookie can be closed via CloseHandle() when - * no longer needed. - * - * @param name Name of the new preference cookie. - * @param description Optional description of the preference cookie. - * @param access What CookieAccess level to assign to this cookie. - * @return A handle to the newly created cookie. If the cookie already - * exists, a handle to it will still be returned. - * @error Cookie name is blank. - */ -native Handle RegClientCookie(const char[] name, const char[] description, CookieAccess access); - -/** - * Searches for a Client preference cookie. - * - * Handles returned by FindClientCookie can be closed via CloseHandle() when - * no longer needed. - * - * @param name Name of cookie to find. - * @return A handle to the cookie if it is found. INVALID_HANDLE otherwise. - */ -native Handle FindClientCookie(const char[] name); - -/** - * Set the value of a Client preference cookie. - * - * @param client Client index. - * @param cookie Client preference cookie handle. - * @param value String value to set. - * @error Invalid cookie handle or invalid client index. - */ -native void SetClientCookie(int client, Handle cookie, const char[] value); - -/** - * Retrieve the value of a Client preference cookie. - * - * @param client Client index. - * @param cookie Client preference cookie handle. - * @param buffer Copyback buffer for value. - * @param maxlen Maximum length of the buffer. - * @error Invalid cookie handle or invalid client index. - */ -native void GetClientCookie(int client, Handle cookie, char[] buffer, int maxlen); - -/** - * Sets the value of a Client preference cookie based on an authID string. - * - * @param authID String Auth/STEAM ID of player to set. - * @param cookie Client preference cookie handle. - * @param value String value to set. - * @error Invalid cookie handle. - */ -native void SetAuthIdCookie(const char[] authID, Handle cookie, const char[] value); - -/** - * Checks if a clients cookies have been loaded from the database. - * - * @param client Client index. - * @return True if loaded, false otherwise. - * @error Invalid client index. - */ -native bool AreClientCookiesCached(int client); - -/** - * Called once a client's saved cookies have been loaded from the database. - * - * @param client Client index. - */ -forward void OnClientCookiesCached(int client); - -/** - * Cookie Menu Callback prototype - * - * @param client Client index. - * @param action CookieMenuAction being performed. - * @param info Info data passed. - * @param buffer Outbut buffer. - * @param maxlen Max length of the output buffer. - */ -typedef CookieMenuHandler = function void ( - int client, - CookieMenuAction action, - any info, - char[] buffer, - int maxlen -); - -/** - * Add a new prefab item to the client cookie settings menu. - * - * Note: This handles everything automatically and does not require a callback - * - * @param cookie Client preference cookie handle. - * @param type A CookieMenu prefab menu type. - * @param display Text to show on the menu. - * @param handler Optional handler callback for translations and output on selection - * @param info Info data to pass to the callback. - * @error Invalid cookie handle. - */ -native void SetCookiePrefabMenu(Handle cookie, CookieMenu type, const char[] display, CookieMenuHandler handler=INVALID_FUNCTION, any info=0); - -/** - * Adds a new item to the client cookie settings menu. - * - * Note: This only adds the top level menu item. You need to handle any submenus from the callback. - * - * @param handler A MenuHandler callback function. - * @param info Data to pass to the callback. - * @param display Text to show on the menu. - * @error Invalid cookie handle. - */ -native void SetCookieMenuItem(CookieMenuHandler handler, any info, const char[] display); - -/** - * Displays the settings menu to a client. - * - * @param client Client index. - */ -native void ShowCookieMenu(int client); - -/** - * Gets a cookie iterator. Must be freed with CloseHandle(). - * - * @return A new cookie iterator. - */ -native Handle GetCookieIterator(); - -/** - * Reads a cookie iterator, then advances to the next cookie if any. - * - * @param iter Cookie iterator Handle. - * @param name Name buffer. - * @param nameLen Name buffer size. - * @param access Access level of the cookie. - * @param desc Cookie description buffer. - * @param descLen Cookie description buffer size. - * @return True on success, false if there are no more commands. - */ -native bool ReadCookieIterator(Handle iter, - char[] name, - int nameLen, - CookieAccess &access, - char[] desc="", - int descLen=0); - -/** - * Returns the access level of a cookie - * - * @param cookie Client preference cookie handle. - * @return CookieAccess access level. - * @error Invalid cookie handle. - */ -native CookieAccess GetCookieAccess(Handle cookie); - -/** - * Returns the last updated timestamp for a client cookie - * - * @param client Client index. - * @param cookie Cookie handle. - * @return Last updated timestamp. - */ -native int GetClientCookieTime(int client, Handle cookie); - -/** - * Do not edit below this line! - */ -public Extension __ext_cprefs = -{ - name = "Client Preferences", - file = "clientprefs.ext", - autoload = 1, -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_EXTENSIONS -public void __ext_cprefs_SetNTVOptional() -{ - MarkNativeAsOptional("RegClientCookie"); - MarkNativeAsOptional("FindClientCookie"); - MarkNativeAsOptional("SetClientCookie"); - MarkNativeAsOptional("GetClientCookie"); - MarkNativeAsOptional("AreClientCookiesCached"); - MarkNativeAsOptional("SetCookiePrefabMenu"); - MarkNativeAsOptional("SetCookieMenuItem"); - MarkNativeAsOptional("ShowCookieMenu"); - MarkNativeAsOptional("GetCookieIterator"); - MarkNativeAsOptional("ReadCookieIterator"); - MarkNativeAsOptional("GetCookieAccess"); - MarkNativeAsOptional("GetClientCookieTime"); -} -#endif diff --git a/scripting/include/clients.inc b/scripting/include/clients.inc deleted file mode 100644 index 77bb236..0000000 --- a/scripting/include/clients.inc +++ /dev/null @@ -1,811 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _clients_included - #endinput -#endif -#define _clients_included - -/** - * Network flow directions. - */ -enum NetFlow -{ - NetFlow_Outgoing = 0, /**< Outgoing traffic */ - NetFlow_Incoming, /**< Incoming traffic */ - NetFlow_Both, /**< Both values added together */ -}; - -/** - * Auth string types. - * - * Note that for the Steam2 and Steam3 types, the following ids are - * also valid values: - * "STEAM_ID_PENDING" - Authentication is pending. - * "STEAM_ID_LAN" - Authentication is disabled because of being on a LAN server. - * "BOT" - The client is a bot. - */ -enum AuthIdType -{ - AuthId_Engine = 0, /**< The game-specific auth string as returned from the engine */ - - // The following are only available on games that support Steam authentication. - AuthId_Steam2, /**< Steam2 rendered format, ex "STEAM_1:1:4153990" */ - AuthId_Steam3, /**< Steam3 rendered format, ex "[U:1:8307981]" */ - AuthId_SteamID64, /**< A SteamID64 (uint64) as a String, ex "76561197968573709" */ -}; - -/** - * MAXPLAYERS is not the same as MaxClients. - * MAXPLAYERS is a hardcoded value as an upper limit. MaxClients changes based on the server. - */ - -#define MAXPLAYERS 65 /**< Maximum number of players SourceMod supports */ -#define MAX_NAME_LENGTH 32 /**< Maximum buffer required to store a client name */ - -public const int MaxClients; /**< Maximum number of players the server supports (dynamic) */ - -/** - * Called on client connection. If you return true, the client will be allowed in the server. - * If you return false (or return nothing), the client will be rejected. If the client is - * rejected by this forward or any other, OnClientDisconnect will not be called. - * - * Note: Do not write to rejectmsg if you plan on returning true. If multiple plugins write - * to the string buffer, it is not defined which plugin's string will be shown to the client, - * but it is guaranteed one of them will. - * - * @param client Client index. - * @param rejectmsg Buffer to store the rejection message when the connection is refused. - * @param maxlen Maximum number of characters for rejection buffer. - * @return True to validate client's connection, false to refuse it. - */ -forward bool OnClientConnect(int client, char[] rejectmsg, int maxlen); - -/** - * Called once a client successfully connects. This callback is paired with OnClientDisconnect. - * - * @param client Client index. - */ -forward void OnClientConnected(int client); - -/** - * Called when a client is entering the game. - * - * Whether a client has a steamid is undefined until OnClientAuthorized - * is called, which may occur either before or after OnClientPutInServer. - * Similarly, use OnClientPostAdminCheck() if you need to verify whether - * connecting players are admins. - * - * GetClientCount() will include clients as they are passed through this - * function, as clients are already in game at this point. - * - * @param client Client index. - */ -forward void OnClientPutInServer(int client); - -/** - * Called when a client is disconnecting from the server. - * - * @param client Client index. - */ -forward void OnClientDisconnect(int client); - -/** - * Called when a client is disconnected from the server. - * - * @param client Client index. - */ -forward void OnClientDisconnect_Post(int client); - -/** - * Called when a client is sending a command. - * - * As of SourceMod 1.3, the client is guaranteed to be in-game. - * Use command listeners (console.inc) for more advanced hooks. - * - * @param client Client index. - * @param args Number of arguments. - * @return Plugin_Handled blocks the command from being sent, - * and Plugin_Continue resumes normal functionality. - */ -forward Action OnClientCommand(int client, int args); - -/** - * Called when a client is sending a KeyValues command. - * - * @param client Client index. - * @param kv Editable KeyValues data to be sent as the command. - * (This handle should not be stored and will be closed - * after this forward completes.) - * @return Plugin_Handled blocks the command from being sent, - * and Plugin_Continue resumes normal functionality. - */ -forward Action OnClientCommandKeyValues(int client, KeyValues kv); - -/** - * Called after a client has sent a KeyValues command. - * - * @param client Client index. - * @param kv KeyValues data sent as the command. - * (This handle should not be stored and will be closed - * after this forward completes.) - */ -forward void OnClientCommandKeyValues_Post(int client, KeyValues kv); - -/** - * Called whenever the client's settings are changed. - * - * @param client Client index. - */ -forward void OnClientSettingsChanged(int client); - -/** - * Called when a client receives an auth ID. The state of a client's - * authorization as an admin is not guaranteed here. Use - * OnClientPostAdminCheck() if you need a client's admin status. - * - * This is called by bots, but the ID will be "BOT". - * - * @param client Client index. - * @param auth Client Steam2 id, if available, else engine auth id. - */ -forward void OnClientAuthorized(int client, const char[] auth); - -/** - * Called once a client is authorized and fully in-game, but - * before admin checks are done. This can be used to override - * the default admin checks for a client. You should only use - * this for overriding; use OnClientPostAdminCheck() instead - * if you want notification. - * - * Note: If handled/blocked, PostAdminCheck must be signalled - * manually via NotifyPostAdminCheck(). - * - * This callback is guaranteed to occur on all clients, and always - * after each OnClientPutInServer() call. - * - * @param client Client index. - * @return Plugin_Handled to block admin checks. - */ -forward Action OnClientPreAdminCheck(int client); - -/** - * Called directly before OnClientPostAdminCheck() as a method to - * alter administrative permissions before plugins perform final - * post-connect operations. - * - * In general, do not use this function unless you are specifically - * attempting to change access permissions. Use OnClientPostAdminCheck() - * instead if you simply want to perform post-connect authorization - * routines. - * - * See OnClientPostAdminCheck() for more information. - * - * @param client Client index. - */ -forward void OnClientPostAdminFilter(int client); - -/** - * Called once a client is authorized and fully in-game, and - * after all post-connection authorizations have been performed. - * - * This callback is guaranteed to occur on all clients, and always - * after each OnClientPutInServer() call. - * - * @param client Client index. - */ -forward void OnClientPostAdminCheck(int client); - -/** - * This function will be deprecated in a future release. Use the MaxClients variable instead. - * - * Returns the maximum number of clients allowed on the server. This may - * return 0 if called before OnMapStart(), and thus should not be called - * in OnPluginStart(). - * - * You should not globally cache the value to GetMaxClients() because it can change from - * SourceTV or TF2's arena mode. Use the "MaxClients" dynamic variable documented at the - * top of this file. - * - * @return Maximum number of clients allowed. - */ -native int GetMaxClients(); - -/** - * Returns the maximum number of human players allowed on the server. This is - * a game-specific function used on newer games to limit the number of humans - * that can join a game and can be lower than MaxClients. It is the number often - * reflected in the server browser or when viewing the output of the status command. - * On unsupported games or modes without overrides, it will return the same value - * as MaxClients. - * - * You should not globally cache the value to GetMaxHumanPlayers() because it can change across - * game modes. You may still cache it locally. - * - * @return Maximum number of humans allowed. - */ -native int GetMaxHumanPlayers(); - -/** - * Returns the client count put in the server. - * - * @param inGameOnly If false connecting players are also counted. - * @return Client count in the server. - */ -native int GetClientCount(bool inGameOnly=true); - -/** - * Returns the client's name. - * - * @param client Player index. - * @param name Buffer to store the client's name. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @return True on success, false otherwise. - * @error If the client is not connected an error will be thrown. - */ -native bool GetClientName(int client, char[] name, int maxlen); - -/** - * Retrieves a client's IP address. - * - * @param client Player index. - * @param ip Buffer to store the client's ip address. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @param remport Remove client's port from the ip string (true by default). - * @return True on success, false otherwise. - * @error If the client is not connected or the index is invalid. - */ -native bool GetClientIP(int client, char[] ip, int maxlen, bool remport=true); - -/** - * Retrieves a client's authentication string (SteamID). - * - * @param client Player index. - * @param auth Buffer to store the client's auth string. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @param validate Check backend validation status. - * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, - * You WILL KNOW if you need to use this, MOST WILL NOT. - * @return True on success, false otherwise. - * @error If the client is not connected or the index is invalid. - */ -#pragma deprecated Use GetClientAuthId -native bool GetClientAuthString(int client, char[] auth, int maxlen, bool validate=true); - -/** - * Retrieves a client's authentication string (SteamID). - * - * @param client Player index. - * @param authType Auth id type and format to use. - * @param auth Buffer to store the client's auth id. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @param validate Check backend validation status. - * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, - * You WILL KNOW if you need to use this, MOST WILL NOT. - * @return True on success, false otherwise. - * @error If the client is not connected or the index is invalid. - */ -native bool GetClientAuthId(int client, AuthIdType authType, char[] auth, int maxlen, bool validate=true); - -/** - * Returns the client's Steam account ID, a number uniquely identifying a given Steam account. - * This number is the basis for the various display SteamID forms, see the AuthIdType enum for examples. - * - * @param client Client Index. - * @param validate Check backend validation status. - * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, - * You WILL KNOW if you need to use this, MOST WILL NOT. - * @return Steam account ID or 0 if not available. - * @error If the client is not connected or the index is invalid. - */ -native int GetSteamAccountID(int client, bool validate=true); - -/** - * Retrieves a client's user id, which is an index incremented for every client - * that joins the server. - * - * @param client Player index. - * @return User id of the client. - * @error If the client is not connected or the index is invalid. - */ -native int GetClientUserId(int client); - -/** - * Returns if a certain player is connected. - * - * @param client Player index. - * @return True if player is connected to the server, false otherwise. - */ -native bool IsClientConnected(int client); - -/** - * Returns if a certain player has entered the game. - * - * @param client Player index (index does not have to be connected). - * @return True if player has entered the game, false otherwise. - * @error Invalid client index. - */ -native bool IsClientInGame(int client); - -/** - * Returns if a client is in the "kick queue" (i.e. the client will be kicked - * shortly and thus they should not appear as valid). - * - * @param client Player index (must be connected). - * @return True if in the kick queue, false otherwise. - * @error Invalid client index. - */ -native bool IsClientInKickQueue(int client); - -/** - * Backwards compatibility stock - use IsClientInGame - * @deprecated Renamed to IsClientInGame - */ -#pragma deprecated Use IsClientInGame() instead -stock bool IsPlayerInGame(int client) -{ - return IsClientInGame(client); -} - -/** - * Returns if a certain player has been authenticated. - * - * @param client Player index. - * @return True if player has been authenticated, false otherwise. - */ -native bool IsClientAuthorized(int client); - -/** - * Returns if a certain player is a fake client. - * - * @param client Player index. - * @return True if player is a fake client, false otherwise. - */ -native bool IsFakeClient(int client); - -/** - * Returns if a certain player is the SourceTV bot. - * - * @param client Player index. - * @return True if player is the SourceTV bot, false otherwise. - */ -native bool IsClientSourceTV(int client); - -/** - * Returns if a certain player is the Replay bot. - * - * @param client Player index. - * @return True if player is the Replay bot, false otherwise. - */ -native bool IsClientReplay(int client); - -/** - * Returns if a certain player is an observer/spectator. - * - * @param client Player index. - * @return True if player is an observer, false otherwise. - */ -native bool IsClientObserver(int client); - -/** - * Returns if the client is alive or dead. - * - * Note: This function was originally in SDKTools and was moved to core. - * - * @param client Player's index. - * @return True if the client is alive, false otherwise. - * @error Invalid client index, client not in game, or no mod support. - */ -native bool IsPlayerAlive(int client); - -/** - * Retrieves values from client replicated keys. - * - * @param client Player's index. - * @param key Key string. - * @param value Buffer to store value. - * @param maxlen Maximum length of valve (UTF-8 safe). - * @return True on success, false otherwise. - * @error Invalid client index, or client not connected. - */ -native bool GetClientInfo(int client, const char[] key, char[] value, int maxlen); - -/** - * Retrieves a client's team index. - * - * @param client Player's index. - * @return Team index the client is on (mod specific). - * @error Invalid client index, client not in game, or no mod support. - */ -native int GetClientTeam(int client); - -/** - * Sets a client's AdminId. - * - * @param client Player's index. - * @param id AdminId to set. INVALID_ADMIN_ID removes admin permissions. - * @param temp True if the id should be freed on disconnect. - * @error Invalid client index, client not connected, or bogus AdminId. - */ -native void SetUserAdmin(int client, AdminId id, bool temp=false); - -/** - * Retrieves a client's AdminId. - * - * @param client Player's index. - * @return AdminId of the client, or INVALID_ADMIN_ID if none. - * @error Invalid client index, or client not connected. - */ -native AdminId GetUserAdmin(int client); - -/** - * Sets access flags on a client. If the client is not an admin, - * a temporary, anonymous AdminId is given. - * - * @param client Player's index. - * @param ... Flags to set on the client. - * @error Invalid client index, or client not connected. - */ -native void AddUserFlags(int client, AdminFlag ...); - -/** - * Removes flags from a client. If the client is not an admin, - * this has no effect. - * - * @param client Player's index. - * @param ... Flags to remove from the client. - * @error Invalid client index, or client not connected. - */ -native void RemoveUserFlags(int client, AdminFlag ...); - -/** - * Sets access flags on a client using bits instead of flags. If the - * client is not an admin, and flags not 0, a temporary, anonymous AdminId is given. - * - * @param client Player's index. - * @param flags Bitstring of flags to set on client. - */ -native void SetUserFlagBits(int client, int flags); - -/** - * Returns client access flags. If the client is not an admin, - * the result is always 0. - * - * @param client Player's index. - * @return Flags - * @error Invalid client index, or client not connected. - */ -native int GetUserFlagBits(int client); - -/** - * Returns whether a user can target another user. - * This is a helper function for CanAdminTarget. - * - * @param client Player's index. - * @param target Target player's index. - * @return True if target is targettable by the player, false otherwise. - * @error Invalid or unconnected player indexers. - */ -native bool CanUserTarget(int client, int target); - -/** - * Runs through the Core-defined admin authorization checks on a player. - * Has no effect if the player is already an admin. - * - * Note: This function is based on the internal cache only. - * - * @param client Client index. - * @return True if access was changed, false if it did not. - * @error Invalid client index or client not in-game AND authorized. - */ -native bool RunAdminCacheChecks(int client); - -/** - * Signals that a player has completed post-connection admin checks. - * Has no effect if the player has already had this event signalled. - * - * Note: This must be sent even if no admin id was assigned. - * - * @param client Client index. - * @error Invalid client index or client not in-game AND authorized. - */ -native void NotifyPostAdminCheck(int client); - -/** - * Creates a fake client. - * - * @param name Name to use. - * @return Client index on success, 0 otherwise. - */ -native int CreateFakeClient(const char[] name); - -/** - * Sets a convar value on a fake client. - * - * @param client Client index. - * @param cvar ConVar name. - * @param value ConVar value. - * @error Invalid client index, client not connected, - * or client not a fake client. - */ -native void SetFakeClientConVar(int client, const char[] cvar, const char[] value); - -/** - * Returns the client's health. - * - * @param client Player's index. - * @return Health value. - * @error Invalid client index, client not in game, or no mod support. - */ -native int GetClientHealth(int client); - -/** - * Returns the client's model name. - * - * @param client Player's index. - * @param model Buffer to store the client's model name. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @error Invalid client index, client not in game, or no mod support. - */ -native void GetClientModel(int client, char[] model, int maxlen); - -/** - * Returns the client's weapon name. - * - * @param client Player's index. - * @param weapon Buffer to store the client's weapon name. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @error Invalid client index, client not in game, or no mod support. - */ -native void GetClientWeapon(int client, char[] weapon, int maxlen); - -/** - * Returns the client's max size vector. - * - * @param client Player's index. - * @param vec Destination vector to store the client's max size. - * @error Invalid client index, client not in game, or no mod support. - */ -native void GetClientMaxs(int client, float vec[3]); - -/** - * Returns the client's min size vector. - * - * @param client Player's index. - * @param vec Destination vector to store the client's min size. - * @error Invalid client index, client not in game, or no mod support. - */ -native void GetClientMins(int client, float vec[3]); - -/** - * Returns the client's position angle. - * - * @param client Player's index. - * @param ang Destination vector to store the client's position angle. - * @error Invalid client index, client not in game, or no mod support. - */ -native void GetClientAbsAngles(int client, float ang[3]); - -/** - * Returns the client's origin vector. - * - * @param client Player's index. - * @param vec Destination vector to store the client's origin vector. - * @error Invalid client index, client not in game, or no mod support. - */ -native void GetClientAbsOrigin(int client, float vec[3]); - -/** - * Returns the client's armor. - * - * @param client Player's index. - * @return Armor value. - * @error Invalid client index, client not in game, or no mod support. - */ -native int GetClientArmor(int client); - -/** - * Returns the client's death count. - * - * @param client Player's index. - * @return Death count. - * @error Invalid client index, client not in game, or no mod support. - */ -native int GetClientDeaths(int client); - -/** - * Returns the client's frag count. - * - * @param client Player's index. - * @return Frag count. - * @error Invalid client index, client not in game, or no mod support. - */ -native int GetClientFrags(int client); - -/** - * Returns the client's send data rate in bytes/sec. - * - * @param client Player's index. - * @return Data rate. - * @error Invalid client index, client not connected, or fake client. - */ -native int GetClientDataRate(int client); - -/** - * Returns if a client is timing out - * - * @param client Player's index. - * @return True if client is timing out, false otherwise. - * @error Invalid client index, client not connected, or fake client. - */ -native bool IsClientTimingOut(int client); - -/** - * Returns the client's connection time in seconds. - * - * @param client Player's index. - * @return Connection time. - * @error Invalid client index, client not connected, or fake client. - */ -native float GetClientTime(int client); - -/** - * Returns the client's current latency (RTT), more accurate than GetAvgLatency but jittering. - * - * @param client Player's index. - * @param flow Traffic flowing direction. - * @return Latency, or -1 if network info is not available. - * @error Invalid client index, client not connected, or fake client. - */ -native float GetClientLatency(int client, NetFlow flow); - -/** - * Returns the client's average packet latency in seconds. - * - * @param client Player's index. - * @param flow Traffic flowing direction. - * @return Latency, or -1 if network info is not available. - * @error Invalid client index, client not connected, or fake client. - */ -native float GetClientAvgLatency(int client, NetFlow flow); - -/** - * Returns the client's average packet loss, values go from 0 to 1 (for percentages). - * - * @param client Player's index. - * @param flow Traffic flowing direction. - * @return Average packet loss, or -1 if network info is not available. - * @error Invalid client index, client not connected, or fake client. - */ -native float GetClientAvgLoss(int client, NetFlow flow); - -/** - * Returns the client's average packet choke, values go from 0 to 1 (for percentages). - * - * @param client Player's index. - * @param flow Traffic flowing direction. - * @return Average packet loss, or -1 if network info is not available. - * @error Invalid client index, client not connected, or fake client. - */ -native float GetClientAvgChoke(int client, NetFlow flow); - -/** - * Returns the client's data flow in bytes/sec. - * - * @param client Player's index. - * @param flow Traffic flowing direction. - * @return Data flow. - * @error Invalid client index, client not connected, or fake client. - */ -native float GetClientAvgData(int client, NetFlow flow); - -/** - * Returns the client's average packet frequency in packets/sec. - * - * @param client Player's index. - * @param flow Traffic flowing direction. - * @return Packet frequency. - * @error Invalid client index, client not connected, or fake client. - */ -native float GetClientAvgPackets(int client, NetFlow flow); - -/** - * Translates an userid index to the real player index. - * - * @param userid Userid value. - * @return Client value. - * @error Returns 0 if invalid userid. - */ -native int GetClientOfUserId(int userid); - -/** - * Disconnects a client from the server as soon as the next frame starts. - * - * Note: Originally, KickClient() was immediate. The delay was introduced - * because despite warnings, plugins were using it in ways that would crash. - * The new safe version can break cases that rely on immediate disconnects, - * but ensures that plugins do not accidentally cause crashes. - * - * If you need immediate disconnects, use KickClientEx(). - * - * Note: IsClientInKickQueue() will return true before the kick occurs. - * - * @param client Client index. - * @param format Optional formatting rules for disconnect reason. - * Note that a period is automatically appended to the string by the engine. - * @param ... Variable number of format parameters. - * @error Invalid client index, or client not connected. - */ -native void KickClient(int client, const char[] format="", any ...); - -/** - * Immediately disconnects a client from the server. - * - * Kicking clients from certain events or callbacks may cause crashes. If in - * doubt, create a short (0.1 second) timer to kick the client in the next - * available frame. - * - * @param client Client index. - * @param format Optional formatting rules for disconnect reason. - * Note that a period is automatically appended to the string by the engine. - * @param ... Variable number of format parameters. - * @error Invalid client index, or client not connected. - */ -native void KickClientEx(int client, const char[] format="", any ...); - -/** - * Changes a client's team through the mod's generic team changing function. - * On CS:S, this will kill the player. - * - * @param client Client index. - * @param team Mod-specific team index. - * @error Invalid client index, client not connected, or lack of - * mod support. - */ -native void ChangeClientTeam(int client, int team); - -/** - * Returns the clients unique serial identifier. - * - * @param client Client index. - * @return Serial number. - * @error Invalid client index, or client not connected. - */ -native int GetClientSerial(int client); - -/** - * Returns the client index by its serial number. - * - * @param serial Serial number. - * @return Client index, or 0 for invalid serial. - */ -native int GetClientFromSerial(int serial); diff --git a/scripting/include/commandfilters.inc b/scripting/include/commandfilters.inc deleted file mode 100644 index 67e1e5c..0000000 --- a/scripting/include/commandfilters.inc +++ /dev/null @@ -1,161 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _commandfilters_included - #endinput -#endif -#define _commandfilters_included - -#define MAX_TARGET_LENGTH 64 - -#define COMMAND_FILTER_ALIVE (1<<0) /**< Only allow alive players */ -#define COMMAND_FILTER_DEAD (1<<1) /**< Only filter dead players */ -#define COMMAND_FILTER_CONNECTED (1<<2) /**< Allow players not fully in-game */ -#define COMMAND_FILTER_NO_IMMUNITY (1<<3) /**< Ignore immunity rules */ -#define COMMAND_FILTER_NO_MULTI (1<<4) /**< Do not allow multiple target patterns */ -#define COMMAND_FILTER_NO_BOTS (1<<5) /**< Do not allow bots to be targetted */ - -#define COMMAND_TARGET_NONE 0 /**< No target was found */ -#define COMMAND_TARGET_NOT_ALIVE -1 /**< Single client is not alive */ -#define COMMAND_TARGET_NOT_DEAD -2 /**< Single client is not dead */ -#define COMMAND_TARGET_NOT_IN_GAME -3 /**< Single client is not in game */ -#define COMMAND_TARGET_IMMUNE -4 /**< Single client is immune */ -#define COMMAND_TARGET_EMPTY_FILTER -5 /**< A multi-filter (such as @all) had no targets */ -#define COMMAND_TARGET_NOT_HUMAN -6 /**< Target was not human */ -#define COMMAND_TARGET_AMBIGUOUS -7 /**< Partial name had too many targets */ - -/** - * Processes a generic command target string, and resolves it to a list - * of clients or one client, based on filtering rules and a pattern. - * - * Note that you should use LoadTranslations("common.phrases") in OnPluginStart(), - * as that file is guaranteed to contain all of the translatable phrases that - * ProcessTargetString() will return. - * - * @param pattern Pattern to find clients against. - * @param admin Admin performing the action, or 0 if the server. - * @param targets Array to hold targets. - * @param max_targets Maximum size of the targets array. - * @param filter_flags Filter flags. - * @param target_name Buffer to store the target name. - * @param tn_maxlength Maximum length of the target name buffer. - * @param tn_is_ml OUTPUT: Will be true if the target name buffer is an ML phrase, - * false if it is a normal string. - * @return If a multi-target pattern was used, the number of clients found - * is returned. If a single-target pattern was used, 1 is returned - * if one valid client is found. Otherwise, a COMMAND_TARGET reason - * for failure is returned. - */ -native int ProcessTargetString(const char[] pattern, - int admin, - int[] targets, - int max_targets, - int filter_flags, - char[] target_name, - int tn_maxlength, - bool &tn_is_ml); - -/** - * Replies to a client with a given message describing a targetting - * failure reason. - * - * Note: The translation phrases are found in common.phrases.txt. - * - * @param client Client index, or 0 for server. - * @param reason COMMAND_TARGET reason. - */ -stock void ReplyToTargetError(int client, int reason) -{ - switch (reason) - { - case COMMAND_TARGET_NONE: - { - ReplyToCommand(client, "[SM] %t", "No matching client"); - } - case COMMAND_TARGET_NOT_ALIVE: - { - ReplyToCommand(client, "[SM] %t", "Target must be alive"); - } - case COMMAND_TARGET_NOT_DEAD: - { - ReplyToCommand(client, "[SM] %t", "Target must be dead"); - } - case COMMAND_TARGET_NOT_IN_GAME: - { - ReplyToCommand(client, "[SM] %t", "Target is not in game"); - } - case COMMAND_TARGET_IMMUNE: - { - ReplyToCommand(client, "[SM] %t", "Unable to target"); - } - case COMMAND_TARGET_EMPTY_FILTER: - { - ReplyToCommand(client, "[SM] %t", "No matching clients"); - } - case COMMAND_TARGET_NOT_HUMAN: - { - ReplyToCommand(client, "[SM] %t", "Cannot target bot"); - } - case COMMAND_TARGET_AMBIGUOUS: - { - ReplyToCommand(client, "[SM] %t", "More than one client matched"); - } - } -} - -/** - * Adds clients to a multi-target filter. - * - * @param pattern Pattern name. - * @param clients Array to fill with unique, valid client indexes. - * @return True if pattern was recognized, false otherwise. - */ -typedef MultiTargetFilter = function bool (const char[] pattern, Handle clients); - -/** - * Adds a multi-target filter function for ProcessTargetString(). - * - * @param pattern Pattern to match (case sensitive). - * @param filter Filter function. - * @param phrase Descriptive phrase to display on successful match. - * @param phraseIsML True if phrase is multi-lingual, false otherwise. - */ -native void AddMultiTargetFilter(const char[] pattern, MultiTargetFilter filter, - const char[] phrase, bool phraseIsML); - -/** - * Removes a multi-target filter function from ProcessTargetString(). - * - * @param pattern Pattern to match (case sensitive). - * @param filter Filter function. - */ -native void RemoveMultiTargetFilter(const char[] pattern, MultiTargetFilter filter); diff --git a/scripting/include/commandline.inc b/scripting/include/commandline.inc deleted file mode 100644 index 5ff7d22..0000000 --- a/scripting/include/commandline.inc +++ /dev/null @@ -1,86 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _commandline_included_ - #endinput -#endif -#define _commandline_included_ - -/** - * Gets the full command line the server was launched with. - * - * @param commandLine Buffer to store the command line in. - * @param maxlen Maximum length of the command line buffer. - * @return True if the command line is valid; otherwise, false. - * @error No command line available, or no mod support. - */ -native bool GetCommandLine(char[] commandLine, int maxlen); - -/** - * Gets the value of a command line parameter the server was launched with. - * - * @param param The command line parameter to get the value of. - * @param value Buffer to store the parameter value in. - * @param maxlen Maximum length of the value buffer. - * @param defValue The default value to return if the parameter wasn't specified. - * @error No command line available, or no mod support. - */ -native void GetCommandLineParam(const char[] param, char[] value, int maxlen, const char[] defValue=""); - -/** - * Gets the value of a command line parameter the server was launched with. - * - * @param param The command line parameter to get the value of. - * @param defValue The default value to return if the parameter wasn't specified. - * @return The integer value of the command line parameter value. - * @error No command line available, or no mod support. - */ -native int GetCommandLineParamInt(const char[] param, int defValue=0); - -/** - * Gets the value of a command line parameter the server was launched with. - * - * @param param The command line parameter to get the value of. - * @param defValue The default value to return if the parameter wasn't specified. - * @return The floating point value of the command line parameter value. - * @error No command line available, or no mod support. - */ -native float GetCommandLineParamFloat(const char[] param, float defValue=0.0); - -/** - * Determines if a specific command line parameter is present. - * - * @param param The command line parameter to test. - * @return True if the command line parameter is specified; otherwise, false. - * @error No command line available, or no mod support. - */ -native bool FindCommandLineParam(const char[] param); diff --git a/scripting/include/console.inc b/scripting/include/console.inc deleted file mode 100644 index 2ea3b5f..0000000 --- a/scripting/include/console.inc +++ /dev/null @@ -1,668 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _console_included - #endinput -#endif -#define _console_included - -#define INVALID_FCVAR_FLAGS (-1) - -/** - * Console variable query helper values. - */ -enum QueryCookie -{ - QUERYCOOKIE_FAILED = 0, -}; - -/** - * Reply sources for commands. - */ -enum ReplySource -{ - SM_REPLY_TO_CONSOLE = 0, - SM_REPLY_TO_CHAT = 1, -}; - -/** - * @section Flags for console commands and console variables. The descriptions - * for each constant come directly from the Source SDK. - */ - -#pragma deprecated No logic using this flag ever existed in a released game. It only ever appeared in the first hl2sdk. -#define FCVAR_PLUGIN 0 // Actual value is same as FCVAR_SS_ADDED in Left 4 Dead and later. -#pragma deprecated Did you mean FCVAR_DEVELOPMENTONLY? (No logic using this flag ever existed in a released game. It only ever appeared in the first hl2sdk.) -#define FCVAR_LAUNCHER (1<<1) // Same value as FCVAR_DEVELOPMENTONLY, which is what most usages of this were intending to use. - - -#define FCVAR_NONE 0 // The default, no flags at all -#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc. -#define FCVAR_DEVELOPMENTONLY (1<<1) // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined. (OB+) -#define FCVAR_GAMEDLL (1<<2) // Defined by the game DLL. -#define FCVAR_CLIENTDLL (1<<3) // Defined by the client DLL. -#define FCVAR_MATERIAL_SYSTEM (1<<4) // Defined by the material system. (EP1-only) -#define FCVAR_HIDDEN (1<<4) // Hidden. Doesn't appear in find or autocomplete. Like DEVELOPMENTONLY, but can't be compiled out.1 (OB+) -#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. - // Sends 1 if it's not bland/zero, 0 otherwise as value. -#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. -#define FCVAR_ARCHIVE (1<<7) // Set to cause it to be saved to vars.rc -#define FCVAR_NOTIFY (1<<8) // Notifies players when changed. -#define FCVAR_USERINFO (1<<9) // Changes the client's info string. -#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters (e.g., used for player name, etc.) -#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log -#define FCVAR_NEVER_AS_STRING (1<<12) // Never try to print that cvar. -#define FCVAR_REPLICATED (1<<13) // Server setting enforced on clients. -#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats -#define FCVAR_SS (1<<15) // causes varnameN where N 2 through max splitscreen slots for mod to be autogenerated (L4D+) -#define FCVAR_DEMO (1<<16) // Record this cvar when starting a demo file. -#define FCVAR_DONTRECORD (1<<17) // Don't record these command in demo files. -#define FCVAR_SS_ADDED (1<<18) // This is one of the "added" FCVAR_SS variables for the splitscreen players (L4D+) -#define FCVAR_RELEASE (1<<19) // Cvars tagged with this are the only cvars available to customers (L4D+) -#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload (OB+) -#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload (OB+) -#define FCVAR_NOT_CONNECTED (1<<22) // Cvar cannot be changed by a client that is connected to a server. -#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread (OB+) -#define FCVAR_ARCHIVE_XBOX (1<<24) // Cvar written to config.cfg on the Xbox. -#define FCVAR_ARCHIVE_GAMECONSOLE (1<<24) // Cvar written to config.cfg on the Xbox. -#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) // used as a debugging tool necessary to check material system thread convars (OB+) -#define FCVAR_SERVER_CAN_EXECUTE (1<<28) // the server is allowed to execute this command on clients via - // ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd. (OB+) -#define FCVAR_SERVER_CANNOT_QUERY (1<<29) // If this is set, then the server is not allowed to query this cvar's value (via - // IServerPluginHelpers::StartQueryCvarValue). -#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command. - // Note: IVEngineClient::ClientCmd_Unrestricted can run any client command. - -/** - * @endsection - */ - -/** - * Executes a server command as if it were on the server console (or RCON) - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -native void ServerCommand(const char[] format, any ...); - -/** - * Executes a server command as if it were on the server console (or RCON) - * and stores the printed text into buffer. - * - * Warning: This calls ServerExecute internally and may have issues if - * certain commands are in the buffer, only use when you really need - * the response. - * Also, on L4D2 this will not print the command output to the server console. - * - * @param buffer String to store command result into. - * @param maxlen Length of buffer. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -native void ServerCommandEx(char[] buffer, int maxlen, const char[] format, any ...); - -/** - * Inserts a server command at the beginning of the server command buffer. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -native void InsertServerCommand(const char[] format, any ...); - -/** - * Executes every command in the server's command buffer, rather than once per frame. - */ -native void ServerExecute(); - -/** - * Executes a client command. Note that this will not work on clients unless - * they have cl_restrict_server_commands set to 0. - * - * @param client Index of the client. - * @param fmt Format of the client command. - * @param ... Format parameters - * @error Invalid client index, or client not connected. - */ -native void ClientCommand(int client, const char[] fmt, any ...); - -/** - * Executes a client command on the server without being networked. - * - * FakeClientCommand() overwrites the command tokenization buffer. This can - * cause undesired effects because future calls to GetCmdArg* will return - * data from the FakeClientCommand(), not the parent command. If you are in - * a hook where this matters (for example, a "say" hook), you should use - * FakeClientCommandEx() instead. - * - * @param client Index of the client. - * @param fmt Format of the client command. - * @param ... Format parameters - * @error Invalid client index, or client not connected. - */ -native void FakeClientCommand(int client, const char[] fmt, any ...); - -/** - * Executes a client command on the server without being networked. The - * execution of the client command is delayed by one frame to prevent any - * re-entrancy issues that might surface with FakeClientCommand(). - * - * @param client Index of the client. - * @param fmt Format of the client command. - * @param ... Format parameters - * @error Invalid client index, or client not connected. - */ -native void FakeClientCommandEx(int client, const char[] fmt, any ...); - -/** - * Executes a KeyValues client command on the server without being networked. - * - * @param client Index of the client. - * @param kv KeyValues data to be sent. - * @error Invalid client index, client not connected, - * or unsupported on current game. - */ -native void FakeClientCommandKeyValues(int client, KeyValues kv); - -/** - * Sends a message to the server console. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -native void PrintToServer(const char[] format, any ...); - -/** - * Sends a message to a client's console. - * - * @param client Client index. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error If the client is not connected an error will be thrown. - */ -native void PrintToConsole(int client, const char[] format, any ...); - - -/** - * Sends a message to every client's console. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -stock void PrintToConsoleAll(const char[] format, any ...) -{ - char buffer[254]; - - for (int i = 1; i <= MaxClients; i++) - { - if (IsClientInGame(i)) - { - SetGlobalTransTarget(i); - VFormat(buffer, sizeof(buffer), format, 2); - PrintToConsole(i, "%s", buffer); - } - } -} - -/** - * Reples to a message in a command. - * - * A client index of 0 will use PrintToServer(). - * If the command was from the console, PrintToConsole() is used. - * If the command was from chat, PrintToChat() is used. - * - * @param client Client index, or 0 for server. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error If the client is not connected or invalid. - */ -native void ReplyToCommand(int client, const char[] format, any ...); - -/** - * Returns the current reply source of a command. - * - * @return ReplySource value. - */ -native ReplySource GetCmdReplySource(); - -/** - * Sets the current reply source of a command. - * - * Only use this if you know what you are doing. You should save the old value - * and restore it once you are done. - * - * @param source New ReplySource value. - * @return Old ReplySource value. - */ -native ReplySource SetCmdReplySource(ReplySource source); - -/** - * Returns whether the current say hook is a chat trigger. - * - * This function is only meaningful inside say or say_team hooks. - * - * @return True if a chat trigger, false otherwise. - */ -native bool IsChatTrigger(); - -/** - * Displays usage of an admin command to users depending on the - * setting of the sm_show_activity cvar. All users receive a message - * in their chat text, except for the originating client, who receives - * the message based on the current ReplySource. - * - * @param client Client index doing the action, or 0 for server. - * @param tag Tag to prepend to the message. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error - */ -native void ShowActivity2(int client, const char[] tag, const char[] format, any ...); - -/** - * Displays usage of an admin command to users depending on the - * setting of the sm_show_activity cvar. - * - * This version does not display a message to the originating client - * if used from chat triggers or menus. If manual replies are used - * for these cases, then this function will suffice. Otherwise, - * ShowActivity2() is slightly more useful. - * - * @param client Client index doing the action, or 0 for server. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error - */ -native void ShowActivity(int client, const char[] format, any ...); - -/** - * Same as ShowActivity(), except the tag parameter is used instead of - * "[SM] " (note that you must supply any spacing). - * - * @param client Client index doing the action, or 0 for server. - * @param tag Tag to display with. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error - */ -native void ShowActivityEx(int client, const char[] tag, const char[] format, any ...); - -/** - * Given an originating client and a target client, returns the string - * that describes the originating client according to the sm_show_activity cvar. - * - * For example, "ADMIN", "PLAYER", or a player's name could be placed in this buffer. - * - * @param client Originating client; may be 0 for server console. - * @param target Targeted client. - * @param namebuf Name buffer. - * @param maxlength Maximum size of the name buffer. - * @return True if activity should be shown. False otherwise. In either - * case, the name buffer is filled. The return value can be used - * to broadcast a "safe" name to all players regardless of the - * sm_show_activity filters. - * @error Invalid client index or client not connected. - */ -native bool FormatActivitySource(int client, int target, const char[] namebuf, int maxlength); - -/** - * Called when a server-only command is invoked. - * - * @param args Number of arguments that were in the argument string. - * @return An Action value. Not handling the command - * means that Source will report it as "not found." - */ -typedef SrvCmd = function Action (int args); - -/** - * Creates a server-only console command, or hooks an already existing one. - * - * Server commands are case sensitive. - * - * @param cmd Name of the command to hook or create. - * @param callback A function to use as a callback for when the command is invoked. - * @param description Optional description to use for command creation. - * @param flags Optional flags to use for command creation. - * @error Command name is the same as an existing convar. - */ -native void RegServerCmd(const char[] cmd, SrvCmd callback, const char[] description="", int flags=0); - -/** - * Called when a generic console command is invoked. - * - * @param client Index of the client, or 0 from the server. - * @param args Number of arguments that were in the argument string. - * @return An Action value. Not handling the command - * means that Source will report it as "not found." - */ -typedef ConCmd = function Action (int client, int args); - -/** - * Creates a console command, or hooks an already existing one. - * - * Console commands are case sensitive. However, if the command already exists in the game, - * a client may enter the command in any case. SourceMod corrects for this automatically, - * and you should only hook the "real" version of the command. - * - * @param cmd Name of the command to hook or create. - * @param callback A function to use as a callback for when the command is invoked. - * @param description Optional description to use for command creation. - * @param flags Optional flags to use for command creation. - * @error Command name is the same as an existing convar. - */ -native void RegConsoleCmd(const char[] cmd, ConCmd callback, const char[] description="", int flags=0); - -/** - * Creates a console command as an administrative command. If the command does not exist, - * it is created. When this command is invoked, the access rights of the player are - * automatically checked before allowing it to continue. - * - * Admin commands are case sensitive from both the client and server. - * - * @param cmd String containing command to register. - * @param callback A function to use as a callback for when the command is invoked. - * @param adminflags Administrative flags (bitstring) to use for permissions. - * @param description Optional description to use for help. - * @param group String containing the command group to use. If empty, - * the plugin's filename will be used instead. - * @param flags Optional console flags. - * @error Command name is the same as an existing convar. - */ -native void RegAdminCmd(const char[] cmd, - ConCmd callback, - int adminflags, - const char[] description="", - const char[] group="", - int flags=0); - -/** - * Returns the number of arguments from the current console or server command. - * @note Unlike the HL2 engine call, this does not include the command itself. - * - * @return Number of arguments to the current command. - */ -native int GetCmdArgs(); - -/** - * Retrieves a command argument given its index, from the current console or - * server command. - * @note Argument indexes start at 1; 0 retrieves the command name. - * - * @param argnum Argument number to retrieve. - * @param buffer Buffer to use for storing the string. - * @param maxlength Maximum length of the buffer. - * @return Length of string written to buffer. - */ -native int GetCmdArg(int argnum, char[] buffer, int maxlength); - -/** - * Retrieves the entire command argument string in one lump from the current - * console or server command. - * - * @param buffer Buffer to use for storing the string. - * @param maxlength Maximum length of the buffer. - * @return Length of string written to buffer. - */ -native int GetCmdArgString(char[] buffer, int maxlength); - -/** - * Gets a command iterator. Must be freed with CloseHandle(). - * - * @return A new command iterator. - */ -native Handle GetCommandIterator(); - -/** - * Reads a command iterator, then advances to the next command if any. - * Only SourceMod specific commands are returned. - * - * @param iter Command iterator Handle. - * @param name Name buffer. - * @param nameLen Name buffer size. - * @param eflags Effective default flags of a command. - * @param desc Command description buffer. - * @param descLen Command description buffer size. - * @return True on success, false if there are no more commands. - */ -native bool ReadCommandIterator(Handle iter, - char[] name, - int nameLen, - int &eflags=0, - char[] desc="", - int descLen=0); - -/** - * Returns whether a client has access to a given command string. The string - * can be any override string, as overrides can be independent of - * commands. This feature essentially allows you to create custom - * flags using the override system. - * - * @param client Client index. - * @param command Command name. If the command is not found, the default - * flags are used. - * @param flags Flag string to use as a default, if the command or override - * is not found. - * @param override_only If true, SourceMod will not attempt to find a matching - * command, and it will only use the default flags specified. - * Otherwise, SourceMod will ignore the default flags if - * there is a matching admin command. - * @return True if the client has access, false otherwise. - */ -native bool CheckCommandAccess(int client, - const char[] command, - int flags, - bool override_only=false); - -/** - * Returns whether an admin has access to a given command string. The string - * can be any override string, as overrides can be independent of - * commands. This feature essentially allows you to create custom flags - * using the override system. - * - * @param id AdminId of the admin. - * @param command Command name. If the command is not found, the default - * flags are used. - * @param flags Flag string to use as a default, if the command or override - * is not found. - * @param override_only If true, SourceMod will not attempt to find a matching - * command, and it will only use the default flags specified. - * Otherwise, SourceMod will ignore the default flags if - * there is a matching admin command. - * @return True if the admin has access, false otherwise. - */ -native bool CheckAccess(AdminId id, - const char[] command, - int flags, - bool override_only=false); - -/** - * Returns the bitstring of flags of a command. - * - * @param name Name of the command. - * @return A bitstring containing the FCVAR_* flags that are enabled - * or INVALID_FCVAR_FLAGS if command not found. - */ -native int GetCommandFlags(const char[] name); - -/** - * Sets the bitstring of flags of a command. - * - * @param name Name of the command. - * @param flags A bitstring containing the FCVAR_* flags to enable. - * @return True on success, otherwise false. - */ -native bool SetCommandFlags(const char[] name, int flags); - -/** - * Starts a ConCommandBase search, traversing the list of ConVars and - * ConCommands. If a Handle is returned, the next entry must be read - * via FindNextConCommand(). The order of the list is undefined. - * - * @param buffer Buffer to store entry name. - * @param max_size Maximum size of the buffer. - * @param isCommand Variable to store whether the entry is a command. - * If it is not a command, it is a ConVar. - * @param flags Variable to store entry flags. - * @param description Buffer to store the description, empty if no description present. - * @param descrmax_size Maximum size of the description buffer. - * @return On success, a ConCmdIter Handle is returned, which - * can be read via FindNextConCommand(), and must be - * closed via CloseHandle(). Additionally, the output - * parameters will be filled with information of the - * first ConCommandBase entry. - * On failure, INVALID_HANDLE is returned, and the - * contents of outputs is undefined. - */ -native Handle FindFirstConCommand(char[] buffer, int max_size, bool &isCommand, int &flags=0, char[] description="", int descrmax_size=0); - -/** - * Reads the next entry in a ConCommandBase iterator. - * - * @param search ConCmdIter Handle to search. - * @param buffer Buffer to store entry name. - * @param max_size Maximum size of the buffer. - * @param isCommand Variable to store whether the entry is a command. - * If it is not a command, it is a ConVar. - * @param flags Variable to store entry flags. - * @param description Buffer to store the description, empty if no description present. - * @param descrmax_size Maximum size of the description buffer. - * @return On success, the outputs are filled, the iterator is - * advanced to the next entry, and true is returned. - * If no more entries exist, false is returned, and the - * contents of outputs is undefined. - */ -native bool FindNextConCommand(Handle search, char[] buffer, int max_size, bool &isCommand, int &flags=0, char[] description="", int descrmax_size=0); - -/** - * Adds an informational string to the server's public "tags". - * This string should be a short, unique identifier. - * - * Note: Tags are automatically removed when a plugin unloads. - * Note: Currently, this function does nothing because of bugs in the Valve master. - * - * @param tag Tag string to append. - */ -native void AddServerTag(const char[] tag); - -/** - * Removes a tag previously added by the calling plugin. - * - * @param tag Tag string to remove. - */ -native void RemoveServerTag(const char[] tag); - -/** - * Callback for command listeners. This is invoked whenever any command - * reaches the server, from the server console itself or a player. - * - * Clients may be in the process of connecting when they are executing commands - * IsClientConnected(client) is not guaranteed to return true. Other functions - * such as GetClientIP() may not work at this point either. - * - * Returning Plugin_Handled or Plugin_Stop will prevent the original, - * baseline code from running. - * - * -- TEXT BELOW IS IMPLEMENTATION, AND NOT GUARANTEED -- - * Even if returning Plugin_Handled or Plugin_Stop, some callbacks will still - * trigger. These are: - * * C++ command dispatch hooks from Metamod:Source plugins - * * Reg*Cmd() hooks that did not create new commands. - * - * @param client Client, or 0 for server. - * Client may not be connected or in game. - * @param command Command name, lower case. To get name as typed, use - * GetCmdArg() and specify argument 0. - * @param argc Argument count. - * @return Action to take (see extended notes above). - */ -typedef CommandListener = function Action (int client, const char[] command, int argc); - -#define FEATURECAP_COMMANDLISTENER "command listener" - -/** - * Adds a callback that will fire when a command is sent to the server. - * - * Registering commands is designed to create a new command as part of the UI, - * whereas this is a lightweight hook on a command string, existing or not. - * Using Reg*Cmd to intercept is in poor practice, as it physically creates a - * new command and can slow down dispatch in general. - * - * To see if this feature is available, use FeatureType_Capability and - * FEATURECAP_COMMANDLISTENER. - * - * @param callback Callback. - * @param command Command, or if not specified, a global listener. - * The command is case insensitive. - * @return True if this feature is available on the current game, - * false otherwise. - */ -native bool AddCommandListener(CommandListener callback, const char[] command=""); - -/** - * Removes a previously added command listener, in reverse order of being added. - * - * @param callback Callback. - * @param command Command, or if not specified, a global listener. - * The command is case insensitive. - * @error Callback has no active listeners. - */ -native void RemoveCommandListener(CommandListener callback, const char[] command=""); - -/** - * Returns true if the supplied command exists. - * - * @param command Command to find. - * @return True if command is found, false otherwise. - */ -stock bool CommandExists(const char[] command) -{ - return (GetCommandFlags(command) != INVALID_FCVAR_FLAGS); -} -/** - * Global listener for the chat commands. - * - * @param client Client index. - * @param command Command name. - * @param sArgs Chat argument string. - * - * @return An Action value. Returning Plugin_Handled bypasses the game function call. - Returning Plugin_Stop bypasses the post hook as well as the game function. - */ -forward Action OnClientSayCommand(int client, const char[] command, const char[] sArgs); - -/** - * Global post listener for the chat commands. - * - * @param client Client index. - * @param command Command name. - * @param sArgs Chat argument string. - */ -forward void OnClientSayCommand_Post(int client, const char[] command, const char[] sArgs); diff --git a/scripting/include/convars.inc b/scripting/include/convars.inc deleted file mode 100644 index 6896ce1..0000000 --- a/scripting/include/convars.inc +++ /dev/null @@ -1,498 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _convars_included - #endinput -#endif -#define _convars_included - -/** - * Console variable bound values used with Get/SetConVarBounds() - */ -enum ConVarBounds -{ - ConVarBound_Upper = 0, - ConVarBound_Lower -}; - -/** - * Console variable query result values. - */ -enum ConVarQueryResult -{ - ConVarQuery_Okay = 0, //< Retrieval of client convar value was successful. */ - ConVarQuery_NotFound, //< Client convar was not found. */ - ConVarQuery_NotValid, //< A console command with the same name was found, but there is no convar. */ - ConVarQuery_Protected //< Client convar was found, but it is protected. The server cannot retrieve its value. */ -}; - -// Called when a console variable's value is changed. -// -// @param convar Handle to the convar that was changed. -// @param oldValue String containing the value of the convar before it was changed. -// @param newValue String containing the new value of the convar. -typedef ConVarChanged = function void (ConVar convar, const char[] oldValue, const char[] newValue); - -// Creates a new console variable. -// -// @param name Name of new convar. -// @param defaultValue String containing the default value of new convar. -// @param description Optional description of the convar. -// @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details. -// @param hasMin Optional boolean that determines if the convar has a minimum value. -// @param min Minimum floating point value that the convar can have if hasMin is true. -// @param hasMax Optional boolean that determines if the convar has a maximum value. -// @param max Maximum floating point value that the convar can have if hasMax is true. -// @return A handle to the newly created convar. If the convar already exists, a handle to it will still be returned. -// @error Convar name is blank or is the same as an existing console command. -native ConVar CreateConVar( - const char[] name, - const char[] defaultValue, - const char[] description="", - int flags=0, - bool hasMin=false, float min=0.0, - bool hasMax=false, float max=0.0); - -// Searches for a console variable. -// -// @param name Name of convar to find. -// @return A ConVar object if found; null otherwise. -native ConVar FindConVar(const char[] name); - -// A ConVar is a configurable, named setting in the srcds console. -methodmap ConVar < Handle -{ - // Retrieves or sets a boolean value for the convar. - property bool BoolValue { - public native get(); - public native set(bool b); - } - - // Retrieves or sets an integer value for the convar. - property int IntValue { - public native get(); - public native set(int value); - } - - // Retrieves or sets a float value for the convar. - property float FloatValue { - public native get(); - public native set(float value); - } - - // Gets or sets the flag bits (FCVAR_*) on the convar. - property int Flags { - public native get(); - public native set(int flags); - } - - // Sets the boolean value of a console variable. - // - // Note: The replicate and notify params are only relevant for the - // original, Dark Messiah, and Episode 1 engines. Newer engines - // automatically do these things when the convar value is changed. - // - // @param value New boolean value. - // @param replicate If set to true, the new convar value will be set on all clients. - // This will only work if the convar has the FCVAR_REPLICATED flag - // and actually exists on clients. - // @param notify If set to true, clients will be notified that the convar has changed. - // This will only work if the convar has the FCVAR_NOTIFY flag. - public native void SetBool(bool value, bool replicate=false, bool notify=false); - - // Sets the integer value of a console variable. - // - // Note: The replicate and notify params are only relevant for the - // original, Dark Messiah, and Episode 1 engines. Newer engines - // automatically do these things when the convar value is changed. - // - // @param value New integer value. - // @param replicate If set to true, the new convar value will be set on all clients. - // This will only work if the convar has the FCVAR_REPLICATED flag - // and actually exists on clients. - // @param notify If set to true, clients will be notified that the convar has changed. - // This will only work if the convar has the FCVAR_NOTIFY flag. - public native void SetInt(int value, bool replicate=false, bool notify=false); - - // Sets the floating point value of a console variable. - // - // Note: The replicate and notify params are only relevant for the - // original, Dark Messiah, and Episode 1 engines. Newer engines - // automatically do these things when the convar value is changed. - // - // @param value New floating point value. - // @param replicate If set to true, the new convar value will be set on all clients. - // This will only work if the convar has the FCVAR_REPLICATED flag - // and actually exists on clients. - // @param notify If set to true, clients will be notified that the convar has changed. - // This will only work if the convar has the FCVAR_NOTIFY flag. - public native void SetFloat(float value, bool replicate=false, bool notify=false); - - // Retrieves the string value of a console variable. - // - // @param convar Handle to the convar. - // @param value Buffer to store the value of the convar. - // @param maxlength Maximum length of string buffer. - public native void GetString(char[] value, int maxlength); - - // Sets the string value of a console variable. - // - // Note: The replicate and notify params are only relevant for the - // original, Dark Messiah, and Episode 1 engines. Newer engines - // automatically do these things when the convar value is changed. - // - // @param value New string value. - // @param replicate If set to true, the new convar value will be set on all clients. - // This will only work if the convar has the FCVAR_REPLICATED flag - // and actually exists on clients. - // @param notify If set to true, clients will be notified that the convar has changed. - // This will only work if the convar has the FCVAR_NOTIFY flag. - public native void SetString(const char[] value, bool replicate=false, bool notify=false); - - // Resets the console variable to its default value. - // - // Note: The replicate and notify params are only relevant for the - // original, Dark Messiah, and Episode 1 engines. Newer engines - // automatically do these things when the convar value is changed. - // - // @param replicate If set to true, the new convar value will be set on all clients. - // This will only work if the convar has the FCVAR_REPLICATED flag - // and actually exists on clients. - // @param notify If set to true, clients will be notified that the convar has changed. - // This will only work if the convar has the FCVAR_NOTIFY flag. - public native void RestoreDefault(bool replicate=false, bool notify=false); - - // Retrieves the default string value of a console variable. - // - // @param value Buffer to store the default value of the convar. - // @param maxlength Maximum length of string buffer. - // @return Number of bytes written to the buffer (UTF-8 safe). - public native int GetDefault(char[] value, int maxlength); - - // Retrieves the specified bound of a console variable. - // - // @param type Type of bound to retrieve, ConVarBound_Lower or ConVarBound_Upper. - // @param value By-reference cell to store the specified floating point bound value. - // @return True if the convar has the specified bound set, false otherwise. - public native bool GetBounds(ConVarBounds type, float &value); - - // Sets the specified bound of a console variable. - // - // @param type Type of bound to set, ConVarBound_Lower or ConVarBound_Upper - // @param set If set to true, convar will use specified bound. If false, bound will be removed. - // @param value Floating point value to use as the specified bound. - public native void SetBounds(ConVarBounds type, bool set, float value=0.0); - - // Retrieves the name of a console variable. - // - // @param name Buffer to store the name of the convar. - // @param maxlength Maximum length of string buffer. - public native void GetName(char[] name, int maxlength); - - // Replicates a convar value to a specific client. This does not change the actual convar value. - // - // @param client Client index - // @param value String value to send - // @return True on success, false on failure - // @error Invalid client index, client not in game, or client is fake - public native bool ReplicateToClient(int client, const char[] value); - - // Creates a hook for when a console variable's value is changed. - // - // @param callback An OnConVarChanged function pointer. - public native void AddChangeHook(ConVarChanged callback); - - // Removes a hook for when a console variable's value is changed. - // - // @param convar Handle to the convar. - // @param callback An OnConVarChanged function pointer. - // @error No active hook on convar. - public native void RemoveChangeHook(ConVarChanged callback); -} - -/** - * Creates a hook for when a console variable's value is changed. - * - * @param convar Handle to the convar. - * @param callback An OnConVarChanged function pointer. - * @error Invalid or corrupt Handle or invalid callback function. - */ -native void HookConVarChange(Handle convar, ConVarChanged callback); - -/** - * Removes a hook for when a console variable's value is changed. - * - * @param convar Handle to the convar. - * @param callback An OnConVarChanged function pointer. - * @error Invalid or corrupt Handle, invalid callback function, or no active hook on convar. - */ -native void UnhookConVarChange(Handle convar, ConVarChanged callback); - -/** - * Returns the boolean value of a console variable. - * - * @param convar Handle to the convar. - * @return The boolean value of the convar. - * @error Invalid or corrupt Handle. - */ -native bool GetConVarBool(Handle convar); - -/** - * Sets the boolean value of a console variable. - * - * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and - * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. - * - * @param convar Handle to the convar. - * @param value New boolean value. - * @param replicate If set to true, the new convar value will be set on all clients. - * This will only work if the convar has the FCVAR_REPLICATED flag - * and actually exists on clients. - * @param notify If set to true, clients will be notified that the convar has changed. - * This will only work if the convar has the FCVAR_NOTIFY flag. - * @error Invalid or corrupt Handle. - */ -native void SetConVarBool(Handle convar, bool value, bool replicate=false, bool notify=false); - -/** - * Returns the integer value of a console variable. - * - * @param convar Handle to the convar. - * @return The integer value of the convar. - * @error Invalid or corrupt Handle. - */ -native int GetConVarInt(Handle convar); - -/** - * Sets the integer value of a console variable. - * - * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and - * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. - * - * @param convar Handle to the convar. - * @param value New integer value. - * @param replicate If set to true, the new convar value will be set on all clients. - * This will only work if the convar has the FCVAR_REPLICATED flag - * and actually exists on clients. - * @param notify If set to true, clients will be notified that the convar has changed. - * This will only work if the convar has the FCVAR_NOTIFY flag. - * @error Invalid or corrupt Handle. - */ -native void SetConVarInt(Handle convar, int value, bool replicate=false, bool notify=false); - -/** - * Returns the floating point value of a console variable. - * - * @param convar Handle to the convar. - * @return The floating point value of the convar. - * @error Invalid or corrupt Handle. - */ -native float GetConVarFloat(Handle convar); - -/** - * Sets the floating point value of a console variable. - * - * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and - * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. - * - * @param convar Handle to the convar. - * @param value New floating point value. - * @param replicate If set to true, the new convar value will be set on all clients. - * This will only work if the convar has the FCVAR_REPLICATED flag - * and actually exists on clients. - * @param notify If set to true, clients will be notified that the convar has changed. - * This will only work if the convar has the FCVAR_NOTIFY flag. - * @error Invalid or corrupt Handle. - */ -native void SetConVarFloat(Handle convar, float value, bool replicate=false, bool notify=false); - -/** - * Retrieves the string value of a console variable. - * - * @param convar Handle to the convar. - * @param value Buffer to store the value of the convar. - * @param maxlength Maximum length of string buffer. - * @error Invalid or corrupt Handle. - */ -native void GetConVarString(Handle convar, char[] value, int maxlength); - -/** - * Sets the string value of a console variable. - * - * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and - * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. - * - * @param convar Handle to the convar. - * @param value New string value. - * @param replicate If set to true, the new convar value will be set on all clients. - * This will only work if the convar has the FCVAR_REPLICATED flag - * and actually exists on clients. - * @param notify If set to true, clients will be notified that the convar has changed. - * This will only work if the convar has the FCVAR_NOTIFY flag. - * @error Invalid or corrupt Handle. - */ -native void SetConVarString(Handle convar, const char[] value, bool replicate=false, bool notify=false); - -/** - * Resets the console variable to its default value. - * - * Note: The replicate and notify params are only relevant for the original, Dark Messiah, and - * Episode 1 engines. Newer engines automatically do these things when the convar value is changed. - * - * @param convar Handle to the convar. - * @param replicate If set to true, the new convar value will be set on all clients. - * This will only work if the convar has the FCVAR_REPLICATED flag - * and actually exists on clients. - * @param notify If set to true, clients will be notified that the convar has changed. - * This will only work if the convar has the FCVAR_NOTIFY flag. - * @error Invalid or corrupt Handle. - */ -native void ResetConVar(Handle convar, bool replicate=false, bool notify=false); - -/** - * Retrieves the default string value of a console variable. - * - * @param convar Handle to the convar. - * @param value Buffer to store the default value of the convar. - * @param maxlength Maximum length of string buffer. - * @return Number of bytes written to the buffer (UTF-8 safe). - * @error Invalid or corrupt Handle. - */ -native int GetConVarDefault(Handle convar, char[] value, int maxlength); - -/** - * Returns the bitstring of flags on a console variable. - * - * @param convar Handle to the convar. - * @return A bitstring containing the FCVAR_* flags that are enabled. - * @error Invalid or corrupt Handle. - */ -native int GetConVarFlags(Handle convar); - -/** - * Sets the bitstring of flags on a console variable. - * - * @param convar Handle to the convar. - * @param flags A bitstring containing the FCVAR_* flags to enable. - * @error Invalid or corrupt Handle. - */ -native void SetConVarFlags(Handle convar, int flags); - -/** - * Retrieves the specified bound of a console variable. - * - * @param convar Handle to the convar. - * @param type Type of bound to retrieve, ConVarBound_Lower or ConVarBound_Upper. - * @param value By-reference cell to store the specified floating point bound value. - * @return True if the convar has the specified bound set, false otherwise. - * @error Invalid or corrupt Handle. - */ -native bool GetConVarBounds(Handle convar, ConVarBounds type, float &value); - -/** - * Sets the specified bound of a console variable. - * - * @param convar Handle to the convar. - * @param type Type of bound to set, ConVarBound_Lower or ConVarBound_Upper - * @param set If set to true, convar will use specified bound. If false, bound will be removed. - * @param value Floating point value to use as the specified bound. - * @error Invalid or corrupt Handle. - */ -native void SetConVarBounds(Handle convar, ConVarBounds type, bool set, float value=0.0); - -/** - * Retrieves the name of a console variable. - * - * @param convar Handle to the convar. - * @param name Buffer to store the name of the convar. - * @param maxlength Maximum length of string buffer. - * @error Invalid or corrupt Handle. - */ -native void GetConVarName(Handle convar, char[] name, int maxlength); - -/** - * Replicates a convar value to a specific client. This does not change the actual convar value. - * - * @param client Client index - * @param convar ConVar handle - * @param value String value to send - * @return True on success, false on failure - * @error Invalid client index, client not in game, or client is fake - */ -native bool SendConVarValue(int client, Handle convar, const char[] value); - -typeset ConVarQueryFinished -{ - // Called when a query to retrieve a client's console variable has finished. - // - // @param cookie Unique identifier of query. - // @param client Player index. - // @param result Result of query that tells one whether or not query was successful. - // See ConVarQueryResult enum for more details. - // @param convarName Name of client convar that was queried. - // @param convarValue Value of client convar that was queried if successful. This will be "" if it was not. - // @param value Value that was passed when query was started. - function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value); - - // Called when a query to retrieve a client's console variable has finished. - // - // @param cookie Unique identifier of query. - // @param client Player index. - // @param result Result of query that tells one whether or not query was successful. - // See ConVarQueryResult enum for more details. - // @param convarName Name of client convar that was queried. - // @param convarValue Value of client convar that was queried if successful. This will be "" if it was not. - function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue); -}; - -/** - * Starts a query to retrieve the value of a client's console variable. - * - * @param client Player index. - * @param cvarName Name of client convar to query. - * @param callback A function to use as a callback when the query has finished. - * @param value Optional value to pass to the callback function. - * @return A cookie that uniquely identifies the query. - * Returns QUERYCOOKIE_FAILED on failure, such as when used on a bot. - */ -native QueryCookie QueryClientConVar(int client, const char[] cvarName, ConVarQueryFinished callback, any value=0); - -/** - * Returns true if the supplied character is valid in a ConVar name. - * - * @param c Character to validate. - * @return True is valid for ConVars, false otherwise - */ -stock bool IsValidConVarChar(int c) -{ - return (c == '_' || IsCharAlpha(c) || IsCharNumeric(c)); -} diff --git a/scripting/include/core.inc b/scripting/include/core.inc deleted file mode 100644 index 47f05e1..0000000 --- a/scripting/include/core.inc +++ /dev/null @@ -1,317 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet: - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _core_included - #endinput -#endif -#define _core_included - -#include - -/** If this gets changed, you need to update Core's check. */ -#define SOURCEMOD_PLUGINAPI_VERSION 5 - -struct PlVers -{ - public int version; - public const char[] filevers; - public const char[] date; - public const char[] time; -}; - -/** - * Specifies what to do after a hook completes. - */ -enum Action -{ - Plugin_Continue = 0, /**< Continue with the original action */ - Plugin_Changed = 1, /**< Inputs or outputs have been overridden with new values */ - Plugin_Handled = 3, /**< Handle the action at the end (don't call it) */ - Plugin_Stop = 4, /**< Immediately stop the hook chain and handle the original */ -}; - -/** - * Specifies identity types. - */ -enum Identity -{ - Identity_Core = 0, - Identity_Extension = 1, - Identity_Plugin = 2 -}; - -public PlVers __version = -{ - version = SOURCEMOD_PLUGINAPI_VERSION, - filevers = SOURCEMOD_VERSION, - date = __DATE__, - time = __TIME__ -}; - -/** - * Plugin status values. - */ -enum PluginStatus -{ - Plugin_Running=0, /**< Plugin is running */ - /* All states below are "temporarily" unexecutable */ - Plugin_Paused, /**< Plugin is loaded but paused */ - Plugin_Error, /**< Plugin is loaded but errored/locked */ - /* All states below do not have all natives */ - Plugin_Loaded, /**< Plugin has passed loading and can be finalized */ - Plugin_Failed, /**< Plugin has a fatal failure */ - Plugin_Created, /**< Plugin is created but not initialized */ - Plugin_Uncompiled, /**< Plugin is not yet compiled by the JIT */ - Plugin_BadLoad, /**< Plugin failed to load */ - Plugin_Evicted /**< Plugin was unloaded due to an error */ -}; - -/** - * Plugin information properties. Plugins can declare a global variable with - * their info. Example, - * - * public Plugin myinfo = { - * name = "Admin Help", - * author = "AlliedModders LLC", - * description = "Display command information", - * version = "1.0", - * url = "http://www.sourcemod.net/" - * }; - * - * SourceMod will display this information when a user inspects plugins in the - * console. - */ -enum PluginInfo -{ - PlInfo_Name, /**< Plugin name */ - PlInfo_Author, /**< Plugin author */ - PlInfo_Description, /**< Plugin description */ - PlInfo_Version, /**< Plugin version */ - PlInfo_URL, /**< Plugin URL */ -}; - -/** - * Defines how an extension must expose itself for autoloading. - */ -struct Extension -{ - public const char[] name; /**< Short name */ - public const char[] file; /**< Default file name */ - public bool autoload; /**< Whether or not to auto-load */ - public bool required; /**< Whether or not to require */ -}; - -/** - * Defines how a plugin must expose itself for native requiring. - */ -struct SharedPlugin -{ - public const char[] name; /**< Short name */ - public const char[] file; /**< File name */ - public bool required; /**< Whether or not to require */ -}; - -public float NULL_VECTOR[3]; /**< Pass this into certain functions to act as a C++ NULL */ -public const char NULL_STRING[1]; /**< pass this into certain functions to act as a C++ NULL */ - -/** - * Check if the given vector is the NULL_VECTOR. - * - * @param vec The vector to test. - * @return True if NULL_VECTOR, false otherwise. - */ -native bool IsNullVector(const float vec[3]); - -/** - * Check if the given string is the NULL_STRING. - * - * @param str The string to test. - * @return True if NULL_STRING, false otherwise. - */ -native bool IsNullString(const char[] str); - -/** - * Horrible compatibility shim. - */ -public Extension __ext_core = -{ - name = "Core", - file = "core", - autoload = 0, - required = 0, -}; - -native int VerifyCoreVersion(); - -/** - * Sets a native as optional, such that if it is unloaded, removed, - * or otherwise non-existent, the plugin will still work. Calling - * removed natives results in a run-time error. - * - * @param name Native name. - */ -native void MarkNativeAsOptional(const char[] name); - -public void __ext_core_SetNTVOptional() -{ - MarkNativeAsOptional("GetFeatureStatus"); - MarkNativeAsOptional("RequireFeature"); - MarkNativeAsOptional("AddCommandListener"); - MarkNativeAsOptional("RemoveCommandListener"); - - MarkNativeAsOptional("BfWriteBool"); - MarkNativeAsOptional("BfWriteByte"); - MarkNativeAsOptional("BfWriteChar"); - MarkNativeAsOptional("BfWriteShort"); - MarkNativeAsOptional("BfWriteWord"); - MarkNativeAsOptional("BfWriteNum"); - MarkNativeAsOptional("BfWriteFloat"); - MarkNativeAsOptional("BfWriteString"); - MarkNativeAsOptional("BfWriteEntity"); - MarkNativeAsOptional("BfWriteAngle"); - MarkNativeAsOptional("BfWriteCoord"); - MarkNativeAsOptional("BfWriteVecCoord"); - MarkNativeAsOptional("BfWriteVecNormal"); - MarkNativeAsOptional("BfWriteAngles"); - MarkNativeAsOptional("BfReadBool"); - MarkNativeAsOptional("BfReadByte"); - MarkNativeAsOptional("BfReadChar"); - MarkNativeAsOptional("BfReadShort"); - MarkNativeAsOptional("BfReadWord"); - MarkNativeAsOptional("BfReadNum"); - MarkNativeAsOptional("BfReadFloat"); - MarkNativeAsOptional("BfReadString"); - MarkNativeAsOptional("BfReadEntity"); - MarkNativeAsOptional("BfReadAngle"); - MarkNativeAsOptional("BfReadCoord"); - MarkNativeAsOptional("BfReadVecCoord"); - MarkNativeAsOptional("BfReadVecNormal"); - MarkNativeAsOptional("BfReadAngles"); - MarkNativeAsOptional("BfGetNumBytesLeft"); - - MarkNativeAsOptional("BfWrite.WriteBool"); - MarkNativeAsOptional("BfWrite.WriteByte"); - MarkNativeAsOptional("BfWrite.WriteChar"); - MarkNativeAsOptional("BfWrite.WriteShort"); - MarkNativeAsOptional("BfWrite.WriteWord"); - MarkNativeAsOptional("BfWrite.WriteNum"); - MarkNativeAsOptional("BfWrite.WriteFloat"); - MarkNativeAsOptional("BfWrite.WriteString"); - MarkNativeAsOptional("BfWrite.WriteEntity"); - MarkNativeAsOptional("BfWrite.WriteAngle"); - MarkNativeAsOptional("BfWrite.WriteCoord"); - MarkNativeAsOptional("BfWrite.WriteVecCoord"); - MarkNativeAsOptional("BfWrite.WriteVecNormal"); - MarkNativeAsOptional("BfWrite.WriteAngles"); - MarkNativeAsOptional("BfRead.ReadBool"); - MarkNativeAsOptional("BfRead.ReadByte"); - MarkNativeAsOptional("BfRead.ReadChar"); - MarkNativeAsOptional("BfRead.ReadShort"); - MarkNativeAsOptional("BfRead.ReadWord"); - MarkNativeAsOptional("BfRead.ReadNum"); - MarkNativeAsOptional("BfRead.ReadFloat"); - MarkNativeAsOptional("BfRead.ReadString"); - MarkNativeAsOptional("BfRead.ReadEntity"); - MarkNativeAsOptional("BfRead.ReadAngle"); - MarkNativeAsOptional("BfRead.ReadCoord"); - MarkNativeAsOptional("BfRead.ReadVecCoord"); - MarkNativeAsOptional("BfRead.ReadVecNormal"); - MarkNativeAsOptional("BfRead.ReadAngles"); - MarkNativeAsOptional("BfRead.GetNumBytesLeft"); - - MarkNativeAsOptional("PbReadInt"); - MarkNativeAsOptional("PbReadFloat"); - MarkNativeAsOptional("PbReadBool"); - MarkNativeAsOptional("PbReadString"); - MarkNativeAsOptional("PbReadColor"); - MarkNativeAsOptional("PbReadAngle"); - MarkNativeAsOptional("PbReadVector"); - MarkNativeAsOptional("PbReadVector2D"); - MarkNativeAsOptional("PbGetRepeatedFieldCount"); - MarkNativeAsOptional("PbSetInt"); - MarkNativeAsOptional("PbSetFloat"); - MarkNativeAsOptional("PbSetBool"); - MarkNativeAsOptional("PbSetString"); - MarkNativeAsOptional("PbSetColor"); - MarkNativeAsOptional("PbSetAngle"); - MarkNativeAsOptional("PbSetVector"); - MarkNativeAsOptional("PbSetVector2D"); - MarkNativeAsOptional("PbAddInt"); - MarkNativeAsOptional("PbAddFloat"); - MarkNativeAsOptional("PbAddBool"); - MarkNativeAsOptional("PbAddString"); - MarkNativeAsOptional("PbAddColor"); - MarkNativeAsOptional("PbAddAngle"); - MarkNativeAsOptional("PbAddVector"); - MarkNativeAsOptional("PbAddVector2D"); - MarkNativeAsOptional("PbRemoveRepeatedFieldValue"); - MarkNativeAsOptional("PbReadMessage"); - MarkNativeAsOptional("PbReadRepeatedMessage"); - MarkNativeAsOptional("PbAddMessage"); - - MarkNativeAsOptional("Protobuf.ReadInt"); - MarkNativeAsOptional("Protobuf.ReadFloat"); - MarkNativeAsOptional("Protobuf.ReadBool"); - MarkNativeAsOptional("Protobuf.ReadString"); - MarkNativeAsOptional("Protobuf.ReadColor"); - MarkNativeAsOptional("Protobuf.ReadAngle"); - MarkNativeAsOptional("Protobuf.ReadVector"); - MarkNativeAsOptional("Protobuf.ReadVector2D"); - MarkNativeAsOptional("Protobuf.GetRepeatedFieldCount"); - MarkNativeAsOptional("Protobuf.SetInt"); - MarkNativeAsOptional("Protobuf.SetFloat"); - MarkNativeAsOptional("Protobuf.SetBool"); - MarkNativeAsOptional("Protobuf.SetString"); - MarkNativeAsOptional("Protobuf.SetColor"); - MarkNativeAsOptional("Protobuf.SetAngle"); - MarkNativeAsOptional("Protobuf.SetVector"); - MarkNativeAsOptional("Protobuf.SetVector2D"); - MarkNativeAsOptional("Protobuf.AddInt"); - MarkNativeAsOptional("Protobuf.AddFloat"); - MarkNativeAsOptional("Protobuf.AddBool"); - MarkNativeAsOptional("Protobuf.AddString"); - MarkNativeAsOptional("Protobuf.AddColor"); - MarkNativeAsOptional("Protobuf.AddAngle"); - MarkNativeAsOptional("Protobuf.AddVector"); - MarkNativeAsOptional("Protobuf.AddVector2D"); - MarkNativeAsOptional("Protobuf.RemoveRepeatedFieldValue"); - MarkNativeAsOptional("Protobuf.ReadMessage"); - MarkNativeAsOptional("Protobuf.ReadRepeatedMessage"); - MarkNativeAsOptional("Protobuf.AddMessage"); - - VerifyCoreVersion(); -} - - -#define AUTOLOAD_EXTENSIONS -#define REQUIRE_EXTENSIONS -#define REQUIRE_PLUGIN diff --git a/scripting/include/cstrike.inc b/scripting/include/cstrike.inc deleted file mode 100644 index 49e0aec..0000000 --- a/scripting/include/cstrike.inc +++ /dev/null @@ -1,458 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _cstrike_included - #endinput -#endif -#define _cstrike_included - -#define CS_TEAM_NONE 0 /**< No team yet. */ -#define CS_TEAM_SPECTATOR 1 /**< Spectators. */ -#define CS_TEAM_T 2 /**< Terrorists. */ -#define CS_TEAM_CT 3 /**< Counter-Terrorists. */ - -#define CS_SLOT_PRIMARY 0 /**< Primary weapon slot. */ -#define CS_SLOT_SECONDARY 1 /**< Secondary weapon slot. */ -#define CS_SLOT_KNIFE 2 /**< Knife slot. */ -#define CS_SLOT_GRENADE 3 /**< Grenade slot (will only return one grenade). */ -#define CS_SLOT_C4 4 /**< C4 slot. */ - -#define CS_DMG_HEADSHOT (1 << 30) /**< Headshot */ - -enum CSRoundEndReason -{ - CSRoundEnd_TargetBombed = 0, /**< Target Successfully Bombed! */ - CSRoundEnd_VIPEscaped, /**< The VIP has escaped! - Doesn't exist on CS:GO */ - CSRoundEnd_VIPKilled, /**< VIP has been assassinated! - Doesn't exist on CS:GO */ - CSRoundEnd_TerroristsEscaped, /**< The terrorists have escaped! */ - CSRoundEnd_CTStoppedEscape, /**< The CTs have prevented most of the terrorists from escaping! */ - CSRoundEnd_TerroristsStopped, /**< Escaping terrorists have all been neutralized! */ - CSRoundEnd_BombDefused, /**< The bomb has been defused! */ - CSRoundEnd_CTWin, /**< Counter-Terrorists Win! */ - CSRoundEnd_TerroristWin, /**< Terrorists Win! */ - CSRoundEnd_Draw, /**< Round Draw! */ - CSRoundEnd_HostagesRescued, /**< All Hostages have been rescued! */ - CSRoundEnd_TargetSaved, /**< Target has been saved! */ - CSRoundEnd_HostagesNotRescued, /**< Hostages have not been rescued! */ - CSRoundEnd_TerroristsNotEscaped, /**< Terrorists have not escaped! */ - CSRoundEnd_VIPNotEscaped, /**< VIP has not escaped! - Doesn't exist on CS:GO */ - CSRoundEnd_GameStart, /**< Game Commencing! */ - - // The below only exist on CS:GO - CSRoundEnd_TerroristsSurrender, /**< Terrorists Surrender */ - CSRoundEnd_CTSurrender, /**< CTs Surrender */ - CSRoundEnd_TerroristsPlanted, /**< Terrorists Planted the bomb */ - CSRoundEnd_CTsReachedHostage, /**< CTs Reached the hostage */ -}; - -enum CSWeaponID -{ - CSWeapon_NONE = 0, - CSWeapon_P228, - CSWeapon_GLOCK, - CSWeapon_SCOUT, - CSWeapon_HEGRENADE, - CSWeapon_XM1014, - CSWeapon_C4, - CSWeapon_MAC10, - CSWeapon_AUG, - CSWeapon_SMOKEGRENADE, - CSWeapon_ELITE, - CSWeapon_FIVESEVEN, - CSWeapon_UMP45, - CSWeapon_SG550, - CSWeapon_GALIL, - CSWeapon_FAMAS, - CSWeapon_USP, - CSWeapon_AWP, - CSWeapon_MP5NAVY, - CSWeapon_M249, - CSWeapon_M3, - CSWeapon_M4A1, - CSWeapon_TMP, - CSWeapon_G3SG1, - CSWeapon_FLASHBANG, - CSWeapon_DEAGLE, - CSWeapon_SG552, - CSWeapon_AK47, - CSWeapon_KNIFE, - CSWeapon_P90, - CSWeapon_SHIELD, - CSWeapon_KEVLAR, - CSWeapon_ASSAULTSUIT, - CSWeapon_NIGHTVISION, //Anything below is CS:GO ONLY - CSWeapon_GALILAR, - CSWeapon_BIZON, - CSWeapon_MAG7, - CSWeapon_NEGEV, - CSWeapon_SAWEDOFF, - CSWeapon_TEC9, - CSWeapon_TASER, - CSWeapon_HKP2000, - CSWeapon_MP7, - CSWeapon_MP9, - CSWeapon_NOVA, - CSWeapon_P250, - CSWeapon_SCAR17, - CSWeapon_SCAR20, - CSWeapon_SG556, - CSWeapon_SSG08, - CSWeapon_KNIFE_GG, - CSWeapon_MOLOTOV, - CSWeapon_DECOY, - CSWeapon_INCGRENADE, - CSWeapon_DEFUSER, - CSWeapon_HEAVYASSAULTSUIT, - //The rest are actual item definition indexes for CS:GO - CSWeapon_CUTTERS = 56, - CSWeapon_HEALTHSHOT = 57, - CSWeapon_KNIFE_T = 59, - CSWeapon_M4A1_SILENCER = 60, - CSWeapon_USP_SILENCER = 61, - CSWeapon_CZ75A = 63, - CSWeapon_REVOLVER = 64, - CSWeapon_TAGGRENADE = 68, - CSWeapon_MAX_WEAPONS_NO_KNIFES, // Max without the knife item defs, useful when treating all knives as a regular knife. - CSWeapon_BAYONET = 500, - CSWeapon_KNIFE_FLIP = 505, - CSWeapon_KNIFE_GUT = 506, - CSWeapon_KNIFE_KARAMBIT = 507, - CSWeapon_KNIFE_M9_BAYONET = 508, - CSWeapon_KNIFE_TATICAL = 509, - CSWeapon_KNIFE_FALCHION = 512, - CSWeapon_KNIFE_SURVIVAL_BOWIE = 514, - CSWeapon_KNIFE_BUTTERFLY = 515, - CSWeapon_KNIFE_PUSH = 516, - CSWeapon_MAX_WEAPONS //THIS MUST BE LAST, EASY WAY TO CREATE LOOPS. When looping, do CS_IsValidWeaponID(i), to check. -}; - -/** - * Called when a player attempts to purchase an item. - * Return Plugin_Continue to allow the purchase or return a - * higher action to deny. - * - * @param client Client index - * @param weapon User input for weapon name - */ -forward Action CS_OnBuyCommand(int client, const char[] weapon); - -/** - * Called when CSWeaponDrop is called - * Return Plugin_Continue to allow the call or return a - * higher action to block. - * - * @param client Client index - * @param weaponIndex Weapon index - */ -forward Action CS_OnCSWeaponDrop(int client, int weaponIndex); - -/** - * Called when game retrieves a weapon's price for a player. - * Return Plugin_Continue to use default value or return a higher - * action to use a newly-set price. - * - * @note This can be called multiple times per weapon purchase - * - * @param client Client index - * @param weapon Weapon classname - * @param price Buffer param for the price of the weapon - * - * @note Not all "weapons" call GetWeaponPrice. Example: c4, knife, vest, vest helmet, night vision. - */ -forward Action CS_OnGetWeaponPrice(int client, const char[] weapon, int &price); - -/** - * Called when TerminateRound is called. - * Return Plugin_Continue to ignore, return Plugin_Changed to continue, - * using the given delay and reason, or return Plugin_Handled or a higher - * action to block TerminateRound from firing. - * - * @param delay Time (in seconds) until new round starts - * @param reason Reason for round end - */ -forward Action CS_OnTerminateRound(float &delay, CSRoundEndReason &reason); - -/** - * Respawns a player. - * - * @param client Player's index. - * @error Invalid client index, client not in game. - */ -native void CS_RespawnPlayer(int client); - -/** - * Switches the player's team. - * - * @param client Player's index. - * @param team Team index. - * @error Invalid client index, client not in game. - */ -native void CS_SwitchTeam(int client, int team); - -/** - * Forces a player to drop or toss their weapon - * - * @param client Player's index. - * @param weaponIndex Index of weapon to drop. - * @param toss True to toss weapon (with velocity) or false to just drop weapon - * @param blockhook Set to true to stop the corresponding CS_OnCSWeaponDrop - * - * @error Invalid client index, client not in game, or invalid weapon index. - */ -native void CS_DropWeapon(int client, int weaponIndex, bool toss, bool blockhook = false); - -/** - * Forces round to end with a reason - * - * @param delay Time (in seconds) to delay before new round starts - * @param reason Reason for the round ending - * @param blockhook Set to true to stop the corresponding CS_OnTerminateRound - * forward from being called. - */ -native void CS_TerminateRound(float delay, CSRoundEndReason reason, bool blockhook = false); - -/** - * Gets a weapon name from a weapon alias - * - * @param alias Weapons alias to get weapon name for. - * @param weapon Buffer to store weapons name - * @param size Size of buffer to store the weapons name. - * - * @note Will set the buffer to the original alias if it is not an alias to a weapon. - */ -native void CS_GetTranslatedWeaponAlias(const char[] alias, char[] weapon, int size); - -/** - * Gets a weapon's price - * - * @param client Client to check weapon price for. - * @param id Weapon id for the weapon to check - * @param defaultprice Set to true to get defaultprice. - * @return Returns price of the weapon (even if modified) - * - * @error Invalid client, failing to get weapon info, or failing to get price offset. - * @note c4, knife and shield will always return 0. vest, vest helmet and night vision will always return default price. - */ -native int CS_GetWeaponPrice(int client, CSWeaponID id, bool defaultprice = false); - -/** - * Gets a clients clan tag - * @param client Client index to get clan tag for. - * @param buffer Buffer to store clients clan tag in. - * @param size Size of the buffer. - * @return Number of non-null bytes written. - * - * @error Invalid client. - */ -native int CS_GetClientClanTag(int client, char[] buffer, int size); - -/** - * Sets a clients clan tag - * @param client Client index to set clan tag for. - * @param tag Tag to set clients clan tag as. - * - * @error Invalid client. - */ -native void CS_SetClientClanTag(int client, const char[] tag); - -/** - * Gets a team's score - * @param team Team index to get score for. - * @return Returns the internal team score. - * - * @error Invalid team index. - */ -native int CS_GetTeamScore(int team); - -/** - * Sets a team's score - * @param team Team index to set score for. - * @param value Value to set teams score as. - * - * @error Invalid team index. - * @note This will update the scoreboard only after the scoreboard update function is called. Use SetTeamScore plus this to update the scoreboard instantly and save values correctly. - */ -native void CS_SetTeamScore(int team, int value); - -/** - * Gets a client's mvp count - * @param client Client index to get mvp count of. - * @return Returns the client's internal MVP count. - * - * @error Invalid client. - */ -native int CS_GetMVPCount(int client); - -/** - * Sets a client's mvp count - * @param client Client index to set mvp count for. - * @param value Value to set client's mvp count as. - * - * @error Invalid client. - */ -native void CS_SetMVPCount(int client, int value); - -/** - * Gets a client's contribution score (CS:GO only) - * @param client Client index to get score of. - * @return Returns the client's score. - * - * @error Invalid client. - */ -native int CS_GetClientContributionScore(int client); - -/** - * Sets a client's contribution score (CS:GO only) - * @param client Client index to set score for. - * @param value Value to set client's score as. - * - * @error Invalid client. - */ -native void CS_SetClientContributionScore(int client, int value); - -/** - * Gets a client's assists (CS:GO only) - * @param client Client index to get assists of. - * @return Returns the client's assists. - * - * @error Invalid client. - */ -native int CS_GetClientAssists(int client); - -/** - * Sets a client's assists (CS:GO only) - * @param client Client index to set assists for. - * @param value Value to set client's assists as. - * - * @error Invalid client. - */ -native void CS_SetClientAssists(int client, int value); - -/** - * Gets a weaponID from a alias - * @param alias Weapon alias to attempt to get an id for. - * @return Returns a weapon id or 0 if failed to find a match. - * - * @note For best results use CS_GetTranslatedWeaponAlias on the weapon name before passing it. - */ -native CSWeaponID CS_AliasToWeaponID(const char[] alias); - -/** - * Gets a alias from a weaponID - * @param weaponID WeaponID to get alias for. - * @param destination Destination string to hold the weapon alias. - * @param len Length of the destination array. - * @return Returns number of cells written. - */ -native int CS_WeaponIDToAlias(CSWeaponID weaponID, char[] destination, int len); - -/** - * Returns weather a WeaponID is valid on the current mod (css or csgo) - * @param weaponID WeaponID to check - * @return Returns true if its a valid WeaponID false otherwise. - * - * @note This will return false always for CSWeapon_NONE. Should only be called after OnMapStart since weapon info isnt intialized before. - */ -native bool CS_IsValidWeaponID(CSWeaponID id); - -/** - * Sets a player's model based on their current class - * - * @param client Player's index. - * @error Invalid client index, client not in game. - */ -native void CS_UpdateClientModel(int client); - -/** - * Returns a CSWeaponID equivalent based on the item definition index. - * - * @param iDefIndex Definition index to get the CSWeaponID value for. - * @return Returns CSWeaponID value for the definition index. - * - * @error Invalid definition index. - * @note In most cases the id will be the item definition index. Works for CS:GO ONLY. - */ -native CSWeaponID CS_ItemDefIndexToID(int iDefIndex); - -/** - * Returns a item definition index equivalent based on the CSWeaponID. - * - * @param id CSWeaponID to get the item definition for. - * @return Returns item definition index value for the weapon id. - * - * @error Invalid weapon id. - * @note In most cases the item deinition index will be the id. Works for CS:GO ONLY. - */ -native int CS_WeaponIDToItemDefIndex(CSWeaponID id); - -/** - * Do not edit below this line! - */ -public Extension __ext_cstrike = -{ - name = "cstrike", - file = "games/game.cstrike.ext", - autoload = 0, -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_EXTENSIONS -public void __ext_cstrike_SetNTVOptional() -{ - MarkNativeAsOptional("CS_RespawnPlayer"); - MarkNativeAsOptional("CS_SwitchTeam"); - MarkNativeAsOptional("CS_DropWeapon"); - MarkNativeAsOptional("CS_TerminateRound"); - MarkNativeAsOptional("CS_GetTranslatedWeaponAlias"); - MarkNativeAsOptional("CS_GetWeaponPrice"); - MarkNativeAsOptional("CS_GetClientClanTag"); - MarkNativeAsOptional("CS_SetClientClanTag"); - MarkNativeAsOptional("CS_GetTeamScore"); - MarkNativeAsOptional("CS_SetTeamScore"); - MarkNativeAsOptional("CS_GetMVPCount"); - MarkNativeAsOptional("CS_SetMVPCount"); - MarkNativeAsOptional("CS_GetClientContributionScore"); - MarkNativeAsOptional("CS_SetClientContributionScore"); - MarkNativeAsOptional("CS_GetClientAssists"); - MarkNativeAsOptional("CS_SetClientAssists"); - MarkNativeAsOptional("CS_AliasToWeaponID"); - MarkNativeAsOptional("CS_WeaponIDToAlias"); - MarkNativeAsOptional("CS_IsValidWeaponID"); - MarkNativeAsOptional("CS_UpdateClientModel"); - MarkNativeAsOptional("CS_ItemDefIndexToID"); - MarkNativeAsOptional("CS_WeaponIDToItemDefIndex"); -} -#endif diff --git a/scripting/include/datapack.inc b/scripting/include/datapack.inc deleted file mode 100644 index 12b7a3b..0000000 --- a/scripting/include/datapack.inc +++ /dev/null @@ -1,225 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _datapack_included - #endinput -#endif -#define _datapack_included - - -/** - * Opaque handle to a datapack position. - */ - enum DataPackPos: {}; - -// A DataPack allows serializing multiple variables into a single stream. -methodmap DataPack < Handle -{ - // Creates a new data pack. - public native DataPack(); - - // Packs a normal cell into a data pack. - // - // @param cell Cell to add. - public native void WriteCell(any cell); - - // Packs a float into a data pack. - // - // @param val Float to add. - public native void WriteFloat(float val); - - // Packs a string into a data pack. - // - // @param str String to add. - public native void WriteString(const char[] str); - - // Packs a function pointer into a data pack. - // - // @param fktptr Function pointer to add. - public native void WriteFunction(Function fktptr); - - // Reads a cell from a data pack. - // - // @param pack Handle to the data pack. - public native any ReadCell(); - - // Reads a float from a data pack. - // - // @param pack Handle to the data pack. - public native float ReadFloat(); - - // Reads a string from a data pack. - // - // @param buffer Destination string buffer. - // @param maxlen Maximum length of output string buffer. - public native void ReadString(char[] buffer, int maxlen); - - // Reads a function pointer from a data pack. - // - // @return Function pointer. - public native Function ReadFunction(); - - // Resets the position in a data pack. - // - // @param clear If true, clears the contained data. - public native void Reset(bool clear=false); - - // Returns whether or not a specified number of bytes from the data pack - // position to the end can be read. - // - // @param bytes Number of bytes to simulate reading. - public native bool IsReadable(int bytes); - - // The read or write position in a data pack. - property DataPackPos Position { - public native get(); - public native set(DataPackPos pos); - } -}; - -/** - * Creates a new data pack. - * - * @return A Handle to the data pack. Must be closed with CloseHandle(). - */ -native DataPack CreateDataPack(); - -/** - * Packs a normal cell into a data pack. - * - * @param pack Handle to the data pack. - * @param cell Cell to add. - * @error Invalid handle. - */ -native void WritePackCell(Handle pack, any cell); - -/** - * Packs a float into a data pack. - * - * @param pack Handle to the data pack. - * @param val Float to add. - * @error Invalid handle. - */ -native void WritePackFloat(Handle pack, float val); - -/** - * Packs a string into a data pack. - * - * @param pack Handle to the data pack. - * @param str String to add. - * @error Invalid handle. - */ -native void WritePackString(Handle pack, const char[] str); - -/** - * Packs a function pointer into a data pack. - * - * @param pack Handle to the data pack. - * @param fktptr Function pointer to add. - * @error Invalid handle. - */ -native void WritePackFunction(Handle pack, Function fktptr); - -/** - * Reads a cell from a data pack. - * - * @param pack Handle to the data pack. - * @return Cell value. - * @error Invalid handle, or bounds error. - */ -native any ReadPackCell(Handle pack); - -/** - * Reads a float from a data pack. - * - * @param pack Handle to the data pack. - * @return Float value. - * @error Invalid handle, or bounds error. - */ -native float ReadPackFloat(Handle pack); - -/** - * Reads a string from a data pack. - * - * @param pack Handle to the data pack. - * @param buffer Destination string buffer. - * @param maxlen Maximum length of output string buffer. - * @error Invalid handle, or bounds error. - */ -native void ReadPackString(Handle pack, char[] buffer, int maxlen); - -/** - * Reads a function pointer from a data pack. - * - * @param pack Handle to the data pack. - * @return Function pointer. - * @error Invalid handle, or bounds error. - */ -native Function ReadPackFunction(Handle pack); - -/** - * Resets the position in a data pack. - * - * @param pack Handle to the data pack. - * @param clear If true, clears the contained data. - * @error Invalid handle. - */ -native void ResetPack(Handle pack, bool clear=false); - -/** - * Returns the read or write position in a data pack. - * - * @param pack Handle to the data pack. - * @return Position in the data pack, only usable with calls to SetPackPosition. - * @error Invalid handle. - */ -native DataPackPos GetPackPosition(Handle pack); - -/** - * Sets the read/write position in a data pack. - * - * @param pack Handle to the data pack. - * @param position New position to set. Must have been previously retrieved from a call to GetPackPosition. - * @error Invalid handle, or position is beyond the pack bounds. - */ -native void SetPackPosition(Handle pack, DataPackPos position); - -/** - * Returns whether or not a specified number of bytes from the data pack - * position to the end can be read. - * - * @param pack Handle to the data pack. - * @param bytes Number of bytes to simulate reading. - * @return True if can be read, false otherwise. - * @error Invalid handle. - */ -native bool IsPackReadable(Handle pack, int bytes); diff --git a/scripting/include/dbi.inc b/scripting/include/dbi.inc deleted file mode 100644 index 55bc695..0000000 --- a/scripting/include/dbi.inc +++ /dev/null @@ -1,1066 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _dbi_included - #endinput -#endif -#define _dbi_included - -/** - * Describes a database field fetch status. - */ -enum DBResult -{ - DBVal_Error = 0, /**< Column number/field is invalid. */ - DBVal_TypeMismatch = 1, /**< You cannot retrieve this data with this type. */ - DBVal_Null = 2, /**< Field has no data (NULL) */ - DBVal_Data = 3, /**< Field has data */ -}; - -/** - * Describes binding types. - */ -enum DBBindType -{ - DBBind_Int = 0, /**< Bind an integer. */ - DBBind_Float = 1, /**< Bind a float. */ - DBBind_String = 2, /**< Bind a string. */ -}; - -/** - * Threading priority level. - */ -enum DBPriority -{ - DBPrio_High = 0, /**< High priority. */ - DBPrio_Normal = 1, /**< Normal priority. */ - DBPrio_Low = 2, /**< Low priority. */ -}; - -// A Driver represents a database backend, currently MySQL or SQLite. -// -// Driver handles cannot be closed. -methodmap DBDriver < Handle -{ - // Finds the driver associated with a name. - // - // Supported driver strings: - // mysql - // sqlite - // - // @param name Driver identification string, or an empty string - // to return the default driver. - // @return Driver handle, or null on failure. - public static native DBDriver Find(const char[] name = ""); - - // Retrieves a driver's identification string. - // - // Example: "mysql", "sqlite" - // - // @param ident Identification string buffer. - // @param maxlength Maximum length of the buffer. - public native void GetIdentifier(char[] ident, int maxlength); - - // Retrieves a driver's product string. - // - // Example: "MySQL", "SQLite" - // - // @param product Product string buffer. - // @param maxlength Maximum length of the buffer. - public native void GetProduct(char[] product, int maxlength); -}; - -// Represents a set of results returned from executing a query. -methodmap DBResultSet < Handle -{ - // Advances to the next set of results. - // - // In some SQL implementations, multiple result sets can exist on one query. - // This is possible in MySQL with simple queries when executing a CALL - // query. If this is the case, all result sets must be processed before - // another query is made. - // - // @return True if there was another result set, false otherwise. - public native bool FetchMoreResults(); - - // Returns whether or not a result set exists. This will - // return true even if 0 results were returned, but false - // on queries like UPDATE, INSERT, or DELETE. - property bool HasResults { - public native get(); - } - - // Retrieves the number of rows in the last result set. - // - // @param query A query (or statement) Handle. - // @return Number of rows in the current result set. - property int RowCount { - public native get(); - } - - // Retrieves the number of fields in the last result set. - property int FieldCount { - public native get(); - } - - // Returns the number of affected rows from the query that generated this - // result set. - property int AffectedRows { - public native get(); - } - - // Returns the insert id from the query that generated this result set. - property int InsertId { - public native get(); - } - - // Retrieves the name of a field by index. - // - // @param field Field number (starting from 0). - // @param name Name buffer. - // @param maxlength Maximum length of the name buffer. - // @error Invalid field index, or no current result set. - public native void FieldNumToName(int field, char[] name, int maxlength); - - // Retrieves a field index by name. - // - // @param name Name of the field (case sensitive). - // @param field Variable to store field index in. - // @return True if found, false if not found. - // @error No current result set. - public native bool FieldNameToNum(const char[] name, int &field); - - // Fetches a row from the current result set. This must be - // successfully called before any results are fetched. - // - // If this function fails, _MoreResults can be used to - // tell if there was an error or the result set is finished. - // - // @return True if a row was fetched, false otherwise. - public native bool FetchRow(); - - // Returns if there are more rows. - // - // @return True if there are more rows, false otherwise. - property bool MoreRows { - public native get(); - } - - // Rewinds a result set back to the first result. - // - // @return True on success, false otherwise. - // @error No current result set. - public native bool Rewind(); - - // Fetches a string from a field in the current row of a result set. - // If the result is NULL, an empty string will be returned. A NULL - // check can be done with the result parameter, or SQL_IsFieldNull(). - // - // @param field The field index (starting from 0). - // @param buffer String buffer. - // @param maxlength Maximum size of the string buffer. - // @param result Optional variable to store the status of the return value. - // @return Number of bytes written. - // @error Invalid field index, invalid type conversion requested - // from the database, or no current result set. - public native int FetchString(int field, char[] buffer, int maxlength, - DBResult &result=DBVal_Error); - - // Fetches a float from a field in the current row of a result set. - // If the result is NULL, a value of 0.0 will be returned. A NULL - // check can be done with the result parameter, or SQL_IsFieldNull(). - // - // @param field The field index (starting from 0). - // @param result Optional variable to store the status of the return value. - // @return A float value. - // @error Invalid field index, invalid type conversion requested - // from the database, or no current result set. - public native float FetchFloat(int field, DBResult &result=DBVal_Error); - - // Fetches an integer from a field in the current row of a result set. - // If the result is NULL, a value of 0 will be returned. A NULL - // check can be done with the result parameter, or SQL_IsFieldNull(). - // - // @param field The field index (starting from 0). - // @param result Optional variable to store the status of the return value. - // @return An integer value. - // @error Invalid field index, invalid type conversion requested - // from the database, or no current result set. - public native int FetchInt(int field, DBResult &result=DBVal_Error); - - // Returns whether a field's data in the current row of a result set is - // NULL or not. NULL is an SQL type which means "no data." - // - // @param field The field index (starting from 0). - // @return True if data is NULL, false otherwise. - // @error Invalid field index, or no current result set. - public native bool IsFieldNull(int field); - - // Returns the length of a field's data in the current row of a result - // set. This only needs to be called for strings to determine how many - // bytes to use. Note that the return value does not include the null - // terminator. - // - // @param field The field index (starting from 0). - // @return Number of bytes for the field's data size. - // @error Invalid field index or no current result set. - public native int FetchSize(int field); -}; - -typeset SQLTxnSuccess -{ - // Callback for a successful transaction. - // - // @param db Database handle. - // @param data Data value passed to SQL_ExecuteTransaction(). - // @param numQueries Number of queries executed in the transaction. - // @param results An array of Query handle results, one for each of numQueries. They are closed automatically. - // @param queryData An array of each data value passed to SQL_AddQuery(). - function void (Database db, any data, int numQueries, Handle[] results, any[] queryData); - - // Callback for a successful transaction. - // - // @param db Database handle. - // @param data Data value passed to SQL_ExecuteTransaction(). - // @param numQueries Number of queries executed in the transaction. - // @param results An array of DBResultSet results, one for each of numQueries. They are closed automatically. - // @param queryData An array of each data value passed to SQL_AddQuery(). - function void (Database db, any data, int numQueries, DBResultSet[] results, any[] queryData); -} - -// Callback for a failed transaction. -// -// @param db Database handle. -// @param data Data value passed to SQL_ExecuteTransaction(). -// @param numQueries Number of queries executed in the transaction. -// @param error Error message. -// @param failIndex Index of the query that failed, or -1 if something else. -// @param queryData An array of each data value passed to SQL_AddQuery(). -typedef SQLTxnFailure = function void (Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData); - -// A Transaction is a collection of SQL statements that must all execute -// successfully or not at all. -methodmap Transaction < Handle -{ - // Create a new transaction. - public native Transaction(); - - // Adds a query to the transaction. - // - // @param query Query string. - // @param data Extra data value to pass to the final callback. - // @return The index of the query in the transaction's query list. - public native int AddQuery(const char[] query, any data=0); -}; - -// A DBStatement is a pre-compiled SQL query that may be executed multiple -// times with different parameters. A DBStatement holds a reference to the -// Database that prepared it. -methodmap DBStatement < Handle -{ - // Binds a parameter in a prepared statement to a given integer value. - // - // @param param The parameter index (starting from 0). - // @param number The number to bind. - // @param signed True to bind the number as signed, false to - // bind it as unsigned. - // @error Invalid parameter index, or SQL error. - public native void BindInt(int param, int number, bool signed=true); - - // Binds a parameter in a prepared statement to a given float value. - // - // @param param The parameter index (starting from 0). - // @param value The float number to bind. - // @error Invalid parameter index, or SQL error. - public native void BindFloat(int param, float value); - - // Binds a parameter in a prepared statement to a given string value. - // - // @param param The parameter index (starting from 0). - // @param value The string to bind. - // @param copy Whether or not SourceMod should copy the value - // locally if necessary. If the string contents - // won't change before calling SQL_Execute(), this - // can be set to false for optimization. - // @error Invalid parameter index, or SQL error. - public native void BindString(int param, const char[] value, bool copy); -}; - -// Callback for receiving asynchronous database connections. -// -// @param db Handle to the database connection. -// @param error Error string if there was an error. The error could be -// empty even if an error condition exists, so it is important -// to check the actual Handle value instead. -// @param data Data passed in via the original threaded invocation. -typedef SQLConnectCallback = function void (Database db, const char[] error, any data); - -// Callback for receiving asynchronous database query results. -// -// @param db Cloned handle to the database connection. -// @param results Result object, or null on failure. -// @param error Error string if there was an error. The error could be -// empty even if an error condition exists, so it is important -// to check the actual results value instead. -// @param data Data passed in via the original threaded invocation. -typedef SQLQueryCallback = function void (Database db, DBResultSet results, const char[] error, any data); - -// A Database represents a live connection to a database, either over the -// wire, through a unix domain socket, or over an open file. -methodmap Database < Handle -{ - // Connects to a database asynchronously, so the game thread is not blocked. - // - // @param callback Callback. If no driver was found, the owner is null. - // @param name Database configuration name. - // @param data Extra data value to pass to the callback. - public static native void Connect(SQLConnectCallback callback, const char[] name="default", any data=0); - - // Returns the driver for this database connection. - property DBDriver Driver { - public native get(); - } - - // Sets the character set of the connection. - // Like SET NAMES .. in mysql, but stays after connection problems. - // - // Example: "utf8", "latin1" - // - // @param characterset The character set string to change to. - // @return True, if character set was changed, false otherwise. - public native bool SetCharset(const char[] charset); - - // Escapes a database string for literal insertion. This is not needed - // for binding strings in prepared statements. - // - // Generally, database strings are inserted into queries enclosed in - // single quotes ('). If user input has a single quote in it, the - // quote needs to be escaped. This function ensures that any unsafe - // characters are safely escaped according to the database engine and - // the database's character set. - // - // NOTE: SourceMod only guarantees properly escaped strings when the query - // encloses the string in ''. While drivers tend to allow " instead, the string - // may be not be escaped (for example, on SQLite)! - // - // @param string String to quote. - // @param buffer Buffer to store quoted string in. - // @param maxlength Maximum length of the buffer. - // @param written Optionally returns the number of bytes written. - // @return True on success, false if buffer is not big enough. - // The buffer must be at least 2*strlen(string)+1. - public native bool Escape(const char[] string, char[] buffer, int maxlength, int &written=0); - - // Formats a string according to the SourceMod format rules (see documentation). - // All format specifiers are escaped (see SQL_EscapeString) unless the '!' flag is used. - // - // @param buffer Destination string buffer. - // @param maxlength Maximum length of output string buffer. - // @param format Formatting rules. - // @param ... Variable number of format parameters. - // @return Number of cells written. - public native int Format(const char[] buffer, int maxlength, const char[] format, any ...); - - // Returns whether a database is the same connection as another database. - public native bool IsSameConnection(Database other); - - // Executes a query via a thread. The result handle is passed through the - // callback. - // - // The database handle returned through the callback is always a new Handle, - // and if necessary, IsSameConnection() should be used to test against other - // connections. - // - // The result handle returned through the callback is temporary and destroyed - // at the end of the callback. - // - // @param callback Callback. - // @param query Query string. - // @param data Extra data value to pass to the callback. - // @param prio Priority queue to use. - public native void Query(SQLQueryCallback callback, const char[] query, - any data = 0, - DBPriority prio = DBPrio_Normal); - - // Sends a transaction to the database thread. The transaction handle is - // automatically closed. When the transaction completes, the optional - // callback is invoked. - // - // @param txn A transaction handle. - // @param onSuccess An optional callback to receive a successful transaction. - // @param onError An optional callback to receive an error message. - // @param data An optional value to pass to callbacks. - // @param prio Priority queue to use. - public native void Execute(Transaction txn, - SQLTxnSuccess onSuccess = INVALID_FUNCTION, - SQLTxnFailure onError = INVALID_FUNCTION, - any data = 0, - DBPriority priority = DBPrio_Normal); -}; - -/** - * Creates an SQL connection from a named configuration. - * - * @param confname Named configuration. - * @param persistent True to re-use a previous persistent connection if - * possible, false otherwise. - * @param error Error buffer. - * @param maxlength Maximum length of the error buffer. - * @return A database connection Handle, or INVALID_HANDLE on failure. - */ -native Database SQL_Connect(const char[] confname, bool persistent, char[] error, int maxlength); - -/** - * Creates a default SQL connection. - * - * @param error Error buffer. - * @param maxlength Maximum length of the error buffer. - * @param persistent True to re-use a previous persistent connection - * if possible, false otherwise. - * @return A database connection Handle, or INVALID_HANDLE on failure. - * On failure the error buffer will be filled with a message. - */ -stock Database SQL_DefConnect(char[] error, int maxlength, bool persistent=true) -{ - return SQL_Connect("default", persistent, error, maxlength); -} - -/** - * Connects to a database using key value pairs containing the database info. - * The key/value pairs should match what would be in databases.cfg. - * - * I.e. "driver" should be "default" or a driver name (or omitted for - * the default). For SQLite, only the "database" parameter is needed in addition. - * For drivers which require external connections, more of the parameters may be - * needed. - * - * In general it is discouraged to use this function. Connections should go through - * databases.cfg for greatest flexibility on behalf of users. - * - * @param keyvalues Key/value pairs from a KeyValues handle, describing the connection. - * @param error Error buffer. - * @param maxlength Maximum length of the error buffer. - * @param persistent True to re-use a previous persistent connection if - * possible, false otherwise. - * @return A database connection Handle, or INVALID_HANDLE on failure. - * On failure the error buffer will be filled with a message. - * @error Invalid KeyValues handle. - */ -native Database SQL_ConnectCustom(Handle keyvalues, - char[] error, - int maxlength, - bool persistent); - -/** - * Grabs a handle to an SQLite database, creating one if it does not exist. - * - * Unless there are extenuating circumstances, you should consider using "sourcemod-local" as the - * database name. This provides some unification between plugins on behalf of users. - * - * As a precaution, you should always create some sort of unique prefix to your table names so - * there are no conflicts, and you should never drop or modify tables that you do not own. - * - * @param database Database name. - * @param error Error buffer. - * @param maxlength Maximum length of the error buffer. - * @return A database connection Handle, or INVALID_HANDLE on failure. - * On failure the error buffer will be filled with a message. - */ -stock Database SQLite_UseDatabase(const char[] database, - char[] error, - int maxlength) -{ - KeyValues kv = new KeyValues(""); - kv.SetString("driver", "sqlite"); - kv.SetString("database", database); - - Database db = SQL_ConnectCustom(kv, error, maxlength, false); - - delete kv; - - return db; -} - -/** - * This function is deprecated. Use SQL_ConnectCustom or SQLite_UseDatabase instead. - */ -#pragma deprecated Use SQL_ConnectCustom instead. -native Handle SQL_ConnectEx(Handle driver, - const char[] host, - const char[] user, - const char[] pass, - const char[] database, - char[] error, - int maxlength, - bool persistent=true, - int port=0, - int maxTimeout=0); - -/** - * Returns if a named configuration is present in databases.cfg. - * - * @param name Configuration name. - * @return True if it exists, false otherwise. - */ -native bool SQL_CheckConfig(const char[] name); - -/** - * Returns a driver Handle from a name string. - * - * If the driver is not found, SourceMod will attempt - * to load an extension named dbi..ext.[dll|so]. - * - * @param name Driver identification string, or an empty - * string to return the default driver. - * @return Driver Handle, or INVALID_HANDLE on failure. - */ -native Handle SQL_GetDriver(const char[] name=""); - -/** - * Reads the driver of an opened database. - * - * @param database Database Handle. - * @param ident Option buffer to store the identification string. - * @param ident_length Maximum length of the buffer. - * @return Driver Handle. - */ -native Handle SQL_ReadDriver(Handle database, char[] ident="", int ident_length=0); - -/** - * Retrieves a driver's identification string. - * - * Example: "mysql", "sqlite" - * - * @param driver Driver Handle, or INVALID_HANDLE for the default driver. - * @param ident Identification string buffer. - * @param maxlength Maximum length of the buffer. - * @error Invalid Handle other than INVALID_HANDLE. - */ -native void SQL_GetDriverIdent(Handle driver, char[] ident, int maxlength); - -/** - * Retrieves a driver's product string. - * - * Example: "MySQL", "SQLite" - * - * @param driver Driver Handle, or INVALID_HANDLE for the default driver. - * @param product Product string buffer. - * @param maxlength Maximum length of the buffer. - * @error Invalid Handle other than INVALID_HANDLE. - */ -native void SQL_GetDriverProduct(Handle driver, char[] product, int maxlength); - -/** - * Sets the character set of the current connection. - * Like SET NAMES .. in mysql, but stays after connection problems. - * - * Example: "utf8", "latin1" - * - * @param database Database Handle. - * @param characterset The character set string to change to. - * @return True, if character set was changed, false otherwise. - */ -native bool SQL_SetCharset(Handle database, const char[] charset); - -/** - * Returns the number of affected rows from the last query. - * - * @param hndl A database OR statement Handle. - * @return Number of rows affected by the last query. - * @error Invalid database or statement Handle. - */ -native int SQL_GetAffectedRows(Handle hndl); - -/** - * Returns the last query's insertion id. - * - * @param hndl A database, query, OR statement Handle. - * @return Last query's insertion id. - * @error Invalid database, query, or statement Handle. - */ -native int SQL_GetInsertId(Handle hndl); - -/** - * Returns the error reported by the last query. - * - * @param hndl A database, query, OR statement Handle. - * @param error Error buffer. - * @param maxlength Maximum length of the buffer. - * @return True if there was an error, false otherwise. - * @error Invalid database, query, or statement Handle. - */ -native bool SQL_GetError(Handle hndl, char[] error, int maxlength); - -/** - * Escapes a database string for literal insertion. This is not needed - * for binding strings in prepared statements. - * - * Generally, database strings are inserted into queries enclosed in - * single quotes ('). If user input has a single quote in it, the - * quote needs to be escaped. This function ensures that any unsafe - * characters are safely escaped according to the database engine and - * the database's character set. - * - * NOTE: SourceMod only guarantees properly escaped strings when the query - * encloses the string in ''. While drivers tend to allow " instead, the string - * may be not be escaped (for example, on SQLite)! - * - * @param database A database Handle. - * @param string String to quote. - * @param buffer Buffer to store quoted string in. - * @param maxlength Maximum length of the buffer. - * @param written Optionally returns the number of bytes written. - * @return True on success, false if buffer is not big enough. - * The buffer must be at least 2*strlen(string)+1. - * @error Invalid database or statement Handle. - */ -native bool SQL_EscapeString(Handle database, - const char[] string, - char[] buffer, - int maxlength, - int &written=0); - -/** - * Formats a string according to the SourceMod format rules (see documentation). - * All format specifiers are escaped (see SQL_EscapeString) unless the '!' flag is used. - * - * @param database A database Handle. - * @param buffer Destination string buffer. - * @param maxlength Maximum length of output string buffer. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @return Number of cells written. - */ -native int SQL_FormatQuery(Handle database, const char[] buffer, int maxlength, const char[] format, any ...); - -/** - * This is a backwards compatibility stock. You should use SQL_EscapeString() - * instead, as this function will probably be deprecated in SourceMod 1.1. - */ -stock bool SQL_QuoteString(Handle database, - const char[] string, - char[] buffer, - int maxlength, - int &written=0) -{ - return SQL_EscapeString(database, string, buffer, maxlength, written); -} - -/** - * Executes a query and ignores the result set. - * - * @param database A database Handle. - * @param query Query string. - * @param len Optional parameter to specify the query length, in - * bytes. This can be used to send binary queries that - * have a premature terminator. - * @return True if query succeeded, false otherwise. Use - * SQL_GetError to find the last error. - * @error Invalid database Handle. - */ -native bool SQL_FastQuery(Handle database, const char[] query, int len=-1); - -/** - * Executes a simple query and returns a new query Handle for - * receiving the results. - * - * @param database A database Handle. - * @param query Query string. - * @param len Optional parameter to specify the query length, in - * bytes. This can be used to send binary queries that - * have a premature terminator. - * @return A new Query Handle on success, INVALID_HANDLE - * otherwise. The Handle must be freed with CloseHandle(). - * @error Invalid database Handle. - */ -native DBResultSet SQL_Query(Handle database, const char[] query, int len=-1); - -/** - * Creates a new prepared statement query. Prepared statements can - * be executed any number of times. They can also have placeholder - * parameters, similar to variables, which can be bound safely and - * securely (for example, you do not need to quote bound strings). - * - * Statement handles will work in any function that accepts a Query handle. - * - * @param database A database Handle. - * @param query Query string. - * @param error Error buffer. - * @param maxlength Maximum size of the error buffer. - * @return A new statement Handle on success, INVALID_HANDLE - * otherwise. The Handle must be freed with CloseHandle(). - * @error Invalid database Handle. - */ -native DBStatement SQL_PrepareQuery(Handle database, const char[] query, char[] error, int maxlength); - -/** - * Advances to the next set of results. - * - * In some SQL implementations, multiple result sets can exist on one query. - * This is possible in MySQL with simple queries when executing a CALL - * query. If this is the case, all result sets must be processed before - * another query is made. - * - * @param query A query Handle. - * @return True if there was another result set, false otherwise. - * @error Invalid query Handle. - */ -native bool SQL_FetchMoreResults(Handle query); - -/** - * Returns whether or not a result set exists. This will - * return true even if 0 results were returned, but false - * on queries like UPDATE, INSERT, or DELETE. - * - * @param query A query (or statement) Handle. - * @return True if there is a result set, false otherwise. - * @error Invalid query Handle. - */ -native bool SQL_HasResultSet(Handle query); - -/** - * Retrieves the number of rows in the last result set. - * - * @param query A query (or statement) Handle. - * @return Number of rows in the current result set. - * @error Invalid query Handle. - */ -native int SQL_GetRowCount(Handle query); - -/** - * Retrieves the number of fields in the last result set. - * - * @param query A query (or statement) Handle. - * @return Number of fields in the current result set. - * @error Invalid query Handle. - */ -native int SQL_GetFieldCount(Handle query); - -/** - * Retrieves the name of a field by index. - * - * @param query A query (or statement) Handle. - * @param field Field number (starting from 0). - * @param name Name buffer. - * @param maxlength Maximum length of the name buffer. - * @error Invalid query Handle, invalid field index, or - * no current result set. - */ -native void SQL_FieldNumToName(Handle query, int field, char[] name, int maxlength); - -/** - * Retrieves a field index by name. - * - * @param query A query (or statement) Handle. - * @param name Name of the field (case sensitive). - * @param field Variable to store field index in. - * @return True if found, false if not found. - * @error Invalid query Handle or no current result set. - */ -native bool SQL_FieldNameToNum(Handle query, const char[] name, int &field); - -/** - * Fetches a row from the current result set. This must be - * successfully called before any results are fetched. - * - * If this function fails, SQL_MoreResults() can be used to - * tell if there was an error or the result set is finished. - * - * @param query A query (or statement) Handle. - * @return True if a row was fetched, false otherwise. - * @error Invalid query Handle. - */ -native bool SQL_FetchRow(Handle query); - -/** - * Returns if there are more rows. - * - * @param query A query (or statement) Handle. - * @return True if there are more rows, false otherwise. - * @error Invalid query Handle. - */ -native bool SQL_MoreRows(Handle query); - -/** - * Rewinds a result set back to the first result. - * - * @param query A query (or statement) Handle. - * @return True on success, false otherwise. - * @error Invalid query Handle or no current result set. - */ -native bool SQL_Rewind(Handle query); - -/** - * Fetches a string from a field in the current row of a result set. - * If the result is NULL, an empty string will be returned. A NULL - * check can be done with the result parameter, or SQL_IsFieldNull(). - * - * @param query A query (or statement) Handle. - * @param field The field index (starting from 0). - * @param buffer String buffer. - * @param maxlength Maximum size of the string buffer. - * @param result Optional variable to store the status of the return value. - * @return Number of bytes written. - * @error Invalid query Handle or field index, invalid - * type conversion requested from the database, - * or no current result set. - */ -native int SQL_FetchString(Handle query, int field, char[] buffer, int maxlength, DBResult &result=DBVal_Error); - -/** - * Fetches a float from a field in the current row of a result set. - * If the result is NULL, a value of 0.0 will be returned. A NULL - * check can be done with the result parameter, or SQL_IsFieldNull(). - * - * @param query A query (or statement) Handle. - * @param field The field index (starting from 0). - * @param result Optional variable to store the status of the return value. - * @return A float value. - * @error Invalid query Handle or field index, invalid - * type conversion requested from the database, - * or no current result set. - */ -native float SQL_FetchFloat(Handle query, int field, DBResult &result=DBVal_Error); - -/** - * Fetches an integer from a field in the current row of a result set. - * If the result is NULL, a value of 0 will be returned. A NULL - * check can be done with the result parameter, or SQL_IsFieldNull(). - * - * @param query A query (or statement) Handle. - * @param field The field index (starting from 0). - * @param result Optional variable to store the status of the return value. - * @return An integer value. - * @error Invalid query Handle or field index, invalid - * type conversion requested from the database, - * or no current result set. - */ -native int SQL_FetchInt(Handle query, int field, DBResult &result=DBVal_Error); - -/** - * Returns whether a field's data in the current row of a result set is - * NULL or not. NULL is an SQL type which means "no data." - * - * @param query A query (or statement) Handle. - * @param field The field index (starting from 0). - * @return True if data is NULL, false otherwise. - * @error Invalid query Handle or field index, or no - * current result set. - */ -native bool SQL_IsFieldNull(Handle query, int field); - -/** - * Returns the length of a field's data in the current row of a result - * set. This only needs to be called for strings to determine how many - * bytes to use. Note that the return value does not include the null - * terminator. - * - * @param query A query (or statement) Handle. - * @param field The field index (starting from 0). - * @return Number of bytes for the field's data size. - * @error Invalid query Handle or field index or no - * current result set. - */ -native int SQL_FetchSize(Handle query, int field); - -/** - * Binds a parameter in a prepared statement to a given integer value. - * - * @param statement A statement (prepared query) Handle. - * @param param The parameter index (starting from 0). - * @param number The number to bind. - * @param signed True to bind the number as signed, false to - * bind it as unsigned. - * @error Invalid statement Handle or parameter index, or - * SQL error. - */ -native void SQL_BindParamInt(Handle statement, int param, int number, bool signed=true); - -/** - * Binds a parameter in a prepared statement to a given float value. - * - * @param statement A statement (prepared query) Handle. - * @param param The parameter index (starting from 0). - * @param value The float number to bind. - * @error Invalid statement Handle or parameter index, or - * SQL error. - */ -native void SQL_BindParamFloat(Handle statement, int param, float value); - -/** - * Binds a parameter in a prepared statement to a given string value. - * - * @param statement A statement (prepared query) Handle. - * @param param The parameter index (starting from 0). - * @param value The string to bind. - * @param copy Whether or not SourceMod should copy the value - * locally if necessary. If the string contents - * won't change before calling SQL_Execute(), this - * can be set to false for optimization. - * @error Invalid statement Handle or parameter index, or - * SQL error. - */ -native void SQL_BindParamString(Handle statement, int param, const char[] value, bool copy); - -/** - * Executes a prepared statement. All parameters must be bound beforehand. - * - * @param statement A statement (prepared query) Handle. - * @return True on success, false on failure. - * @error Invalid statement Handle. - */ -native bool SQL_Execute(Handle statement); - -/** - * Locks a database so threading operations will not interrupt. - * - * If you are using a database Handle for both threading and non-threading, - * this MUST be called before doing any set of non-threading DB operations. - * Otherwise you risk corrupting the database driver's memory or network - * connection. - * - * Leaving a lock on a database and then executing a threaded query results - * in a dead lock! Make sure to call SQL_UnlockDatabase()! - * - * If the lock cannot be acquired, the main thread will pause until the - * threaded operation has concluded. - * - * @param database A database Handle. - * @error Invalid database Handle. - */ -native void SQL_LockDatabase(Handle database); - -/** - * Unlocks a database so threading operations may continue. - * - * @param database A database Handle. - * @error Invalid database Handle. - */ -native void SQL_UnlockDatabase(Handle database); - -// General callback for threaded SQL stuff. -// -// @param owner Parent object of the Handle (or INVALID_HANDLE if none). -// @param hndl Handle to the child object (or INVALID_HANDLE if none). -// @param error Error string if there was an error. The error could be -// empty even if an error condition exists, so it is important -// to check the actual Handle value instead. -// @param data Data passed in via the original threaded invocation. -typedef SQLTCallback = function void (Handle owner, Handle hndl, const char[] error, any data); - -/** - * Tells whether two database handles both point to the same database - * connection. - * - * @param hndl1 First database Handle. - * @param hndl2 Second database Handle. - * @return True if the Handles point to the same - * connection, false otherwise. - * @error Invalid Handle. - */ -native bool SQL_IsSameConnection(Handle hndl1, Handle hndl2); - -/** - * Connects to a database via a thread. This can be used instead of - * SQL_Connect() if you wish for non-blocking functionality. - * - * It is not necessary to use this to use threaded queries. However, if you - * don't (or you mix threaded/non-threaded queries), you should see - * SQL_LockDatabase(). - * - * @param callback Callback; new Handle will be in hndl, owner is the driver. - * If no driver was found, the owner is INVALID_HANDLE. - * @param name Database name. - * @param data Extra data value to pass to the callback. - */ -native void SQL_TConnect(SQLTCallback callback, const char[] name="default", any data=0); - -/** - * Executes a simple query via a thread. The query Handle is passed through - * the callback. - * - * The database Handle returned through the callback is always a new Handle, - * and if necessary, SQL_IsSameConnection() should be used to test against - * other connections. - * - * The query Handle returned through the callback is temporary and destroyed - * at the end of the callback. If you need to hold onto it, use CloneHandle(). - * - * @param database A database Handle. - * @param callback Callback; database is in "owner" and the query Handle - * is passed in "hndl". - * @param query Query string. - * @param data Extra data value to pass to the callback. - * @param prio Priority queue to use. - * @error Invalid database Handle. - */ -native void SQL_TQuery(Handle database, SQLTCallback callback, const char[] query, any data=0, DBPriority prio=DBPrio_Normal); - -/** - * Creates a new transaction object. A transaction object is a list of queries - * that can be sent to the database thread and executed as a single transaction. - * - * @return A transaction handle. - */ -native Transaction SQL_CreateTransaction(); - -/** - * Adds a query to a transaction object. - * - * @param txn A transaction handle. - * @param query Query string. - * @param data Extra data value to pass to the final callback. - * @return The index of the query in the transaction's query list. - * @error Invalid transaction handle. - */ -native int SQL_AddQuery(Transaction txn, const char[] query, any data=0); - -/** - * Sends a transaction to the database thread. The transaction handle is - * automatically closed. When the transaction completes, the optional - * callback is invoked. - * - * @param db A database handle. - * @param txn A transaction handle. - * @param onSuccess An optional callback to receive a successful transaction. - * @param onError An optional callback to receive an error message. - * @param data An optional value to pass to callbacks. - * @param prio Priority queue to use. - * @error An invalid handle. - */ -native void SQL_ExecuteTransaction( - Handle db, - Transaction txn, - SQLTxnSuccess onSuccess = INVALID_FUNCTION, - SQLTxnFailure onError = INVALID_FUNCTION, - any data=0, - DBPriority priority=DBPrio_Normal); diff --git a/scripting/include/entity.inc b/scripting/include/entity.inc deleted file mode 100644 index fba1e80..0000000 --- a/scripting/include/entity.inc +++ /dev/null @@ -1,759 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _entity_included - #endinput -#endif -#define _entity_included - -/** - * Property types for entities. - */ -enum PropType -{ - Prop_Send = 0, /**< This property is networked. */ - Prop_Data = 1, /**< This property is for save game data fields. */ -}; - -/** - * @section For more information on these, see the HL2SDK (public/edict.h) - */ -#define FL_EDICT_CHANGED (1<<0) /**< Game DLL sets this when the entity state changes - Mutually exclusive with FL_EDICT_PARTIAL_CHANGE. */ -#define FL_EDICT_FREE (1<<1) /**< this edict if free for reuse */ -#define FL_EDICT_FULL (1<<2) /**< this is a full server entity */ -#define FL_EDICT_FULLCHECK (0<<0) /**< call ShouldTransmit() each time, this is a fake flag */ -#define FL_EDICT_ALWAYS (1<<3) /**< always transmit this entity */ -#define FL_EDICT_DONTSEND (1<<4) /**< don't transmit this entity */ -#define FL_EDICT_PVSCHECK (1<<5) /**< always transmit entity, but cull against PVS */ -#define FL_EDICT_PENDING_DORMANT_CHECK (1<<6) -#define FL_EDICT_DIRTY_PVS_INFORMATION (1<<7) -#define FL_FULL_EDICT_CHANGED (1<<8) - -enum PropFieldType -{ - PropField_Unsupported, /**< The type is unsupported. */ - PropField_Integer, /**< Valid for SendProp and Data fields */ - PropField_Float, /**< Valid for SendProp and Data fields */ - PropField_Entity, /**< Valid for Data fields only (SendProp shows as int) */ - PropField_Vector, /**< Valid for SendProp and Data fields */ - PropField_String, /**< Valid for SendProp and Data fields */ - PropField_String_T, /**< Valid for Data fields. Read only. - Note that the size of a string_t is dynamic, and - thus FindDataMapOffs() will return the constant size - of the string_t container (which is 32 bits right now). - */ - PropField_Variant, /**< Valid for Data fields only Type is not known at the field level, - (for this call), but dependent on current field value. */ -}; - -/** - * @endsection - */ - -/** - * Returns the maximum number of networked entities. - * - * Note: For legacy reasons, this only returns the maximum - * networked entities (maximum edicts), rather than total - * maximum entities. - * - * @return Maximum number of networked entities. - */ -native int GetMaxEntities(); - -/** - * Returns the number of networked entities in the server. - * - * Note: For legacy reasons, this only returns the current count - * of networked entities (current edicts), rather than total - * count of current entities. - * - * @return Number of entities in the server. - */ -native int GetEntityCount(); - -/** - * Returns whether or not an entity is valid. Returns false - * if there is no matching CBaseEntity for this entity index. - * - * @param entity Index of the entity. - * @return True if valid, false otherwise. - */ -native bool IsValidEntity(int entity); - -/** - * Returns whether or not an edict index is valid. - * - * @param edict Index of the edict. - * @return True if valid, false otherwise. - */ -native bool IsValidEdict(int edict); - -/** - * Returns whether or not an entity has a valid networkable edict. - * - * @param edict Index of the entity. - * @return True if networkable, false if invalid or not networkable. - */ -native bool IsEntNetworkable(int entiy); - -/** - * Creates a new edict (the basis of a networkable entity) - * - * @return Index of the edict, 0 on failure. - */ -native int CreateEdict(); - -/** - * Removes an edict from the world. - * - * @param edict Index of the edict. - * @error Invalid edict index. - */ -native void RemoveEdict(int edict); - -/** - * Marks an entity for deletion. - * - * @param entity Index of the entity. - * @error Invalid entity index. - */ -native void RemoveEntity(int entity); - -/** - * Returns the flags on an edict. These are not the same as entity flags. - * - * @param edict Index of the entity. - * @return Edict flags. - * @error Invalid edict index. - */ -native int GetEdictFlags(int edict); - -/** - * Sets the flags on an edict. These are not the same as entity flags. - * - * @param edict Index of the entity. - * @param flags Flags to set. - * @error Invalid edict index. - */ -native void SetEdictFlags(int edict, int flags); - -/** - * Retrieves an edict classname. - * - * @param edict Index of the entity. - * @param clsname Buffer to store the classname. - * @param maxlength Maximum length of the buffer. - * @return True on success, false if there is no classname set. - */ -native bool GetEdictClassname(int edict, char[] clsname, int maxlength); - -/** - * Retrieves an entity's networkable serverclass name. - * This is not the same as the classname and is used for networkable state changes. - * - * @param edict Index of the entity. - * @param clsname Buffer to store the serverclass name. - * @param maxlength Maximum length of the buffer. - * @return True on success, false if the edict is not networkable. - * @error Invalid edict index. - */ -native bool GetEntityNetClass(int edict, char[] clsname, int maxlength); - -/** - * @section Entity offset functions - * - * Offsets should be specified in byte distance from the CBaseEntity - * structure, not short (double byte) or integer (four byte) multiples. - * It is somewhat common practice to use offsets aligned to their final - * type, and thus make sure you are not falling to this error in SourceMod. - * For example, if your "integer-aligned" offset was 119, your byte-aligned - * offset is 119*4, or 476. - - * Specifying incorrect offsets or the incorrect data type for an offset - * can have fatal consequences. If you are hardcoding offsets, and the - * layout of CBaseEntity does not match, you can easily crash the server. - * - * The reasonable bounds for offsets is greater than or equal to 0 and - * below 32768. Offsets out of these bounds will throw an error. However, - * this does not represent any real range, it is simply a sanity check for - * illegal values. Any range outside of the CBaseEntity structure's private - * size will cause undefined behavior or even crash. - */ - -/** - * Marks an entity as state changed. This can be useful if you set an offset - * and wish for it to be immediately changed over the network. By default this - * is not done for offset setting functions. - * - * @param edict Index to the edict. - * @param offset Offset to mark as changed. If 0, - * the entire edict is marked as changed. - * @error Invalid entity or offset out of bounds. - */ -native void ChangeEdictState(int edict, int offset = 0); - -/** - * Peeks into an entity's object data and retrieves the integer value at - * the given offset. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param size Number of bytes to read (valid values are 1, 2, or 4). - * @return Value at the given memory location. - * @error Invalid entity or offset out of reasonable bounds. - */ -native int GetEntData(int entity, int offset, int size=4); - -/** - * Peeks into an entity's object data and sets the integer value at - * the given offset. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param value Value to set. - * @param size Number of bytes to write (valid values are 1, 2, or 4). - * @param changeState If true, change will be sent over the network. - * @error Invalid entity or offset out of reasonable bounds. - */ -native void SetEntData(int entity, int offset, any value, int size=4, bool changeState=false); - -/** - * Peeks into an entity's object data and retrieves the float value at - * the given offset. - * - * @param entity Edict index. - * @param offset Offset to use. - * @return Value at the given memory location. - * @error Invalid entity or offset out of reasonable bounds. - */ -native float GetEntDataFloat(int entity, int offset); - -/** - * Peeks into an entity's object data and sets the float value at - * the given offset. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param value Value to set. - * @param changeState If true, change will be sent over the network. - * @error Invalid entity or offset out of reasonable bounds. - */ -native void SetEntDataFloat(int entity, int offset, float value, bool changeState=false); - -/** - * This function is deprecated. Use GetEntDataEnt2 instead, for - * reasons explained in the notes. - * - * Note: This function returns 0 on failure, which may be misleading, - * as the number 0 is also used for the world entity index. - * - * Note: This function makes no attempt to validate the returned - * entity, and in fact, it could be garbage or completely unexpected. - * - * @param entity Edict index. - * @param offset Offset to use. - * @return Entity index at the given location, or 0 if none. - * @error Invalid entity or offset out of reasonable bounds. - */ -#pragma deprecated Use GetEntDataEnt2() instead. -native int GetEntDataEnt(int entity, int offset); - -/** - * This function is deprecated. Use SetEntDataEnt2 instead, for - * reasons explained in the notes. - * - * Note: This function uses 0 as an indicator to unset data, but - * 0 is also the world entity index. Thus, a property cannot - * be set to the world entity using this native. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param other Entity index to set, or 0 to clear. - * @param changeState If true, change will be sent over the network. - * @error Invalid entity or offset out of reasonable bounds. - */ -#pragma deprecated Use SetEntDataEnt2() instead. -native void SetEntDataEnt(int entity, int offset, int other, bool changeState=false); - -/** - * Peeks into an entity's object data and retrieves the entity index - * at the given offset. - * - * Note: This will only work on offsets that are stored as "entity - * handles" (which usually looks like m_h* in properties). These - * are not SourceMod Handles, but internal Source structures. - * - * @param entity Edict index. - * @param offset Offset to use. - * @return Entity index at the given location. If there is no entity, - * or the stored entity is invalid, then -1 is returned. - * @error Invalid input entity, or offset out of reasonable bounds. - */ -native int GetEntDataEnt2(int entity, int offset); - -/** - * Peeks into an entity's object data and sets the entity index at the - * given offset. - * - * Note: This will only work on offsets that are stored as "entity - * handles" (which usually looks like m_h* in properties). These - * are not SourceMod Handles, but internal Source structures. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param other Entity index to set, or -1 to clear. - * @param changeState If true, change will be sent over the network. - * @error Invalid input entity, or offset out of reasonable bounds. - */ -native void SetEntDataEnt2(int entity, int offset, int other, bool changeState=false); - -/** - * Peeks into an entity's object data and retrieves the vector at the - * given offset. - * @note Both a Vector and a QAngle are three floats. This is a - * convenience function and will work with both types. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param vec Vector buffer to store data in. - * @error Invalid entity or offset out of reasonable bounds. - */ -native void GetEntDataVector(int entity, int offset, float vec[3]); - -/** - * Peeks into an entity's object data and sets the vector at the given - * offset. - * @note Both a Vector and a QAngle are three floats. This is a - * convenience function and will work with both types. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param vec Vector to set. - * @param changeState If true, change will be sent over the network. - * @error Invalid entity or offset out of reasonable bounds. - */ -native void SetEntDataVector(int entity, int offset, const float vec[3], bool changeState=false); - -/** - * Peeks into an entity's object data and retrieves the string at - * the given offset. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param buffer Destination string buffer. - * @param maxlen Maximum length of output string buffer. - * @return Number of non-null bytes written. - * @error Invalid entity or offset out of reasonable bounds. - */ -native int GetEntDataString(int entity, int offset, char[] buffer, int maxlen); - -/** - * Peeks into an entity's object data and sets the string at - * the given offset. - * - * @param entity Edict index. - * @param offset Offset to use. - * @param buffer String to set. - * @param maxlen Maximum length of bytes to write. - * @param changeState If true, change will be sent over the network. - * @return Number of non-null bytes written. - * @error Invalid entity or offset out of reasonable bounds. - */ -native int SetEntDataString(int entity, int offset, const char[] buffer, int maxlen, bool changeState=false); - -/** - * @endsection - */ - -/** - * Given a ServerClass name, finds a networkable send property offset. - * This information is cached for future calls. - * - * Note, this function may return offsets that do not work! - * If a property is nested beneath a parent object, the resulting offset - * will be invalid for direct use with data functions. Therefore, you - * should use FindSendPropInfo() instead. An example of such a property is - * CTFPlayer::DT_LocalPlayer.m_nDisguiseClass on Team Fortress. - * - * @param cls Classname. - * @param prop Property name. - * @return An offset, or -1 on failure. - */ -#pragma deprecated Use FindSendPropInfo instead, or HasEntProp if you just want to check for existence. -native int FindSendPropOffs(const char[] cls, const char[] prop); - -/** - * Given a ServerClass name, finds a networkable send property offset. - * This information is cached for future calls. - * - * @param cls Classname. - * @param prop Property name. - * @param type Optional parameter to store the type. - * @param num_bits Optional parameter to store the number of bits the field - * uses, if applicable (otherwise 0 is stored). The number - * of bits varies for integers and floats, and is always 0 - * for strings. - * @param local_offset Optional parameter to store the local offset, as - * FindSendPropOffs() would return. - * @return On success, returns an absolutely computed offset. - * If no offset is available, 0 is returned. - * If the property is not found, -1 is returned. - */ -native int FindSendPropInfo(const char[] cls, - const char[] prop, - PropFieldType &type=view_as(0), - int &num_bits=0, - int &local_offset=0); - -/** - * Given an entity, finds a datamap property offset. - * This information is cached for future calls. - * - * @param entity Entity index. - * @param prop Property name. - * @param type Optional parameter to store the type. - * @param num_bits Optional parameter to store the number of bits the field - * uses. The bit count will either be 1 (for boolean) or - * divisible by 8 (including 0 if unknown). - * @return An offset, or -1 on failure. - */ -#pragma deprecated Use FindDataMapInfo instead, or HasEntProp if you just want to check for existence. -native int FindDataMapOffs(int entity, - const char[] prop, - PropFieldType &type=view_as(0), - int &num_bits=0); - -/** - * Given an entity, finds a nested datamap property offset. - * This information is cached for future calls. - * - * @param entity Entity index. - * @param prop Property name. - * @param type Optional parameter to store the type. - * @param num_bits Optional parameter to store the number of bits the field - * uses. The bit count will either be 1 (for boolean) or - * divisible by 8 (including 0 if unknown). - * @param local_offset Optional parameter to store the local offset, as - * FindDataMapOffs() would return. - * @return An offset, or -1 on failure. - */ -native int FindDataMapInfo(int entity, - const char[] prop, - PropFieldType &type=view_as(0), - int &num_bits=0, - int &local_offset=0); - -/** - * Wrapper function for finding a send property for a particular entity. - * - * @param ent Entity index. - * @param prop Property name. - * @param actual Defaults to false for backwards compatibility. - * If true, the newer FindSendPropInfo() function - * is used instead. - * @return An offset, or -1 on failure. - */ -stock int GetEntSendPropOffs(int ent, const char[] prop, bool actual=false) -{ - char cls[64]; - - if (!GetEntityNetClass(ent, cls, sizeof(cls))) - { - return -1; - } - - int local = -1; - int offset = FindSendPropInfo(cls, prop, _, _, local); - - if (actual) - { - return offset; - } else { - return local; - } -} - -/** - * Checks if an entity property exists on an entity. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @return Whether the property exists on the entity. - * @error Invalid entity. - */ -stock bool HasEntProp(int entity, PropType type, const char[] prop) -{ - if (type == Prop_Data) { - return (FindDataMapInfo(entity, prop) != -1); - } - - if (type != Prop_Send) { - return false; - } - - char cls[64]; - if (!GetEntityNetClass(entity, cls, sizeof(cls))) { - return false; - } - - return (FindSendPropInfo(cls, prop) != -1); -} - -/** - * Retrieves an integer value from an entity's property. - * - * This function is considered safer and more robust over GetEntData, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param size Number of bytes to write (valid values are 1, 2, or 4). - * This value is auto-detected, and the size parameter is - * only used as a fallback in case detection fails. - * @param element Element # (starting from 0) if property is an array. - * @return Value at the given property offset. - * @error Invalid entity or property not found. - */ -native int GetEntProp(int entity, PropType type, const char[] prop, int size=4, int element=0); - -/** - * Sets an integer value in an entity's property. - * - * This function is considered safer and more robust over SetEntData, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param value Value to set. - * @param size Number of bytes to write (valid values are 1, 2, or 4). - * This value is auto-detected, and the size parameter is - * only used as a fallback in case detection fails. - * @param element Element # (starting from 0) if property is an array. - * @error Invalid entity or offset out of reasonable bounds. - */ -native void SetEntProp(int entity, PropType type, const char[] prop, any value, int size=4, int element=0); - -/** - * Retrieves a float value from an entity's property. - * - * This function is considered safer and more robust over GetEntDataFloat, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param element Element # (starting from 0) if property is an array. - * @return Value at the given property offset. - * @error Invalid entity or offset out of reasonable bounds. - */ -native float GetEntPropFloat(int entity, PropType type, const char[] prop, int element=0); - -/** - * Sets a float value in an entity's property. - * - * This function is considered safer and more robust over SetEntDataFloat, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param value Value to set. - * @param element Element # (starting from 0) if property is an array. - * @error Invalid entity or offset out of reasonable bounds. - */ -native void SetEntPropFloat(int entity, PropType type, const char[] prop, float value, int element=0); - -/** - * Retrieves an entity index from an entity's property. - * - * This function is considered safer and more robust over GetEntDataEnt*, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param element Element # (starting from 0) if property is an array. - * @return Entity index at the given property. - * If there is no entity, or the entity is not valid, - * then -1 is returned. - * @error Invalid entity or offset out of reasonable bounds. - */ -native int GetEntPropEnt(int entity, PropType type, const char[] prop, int element=0); - -/** - * Sets an entity index in an entity's property. - * - * This function is considered safer and more robust over SetEntDataEnt*, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param other Entity index to set, or -1 to unset. - * @param element Element # (starting from 0) if property is an array. - * @error Invalid entity or offset out of reasonable bounds. - */ -native void SetEntPropEnt(int entity, PropType type, const char[] prop, int other, int element=0); - -/** - * Retrieves a vector of floats from an entity, given a named network property. - * - * This function is considered safer and more robust over GetEntDataVector, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param vec Vector buffer to store data in. - * @param element Element # (starting from 0) if property is an array. - * @error Invalid entity, property not found, or property not - * actually a vector data type. - */ -native void GetEntPropVector(int entity, PropType type, const char[] prop, float vec[3], int element=0); - -/** - * Sets a vector of floats in an entity, given a named network property. - * - * This function is considered safer and more robust over SetEntDataVector, - * because it performs strict offset checking and typing rules. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @param vec Vector to set. - * @param element Element # (starting from 0) if property is an array. - * @error Invalid entity, property not found, or property not - * actually a vector data type. - */ -native void SetEntPropVector(int entity, PropType type, const char[] prop, const float vec[3], int element=0); - -/** - * Gets a network property as a string. - * - * @param entity Edict index. - * @param type Property type. - * @param prop Property to use. - * @param buffer Destination string buffer. - * @param maxlen Maximum length of output string buffer. - * @param element Element # (starting from 0) if property is an array. - * @return Number of non-null bytes written. - * @error Invalid entity, offset out of reasonable bounds, or property is not a valid string. - */ -native int GetEntPropString(int entity, PropType type, const char[] prop, char[] buffer, int maxlen, int element=0); - -/** - * Sets a network property as a string. - * - * @param entity Edict index. - * @param type Property type. - * @param prop Property to use. - * @param buffer String to set. - * @param element Element # (starting from 0) if property is an array. - * @return Number of non-null bytes written. - * @error Invalid entity, offset out of reasonable bounds, or property is not a valid string. - */ -native int SetEntPropString(int entity, PropType type, const char[] prop, const char[] buffer, int element=0); - -/** - * Retrieves the count of values that an entity property's array can store. - * - * @param entity Entity/edict index. - * @param type Property type. - * @param prop Property name. - * @return Size of array (in elements) or 1 if property is not an array. - * @error Invalid entity or property not found. - */ -native int GetEntPropArraySize(int entity, PropType type, const char[] prop); - -/** - * Copies an array of cells from an entity at a given offset. - * - * @param entity Entity index. - * @param offset Offset to use. - * @param array Array to read into. - * @param arraySize Number of values to read. - * @param dataSize Size of each value in bytes (1, 2, or 4). - * @error Invalid entity or offset out of reasonable bounds. - */ -stock void GetEntDataArray(int entity, int offset, int[] array, int arraySize, int dataSize=4) -{ - for (int i=0; i. - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _entity_prop_stocks_included - #endinput -#endif -#define _entity_prop_stocks_included - -enum MoveType -{ - MOVETYPE_NONE = 0, /**< never moves */ - MOVETYPE_ISOMETRIC, /**< For players */ - MOVETYPE_WALK, /**< Player only - moving on the ground */ - MOVETYPE_STEP, /**< gravity, special edge handling -- monsters use this */ - MOVETYPE_FLY, /**< No gravity, but still collides with stuff */ - MOVETYPE_FLYGRAVITY, /**< flies through the air + is affected by gravity */ - MOVETYPE_VPHYSICS, /**< uses VPHYSICS for simulation */ - MOVETYPE_PUSH, /**< no clip to world, push and crush */ - MOVETYPE_NOCLIP, /**< No gravity, no collisions, still do velocity/avelocity */ - MOVETYPE_LADDER, /**< Used by players only when going onto a ladder */ - MOVETYPE_OBSERVER, /**< Observer movement, depends on player's observer mode */ - MOVETYPE_CUSTOM, /**< Allows the entity to describe its own physics */ -}; - -enum RenderMode -{ - RENDER_NORMAL, /**< src */ - RENDER_TRANSCOLOR, /**< c*a+dest*(1-a) */ - RENDER_TRANSTEXTURE, /**< src*a+dest*(1-a) */ - RENDER_GLOW, /**< src*a+dest -- No Z buffer checks -- Fixed size in screen space */ - RENDER_TRANSALPHA, /**< src*srca+dest*(1-srca) */ - RENDER_TRANSADD, /**< src*a+dest */ - RENDER_ENVIRONMENTAL, /**< not drawn, used for environmental effects */ - RENDER_TRANSADDFRAMEBLEND, /**< use a fractional frame value to blend between animation frames */ - RENDER_TRANSALPHAADD, /**< src + dest*(1-a) */ - RENDER_WORLDGLOW, /**< Same as kRenderGlow but not fixed size in screen space */ - RENDER_NONE, /**< Don't render. */ -}; - -enum RenderFx -{ - RENDERFX_NONE = 0, - RENDERFX_PULSE_SLOW, - RENDERFX_PULSE_FAST, - RENDERFX_PULSE_SLOW_WIDE, - RENDERFX_PULSE_FAST_WIDE, - RENDERFX_FADE_SLOW, - RENDERFX_FADE_FAST, - RENDERFX_SOLID_SLOW, - RENDERFX_SOLID_FAST, - RENDERFX_STROBE_SLOW, - RENDERFX_STROBE_FAST, - RENDERFX_STROBE_FASTER, - RENDERFX_FLICKER_SLOW, - RENDERFX_FLICKER_FAST, - RENDERFX_NO_DISSIPATION, - RENDERFX_DISTORT, /**< Distort/scale/translate flicker */ - RENDERFX_HOLOGRAM, /**< kRenderFxDistort + distance fade */ - RENDERFX_EXPLODE, /**< Scale up really big! */ - RENDERFX_GLOWSHELL, /**< Glowing Shell */ - RENDERFX_CLAMP_MIN_SCALE, /**< Keep this sprite from getting very small (SPRITES only!) */ - RENDERFX_ENV_RAIN, /**< for environmental rendermode, make rain */ - RENDERFX_ENV_SNOW, /**< " " " , make snow */ - RENDERFX_SPOTLIGHT, /**< TEST CODE for experimental spotlight */ - RENDERFX_RAGDOLL, /**< HACKHACK: TEST CODE for signalling death of a ragdoll character */ - RENDERFX_PULSE_FAST_WIDER, - RENDERFX_MAX -}; - -// These defines are for client button presses. -#define IN_ATTACK (1 << 0) -#define IN_JUMP (1 << 1) -#define IN_DUCK (1 << 2) -#define IN_FORWARD (1 << 3) -#define IN_BACK (1 << 4) -#define IN_USE (1 << 5) -#define IN_CANCEL (1 << 6) -#define IN_LEFT (1 << 7) -#define IN_RIGHT (1 << 8) -#define IN_MOVELEFT (1 << 9) -#define IN_MOVERIGHT (1 << 10) -#define IN_ATTACK2 (1 << 11) -#define IN_RUN (1 << 12) -#define IN_RELOAD (1 << 13) -#define IN_ALT1 (1 << 14) -#define IN_ALT2 (1 << 15) -#define IN_SCORE (1 << 16) /**< Used by client.dll for when scoreboard is held down */ -#define IN_SPEED (1 << 17) /**< Player is holding the speed key */ -#define IN_WALK (1 << 18) /**< Player holding walk key */ -#define IN_ZOOM (1 << 19) /**< Zoom key for HUD zoom */ -#define IN_WEAPON1 (1 << 20) /**< weapon defines these bits */ -#define IN_WEAPON2 (1 << 21) /**< weapon defines these bits */ -#define IN_BULLRUSH (1 << 22) -#define IN_GRENADE1 (1 << 23) /**< grenade 1 */ -#define IN_GRENADE2 (1 << 24) /**< grenade 2 */ -#define IN_ATTACK3 (1 << 25) - -// Note: these are only for use with GetEntityFlags and SetEntityFlags -// and may not match the game's actual, internal m_fFlags values. -// PLAYER SPECIFIC FLAGS FIRST BECAUSE WE USE ONLY A FEW BITS OF NETWORK PRECISION -#define FL_ONGROUND (1 << 0) /**< At rest / on the ground */ -#define FL_DUCKING (1 << 1) /**< Player flag -- Player is fully crouched */ -#define FL_WATERJUMP (1 << 2) /**< player jumping out of water */ -#define FL_ONTRAIN (1 << 3) /**< Player is _controlling_ a train, so movement commands should be ignored on client during prediction. */ -#define FL_INRAIN (1 << 4) /**< Indicates the entity is standing in rain */ -#define FL_FROZEN (1 << 5) /**< Player is frozen for 3rd person camera */ -#define FL_ATCONTROLS (1 << 6) /**< Player can't move, but keeps key inputs for controlling another entity */ -#define FL_CLIENT (1 << 7) /**< Is a player */ -#define FL_FAKECLIENT (1 << 8) /**< Fake client, simulated server side; don't send network messages to them */ -// NOTE if you move things up, make sure to change this value -#define PLAYER_FLAG_BITS 9 -// NON-PLAYER SPECIFIC (i.e., not used by GameMovement or the client .dll ) -- Can still be applied to players, though -#define FL_INWATER (1 << 9) /**< In water */ -#define FL_FLY (1 << 10) /**< Changes the SV_Movestep() behavior to not need to be on ground */ -#define FL_SWIM (1 << 11) /**< Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) */ -#define FL_CONVEYOR (1 << 12) -#define FL_NPC (1 << 13) -#define FL_GODMODE (1 << 14) -#define FL_NOTARGET (1 << 15) -#define FL_AIMTARGET (1 << 16) /**< set if the crosshair needs to aim onto the entity */ -#define FL_PARTIALGROUND (1 << 17) /**< not all corners are valid */ -#define FL_STATICPROP (1 << 18) /**< Eetsa static prop! */ -#define FL_GRAPHED (1 << 19) /**< worldgraph has this ent listed as something that blocks a connection */ -#define FL_GRENADE (1 << 20) -#define FL_STEPMOVEMENT (1 << 21) /**< Changes the SV_Movestep() behavior to not do any processing */ -#define FL_DONTTOUCH (1 << 22) /**< Doesn't generate touch functions, generates Untouch() for anything it was touching when this flag was set */ -#define FL_BASEVELOCITY (1 << 23) /**< Base velocity has been applied this frame (used to convert base velocity into momentum) */ -#define FL_WORLDBRUSH (1 << 24) /**< Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) */ -#define FL_OBJECT (1 << 25) /**< Terrible name. This is an object that NPCs should see. Missiles, for example. */ -#define FL_KILLME (1 << 26) /**< This entity is marked for death -- will be freed by game DLL */ -#define FL_ONFIRE (1 << 27) /**< You know... */ -#define FL_DISSOLVING (1 << 28) /**< We're dissolving! */ -#define FL_TRANSRAGDOLL (1 << 29) /**< In the process of turning into a client side ragdoll. */ -#define FL_UNBLOCKABLE_BY_PLAYER (1 << 30) /**< pusher that can't be blocked by the player */ -#define FL_FREEZING (1 << 31) /**< We're becoming frozen! */ -#define FL_EP2V_UNKNOWN1 (1 << 31) /**< Unknown */ -// END entity flag #defines - -/** - * Get an entity's flags. - * - * @note The game's actual flags are internally translated by SM - * to match the entity flags defined above as the actual values - * can differ per engine. - * - * @param entity Entity index. - * @return Entity's flags, see entity flag defines above. - * @error Invalid entity index, or lack of mod compliance. - */ -native int GetEntityFlags(int entity); - -/** - * Sets an entity's flags. - * - * @note The entity flags as defined above are internally translated by SM - * to match the current game's expected value for the flags as - * the actual values can differ per engine. - * - * @param entity Entity index. - * @param flags Entity flags, see entity flag defines above. - * @error Invalid entity index, or lack of mod compliance. - */ -native void SetEntityFlags(int entity, int flags); - - -/** - * Gets an entity's movetype. - * - * @param entity Entity index. - * @return Movetype, see enum above. - * @error Invalid entity index, or lack of mod compliance. - */ -stock MoveType GetEntityMoveType(int entity) -{ - static bool gotconfig = false; - static char datamap[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_MoveType", datamap, sizeof(datamap)); - CloseHandle(gc); - - if (!exists) - { - strcopy(datamap, sizeof(datamap), "m_MoveType"); - } - - gotconfig = true; - } - - return view_as(GetEntProp(entity, Prop_Data, datamap)); -} - -/** - * Sets an entity's movetype. - * - * @param entity Entity index. - * @param mt Movetype, see enum above. - * @error Invalid entity index, or lack of mod compliance. - */ -stock void SetEntityMoveType(int entity, MoveType mt) -{ - static bool gotconfig = false; - static char datamap[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_MoveType", datamap, sizeof(datamap)); - CloseHandle(gc); - - if (!exists) - { - strcopy(datamap, sizeof(datamap), "m_MoveType"); - } - - gotconfig = true; - } - - SetEntProp(entity, Prop_Data, datamap, mt); -} - -/** - * Gets an entity's render mode. - * - * @param entity Entity index. - * @return RenderMode value. - * @error Invalid entity index, or lack of mod compliance. - */ -stock RenderMode GetEntityRenderMode(int entity) -{ - static bool gotconfig = false; - static char prop[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_nRenderMode", prop, sizeof(prop)); - CloseHandle(gc); - - if (!exists) - { - strcopy(prop, sizeof(prop), "m_nRenderMode"); - } - - gotconfig = true; - } - - return view_as(GetEntProp(entity, Prop_Send, prop, 1)); -} - -/** - * Sets an entity's render mode. - * - * @param entity Entity index. - * @param mode RenderMode value. - * @error Invalid entity index, or lack of mod compliance. - */ -stock void SetEntityRenderMode(int entity, RenderMode mode) -{ - static bool gotconfig = false; - static char prop[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_nRenderMode", prop, sizeof(prop)); - CloseHandle(gc); - - if (!exists) - { - strcopy(prop, sizeof(prop), "m_nRenderMode"); - } - - gotconfig = true; - } - - SetEntProp(entity, Prop_Send, prop, mode, 1); -} - -/** - * Gets an entity's render Fx. - * - * @param entity Entity index. - * @return RenderFx value. - * @error Invalid entity index, or lack of mod compliance. - */ -stock RenderFx GetEntityRenderFx(int entity) -{ - static bool gotconfig = false; - static char prop[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_nRenderFX", prop, sizeof(prop)); - CloseHandle(gc); - - if (!exists) - { - strcopy(prop, sizeof(prop), "m_nRenderFX"); - } - - gotconfig = true; - } - - return view_as(GetEntProp(entity, Prop_Send, prop, 1)); -} - -/** - * Sets an entity's render Fx. - * - * @param entity Entity index. - * @param fx RenderFx value. - * @error Invalid entity index, or lack of mod compliance. - */ -stock void SetEntityRenderFx(int entity, RenderFx fx) -{ - static bool gotconfig = false; - static char prop[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_nRenderFX", prop, sizeof(prop)); - CloseHandle(gc); - - if (!exists) - { - strcopy(prop, sizeof(prop), "m_nRenderFX"); - } - - gotconfig = true; - } - - SetEntProp(entity, Prop_Send, prop, fx, 1); -} - -/** - * Gets an entity's color. - * - * @param entity Entity index. - * @param r Amount of red (0-255) - * @param g Amount of green (0-255) - * @param b Amount of blue (0-255) - * @param a Amount of alpha (0-255) - * @error Invalid entity index, or lack of mod compliance. - */ -stock void GetEntityRenderColor(int entity, int &r, int &g, int &b, int &a) -{ - static bool gotconfig = false; - static char prop[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_clrRender", prop, sizeof(prop)); - CloseHandle(gc); - - if (!exists) - { - strcopy(prop, sizeof(prop), "m_clrRender"); - } - - gotconfig = true; - } - - int offset = GetEntSendPropOffs(entity, prop); - - if (offset <= 0) - { - ThrowError("GetEntityRenderColor not supported by this mod"); - } - - r = GetEntData(entity, offset, 1); - g = GetEntData(entity, offset + 1, 1); - b = GetEntData(entity, offset + 2, 1); - a = GetEntData(entity, offset + 3, 1); -} - -/** - * Sets an entity's color. - * - * @param entity Entity index - * @param r Amount of red (0-255) - * @param g Amount of green (0-255) - * @param b Amount of blue (0-255) - * @param a Amount of alpha (0-255) - * @error Invalid entity index, or lack of mod compliance. - */ -stock void SetEntityRenderColor(int entity, int r=255, int g=255, int b=255, int a=255) -{ - static bool gotconfig = false; - static char prop[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_clrRender", prop, sizeof(prop)); - CloseHandle(gc); - - if (!exists) - { - strcopy(prop, sizeof(prop), "m_clrRender"); - } - - gotconfig = true; - } - - int offset = GetEntSendPropOffs(entity, prop); - - if (offset <= 0) - { - ThrowError("SetEntityRenderColor not supported by this mod"); - } - - SetEntData(entity, offset, r, 1, true); - SetEntData(entity, offset + 1, g, 1, true); - SetEntData(entity, offset + 2, b, 1, true); - SetEntData(entity, offset + 3, a, 1, true); -} - -/** - * Gets an entity's gravity. - * - * @param entity Entity index. - * @return Entity's m_flGravity value. - * @error Invalid entity index, or lack of mod compliance. - */ -stock float GetEntityGravity(int entity) -{ - static bool gotconfig = false; - static char datamap[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_flGravity", datamap, sizeof(datamap)); - CloseHandle(gc); - - if (!exists) - { - strcopy(datamap, sizeof(datamap), "m_flGravity"); - } - - gotconfig = true; - } - - return GetEntPropFloat(entity, Prop_Data, datamap); -} - -/** - * Sets an entity's gravity. - * - * @param entity Entity index. - * @param amount Gravity to set (default = 1.0, half = 0.5, double = 2.0). - * @error Invalid entity index, or lack of mod compliance. - */ -stock void SetEntityGravity(int entity, float amount) -{ - static bool gotconfig = false; - static char datamap[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_flGravity", datamap, sizeof(datamap)); - CloseHandle(gc); - - if (!exists) - { - strcopy(datamap, sizeof(datamap), "m_flGravity"); - } - - gotconfig = true; - } - - SetEntPropFloat(entity, Prop_Data, datamap, amount); -} - -/** - * Sets an entity's health - * - * @param entity Entity index. - * @param amount Health amount. - * @error Invalid entity index, or lack of mod compliance. - */ -stock void SetEntityHealth(int entity, int amount) -{ - static bool gotconfig = false; - static char prop[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_iHealth", prop, sizeof(prop)); - CloseHandle(gc); - - if (!exists) - { - strcopy(prop, sizeof(prop), "m_iHealth"); - } - - gotconfig = true; - } - - char cls[64]; - PropFieldType type; - int offset; - - if (!GetEntityNetClass(entity, cls, sizeof(cls))) - { - ThrowError("SetEntityHealth not supported by this mod: Could not get serverclass name"); - return; - } - - offset = FindSendPropInfo(cls, prop, type); - - if (offset <= 0) - { - ThrowError("SetEntityHealth not supported by this mod"); - return; - } - - /* Dark Messiah uses a float for the health instead an integer */ - if (type == PropField_Float) - { - SetEntDataFloat(entity, offset, float(amount)); - } - else - { - SetEntProp(entity, Prop_Send, prop, amount); - } -} - -/** - * Get's a users current pressed buttons - * - * @param client Client index - * @return Bitsum of buttons - * @error Invalid client index, client not in game, - * or lack of mod compliance. - */ -stock int GetClientButtons(int client) -{ - static bool gotconfig = false; - static char datamap[32]; - - if (!gotconfig) - { - Handle gc = LoadGameConfigFile("core.games"); - bool exists = GameConfGetKeyValue(gc, "m_nButtons", datamap, sizeof(datamap)); - CloseHandle(gc); - - if (!exists) - { - strcopy(datamap, sizeof(datamap), "m_nButtons"); - } - - gotconfig = true; - } - - return GetEntProp(client, Prop_Data, datamap); -} diff --git a/scripting/include/events.inc b/scripting/include/events.inc deleted file mode 100644 index d7d799a..0000000 --- a/scripting/include/events.inc +++ /dev/null @@ -1,340 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _events_included - #endinput -#endif -#define _events_included - -/** - * Event hook modes determining how hooking should be handled - */ -enum EventHookMode -{ - EventHookMode_Pre, //< Hook callback fired before event is fired */ - EventHookMode_Post, //< Hook callback fired after event is fired */ - EventHookMode_PostNoCopy //< Hook callback fired after event is fired, but event data won't be copied */ -}; - -/** - * Hook function types for events. - */ -typeset EventHook -{ - // Called when a game event is fired. - // - // @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking - // this event has set the hook mode EventHookMode_PostNoCopy. - // @param name String containing the name of the event. - // @param dontBroadcast True if event was not broadcast to clients, false otherwise. - // @return Ignored for post hooks. Plugin_Handled will block event if hooked as pre. - /// - function Action (Event event, const char[] name, bool dontBroadcast); - // - // Called when a game event is fired. - // - // @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking - // this event has set the hook mode EventHookMode_PostNoCopy. - // @param name String containing the name of the event. - // @param dontBroadcast True if event was not broadcast to clients, false otherwise. - /// - function void (Event event, const char[] name, bool dontBroadcast); -}; - -methodmap Event < Handle -{ - // Fires a game event. - // - // This function closes the event Handle after completing. - // - // @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. - public native void Fire(bool dontBroadcast=false); - - // Fires a game event to only the specified client. - // - // Unlike Fire, this function DOES NOT close the event Handle. - // - // @param client Index of client to receive the event.. - public native void FireToClient(int client); - - // Cancels a previously created game event that has not been fired. This - // is necessary to avoid leaking memory when an event isn't fired. - public native void Cancel(); - - // Returns the boolean value of a game event's key. - // - // @param key Name of event key. - // @param defValue Optional default value to use if the key is not found. - // @return The boolean value of the specified event key. - public native bool GetBool(const char[] key, bool defValue=false); - - // Sets the boolean value of a game event's key. - // - // @param key Name of event key. - // @param value New boolean value. - public native void SetBool(const char[] key, bool value); - - // Returns the integer value of a game event's key. - // - // @param key Name of event key. - // @param defValue Optional default value to use if the key is not found. - // @return The integer value of the specified event key. - public native int GetInt(const char[] key, int defValue=0); - - // Sets the integer value of a game event's key. - // - // Integer value refers to anything that can be reduced to an integer. - // The various size specifiers, such as "byte" and "short" are still - // integers, and only refer to how much data will actually be sent - // over the network (if applicable). - // - // @param key Name of event key. - // @param value New integer value. - public native void SetInt(const char[] key, int value); - - // Returns the floating point value of a game event's key. - // - // @param key Name of event key. - // @param defValue Optional default value to use if the key is not found. - // @return The floating point value of the specified event key. - public native float GetFloat(const char[] key, float defValue=0.0); - - // Sets the floating point value of a game event's key. - // - // @param key Name of event key. - // @param value New floating point value. - public native void SetFloat(const char[] key, float value); - - // Retrieves the string value of a game event's key. - // - // @param key Name of event key. - // @param value Buffer to store the value of the specified event key. - // @param maxlength Maximum length of string buffer. - // @param defValue Optional default value to use if the key is not found. - public native void GetString(const char[] key, char[] value, int maxlength, const char[] defvalue=""); - - // Sets the string value of a game event's key. - // - // @param key Name of event key. - // @param value New string value. - public native void SetString(const char[] key, const char[] value); - - // Retrieves the name of a game event. - // - // @param name Buffer to store the name of the event. - // @param maxlength Maximum length of string buffer. - public native void GetName(char[] name, int maxlength); - - // Sets whether an event's broadcasting will be disabled or not. - // - // This has no effect on events Handles that are not from HookEvent - // or HookEventEx callbacks. - property bool BroadcastDisabled { - public native set(bool dontBroadcast); - } -} - -/** - * Creates a hook for when a game event is fired. - * - * @param name Name of event. - * @param callback An EventHook function pointer. - * @param mode Optional EventHookMode determining the type of hook. - * @error Invalid event name or invalid callback function. - */ -native void HookEvent(const char[] name, EventHook callback, EventHookMode mode=EventHookMode_Post); - -/** - * Creates a hook for when a game event is fired. - * - * @param name Name of event. - * @param callback An EventHook function pointer. - * @param mode Optional EventHookMode determining the type of hook. - * @return True if event exists and was hooked successfully, false otherwise. - * @error Invalid callback function. - */ -native bool HookEventEx(const char[] name, EventHook callback, EventHookMode mode=EventHookMode_Post); - -/** - * Removes a hook for when a game event is fired. - * - * @param name Name of event. - * @param callback An EventHook function pointer. - * @param mode Optional EventHookMode determining the type of hook. - * @error Invalid callback function or no active hook for specified event. - */ -native void UnhookEvent(const char[] name, EventHook callback, EventHookMode mode=EventHookMode_Post); - -/** - * Creates a game event to be fired later. - * - * The Handle should not be closed via CloseHandle(). It must be closed via - * event.Fire() or event.Cancel(). - * - * @param name Name of event. - * @param force If set to true, this forces the event to be created even if it's not being hooked. - * Note that this will not force it if the event doesn't exist at all. - * @return Handle to event. INVALID_HANDLE is returned if the event doesn't exist or isn't - being hooked (unless force is true). - */ -native Event CreateEvent(const char[] name, bool force=false); - -/** - * Fires a game event. - * - * This function closes the event Handle after completing. - * - * @param event Handle to the event. - * @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. - * @error Invalid or corrupt Handle. - */ -native void FireEvent(Handle event, bool dontBroadcast=false); - -/** - * Cancels a previously created game event that has not been fired. - * - * @param event Handled to the event. - * @error Invalid or corrupt Handle. - */ -native void CancelCreatedEvent(Handle event); - -/** - * Returns the boolean value of a game event's key. - * - * @param event Handle to the event. - * @param key Name of event key. - * @param defValue Optional default value to use if the key is not found. - * @return The boolean value of the specified event key. - * @error Invalid or corrupt Handle. - */ -native bool GetEventBool(Handle event, const char[] key, bool defValue=false); - -/** - * Sets the boolean value of a game event's key. - * - * @param event Handle to the event. - * @param key Name of event key. - * @param value New boolean value. - * @error Invalid or corrupt Handle. - */ -native void SetEventBool(Handle event, const char[] key, bool value); - -/** - * Returns the integer value of a game event's key. - * - * @param event Handle to the event. - * @param key Name of event key. - * @param defValue Optional default value to use if the key is not found. - * @return The integer value of the specified event key. - * @error Invalid or corrupt Handle. - */ -native int GetEventInt(Handle event, const char[] key, int defValue=0); - -/** - * Sets the integer value of a game event's key. - * - * Integer value refers to anything that can be reduced to an integer. - * The various size specifiers, such as "byte" and "short" are still - * integers, and only refer to how much data will actually be sent - * over the network (if applicable). - * - * @param event Handle to the event. - * @param key Name of event key. - * @param value New integer value. - * @error Invalid or corrupt Handle. - */ -native void SetEventInt(Handle event, const char[] key, int value); - -/** - * Returns the floating point value of a game event's key. - * - * @param event Handle to the event. - * @param key Name of event key. - * @param defValue Optional default value to use if the key is not found. - * @return The floating point value of the specified event key. - * @error Invalid or corrupt Handle. - */ -native float GetEventFloat(Handle event, const char[] key, float defValue=0.0); - -/** - * Sets the floating point value of a game event's key. - * - * @param event Handle to the event. - * @param key Name of event key. - * @param value New floating point value. - * @error Invalid or corrupt Handle. - */ -native void SetEventFloat(Handle event, const char[] key, float value); - -/** - * Retrieves the string value of a game event's key. - * - * @param event Handle to the event. - * @param key Name of event key. - * @param value Buffer to store the value of the specified event key. - * @param maxlength Maximum length of string buffer. - * @param defValue Optional default value to use if the key is not found. - * @error Invalid or corrupt Handle. - */ -native void GetEventString(Handle event, const char[] key, char[] value, int maxlength, const char[] defvalue=""); - -/** - * Sets the string value of a game event's key. - * - * @param event Handle to the event. - * @param key Name of event key. - * @param value New string value. - * @error Invalid or corrupt Handle. - */ -native void SetEventString(Handle event, const char[] key, const char[] value); - -/** - * Retrieves the name of a game event. - * - * @param event Handle to the event. - * @param name Buffer to store the name of the event. - * @param maxlength Maximum length of string buffer. - * @error Invalid or corrupt Handle. - */ -native void GetEventName(Handle event, char[] name, int maxlength); - -/** - * Sets whether an event's broadcasting will be disabled or not. - * - * This has no effect on events Handles that are not from HookEvent - * or HookEventEx callbacks. - * - * @param event Handle to an event from an event hook. - * @param dontBroadcast True to disable broadcasting, false otherwise. - * @error Invalid Handle. - */ -native void SetEventBroadcast(Handle event, bool dontBroadcast); diff --git a/scripting/include/files.inc b/scripting/include/files.inc deleted file mode 100644 index cae2088..0000000 --- a/scripting/include/files.inc +++ /dev/null @@ -1,618 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _files_included - #endinput -#endif -#define _files_included - -/** - * @global All paths in SourceMod natives are relative to the mod folder - * unless otherwise noted. - * - * Most functions in SourceMod (at least, ones that deal with direct - * file manipulation) will support an alternate path specification. - * - * If the path starts with the string "file://" and the PathType is - * not relative, then the "file://" portion is stripped off, and the - * rest of the path is used without any modification (except for - * correcting slashes). This can be used to override the path - * builder to supply alternate absolute paths. Examples: - * - * file://C:/Temp/file.txt - * file:///tmp/file.txt - */ - -/** - * File inode types. - */ -enum FileType -{ - FileType_Unknown = 0, /* Unknown file type (device/socket) */ - FileType_Directory = 1, /* File is a directory */ - FileType_File = 2, /* File is a file */ -}; - -/** - * File time modes. - */ -enum FileTimeMode -{ - FileTime_LastAccess = 0, /* Last access (does not work on FAT) */ - FileTime_Created = 1, /* Creation (does not work on FAT) */ - FileTime_LastChange = 2, /* Last modification */ -}; - -#define PLATFORM_MAX_PATH 256 /**< Maximum path length. */ - -#define SEEK_SET 0 /**< Seek from start. */ -#define SEEK_CUR 1 /**< Seek from current position. */ -#define SEEK_END 2 /**< Seek from end position. */ - -/** - * Path types. - */ -enum PathType -{ - Path_SM, /**< SourceMod root folder */ -}; - -// A DirectoryListing iterates over the contents of a directory. To obtain a -// DirectoryListing handle, call OpenDirectory(). -methodmap DirectoryListing < Handle -{ - // Reads the current directory entry as a local filename, then moves to the - // next file. - // - // Note: Both the '.' and '..' automatic directory entries will be retrieved. - // - // @param buffer String buffer to hold directory name. - // @param maxlength Maximum size of string buffer. - // @param type Optional variable to store the file type. - // @return True on success, false if there are no more files to read. - public native bool GetNext(char[] buffer, int maxlength, FileType &type=FileType_Unknown); -}; - -// A File object can be obtained by calling OpenFile(). File objects should be -// closed with delete or Close(). Note that, "delete file" does not -// actually a file, it just closes it. -methodmap File < Handle -{ - // Close the file handle. This is the same as using CloseHandle() or delete. - public void Close() { - CloseHandle(this); - } - - // Reads a line of text from a file. - // - // @param buffer String buffer to hold the line. - // @param maxlength Maximum size of string buffer. - // @return True on success, false otherwise. - public native bool ReadLine(char[] buffer, int maxlength); - - // Reads binary data from a file. - // - // @param items Array to store each item read. - // @param num_items Number of items to read into the array. - // @param size Size of each element, in bytes, to be read. - // Valid sizes are 1, 2, or 4. - // @return Number of elements read, or -1 on error. - public native int Read(int[] items, int num_items, int size); - - // Reads a UTF8 or ANSI string from a file. - // - // @param buffer Buffer to store the string. - // @param max_size Maximum size of the string buffer. - // @param read_count If -1, reads until a null terminator is encountered in - // the file. Otherwise, read_count bytes are read - // into the buffer provided. In this case the buffer - // is not explicitly null terminated, and the buffer - // will contain any null terminators read from the file. - // @return Number of characters written to the buffer, or -1 - // if an error was encountered. - // @error read_count > max_size. - public native int ReadString(char[] buffer, int max_size, int read_count=-1); - - // Writes binary data to a file. - // - // @param items Array of items to write. The data is read directly. - // That is, in 1 or 2-byte mode, the lower byte(s) in - // each cell are used directly, rather than performing - // any casts from a 4-byte number to a smaller number. - // @param num_items Number of items in the array. - // @param size Size of each item in the array in bytes. - // Valid sizes are 1, 2, or 4. - // @return True on success, false on error. - public native bool Write(const int[] items, int num_items, int size); - - // Writes a binary string to a file. - // - // @param buffer String to write. - // @param term True to append NUL terminator, false otherwise. - // @return True on success, false on error. - public native bool WriteString(const char[] buffer, bool term); - - // Writes a line of text to a text file. A newline is automatically appended. - // - // @param hndl Handle to the file. - // @param format Formatting rules. - // @param ... Variable number of format parameters. - // @return True on success, false otherwise. - public native bool WriteLine(const char[] format, any ...); - - // Reads a single int8 (byte) from a file. The returned value is sign- - // extended to an int32. - // - // @param data Variable to store the data read. - // @return True on success, false on failure. - public native bool ReadInt8(int &data); - - // Reads a single uint8 (unsigned byte) from a file. The returned value is - // zero-extended to an int32. - // - // @param data Variable to store the data read. - // @return True on success, false on failure. - public native bool ReadUint8(int &data); - - // Reads a single int16 (short) from a file. The value is sign-extended to - // an int32. - // - // @param data Variable to store the data read. - // @return True on success, false on failure. - public native bool ReadInt16(int &data); - - // Reads a single unt16 (unsigned short) from a file. The value is zero- - // extended to an int32. - // - // @param data Variable to store the data read. - // @return True on success, false on failure. - public native bool ReadUint16(int &data); - - // Reads a single int32 (int/cell) from a file. - // - // @param data Variable to store the data read. - // @return True on success, false on failure. - public native bool ReadInt32(int &data); - - // Writes a single int8 (byte) to a file. - // - // @param data Data to write (truncated to an int8). - // @return True on success, false on failure. - public native bool WriteInt8(int data); - - // Writes a single int16 (short) to a file. - // - // @param data Data to write (truncated to an int16). - // @return True on success, false on failure. - public native bool WriteInt16(int data); - - // Writes a single int32 (int/cell) to a file. - // - // @param data Data to write. - // @return True on success, false on failure. - public native bool WriteInt32(int data); - - // Tests if the end of file has been reached. - // - // @return True if end of file has been reached, false otherwise. - public native bool EndOfFile(); - - // Sets the file position indicator. - // - // @param position Position relative to what is specified in whence. - // @param where SEEK_ constant value of where to see from. - // @return True on success, false otherwise. - public native bool Seek(int position, int where); - - // Get the current position in the file; returns -1 on failure. - property int Position { - public native get(); - } -} - -/** - * Builds a path relative to the SourceMod folder. This should be used instead of - * directly referencing addons/sourcemod, in case users change the name of their - * folder layout. - * - * @param type Type of path to build as the base. - * @param buffer Buffer to store the path. - * @param maxlength Maximum length of buffer. - * @param fmt Format string. - * @param ... Format arguments. - * @return Number of bytes written to buffer (not including null terminator). - */ -native int BuildPath(PathType type, char[] buffer, int maxlength, const char[] fmt, any ...); - -/** - * Opens a directory/folder for contents enumeration. - * - * @note Directories are closed with CloseHandle() or delete. - * @note Directories Handles can be cloned. - * @note OpenDirectory() supports the "file://" notation. - * - * @param path Path to open. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to find files existing in any of - * the Valve search paths, rather than solely files - * existing directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. - * @return A Handle to the directory, null on error. - */ -native DirectoryListing OpenDirectory(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); - -/** - * Reads the current directory entry as a local filename, then moves to the next file. - * - * @note Contents of buffers are undefined when returning false. - * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux. - * - * @param dir Handle to a directory. - * @param buffer String buffer to hold directory name. - * @param maxlength Maximum size of string buffer. - * @param type Optional variable to store the file type. - * @return True on success, false if there are no more files to read. - * @error Invalid or corrupt Handle. - */ -native bool ReadDirEntry(Handle dir, char[] buffer, int maxlength, FileType &type=FileType_Unknown); - -/** - * Opens or creates a file, returning a File handle on success. File handles - * should be closed with delete or CloseHandle(). - * - * The open mode may be one of the following strings: - * "r": Open an existing file for reading. - * "w": Create a file for writing, or truncate (delete the contents of) an - * existing file and then open it for writing. - * "a": Create a file for writing, or open an existing file such that writes - * will be appended to the end. - * "r+": Open an existing file for both reading and writing. - * "w+": Create a file for reading and writing, or truncate an existing file - * and then open it for reading and writing. - * "a+": Create a file for both reading and writing, or open an existing file - * such that writes will be appended to the end. - * - * The open mode may also contain an additional character after "r", "w", or "a", - * but before any "+" sign. This character may be "b" (indicating binary mode) or - * "t" (indicating text mode). By default, "text" mode is implied. On Linux and - * Mac, this has no distinction from binary mode. On Windows, it causes the '\n' - * character (0xA) to be written as "\r\n" (0xD, 0xA). - * - * Example: "rb" opens a binary file for writing; "at" opens a text file for - * appending. - * - * @param file File to open. - * @param mode Open mode. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to find files existing in valve - * search paths, rather than solely files existing directly - * in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. - * @return A File handle, or null if the file could not be opened. - */ -native File OpenFile(const char[] file, const char[] mode, bool use_valve_fs=false, const char[] valve_path_id="GAME"); - -/** - * Deletes a file. - * - * @param path Path of the file to delete. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to delete files existing in the Valve - * search path, rather than solely files existing directly - * in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. - * @return True on success, false on failure or if file not immediately removed. - */ -native bool DeleteFile(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="DEFAULT_WRITE_PATH"); - -/** - * Reads a line from a text file. - * - * @param hndl Handle to the file. - * @param buffer String buffer to hold the line. - * @param maxlength Maximum size of string buffer. - * @return True on success, false otherwise. - */ -native bool ReadFileLine(Handle hndl, char[] buffer, int maxlength); - -/** - * Reads binary data from a file. - * - * @param hndl Handle to the file. - * @param items Array to store each item read. - * @param num_items Number of items to read into the array. - * @param size Size of each element, in bytes, to be read. - * Valid sizes are 1, 2, or 4. - * @return Number of elements read, or -1 on error. - */ -native int ReadFile(Handle hndl, int[] items, int num_items, int size); - -/** - * Reads a UTF8 or ANSI string from a file. - * - * @param hndl Handle to the file. - * @param buffer Buffer to store the string. - * @param max_size Maximum size of the string buffer. - * @param read_count If -1, reads until a null terminator is encountered in - * the file. Otherwise, read_count bytes are read - * into the buffer provided. In this case the buffer - * is not explicitly null terminated, and the buffer - * will contain any null terminators read from the file. - * @return Number of characters written to the buffer, or -1 - * if an error was encountered. - * @error Invalid Handle, or read_count > max_size. - */ -native int ReadFileString(Handle hndl, char[] buffer, int max_size, int read_count=-1); - -/** - * Writes binary data to a file. - * - * @param hndl Handle to the file. - * @param items Array of items to write. The data is read directly. - * That is, in 1 or 2-byte mode, the lower byte(s) in - * each cell are used directly, rather than performing - * any casts from a 4-byte number to a smaller number. - * @param num_items Number of items in the array. - * @param size Size of each item in the array in bytes. - * Valid sizes are 1, 2, or 4. - * @return True on success, false on error. - * @error Invalid Handle. - */ -native bool WriteFile(Handle hndl, const int[] items, int num_items, int size); - -/** - * Writes a binary string to a file. - * - * @param hndl Handle to the file. - * @param buffer String to write. - * @param term True to append NUL terminator, false otherwise. - * @return True on success, false on error. - * @error Invalid Handle. - */ -native bool WriteFileString(Handle hndl, const char[] buffer, bool term); - -/** - * Writes a line of text to a text file. A newline is automatically appended. - * - * @param hndl Handle to the file. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @return True on success, false otherwise. - * @error Invalid Handle. - */ -native bool WriteFileLine(Handle hndl, const char[] format, any ...); - -/** - * Reads a single binary cell from a file. - * - * @param hndl Handle to the file. - * @param data Variable to store the data read. - * @param size Size of the data to read in bytes. Valid - * sizes are 1, 2, or 4 bytes. - * @return Number of elements read (max 1), or -1 on error. - * @error Invalid Handle. - */ -stock int ReadFileCell(Handle hndl, int &data, int size) -{ - int ret; - int array[1]; - - if ((ret = ReadFile(hndl, array, 1, size)) == 1) - data = array[0]; - - return ret; -} - -/** - * Writes a single binary cell to a file. - * - * @param hndl Handle to the file. - * @param data Cell to write to the file. - * @param size Size of the data to read in bytes. Valid - * sizes are 1, 2, or 4 bytes. If the size - * is less than 4 bytes, the data is truncated - * rather than casted. That is, only the lower - * bits will be read. - * @return True on success, false on error. - * @error Invalid Handle. - */ -stock bool WriteFileCell(Handle hndl, int data, int size) -{ - int array[1]; - - array[0] = data; - return WriteFile(hndl, array, 1, size); -} - -/** - * Tests if the end of file has been reached. - * - * @param file Handle to the file. - * @return True if end of file has been reached, false otherwise. - * @error Invalid Handle. - */ -native bool IsEndOfFile(Handle file); - -/** - * Sets the file position indicator. - * - * @param file Handle to the file. - * @param position Position relative to what is specified in whence. - * @param where SEEK_ constant value of where to see from. - * @return True on success, false otherwise. - * @error Invalid Handle. - */ -native bool FileSeek(Handle file, int position, int where); - -/** - * Get current position in the file. - * - * @param file Handle to the file. - * @return Value for the file position indicator. - * @error Invalid Handle. - */ -native int FilePosition(Handle file); - -/** - * Checks if a file exists. - * - * @param path Path to the file. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to find files existing in any of - * the Valve search paths, rather than solely files - * existing directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. - * @return True if the file exists, false otherwise. - */ -native bool FileExists(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); - -/** - * Renames a file. - * - * @param newpath New path to the file. - * @param oldpath Path to the existing file. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to rename files in the game's - * Valve search paths, rather than directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. - * @return True on success or use_valve_fs specified, false otherwise. - */ -native bool RenameFile(const char[] newpath, const char[] oldpath, bool use_valve_fs=false, const char[] valve_path_id="DEFAULT_WRITE_PATH"); - -/** - * Checks if a directory exists. - * - * @param path Path to the directory. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to find files existing in any of - * the Valve search paths, rather than solely files - * existing directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. - * @return True if the directory exists, false otherwise. - */ -native bool DirExists(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); - -/** - * Get the file size in bytes. - * - * @param path Path to the file. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to find files existing in any of - * the Valve search paths, rather than solely files - * existing directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths. - * @return File size in bytes, -1 if file not found. - */ -native int FileSize(const char[] path, bool use_valve_fs=false, const char[] valve_path_id="GAME"); - -/** - * Flushes a file's buffered output; any buffered output - * is immediately written to the file. - * - * @param file Handle to the file. - * @return True on success or use_valve_fs specified with OpenFile, - * otherwise false on failure. - */ -native bool FlushFile(Handle file); - -/** - * Removes a directory. - * @note On most Operating Systems you cannot remove a directory which has files inside it. - * - * @param path Path to the directory. - * @return True on success, false otherwise. - */ -native bool RemoveDir(const char[] path); - -#define FPERM_U_READ 0x0100 /* User can read. */ -#define FPERM_U_WRITE 0x0080 /* User can write. */ -#define FPERM_U_EXEC 0x0040 /* User can exec. */ -#define FPERM_G_READ 0x0020 /* Group can read. */ -#define FPERM_G_WRITE 0x0010 /* Group can write. */ -#define FPERM_G_EXEC 0x0008 /* Group can exec. */ -#define FPERM_O_READ 0x0004 /* Anyone can read. */ -#define FPERM_O_WRITE 0x0002 /* Anyone can write. */ -#define FPERM_O_EXEC 0x0001 /* Anyone can exec. */ - -/** - * Creates a directory. - * - * @param path Path to create. - * @param mode Permissions (default is o=rx,g=rx,u=rwx). Note that folders must have - * the execute bit set on Linux. On Windows, the mode is ignored. - * @param use_valve_fs If true, the Valve file system will be used instead. - * This can be used to create folders in the game's - * Valve search paths, rather than directly in the gamedir. - * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for default. - * In this case, mode is ignored. - */ -native bool CreateDirectory(const char[] path, int mode, bool use_valve_fs=false, const char[] valve_path_id="DEFAULT_WRITE_PATH"); - -/** - * Changes a file or directories permissions. - * - * @param path Path to the file. - * @param mode Permissions to set. - * @return True on success, false otherwise. - */ -native bool SetFilePermissions(const char[] path, int mode); - -/** - * Returns a file timestamp as a unix timestamp. - * - * @param file File name. - * @param tmode Time mode. - * @return Time value, or -1 on failure. - */ -native int GetFileTime(const char[] file, FileTimeMode tmode); - -/** - * Same as LogToFile(), except uses an open file Handle. The file must - * be opened in text appending mode. - * - * @param hndl Handle to the file. - * @param message Message format. - * @param ... Message format parameters. - * @error Invalid Handle. - */ -native void LogToOpenFile(Handle hndl, const char[] message, any ...); - -/** - * Same as LogToFileEx(), except uses an open file Handle. The file must - * be opened in text appending mode. - * - * @param hndl Handle to the file. - * @param message Message format. - * @param ... Message format parameters. - * @error Invalid Handle. - */ -native void LogToOpenFileEx(Handle hndl, const char[] message, any ...); diff --git a/scripting/include/float.inc b/scripting/include/float.inc deleted file mode 100644 index 99d90f6..0000000 --- a/scripting/include/float.inc +++ /dev/null @@ -1,436 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _float_included - #endinput -#endif -#define _float_included - -#if !defined __sourcepawn2__ -/** - * Converts an integer into a floating point value. - * - * @param value Integer to convert. - * @return Floating point value. - */ -native float float(int value); -#endif - -/** - * Multiplies two floats together. - * - * @param oper1 First value. - * @param oper2 Second value. - * @return oper1*oper2. - */ -native float FloatMul(float oper1, float oper2); - -/** - * Divides the dividend by the divisor. - * - * @param dividend First value. - * @param divisor Second value. - * @return dividend/divisor. - */ -native float FloatDiv(float dividend, float divisor); - -/** - * Adds two floats together. - * - * @param oper1 First value. - * @param oper2 Second value. - * @return oper1+oper2. - */ -native float FloatAdd(float oper1, float oper2); - -/** - * Subtracts oper2 from oper1. - * - * @param oper1 First value. - * @param oper2 Second value. - * @return oper1-oper2. - */ -native float FloatSub(float oper1, float oper2); - -/** - * Returns the decimal part of a float. - * - * @param value Input value. - * @return Decimal part. - */ -native float FloatFraction(float value); - -/** - * Rounds a float to the closest integer to zero. - * - * @param value Input value to be rounded. - * @return Rounded value. - */ -native int RoundToZero(float value); - -/** - * Rounds a float to the next highest integer value. - * - * @param value Input value to be rounded. - * @return Rounded value. - */ -native int RoundToCeil(float value); - -/** - * Rounds a float to the next lowest integer value. - * - * @param value Input value to be rounded. - * @return Rounded value. - */ -native int RoundToFloor(float value); - -/** - * Standard IEEE rounding. - * - * @param value Input value to be rounded. - * @return Rounded value. - */ -native int RoundToNearest(float value); - -/** - * Compares two floats. - * - * @param fOne First value. - * @param fTwo Second value. - * @return Returns 1 if the first argument is greater than the second argument. - * Returns -1 if the first argument is smaller than the second argument. - * Returns 0 if both arguments are equal. - */ -native int FloatCompare(float fOne, float fTwo); - -/** - * Returns the square root of the input value, equivalent to floatpower(value, 0.5). - * - * @param value Input value. - * @return Square root of the value. - */ -native float SquareRoot(float value); - -/** - * Returns the value raised to the power of the exponent. - * - * @param value Value to be raised. - * @param exponent Value to raise the base. - * @return value^exponent. - */ -native float Pow(float value, float exponent); - -/** - * Returns the value of raising the input by e. - * - * @param value Input value. - * @return exp(value). - */ -native float Exponential(float value); - -/** - * Returns the logarithm of any base specified. - * - * @param value Input value. - * @param base Logarithm base to use, default is 10. - * @return log(value)/log(base). - */ -native float Logarithm(float value, float base=10.0); - -/** - * Returns the sine of the argument. - * - * @param value Input value in radians. - * @return sin(value). - */ -native float Sine(float value); - -/** - * Returns the cosine of the argument. - * - * @param value Input value in radians. - * @return cos(value). - */ -native float Cosine(float value); - -/** - * Returns the tangent of the argument. - * - * @param value Input value in radians. - * @return tan(value). - */ -native float Tangent(float value); - -/** - * Returns an absolute value. - * - * @param value Input value. - * @return Absolute value of the input. - */ -native float FloatAbs(float value); - -/** - * Returns the arctangent of the input value. - * - * @param angle Input value. - * @return atan(value) in radians. - */ -native float ArcTangent(float angle); - -/** - * Returns the arccosine of the input value. - * - * @param angle Input value. - * @return acos(value) in radians. - */ -native float ArcCosine(float angle); - -/** - * Returns the arcsine of the input value. - * - * @param angle Input value. - * @return asin(value) in radians. - */ -native float ArcSine(float angle); - -/** - * Returns the arctangent2 of the input values. - * - * @param x Horizontal value. - * @param y Vertical value. - * @return atan2(value) in radians. - */ -native float ArcTangent2(float x, float y); - -/** - * Rounds a floating point number using the "round to nearest" algorithm. - * - * @param value Floating point value to round. - * @return The value rounded to the nearest integer. - */ -stock int RoundFloat(float value) -{ - return RoundToNearest(value); -} - -/** - * User defined operators. - */ -#if !defined __sourcepawn2__ -#pragma rational Float - -native bool __FLOAT_GT__(float a, float b); -native bool __FLOAT_GE__(float a, float b); -native bool __FLOAT_LT__(float a, float b); -native bool __FLOAT_LE__(float a, float b); -native bool __FLOAT_EQ__(float a, float b); -native bool __FLOAT_NE__(float a, float b); -native bool __FLOAT_NOT__(float a); - -native float operator*(float oper1, float oper2) = FloatMul; -native float operator/(float oper1, float oper2) = FloatDiv; -native float operator+(float oper1, float oper2) = FloatAdd; -native float operator-(float oper1, float oper2) = FloatSub; -native bool operator!(float oper1) = __FLOAT_NOT__; -native bool operator>(float oper1, float oper2) = __FLOAT_GT__; -native bool operator>=(float oper1, float oper2) = __FLOAT_GE__; -native bool operator<(float oper1, float oper2) = __FLOAT_LT__; -native bool operator<=(float oper1, float oper2) = __FLOAT_LE__; -native bool operator!=(float oper1, float oper2) = __FLOAT_NE__; -native bool operator==(float oper1, float oper2) = __FLOAT_EQ__; - -stock float operator++(float oper) -{ - return oper+1.0; -} - -stock float operator--(float oper) -{ - return oper-1.0; -} - -stock float operator-(float oper) -{ - return oper^view_as(cellmin); /* IEEE values are sign/magnitude */ -} - -stock float operator*(float oper1, int oper2) -{ - return FloatMul(oper1, float(oper2)); /* "*" is commutative */ -} - -stock float operator/(float oper1, int oper2) -{ - return FloatDiv(oper1, float(oper2)); -} - -stock float operator/(int oper1, float oper2) -{ - return FloatDiv(float(oper1), oper2); -} - -stock float operator+(float oper1, int oper2) -{ - return FloatAdd(oper1, float(oper2)); /* "+" is commutative */ -} - -stock float operator-(float oper1, int oper2) -{ - return FloatSub(oper1, float(oper2)); -} - -stock float operator-(int oper1, float oper2) -{ - return FloatSub(float(oper1), oper2); -} - -stock bool operator==(float oper1, int oper2) -{ - return __FLOAT_EQ__(oper1, float(oper2)); -} - -stock bool operator!=(float oper1, int oper2) -{ - return __FLOAT_NE__(oper1, float(oper2)); -} - -stock bool operator>(float oper1, int oper2) -{ - return __FLOAT_GT__(oper1, float(oper2)); -} - -stock bool operator>(int oper1, float oper2) -{ - return __FLOAT_GT__(float(oper1), oper2); -} - -stock bool operator>=(float oper1, int oper2) -{ - return __FLOAT_GE__(oper1, float(oper2)); -} - -stock bool operator>=(int oper1, float oper2) -{ - return __FLOAT_GE__(float(oper1), oper2); -} - -stock bool operator<(float oper1, int oper2) -{ - return __FLOAT_LT__(oper1, float(oper2)); -} - -stock bool operator<(int oper1, float oper2) -{ - return __FLOAT_LT__(float(oper1), oper2); -} - -stock bool operator<=(float oper1, int oper2) -{ - return __FLOAT_LE__(oper1, float(oper2)); -} - -stock bool operator<=(int oper1, float oper2) -{ - return __FLOAT_LE__(float(oper1), oper2); -} - -/** - * Forbidden operators. - */ -forward operator%(float oper1, float oper2); -forward operator%(float oper1, int oper2); -forward operator%(int oper1, float oper2); -#endif // __sourcepawn2__ - -#define FLOAT_PI 3.1415926535897932384626433832795 - -/** - * Converts degrees to radians. - * - * @param angle Degrees. - * @return Radians. - */ -stock float DegToRad(float angle) -{ - return (angle*FLOAT_PI)/180; -} - -/** - * Converts radians to degrees. - * - * @param angle Radians. - * @return Degrees. - */ -stock float RadToDeg(float angle) -{ - return (angle*180)/FLOAT_PI; -} - -/** - * Returns a random integer in the range [0, 2^31-1]. - * - * Note: Uniform random number streams are seeded automatically per-plugin. - * - * @return Random integer. - */ -native int GetURandomInt(); - -/** - * Returns a uniform random float in the range [0, 1). - * - * Note: Uniform random number streams are seeded automatically per-plugin. - * - * @return Uniform random floating-point number. - */ -native float GetURandomFloat(); - -/** - * Seeds a plugin's uniform random number stream. This is done automatically, - * so normally it is totally unnecessary to call this. - * - * @param seeds Array of numbers to use as seeding data. - * @param numSeeds Number of seeds in the seeds array. - */ -native void SetURandomSeed(const int[] seeds, int numSeeds); - -/** - * Seeds a plugin's uniform random number stream. This is done automatically, - * so normally it is totally unnecessary to call this. - * - * @param seed Single seed value. - */ -stock void SetURandomSeedSimple(int seed) -{ - int seeds[1]; - seeds[0] = seed; - SetURandomSeed(seeds, 1); -} diff --git a/scripting/include/functions.inc b/scripting/include/functions.inc deleted file mode 100644 index b9bd2f9..0000000 --- a/scripting/include/functions.inc +++ /dev/null @@ -1,541 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _functions_included - #endinput -#endif -#define _functions_included - -#define SP_PARAMFLAG_BYREF (1<<0) /**< Internal use only. */ - -/** - * Describes the various ways to pass parameters to functions or forwards. - */ -enum ParamType -{ - Param_Any = 0, /**< Any data type can be pushed */ - Param_Cell = (1<<1), /**< Only basic cells can be pushed */ - Param_Float = (2<<1), /**< Only floats can be pushed */ - Param_String = (3<<1)|SP_PARAMFLAG_BYREF, /**< Only strings can be pushed */ - Param_Array = (4<<1)|SP_PARAMFLAG_BYREF, /**< Only arrays can be pushed */ - Param_VarArgs = (5<<1), /**< Same as "..." in plugins, anything can be pushed, but it will always be byref */ - Param_CellByRef = (1<<1)|SP_PARAMFLAG_BYREF, /**< Only a cell by reference can be pushed */ - Param_FloatByRef = (2<<1)|SP_PARAMFLAG_BYREF /**< Only a float by reference can be pushed */ -}; - -/** - * Defines how a forward iterates through plugin functions. - */ -enum ExecType -{ - ET_Ignore = 0, /**< Ignore all return values, return 0 */ - ET_Single = 1, /**< Only return the last exec, ignore all others */ - ET_Event = 2, /**< Acts as an event with the Actions defined in core.inc, no mid-Stops allowed, returns highest */ - ET_Hook = 3 /**< Acts as a hook with the Actions defined in core.inc, mid-Stops allowed, returns highest */ -}; - -/** - * @section Flags that are used with Call_PushArrayEx() and Call_PushStringEx() - */ - -#define SM_PARAM_COPYBACK (1<<0) /**< Copy an array/reference back after call */ - -#define SM_PARAM_STRING_UTF8 (1<<0) /**< String should be UTF-8 handled */ -#define SM_PARAM_STRING_COPY (1<<1) /**< String should be copied into the plugin */ -#define SM_PARAM_STRING_BINARY (1<<2) /**< Treat the string as a binary string */ - -/** - * @endsection - */ - -/** - * @section Error codes - */ -#define SP_ERROR_NONE 0 /**< No error occurred */ -#define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */ -#define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */ -#define SP_ERROR_HEAPLOW 3 /**< Not enough space left on the heap */ -#define SP_ERROR_PARAM 4 /**< Invalid parameter or parameter type */ -#define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */ -#define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */ -#define SP_ERROR_INDEX 7 /**< Invalid index parameter */ -#define SP_ERROR_STACKLOW 8 /**< Not enough space left on the stack */ -#define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */ -#define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */ -#define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */ -#define SP_ERROR_STACKMIN 12 /**< Stack went beyond its minimum value */ -#define SP_ERROR_HEAPMIN 13 /**< Heap went beyond its minimum value */ -#define SP_ERROR_DIVIDE_BY_ZERO 14 /**< Division by zero */ -#define SP_ERROR_ARRAY_BOUNDS 15 /**< Array index is out of bounds */ -#define SP_ERROR_INSTRUCTION_PARAM 16 /**< Instruction had an invalid parameter */ -#define SP_ERROR_STACKLEAK 17 /**< A native leaked an item on the stack */ -#define SP_ERROR_HEAPLEAK 18 /**< A native leaked an item on the heap */ -#define SP_ERROR_ARRAY_TOO_BIG 19 /**< A dynamic array is too big */ -#define SP_ERROR_TRACKER_BOUNDS 20 /**< Tracker stack is out of bounds */ -#define SP_ERROR_INVALID_NATIVE 21 /**< Native was pending or invalid */ -#define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */ -#define SP_ERROR_NATIVE 23 /**< Error originates from a native */ -#define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */ -#define SP_ERROR_ABORTED 25 /**< Function call was aborted */ - -/** - * @endsection - */ - -/** - * Gets a function id from a function name. - * - * @param plugin Handle of the plugin that contains the function. - Pass INVALID_HANDLE to search in the calling plugin. - * @param name Name of the function. - * @return Function id or INVALID_FUNCTION if not found. - * @error Invalid or corrupt plugin handle. - */ -native Function GetFunctionByName(Handle plugin, const char[] name); - -/** - * Creates a global forward. - * - * @note The name used to create the forward is used as its public function in all target plugins. - * @note This is ideal for global, static forwards that are never changed. - * @note Global forwards cannot be cloned. - * @note Use CloseHandle() to destroy these. - * - * @param name Name of public function to use in forward. - * @param type Execution type to be used. - * @param ... Variable number of parameter types (up to 32). - * @return Handle to new global forward. - * @error More than 32 paramater types passed. - */ -native Handle CreateGlobalForward(const char[] name, ExecType type, ParamType ...); - -/** - * Creates a private forward. - * - * @note No functions are automatically added. Use AddToForward() to do this. - * @note Private forwards can be cloned. - * @note Use CloseHandle() to destroy these. - * - * @param type Execution type to be used. - * @param ... Variable number of parameter types (up to 32). - * @return Handle to new private forward. - * @error More than 32 paramater types passed. - */ -native Handle CreateForward(ExecType type, ParamType ...); - -/** - * Returns the number of functions in a global or private forward's call list. - * - * @param fwd Handle to global or private forward. - * @return Number of functions in forward. - * @error Invalid or corrupt forward handle. - */ -native int GetForwardFunctionCount(Handle fwd); - -/** - * Adds a function to a private forward's call list. - * - * @note Cannot be used during an incomplete call. - * - * @param fwd Handle to private forward. - * @param plugin Handle of the plugin that contains the function. - * Pass INVALID_HANDLE to specify the calling plugin. - * @param func Function to add to forward. - * @return True on success, false otherwise. - * @error Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function. - */ -native bool AddToForward(Handle fwd, Handle plugin, Function func); - -/** - * Removes a function from a private forward's call list. - * - * @note Only removes one instance. - * @note Functions will be removed automatically if their parent plugin is unloaded. - * - * @param fwd Handle to private forward. - * @param plugin Handle of the plugin that contains the function. - * Pass INVALID_HANDLE to specify the calling plugin. - * @param func Function to remove from forward. - * @return True on success, false otherwise. - * @error Invalid or corrupt private forward handle, invalid or corrupt plugin handle, or invalid function. - */ -native bool RemoveFromForward(Handle fwd, Handle plugin, Function func); - -/** - * Removes all instances of a plugin from a private forward's call list. - * - * @note Functions will be removed automatically if their parent plugin is unloaded. - * - * @param fwd Handle to private forward. - * @param plugin Handle of the plugin to remove instances of. - * Pass INVALID_HANDLE to specify the calling plugin. - * @return Number of functions removed from forward. - * @error Invalid or corrupt private forward handle or invalid or corrupt plugin handle. - */ -native int RemoveAllFromForward(Handle fwd, Handle plugin); - -/** - * Starts a call to functions in a forward's call list. - * - * @note Cannot be used during an incomplete call. - * - * @param fwd Handle to global or private forward. - * @error Invalid or corrupt forward handle or called before another call has completed. - */ -native void Call_StartForward(Handle fwd); - -/** - * Starts a call to a function. - * - * @note Cannot be used during an incomplete call. - * - * @param plugin Handle of the plugin that contains the function. - * Pass INVALID_HANDLE to specify the calling plugin. - * @param func Function to call. - * @error Invalid or corrupt plugin handle, invalid function, or called before another call has completed. - */ -native void Call_StartFunction(Handle plugin, Function func); - -/** - * Pushes a cell onto the current call. - * - * @note Cannot be used before a call has been started. - * - * @param value Cell value to push. - * @error Called before a call has been started. - */ -native void Call_PushCell(any value); - -/** - * Pushes a cell by reference onto the current call. - * - * @note Cannot be used before a call has been started. - * - * @param value Cell reference to push. - * @error Called before a call has been started. - */ -native void Call_PushCellRef(any &value); - -/** - * Pushes a float onto the current call. - * - * @note Cannot be used before a call has been started. - * - * @param value Floating point value to push. - * @error Called before a call has been started. - */ -native void Call_PushFloat(float value); - -/** - * Pushes a float by reference onto the current call. - * - * @note Cannot be used before a call has been started. - * - * @param value Floating point reference to push. - * @error Called before a call has been started. - */ -native void Call_PushFloatRef(float &value); - -/** - * Pushes an array onto the current call. - * - * @note Changes to array are not copied back to caller. Use PushArrayEx() to do this. - * @note Cannot be used before a call has been started. - * - * @param value Array to push. - * @param size Size of array. - * @error Called before a call has been started. - */ -native void Call_PushArray(const any[] value, int size); - -/** - * Pushes an array onto the current call. - * - * @note Cannot be used before a call has been started. - * - * @param value Array to push. - * @param size Size of array. - * @param cpflags Whether or not changes should be copied back to the input array. - * See SP_PARAM_* constants for details. - * @error Called before a call has been started. - */ -native void Call_PushArrayEx(any[] value, int size, int cpflags); - -/** - * Pushes the NULL_VECTOR onto the current call. - * @see IsNullVector - * - * @note Cannot be used before a call has been started. - * - * @error Called before a call has been started. - */ -native void Call_PushNullVector(); - -/** - * Pushes a string onto the current call. - * - * @note Changes to string are not copied back to caller. Use PushStringEx() to do this. - * @note Cannot be used before a call has been started. - * - * @param value String to push. - * @error Called before a call has been started. - */ -native void Call_PushString(const char[] value); - -/** - * Pushes a string onto the current call. - * - * @note Cannot be used before a call has been started. - * - * @param value String to push. - * @param length Length of string buffer. - * @param szflags Flags determining how string should be handled. - * See SM_PARAM_STRING_* constants for details. - * The default (0) is to push ASCII. - * @param cpflags Whether or not changes should be copied back to the input array. - * See SM_PARAM_* constants for details. - * @error Called before a call has been started. - */ -native void Call_PushStringEx(char[] value, int length, int szflags, int cpflags); - -/** - * Pushes the NULL_STRING onto the current call. - * @see IsNullString - * - * @note Cannot be used before a call has been started. - * - * @error Called before a call has been started. - */ -native void Call_PushNullString(); - -/** - * Completes a call to a function or forward's call list. - * - * @note Cannot be used before a call has been started. - * - * @param result Return value of function or forward's call list. - * @return SP_ERROR_NONE on success, any other integer on failure. - * @error Called before a call has been started. - */ -native int Call_Finish(any &result=0); - -/** - * Cancels a call to a function or forward's call list. - * - * @note Cannot be used before a call has been started. - * - * @error Called before a call has been started. - */ -native void Call_Cancel(); - -/** - * Defines a native function. - * - * It is not necessary to validate the parameter count - * - * @param plugin Handle of the calling plugin. - * @param numParams Number of parameters passed to the native. - * @return Value for the native call to return. - */ -typedef NativeCall = function int (Handle plugin, int numParams); - -/** - * Creates a dynamic native. This should only be called in AskPluginLoad(), or - * else you risk not having your native shared with other plugins. - * - * @param name Name of the dynamic native; must be unique among - * all other registered dynamic natives. - * @param func Function to use as the dynamic native. - */ -native void CreateNative(const char[] name, NativeCall func); - -/** - * Throws an error in the calling plugin of a native, instead of your own plugin. - * - * @param error Error code to use. - * @param fmt Error message format. - * @param ... Format arguments. - */ -native int ThrowNativeError(int error, const char[] fmt, any ...); - -/** - * Retrieves the string length from a native parameter string. This is useful - * fetching the entire string using dynamic arrays. - * @note If this function succeeds, Get/SetNativeString will also succeed. - * - * @param param Parameter number, starting from 1. - * @param length Stores the length of the string. - * @return SP_ERROR_NONE on success, any other integer on failure. - * @error Invalid parameter number or calling from a non-native function. - */ -native int GetNativeStringLength(int param, int &length); - -/** - * Retrieves a string from a native parameter. - * @note Output conditions are undefined on failure. - * - * @param param Parameter number, starting from 1. - * @param buffer Buffer to store the string in. - * @param maxlength Maximum length of the buffer. - * @param bytes Optionally store the number of bytes written. - * @return SP_ERROR_NONE on success, any other integer on failure. - * @error Invalid parameter number or calling from a non-native function. - */ -native int GetNativeString(int param, char[] buffer, int maxlength, int &bytes=0); - -/** - * Sets a string in a native parameter. - * @note Output conditions are undefined on failure. - * - * @param param Parameter number, starting from 1. - * @param source Source string to use. - * @param maxlength Maximum number of bytes to write. - * @param utf8 If false, string will not be written - * with UTF8 safety. - * @param bytes Optionally store the number of bytes written. - * @return SP_ERROR_NONE on success, any other integer on failure. - * @error Invalid parameter number or calling from a non-native function. - */ -native int SetNativeString(int param, const char[] source, int maxlength, bool utf8=true, int &bytes=0); - -/** - * Gets a cell from a native parameter. - * - * @param param Parameter number, starting from 1. - * @return Cell value at the parameter number. - * @error Invalid parameter number or calling from a non-native function. - */ -native any GetNativeCell(int param); - -/** - * Gets a function pointer from a native parameter. - * - * @param param Parameter number, starting from 1. - * @return Function pointer at the given parameter number. - * @error Invalid parameter number, or calling from a non-native function. - */ -native Function GetNativeFunction(int param); - -/** - * Gets a cell from a native parameter, by reference. - * - * @param param Parameter number, starting from 1. - * @return Cell value at the parameter number. - * @error Invalid parameter number or calling from a non-native function. - */ -native any GetNativeCellRef(int param); - -/** - * Sets a cell from a native parameter, by reference. - * - * @param param Parameter number, starting from 1. - * @param value Cell value at the parameter number to set by reference. - * @error Invalid parameter number or calling from a non-native function. - */ -native void SetNativeCellRef(int param, any value); - -/** - * Gets an array from a native parameter (always by reference). - * - * @param param Parameter number, starting from 1. - * @param local Local array to copy into. - * @param size Maximum size of local array. - * @return SP_ERROR_NONE on success, anything else on failure. - * @error Invalid parameter number or calling from a non-native function. - */ -native int GetNativeArray(int param, any[] local, int size); - -/** - * Copies a local array into a native parameter array (always by reference). - * - * @param param Parameter number, starting from 1. - * @param local Local array to copy from. - * @param size Size of the local array to copy. - * @return SP_ERROR_NONE on success, anything else on failure. - * @error Invalid parameter number or calling from a non-native function. - */ -native int SetNativeArray(int param, const any[] local, int size); - -/** - * Check if the native parameter is the NULL_VECTOR. - * - * @param param Parameter number, starting from 1. - * @return True if NULL_VECTOR, false otherwise. - */ -native bool IsNativeParamNullVector(int param); - -/** - * Check if the native parameter is the NULL_STRING. - * - * @param param Parameter number, starting from 1. - * @return True if NULL_STRING, false otherwise. - */ -native bool IsNativeParamNullString(int param); - -/** - * Formats a string using parameters from a native. - * - * @note All parameter indexes start at 1. - * @note If the input and output buffers overlap, the contents - * of the output buffer at the end is undefined. - * - * @param out_param Output parameter number to write to. If 0, out_string is used. - * @param fmt_param Format parameter number. If 0, fmt_string is used. - * @param vararg_param First variable parameter number. - * @param out_len Output string buffer maximum length (always required). - * @param written Optionally stores the number of bytes written. - * @param out_string Output string buffer to use if out_param is not used. - * @param fmt_string Format string to use if fmt_param is not used. - * @return SP_ERROR_NONE on success, anything else on failure. - */ -native int FormatNativeString(int out_param, - int fmt_param, - int vararg_param, - int out_len, - int &written=0, - char[] out_string="", - const char[] fmt_string=""); - -/** - * Defines a RequestFrame Callback. - * - * @param data Data passed to the RequestFrame native. - */ -typedef RequestFrameCallback = function void (any data); - -/** - * Creates a single use Next Frame hook. - * - * @param Function Function to call on the next frame. - * @param data Value to be passed on the invocation of the Function. - */ -native void RequestFrame(RequestFrameCallback Function, any data=0); diff --git a/scripting/include/geoip.inc b/scripting/include/geoip.inc deleted file mode 100644 index 57d0862..0000000 --- a/scripting/include/geoip.inc +++ /dev/null @@ -1,102 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _geoip_included - #endinput -#endif -#define _geoip_included - -#include - -/** - * @section IP addresses can contain ports, the ports will be stripped out. - */ - -/** - * Gets the two character country code from an IP address. (US, CA, etc) - * - * @param ip Ip to determine the country code. - * @param ccode Destination string buffer to store the code. - * @return True on success, false if no country found. - */ -native bool GeoipCode2(const char[] ip, char ccode[3]); - -/** - * Gets the three character country code from an IP address. (USA, CAN, etc) - * - * @param ip Ip to determine the country code. - * @param ccode Destination string buffer to store the code. - * @return True on success, false if no country found. - */ -native bool GeoipCode3(const char[] ip, char ccode[4]); - -/** - * Gets the full country name. (max length of output string is 45) - * - * @param ip Ip to determine the country code. - * @param name Destination string buffer to store the country name. - * @param maxlength Maximum length of output string buffer. - * @return True on success, false if no country found. - */ -native bool GeoipCountry(const char[] ip, char[] name, int maxlength); - -/** - * @endsection - */ - -/** - * Do not edit below this line! - */ -public Extension __ext_geoip = -{ - name = "GeoIP", - file = "geoip.ext", -#if defined AUTOLOAD_EXTENSIONS - autoload = 1, -#else - autoload = 0, -#endif -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_EXTENSIONS -public void __ext_geoip_SetNTVOptional() -{ - MarkNativeAsOptional("GeoipCode2"); - MarkNativeAsOptional("GeoipCode3"); - MarkNativeAsOptional("GeoipCountry"); -} -#endif diff --git a/scripting/include/halflife.inc b/scripting/include/halflife.inc deleted file mode 100644 index fd6344d..0000000 --- a/scripting/include/halflife.inc +++ /dev/null @@ -1,706 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2016 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _halflife_included - #endinput -#endif -#define _halflife_included - -#define SOURCE_SDK_UNKNOWN 0 /**< Could not determine the engine version */ -#define SOURCE_SDK_ORIGINAL 10 /**< Original Source engine (still used by "The Ship") */ -#define SOURCE_SDK_DARKMESSIAH 15 /**< Modified version of original engine used by Dark Messiah (no SDK) */ -#define SOURCE_SDK_EPISODE1 20 /**< SDK+Engine released after Episode 1 */ -#define SOURCE_SDK_EPISODE2 30 /**< SDK+Engine released after Episode 2/Orange Box */ -#define SOURCE_SDK_BLOODYGOODTIME 32 /**< Modified version of ep2 engine used by Bloody Good Time (no SDK) */ -#define SOURCE_SDK_EYE 33 /**< Modified version of ep2 engine used by E.Y.E Divine Cybermancy (no SDK) */ -#define SOURCE_SDK_CSS 34 /**< Sometime-older version of Source 2009 SDK+Engine, used for Counter-Strike: Source */ -#define SOURCE_SDK_EPISODE2VALVE 35 /**< SDK+Engine released after Episode 2/Orange Box, "Source 2009" or "Source MP" */ -#define SOURCE_SDK_LEFT4DEAD 40 /**< Engine released after Left 4 Dead (no SDK yet) */ -#define SOURCE_SDK_LEFT4DEAD2 50 /**< Engine released after Left 4 Dead 2 (no SDK yet) */ -#define SOURCE_SDK_ALIENSWARM 60 /**< SDK+Engine released after Alien Swarm */ -#define SOURCE_SDK_CSGO 80 /**< Engine released after CS:GO (no SDK yet) */ -#define SOURCE_SDK_DOTA 90 /**< Engine released after Dota 2 (no SDK) */ - -#define MOTDPANEL_TYPE_TEXT 0 /**< Treat msg as plain text */ -#define MOTDPANEL_TYPE_INDEX 1 /**< Msg is auto determined by the engine */ -#define MOTDPANEL_TYPE_URL 2 /**< Treat msg as an URL link */ -#define MOTDPANEL_TYPE_FILE 3 /**< Treat msg as a filename to be opened */ - -enum DialogType -{ - DialogType_Msg = 0, /**< just an on screen message */ - DialogType_Menu, /**< an options menu */ - DialogType_Text, /**< a richtext dialog */ - DialogType_Entry, /**< an entry box */ - DialogType_AskConnect /**< ask the client to connect to a specified IP */ -}; - -enum EngineVersion -{ - Engine_Unknown, /**< Could not determine the engine version */ - Engine_Original, /**< Original Source Engine (used by The Ship) */ - Engine_SourceSDK2006, /**< Episode 1 Source Engine (second major SDK) */ - Engine_SourceSDK2007, /**< Orange Box Source Engine (third major SDK) */ - Engine_Left4Dead, /**< Left 4 Dead */ - Engine_DarkMessiah, /**< Dark Messiah Multiplayer (based on original engine) */ - Engine_Left4Dead2 = 7, /**< Left 4 Dead 2 */ - Engine_AlienSwarm, /**< Alien Swarm (and Alien Swarm SDK) */ - Engine_BloodyGoodTime, /**< Bloody Good Time */ - Engine_EYE, /**< E.Y.E Divine Cybermancy */ - Engine_Portal2, /**< Portal 2 */ - Engine_CSGO, /**< Counter-Strike: Global Offensive */ - Engine_CSS, /**< Counter-Strike: Source */ - Engine_DOTA, /**< Dota 2 */ - Engine_HL2DM, /**< Half-Life 2 Deathmatch */ - Engine_DODS, /**< Day of Defeat: Source */ - Engine_TF2, /**< Team Fortress 2 */ - Engine_NuclearDawn, /**< Nuclear Dawn */ - Engine_SDK2013, /**< Source SDK 2013 */ - Engine_Blade, /**< Blade Symphony */ - Engine_Insurgency, /**< Insurgency (2013 Retail version)*/ - Engine_Contagion, /**< Contagion */ - Engine_BlackMesa, /**< Black Mesa Multiplayer */ - Engine_DOI, /**< Day of Infamy */ -}; - -enum FindMapResult -{ - // A direct match for this name was found - FindMap_Found, - // No match for this map name could be found. - FindMap_NotFound, - // A fuzzy match for this map name was found. - // Ex: cp_dust -> cp_dustbowl, c1m1 -> c1m1_hotel - // Only supported for maps that the engine knows about. (This excludes workshop maps on Orangebox). - FindMap_FuzzyMatch, - // A non-canonical match for this map name was found. - // Ex: workshop/1234 -> workshop/cp_qualified_name.ugc1234 - // Only supported on "Orangebox" games with workshop support. - FindMap_NonCanonical, - // No currently available match for this map name could be found, but it may be possible to load - // Only supported on "Orangebox" games with workshop support. - FindMap_PossiblyAvailable -}; - -#define INVALID_ENT_REFERENCE 0xFFFFFFFF - -/** - * Logs a generic message to the HL2 logs. - * - * @param format String format. - * @param ... Format arguments. - */ -native void LogToGame(const char[] format, any ...); - -/** - * Sets the seed value for the global Half-Life 2 Random Stream. - * - * @param seed Seed value. - */ -native void SetRandomSeed(int seed); - -/** - * Returns a random floating point number from the Half-Life 2 Random Stream. - * - * @param fMin Minimum random bound. - * @param fMax Maximum random bound. - * @return A random number between (inclusive) fMin and fMax. - */ -native float GetRandomFloat(float fMin=0.0, float fMax=1.0); - -/** - * Returns a random number from the Half-Life 2 Random Stream. - * - * @param nmin Minimum random bound. - * @param nmax Maximum random bound. - * @return A random number between (inclusive) nmin and nmax. - */ -native int GetRandomInt(int nmin, int nmax); - -/** - * Returns whether a map is valid or not. - * - * @param map Map name, excluding .bsp extension. - * @return True if valid, false otherwise. - */ -native bool IsMapValid(const char[] map); - -/** - * Returns whether a full or partial map name is found or can be resolved - * - * @param map Map name (usually same as map path relative to maps/ dir, - * excluding .bsp extension). - * @param foundmap Resolved map name. If the return is FindMap_FuzzyMatch - * or FindMap_NonCanonical the buffer will be the full path. - * @param maxlen Maximum length to write to map var. - * @return Result of the find operation. Not all result types are supported on all games. - */ -native FindMapResult FindMap(const char[] map, char[] foundmap, int maxlen); - -/** - * Get the display name of a workshop map. - * - * Note: You do not need to call FindMap first. This native will call FindMap internally. - * - * @param map Map name (usually same as map path relative to maps/ dir, - * excluding .bsp extension). - * @param displayName Map's display name, i.e. cp_mymapname or de_mymapname. - * If FindMap returns FindMap_PossiblyAvailable or FindMap_NotFound, - * the map cannot be resolved and this native will return false, - * but displayName will be a copy of map. - * @param maxlen Maximum length to write to displayName var. - * @return true if FindMap returns FindMap_Found, FindMap_FuzzyMatch, or - * FindMap_NonCanonical. - * false if FindMap returns FindMap_PossiblyAvailable or FindMap_NotFound. - */ -native bool GetMapDisplayName(const char[] map, char[] displayName, int maxlen); - -/** - * Returns whether the server is dedicated. - * - * @return True if dedicated, false otherwise. - */ -native bool IsDedicatedServer(); - -/** - * Returns a high-precision time value for profiling the engine. - * - * @return A floating point time value. - */ -native float GetEngineTime(); - -/** - * Returns the game time based on the game tick. - * - * @return Game tick time. - */ -native float GetGameTime(); - -/** - * Returns the game's internal tick count. - * - * @return Game tick count. - */ -native int GetGameTickCount(); - -/** - * Returns the time the Game took processing the last frame. - * - * @return Game frame time. - */ -native float GetGameFrameTime(); - -/** - * Returns the game description from the mod. - * - * @param buffer Buffer to store the description. - * @param maxlength Maximum size of the buffer. - * @param original If true, retrieves the original game description, - * ignoring any potential hooks from plugins. - * @return Number of bytes written to the buffer (UTF-8 safe). - */ -native int GetGameDescription(char[] buffer, int maxlength, bool original=false); - -/** - * Returns the name of the game's directory. - * - * @param buffer Buffer to store the directory name. - * @param maxlength Maximum size of the buffer. - * @return Number of bytes written to the buffer (UTF-8 safe). - */ -native int GetGameFolderName(char[] buffer, int maxlength); - -/** - * Returns the current map name. - * - * @param buffer Buffer to store map name. - * @param maxlength Maximum length of buffer. - * @return Number of bytes written (UTF-8 safe). - */ -native int GetCurrentMap(char[] buffer, int maxlength); - -/** - * Precaches a given model. - * - * @param model Name of the model to precache. - * @param preload If preload is true the file will be precached before level startup. - * @return Returns the model index, 0 for error. - */ -native int PrecacheModel(const char[] model, bool preload=false); - -/** - * Precaches a given sentence file. - * - * @param file Name of the sentence file to precache. - * @param preload If preload is true the file will be precached before level startup. - * @return Returns a sentence file index. - */ -native int PrecacheSentenceFile(const char[] file, bool preload=false); - -/** - * Precaches a given decal. - * - * @param decal Name of the decal to precache. - * @param preload If preload is true the file will be precached before level startup. - * @return Returns a decal index. - */ -native int PrecacheDecal(const char[] decal, bool preload=false); - -/** - * Precaches a given generic file. - * - * @param generic Name of the generic file to precache. - * @param preload If preload is true the file will be precached before level startup. - * @return Returns a generic file index. - */ -native int PrecacheGeneric(const char[] generic, bool preload=false); - -/** - * Returns if a given model is precached. - * - * @param model Name of the model to check. - * @return True if precached, false otherwise. - */ -native bool IsModelPrecached(const char[] model); - -/** - * Returns if a given decal is precached. - * - * @param decal Name of the decal to check. - * @return True if precached, false otherwise. - */ -native bool IsDecalPrecached(const char[] decal); - -/** - * Returns if a given generic file is precached. - * - * @param generic Name of the generic file to check. - * @return True if precached, false otherwise. - */ -native bool IsGenericPrecached(const char[] generic); - -/** - * Precaches a given sound. - * - * @param sound Name of the sound to precache. - * @param preload If preload is true the file will be precached before level startup. - * @return True if successfully precached, false otherwise. - */ -native bool PrecacheSound(const char[] sound, bool preload=false); - -/** - * Returns if a given sound is precached. - * - * @param sound Name of the sound to check. - * @return True if precached, false otherwise. - */ -native bool IsSoundPrecached(const char[] sound); - -/** - * Creates different types of ingame messages. - * - * @param client Index of the client. - * @param kv KeyValues handle to set the menu keys and options. (Check iserverplugin.h for more information). - * @param type Message type to display ingame. - * @error Invalid client index, or client not connected. - */ -native void CreateDialog(int client, Handle kv, DialogType type); - -/** - * Guesses the SDK version a mod was compiled against. If nothing - * specific is known about the game, the engine version is used instead. - * - * The return values are guaranteed to increase chronologically (that is, - * a later release will have a higher value). - * - * @return SOURCE_SDK version code. - */ -#pragma deprecated See GetEngineVersion() -native int GuessSDKVersion(); - -/** - * Gets the engine version that the currently-loaded SM core was compiled against. - * - * The engine version values are not guaranteed to be in any particular order, - * and should only be compared by (in)equality. - * - * @return An EngineVersion value. - */ -native EngineVersion GetEngineVersion(); - -/** - * Prints a message to a specific client in the chat area. - * - * @param client Client index. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error If the client is not connected an error will be thrown. - */ -native void PrintToChat(int client, const char[] format, any ...); - -/** - * Prints a message to all clients in the chat area. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -stock void PrintToChatAll(const char[] format, any ...) -{ - char buffer[254]; - - for (int i = 1; i <= MaxClients; i++) - { - if (IsClientInGame(i)) - { - SetGlobalTransTarget(i); - VFormat(buffer, sizeof(buffer), format, 2); - PrintToChat(i, "%s", buffer); - } - } -} - -/** - * Prints a message to a specific client in the center of the screen. - * - * @param client Client index. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error If the client is not connected an error will be thrown. - */ -native void PrintCenterText(int client, const char[] format, any ...); - -/** - * Prints a message to all clients in the center of the screen. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -stock void PrintCenterTextAll(const char[] format, any ...) -{ - char buffer[254]; - - for (int i = 1; i <= MaxClients; i++) - { - if (IsClientInGame(i)) - { - SetGlobalTransTarget(i); - VFormat(buffer, sizeof(buffer), format, 2); - PrintCenterText(i, "%s", buffer); - } - } -} - -/** - * Prints a message to a specific client with a hint box. - * - * @param client Client index. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @error If the client is not connected an error will be thrown. - */ -native void PrintHintText(int client, const char[] format, any ...); - -/** - * Prints a message to all clients with a hint box. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - */ -stock void PrintHintTextToAll(const char[] format, any ...) -{ - char buffer[254]; - - for (int i = 1; i <= MaxClients; i++) - { - if (IsClientInGame(i)) - { - SetGlobalTransTarget(i); - VFormat(buffer, sizeof(buffer), format, 2); - PrintHintText(i, "%s", buffer); - } - } -} - -/** - * Shows a VGUI panel to a specific client. - * - * @param client Client index. - * @param name Panel type name (Check viewport_panel_names.h to see a list of - * some panel names). - * @param Kv KeyValues handle with all the data for the panel setup (Depends - * on the panel type and may be unused). - * @param show True to show the panel, or false to remove it from the client screen. - * @error If the client is not connected an error will be thrown. - */ -native void ShowVGUIPanel(int client, const char[] name, Handle Kv=INVALID_HANDLE, bool show=true); - -/** - * Creates a HUD synchronization object. This object is used to automatically assign and - * re-use channels for a set of messages. - * - * The HUD has a hardcoded number of channels (usually 6) for displaying - * text. You can use any channel for any area of the screen. Text on - * different channels can overlap, but text on the same channel will - * erase the old text first. This overlapping and overwriting gets problematic. - * - * A HUD synchronization object automatically selects channels for you based on - * the following heuristics: - * - If channel X was last used by the object, and hasn't been modified again, - * channel X gets re-used. - * - Otherwise, a new channel is chosen based on the least-recently-used channel. - * - * This ensures that if you display text on a sync object, that the previous text - * displayed on it will always be cleared first. This is because your new text - * will either overwrite the old text on the same channel, or because another - * channel has already erased your text. - * - * Note that messages can still overlap if they are on different synchronization - * objects, or they are displayed to manual channels. - * - * These are particularly useful for displaying repeating or refreshing HUD text, in - * addition to displaying multiple message sets in one area of the screen (for example, - * center-say messages that may pop up randomly that you don't want to overlap each - * other). - * - * @return New HUD synchronization object. - * The Handle can be closed with CloseHandle(). - * If HUD text is not supported on this mod, then - * INVALID_HANDLE is returned. - */ -native Handle CreateHudSynchronizer(); - -/** - * Sets the HUD parameters for drawing text. These parameters are stored - * globally, although nothing other than this function and SetHudTextParamsEx - * modify them. - * - * You must call this function before drawing text. If you are drawing - * text to multiple clients, you can set the parameters once, since - * they won't be modified. However, as soon as you pass control back - * to other plugins, you must reset the parameters next time you draw. - * - * @param x x coordinate, from 0 to 1. -1.0 is the center. - * @param y y coordinate, from 0 to 1. -1.0 is the center. - * @param holdTime Number of seconds to hold the text. - * @param r Red color value. - * @param g Green color value. - * @param b Blue color value. - * @param a Alpha transparency value. - * @param effect 0/1 causes the text to fade in and fade out. - * 2 causes the text to flash[?]. - * @param fxTime Duration of chosen effect (may not apply to all effects). - * @param fadeIn Number of seconds to spend fading in. - * @param fadeOut Number of seconds to spend fading out. - */ -native void SetHudTextParams(float x, float y, float holdTime, int r, int g, int b, int a, int effect = 0, - float fxTime=6.0, float fadeIn=0.1, float fadeOut=0.2); - -/** - * Sets the HUD parameters for drawing text. These parameters are stored - * globally, although nothing other than this function and SetHudTextParams - * modify them. - * - * This is the same as SetHudTextParams(), except it lets you set the alternate - * color for when effects require it. - * - * @param x x coordinate, from 0 to 1. -1.0 is the center. - * @param y y coordinate, from 0 to 1. -1.0 is the center. - * @param holdTime Number of seconds to hold the text. - * @param color1 First color set, array values being [red, green, blue, alpha] - * @param color2 Second color set, array values being [red, green, blue, alpha] - * @param effect 0/1 causes the text to fade in and fade out. - * 2 causes the text to flash[?]. - * @param fxTime Duration of chosen effect (may not apply to all effects). - * @param fadeIn Number of seconds to spend fading in. - * @param fadeOut Number of seconds to spend fading out. - */ -native void SetHudTextParamsEx(float x, float y, float holdTime, int color1[4], - int color2[4]={255,255,255,0}, int effect = 0, float fxTime=6.0, - float fadeIn=0.1, float fadeOut=0.2); - -/** - * Shows a synchronized HUD message to a client. - * - * As of this writing, only TF, HL2MP, and SourceForts support HUD Text. - * - * @param client Client index to send the message to. - * @param sync Synchronization object. - * @param message Message text or formatting rules. - * @param ... Message formatting parameters. - * @return -1 on failure, anything else on success. - * This function fails if the mod does not support it. - * @error Client not in-game, or sync object not valid. - */ -native int ShowSyncHudText(int client, Handle sync, const char[] message, any ...); - -/** - * Clears the text on a synchronized HUD channel. - * - * This is not the same as sending "" because it guarantees that it won't - * overwrite text on another channel. For example, consider the scenario: - * - * 1. Your synchronized message goes to channel 3. - * 2. Someone else's non-synchronized message goes to channel 3. - * - * If you were to simply send "" on your synchronized message, - * then someone else's text could be overwritten. - * - * @param client Client index to send the message to. - * @param sync Synchronization object. - * @error Client not in-game, or sync object not valid. - */ -native void ClearSyncHud(int client, Handle sync); - -/** - * Shows a HUD message to a client on the given channel. - * - * As of this writing, only TF, HL2MP, and SourceForts support HUD Text. - * - * @param client Client index to send the message to. - * @param channel A channel number. - * If -1, then a channel will automatically be selected - * based on the least-recently-used channel. If the - * channel is any other number, it will be modulo'd with - * the channel count to get a final channel number. - * @param message Message text or formatting rules. - * @param ... Message formatting parameters. - * @return -1 on failure (lack of mod support). - * Any other return value is the channel number that was - * used to render the text. - */ -native int ShowHudText(int client, int channel, const char[] message, any ...); - -/** - * Shows a MOTD panel to a specific client. - * - * @param client Client index. - * @param title Title of the panel (printed on the top border of the window). - * @param msg Contents of the panel, it can be treated as an url, filename or plain text - * depending on the type parameter (WARNING: msg has to be 192 bytes maximum!) - * @param type Determines the way to treat the message body of the panel. - * @error If the client is not connected an error will be thrown. - */ -stock void ShowMOTDPanel(int client, const char[] title, const char[] msg, int type=MOTDPANEL_TYPE_INDEX) -{ - char num[3]; - IntToString(type, num, sizeof(num)); - - KeyValues kv = new KeyValues("data"); - kv.SetString("title", title); - kv.SetString("type", num); - kv.SetString("msg", msg); - ShowVGUIPanel(client, "info", kv); - delete kv; -} - -/** - * Displays a panel asking the client to connect to a specified IP. - * - * @param client Client index. - * @param time Duration to hold the panel on the client's screen. - * @param ip Destination IP. - * @param password Password to connect to the destination IP. The client will be able to see this. - */ -stock void DisplayAskConnectBox(int client, float time, const char[] ip, const char[] password = "") -{ - char destination[288]; - FormatEx(destination, sizeof(destination), "%s/%s", ip, password); - - KeyValues kv = new KeyValues("data"); - kv.SetFloat("time", time); - kv.SetString("title", destination); - CreateDialog(client, kv, DialogType_AskConnect); - delete kv; -} - -/** - * Converts an entity index into a serial encoded entity reference. - * - * @param entity Entity index. - * @return Entity reference. - */ -native int EntIndexToEntRef(int entity); - -/** - * Retrieves the entity index from a reference. - * - * @param ref Entity reference. - * @return Entity index. - */ -native int EntRefToEntIndex(int ref); - -/** - * Converts a reference into a backwards compatible version. - * - * @param ref Entity reference. - * @return Bcompat reference. - */ -native int MakeCompatEntRef(int ref); - - -enum ClientRangeType -{ - RangeType_Visibility = 0, - RangeType_Audibility, -} - -/** - * Find clients that are potentially in range of a position. - * - * @param origin Coordinates from which to test range. - * @param rangeType Range type to use for filtering clients. - * @param clients Array to which found client indexes will be written. - * @param size Maximum size of clients array. - * @return Number of client indexes written to clients array. - */ -native int GetClientsInRange(float origin[3], ClientRangeType rangeType, int[] clients, int size); - -/** - * Retrieves the server's authentication string (SteamID). - * - * Note: If called before server is connected to Steam, auth id - * will be invalid ([I:0:1], 1, etc.) - * - * @param authType Auth id type and format to use. - * (Only AuthId_Steam3 and AuthId_SteamID64 are supported) - * @param auth Buffer to store the server's auth id. - * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @error Invalid AuthIdType given. - */ -native void GetServerAuthId(AuthIdType authType, char[] auth, int maxlen); - -/** - * Returns the server's Steam account ID. - * - * @return Steam account ID or 0 if not available. - */ -native int GetServerSteamAccountId(); diff --git a/scripting/include/handles.inc b/scripting/include/handles.inc deleted file mode 100644 index c7d5992..0000000 --- a/scripting/include/handles.inc +++ /dev/null @@ -1,97 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _handles_included - #endinput -#endif -#define _handles_included - -/** - * Preset Handle values. - */ -enum Handle // Tag disables introducing "Handle" as a symbol. -{ - INVALID_HANDLE = 0, -}; - - -/** - * Closes a Handle. If the handle has multiple copies open, - * it is not destroyed unless all copies are closed. - * - * @note Closing a Handle has a different meaning for each Handle type. Make - * sure you read the documentation on whatever provided the Handle. - * - * @param hndl Handle to close. - * @error Invalid handles will cause a run time error. - */ -native void CloseHandle(Handle hndl); - -/** - * Clones a Handle. When passing handles in between plugins, caching handles - * can result in accidental invalidation when one plugin releases the Handle, or is its owner - * is unloaded from memory. To prevent this, the Handle may be "cloned" with a new owner. - * - * @note Usually, you will be cloning Handles for other plugins. This means that if you clone - * the Handle without specifying the new owner, it will assume the identity of your original calling - * plugin, which is not very useful. You should either specify that the receiving plugin should - * clone the handle on its own, or you should explicitly clone the Handle using the receiving plugin's - * identity Handle. - * - * @param hndl Handle to clone/duplicate. - * @param plugin Optional Handle to another plugin to mark as the new owner. - * If no owner is passed, the owner becomes the calling plugin. - * @return Handle on success, INVALID_HANDLE if not cloneable. - * @error Invalid handles will cause a run time error. - */ -native Handle CloneHandle(Handle hndl, Handle plugin=INVALID_HANDLE); - -using __intrinsics__.Handle; - -/** - * Do not use this function. Returns if a Handle and its contents - * are readable, whereas INVALID_HANDLE only checks for the absence - * of a Handle. - * - * This function is intended only for tests where the validity of a - * Handle can absolutely not be known. - * - * Do not use this to check the return values of functions, or to - * check if timers should be closed (except in very rare cases). - * This function is for very specific usage and using it for general - * purpose routines can and will hide very subtle bugs. - * - * @param hndl Handle to test for validity. - * @return True if handle is valid, false otherwise. - */ -#pragma deprecated Do not use this function. -native bool IsValidHandle(Handle hndl); diff --git a/scripting/include/helpers.inc b/scripting/include/helpers.inc deleted file mode 100644 index aa15a22..0000000 --- a/scripting/include/helpers.inc +++ /dev/null @@ -1,279 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _helpers_included - #endinput -#endif -#define _helpers_included - -/** - * Formats a user's info as log text. This is usually not needed because - * %L can be used to auto-format client information into a string. - * - * @param client Client index. - * @param buffer Buffer for text. - * @param maxlength Maximum length of text. - */ -stock void FormatUserLogText(int client, char[] buffer, int maxlength) -{ - char auth[32]; - char name[MAX_NAME_LENGTH]; - - int userid = GetClientUserId(client); - if (!GetClientAuthString(client, auth, sizeof(auth))) - { - strcopy(auth, sizeof(auth), "UNKNOWN"); - } - if (!GetClientName(client, name, sizeof(name))) - { - strcopy(name, sizeof(name), "UNKNOWN"); - } - - /** Currently, no team stuff ... */ - - Format(buffer, maxlength, "\"%s<%d><%s><>\"", name, userid, auth); -} - -/** - * Returns plugin handle from plugin filename. - * - * @param filename Filename of the plugin to search for. - * @return Handle to plugin if found, INVALID_HANDLE otherwise. - */ -stock Handle FindPluginByFile(const char[] filename) -{ - char buffer[256]; - - Handle iter = GetPluginIterator(); - Handle pl; - - while (MorePlugins(iter)) - { - pl = ReadPlugin(iter); - - GetPluginFilename(pl, buffer, sizeof(buffer)); - if (strcmp(buffer, filename, false) == 0) - { - CloseHandle(iter); - return pl; - } - } - - CloseHandle(iter); - - return INVALID_HANDLE; -} - -/** - * @deprecated Use FindTarget() or ProcessTargetString(). - */ -#pragma deprecated Use FindTarget() or ProcessTargetString() -stock int SearchForClients(const char[] pattern, int[] clients, int maxClients) -{ - int total = 0; - - if (maxClients == 0) - return 0; - - if (pattern[0] == '#') { - int input = StringToInt(pattern[1]); - if (!input) { - char name[MAX_NAME_LENGTH]; - for (int i=1; i<=MaxClients; i++) { - if (!IsClientInGame(i)) - continue; - GetClientName(i, name, sizeof(name)); - if (strcmp(name, pattern, false) == 0) { - clients[0] = i; - return 1; - } - } - } else { - int client = GetClientOfUserId(input); - if (client) { - clients[0] = client; - return 1; - } - } - } - - char name[MAX_NAME_LENGTH]; - for (int i=1; i<=MaxClients; i++) - { - if (!IsClientInGame(i)) - continue; - GetClientName(i, name, sizeof(name)); - if (StrContains(name, pattern, false) != -1) { - clients[total++] = i; - if (total >= maxClients) - break; - } - } - - return total; -} - -/** - * Wraps ProcessTargetString() and handles producing error messages for - * bad targets. - * - * @param client Client who issued command - * @param target Client's target argument - * @param nobots Optional. Set to true if bots should NOT be targetted - * @param immunity Optional. Set to false to ignore target immunity. - * @return Index of target client, or -1 on error. - */ -stock int FindTarget(int client, const char[] target, bool nobots = false, bool immunity = true) -{ - char target_name[MAX_TARGET_LENGTH]; - int target_list[1], target_count; - bool tn_is_ml; - - int flags = COMMAND_FILTER_NO_MULTI; - if (nobots) - { - flags |= COMMAND_FILTER_NO_BOTS; - } - if (!immunity) - { - flags |= COMMAND_FILTER_NO_IMMUNITY; - } - - if ((target_count = ProcessTargetString( - target, - client, - target_list, - 1, - flags, - target_name, - sizeof(target_name), - tn_is_ml)) > 0) - { - return target_list[0]; - } - else - { - ReplyToTargetError(client, target_count); - return -1; - } -} - -/** - * This function is no longer supported. It has been replaced with ReadMapList(), - * which uses a more unified caching and configuration mechanism. This function also - * has a bug where if the cvar contents changes, the fileTime change won't be recognized. - * - * Loads a specified array with maps. The maps will be either loaded from mapcyclefile, or if supplied - * a cvar containing a file name. If the file in the cvar is bad, it will use mapcyclefile. The fileTime - * parameter is used to store a timestamp of the file. If specified, the file will only be reloaded if it - * has changed. - * - * @param array Valid array handle, should be created with CreateArray(33) or larger. - * @param fileTime Variable containing the "last changed" time of the file. Used to avoid needless reloading. - * @param fileCvar CVAR set to the file to be loaded. Optional. - * @return Number of maps loaded or 0 if in error. - */ -#pragma deprecated Use ReadMapList() instead. - stock int LoadMaps(Handle array, int &fileTime = 0, Handle fileCvar = INVALID_HANDLE) - { - char mapPath[256], mapFile[64]; - bool fileFound = false; - - if (fileCvar != INVALID_HANDLE) - { - GetConVarString(fileCvar, mapFile, 64); - BuildPath(Path_SM, mapPath, sizeof(mapPath), mapFile); - fileFound = FileExists(mapPath); - } - - if (!fileFound) - { - Handle mapCycleFile = FindConVar("mapcyclefile"); - GetConVarString(mapCycleFile, mapPath, sizeof(mapPath)); - fileFound = FileExists(mapPath); - } - - if (!fileFound) - { - LogError("Failed to find a file to load maps from. No maps loaded."); - ClearArray(array); - - return 0; - } - - // If the file hasn't changed, there's no reason to reload - // all of the maps. - int newTime = GetFileTime(mapPath, FileTime_LastChange); - if (fileTime == newTime) - { - return GetArraySize(array); - } - - fileTime = newTime; - - ClearArray(array); - - File file = OpenFile(mapPath, "rt"); - if (!file) { - LogError("Could not open file: %s", mapPath); - return 0; - } - - LogMessage("Loading maps from file: %s", mapPath); - - int len; - char buffer[64]; - while (!file.EndOfFile() && file.ReadLine(buffer, sizeof(buffer))) - { - TrimString(buffer); - - if ((len = StrContains(buffer, ".bsp", false)) != -1) - { - buffer[len] = '\0'; - } - - if (buffer[0] == '\0' || !IsValidConVarChar(buffer[0]) || !IsMapValid(buffer)) - { - continue; - } - - if (FindStringInArray(array, buffer) != -1) - { - continue; - } - - PushArrayString(array, buffer); - } - - file.Close(); - return GetArraySize(array); -} diff --git a/scripting/include/keyvalues.inc b/scripting/include/keyvalues.inc deleted file mode 100644 index 134df4d..0000000 --- a/scripting/include/keyvalues.inc +++ /dev/null @@ -1,707 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _keyvalues_included - #endinput -#endif -#define _keyvalues_included - -/** - * KeyValue data value types - */ -enum KvDataTypes -{ - KvData_None = 0, /**< Type could not be identified, or no type */ - KvData_String, /**< String value */ - KvData_Int, /**< Integer value */ - KvData_Float, /**< Floating point value */ - KvData_Ptr, /**< Pointer value (sometimes called "long") */ - KvData_WString, /**< Wide string value */ - KvData_Color, /**< Color value */ - KvData_UInt64, /**< Large integer value */ - /* --- */ - KvData_NUMTYPES, -}; - -methodmap KeyValues < Handle -{ - // Creates a new KeyValues structure. The Handle must be closed with - // CloseHandle() or delete. - // - // @param name Name of the root section. - // @param firstKey If non-empty, specifies the first key value. - // @param firstValue If firstKey is non-empty, specifies the first key's value. - public native KeyValues(const char[] name, const char[] firstKey="", const char[] firstValue=""); - - // Exports a KeyValues tree to a file. The tree is dumped from the current position. - // - // @param file File to dump write to. - // @return True on success, false otherwise. - public native bool ExportToFile(const char[] file); - - // Exports a KeyValues tree to a string. The string is dumped from the current position. - // - // @param buffer Buffer to write to. - // @param maxlength Max length of buffer. - // @return Number of bytes that can be written to buffer. - public native int ExportToString(char[] buffer, int maxlength); - - // Amount of bytes written by ExportToFile & ExportToString. - property int ExportLength { - public native get(); - } - - // Imports a file in KeyValues format. The file is read into the current - // position of the tree. - // - // @param file File to read from. - // @return True on success, false otherwise. - public native bool ImportFromFile(const char[] file); - - // Converts a given string to a KeyValues tree. The string is read into - // the current postion of the tree. - // - // @param buffer String buffer to load into the KeyValues. - // @param resourceName The resource name of the KeyValues, used for error tracking purposes. - // @return True on success, false otherwise. - public native bool ImportFromString(const char[] buffer, const char[] resourceName="StringToKeyValues"); - - // Imports subkeys in the given KeyValues, at the current position in that - // KeyValues, into the current position in this KeyValues. Note that this - // copies keys; it does not embed a reference to them. - // - // @param other Origin KeyValues Handle. - public native void Import(KeyValues other); - - // Sets a string value of a KeyValues key. - // - // @param kv KeyValues Handle. - // @param key Name of the key, or NULL_STRING. - // @param value String value. - public native void SetString(const char[] key, const char[] value); - - // Sets an integer value of a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param value Value number. - public native void SetNum(const char[] key, int value); - - // Sets a large integer value of a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param value Large integer value (0=High bits, 1=Low bits) - public native void SetUInt64(const char[] key, const int value[2]); - - // Sets a floating point value of a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param value Floating point value. - public native void SetFloat(const char[] key, float value); - - // Sets a set of color values of a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param r Red value. - // @param g Green value. - // @param b Blue value. - // @param a Alpha value. - public native void SetColor(const char[] key, int r, int g, int b, int a=0); - - // Sets a set of color values of a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param color Red, green, blue and alpha channels. - public void SetColor4(const char[] key, const int color[4]) { - this.SetColor(key, color[0], color[1], color[2], color[3]); - } - - // Sets a vector value of a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param vec Vector value. - public native void SetVector(const char[] key, const float vec[3]); - - // Retrieves a string value from a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param value Buffer to store key value in. - // @param maxlength Maximum length of the value buffer. - // @param defvalue Optional default value to use if the key is not found. - public native void GetString(const char[] key, char[] value, int maxlength, const char[] defvalue=""); - - // Retrieves an integer value from a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param defvalue Optional default value to use if the key is not found. - // @return Integer value of the key. - public native int GetNum(const char[] key, int defvalue=0); - - // Retrieves a floating point value from a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param defvalue Optional default value to use if the key is not found. - // @return Floating point value of the key. - public native float GetFloat(const char[] key, float defvalue=0.0); - - // Retrieves a set of color values from a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param r Red value, set by reference. - // @param g Green value, set by reference. - // @param b Blue value, set by reference. - // @param a Alpha value, set by reference. - public native void GetColor(const char[] key, int &r, int &g, int &b, int &a); - - // Retrieves a set of color values from a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param color Red, green, blue, and alpha channels. - public void GetColor4(const char[] key, int color[4]) { - int r, g, b, a; - this.GetColor(key, r, g, b, a); - color[0] = r; - color[1] = g; - color[2] = b; - color[3] = a; - } - - // Retrieves a large integer value from a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param value Array to represent the large integer. - // @param defvalue Optional default value to use if the key is not found. - public native void GetUInt64(const char[] key, int value[2], int defvalue[2]={0,0}); - - // Retrieves a vector value from a KeyValues key. - // - // @param key Name of the key, or NULL_STRING. - // @param vec Destination vector to store the value in. - // @param defvalue Optional default value to use if the key is not found. - public native void GetVector(const char[] key, float vec[3], const float defvalue[3]={0.0, 0.0, 0.0}); - - // Sets the current position in the KeyValues tree to the given key. - // - // @param key Name of the key. - // @param create If true, and the key does not exist, it will be created. - // @return True if the key exists, false if it does not and was not created. - public native bool JumpToKey(const char[] key, bool create=false); - - // Sets the current position in the KeyValues tree to the given key. - // - // @param id KeyValues id. - // @return True if the key exists, false if it does not. - public native bool JumpToKeySymbol(int id); - - // Sets the current position in the KeyValues tree to the first sub key. - // This native adds to the internal traversal stack. - // - // @param keyOnly If false, non-keys will be traversed (values). - // @return True on success, false if there was no first sub key. - public native bool GotoFirstSubKey(bool keyOnly=true); - - // Sets the current position in the KeyValues tree to the next sub key. - // This native does NOT add to the internal traversal stack, and thus - // GoBack() is not needed for each successive call to this function. - // - // @param keyOnly If false, non-keys will be traversed (values). - // @return True on success, false if there was no next sub key. - public native bool GotoNextKey(bool keyOnly=true); - - // Saves the current position in the traversal stack onto the traversal - // stack. This can be useful if you wish to use KvGotoNextKey() and - // have the previous key saved for backwards traversal. - // - // @param kv KeyValues Handle. - public native void SavePosition(); - - // Jumps back to the previous position. Returns false if there are no - // previous positions (i.e., at the root node). This should be called - // once for each successful Jump call, in order to return to the top node. - // This function pops one node off the internal traversal stack. - // - // @return True on success, false if there is no higher node. - public native bool GoBack(); - - // Removes the given key from the current position. - // - // @param key Name of the key. - // @return True on success, false if key did not exist. - public native bool DeleteKey(const char[] key); - - // Removes the current sub-key and attempts to set the position - // to the sub-key after the removed one. If no such sub-key exists, - // the position will be the parent key in the traversal stack. - // Given the sub-key having position "N" in the traversal stack, the - // removal will always take place from position "N-1." - // - // @param kv KeyValues Handle. - // @return 1 if removal succeeded and there was another key. - // 0 if the current node was not contained in the - // previous node, or no previous node exists. - // -1 if removal succeeded and there were no more keys, - // thus the state is as if KvGoBack() was called. - public native int DeleteThis(); - - // Sets the position back to the top node, emptying the entire node - // traversal history. This can be used instead of looping KvGoBack() - // if recursive iteration is not important. - // - // @param kv KeyValues Handle. - public native void Rewind(); - - // Retrieves the current section name. - // - // @param section Buffer to store the section name. - // @param maxlength Maximum length of the name buffer. - // @return True on success, false on failure. - public native bool GetSectionName(char[] section, int maxlength); - - // Sets the current section name. - // - // @param section Section name. - public native void SetSectionName(const char[] section); - - // Returns the data type at a key. - // - // @param key Key name. - // @return KvDataType value of the key. - public native KvDataTypes GetDataType(const char[] key); - - // Sets whether or not the KeyValues parser will read escape sequences. - // For example, \n would be read as a literal newline. This defaults - // to false for new KeyValues structures. - // - // @param useEscapes Whether or not to read escape sequences. - public native void SetEscapeSequences(bool useEscapes); - - // Returns the position in the jump stack; I.e. the number of calls - // required for KvGoBack to return to the root node. If at the root node, - // 0 is returned. - // - // @return Number of non-root nodes in the jump stack. - public native int NodesInStack(); - - // Finds a KeyValues name by id. - // - // @param id KeyValues id. - // @param name Buffer to store the name. - // @param maxlength Maximum length of the value buffer. - // @return True on success, false if id not found. - public native bool FindKeyById(int id, char[] name, int maxlength); - - // Finds a KeyValues id inside a KeyValues tree. - // - // @param key Key name. - // @param id Id of the found KeyValue. - // @return True on success, false if key not found. - public native bool GetNameSymbol(const char[] key, int &id); - - // Retrieves the current section id. - // - // @param kv KeyValues Handle. - // @param id Id of the current section. - // @return True on success, false on failure. - public native bool GetSectionSymbol(int &id); -}; - -/** - * Creates a new KeyValues structure. The Handle must always be closed. - * - * @param name Name of the root section. - * @param firstKey If non-empty, specifies the first key value. - * @param firstValue If firstKey is non-empty, specifies the first key's value. - * @return A Handle to a new KeyValues structure. - */ -native KeyValues CreateKeyValues(const char[] name, const char[] firstKey="", const char[] firstValue=""); - -/** - * Sets a string value of a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param value String value. - * @error Invalid Handle. - */ -native void KvSetString(Handle kv, const char[] key, const char[] value); - -/** - * Sets an integer value of a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param value Value number. - * @error Invalid Handle. - */ -native void KvSetNum(Handle kv, const char[] key, int value); - -/** - * Sets a large integer value of a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param value Large integer value (0=High bits, 1=Low bits) - * @error Invalid Handle. - */ -native void KvSetUInt64(Handle kv, const char[] key, const int value[2]); - -/** - * Sets a floating point value of a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param value Floating point value. - * @error Invalid Handle. - */ -native void KvSetFloat(Handle kv, const char[] key, float value); - -/** - * Sets a set of color values of a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param r Red value. - * @param g Green value. - * @param b Blue value. - * @param a Alpha value. - * @error Invalid Handle. - */ -native void KvSetColor(Handle kv, const char[] key, int r, int g, int b, int a=0); - -/** - * Sets a vector value of a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param vec Vector value. - * @error Invalid Handle. - */ -native void KvSetVector(Handle kv, const char[] key, const float vec[3]); - -/** - * Retrieves a string value from a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param value Buffer to store key value in. - * @param maxlength Maximum length of the value buffer. - * @param defvalue Optional default value to use if the key is not found. - * @error Invalid Handle. - */ -native void KvGetString(Handle kv, const char[] key, char[] value, int maxlength, const char[] defvalue=""); - -/** - * Retrieves an integer value from a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param defvalue Optional default value to use if the key is not found. - * @return Integer value of the key. - * @error Invalid Handle. - */ -native int KvGetNum(Handle kv, const char[] key, int defvalue=0); - -/** - * Retrieves a floating point value from a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param defvalue Optional default value to use if the key is not found. - * @return Floating point value of the key. - * @error Invalid Handle. - */ -native float KvGetFloat(Handle kv, const char[] key, float defvalue=0.0); - -/** - * Retrieves a set of color values from a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param r Red value, set by reference. - * @param g Green value, set by reference. - * @param b Blue value, set by reference. - * @param a Alpha value, set by reference. - * @error Invalid Handle. - */ -native void KvGetColor(Handle kv, const char[] key, int &r, int &g, int &b, int &a); - -/** - * Retrieves a large integer value from a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param value Array to represent the large integer. - * @param defvalue Optional default value to use if the key is not found. - * @error Invalid Handle. - */ -native void KvGetUInt64(Handle kv, const char[] key, int value[2], int defvalue[2]={0,0}); - -/** - * Retrieves a vector value from a KeyValues key. - * - * @param kv KeyValues Handle. - * @param key Name of the key, or NULL_STRING. - * @param vec Destination vector to store the value in. - * @param defvalue Optional default value to use if the key is not found. - * @error Invalid Handle. - */ -native void KvGetVector(Handle kv, const char[] key, float vec[3], const float defvalue[3]={0.0, 0.0, 0.0}); - -/** - * Sets the current position in the KeyValues tree to the given key. - * - * @param kv KeyValues Handle. - * @param key Name of the key. - * @param create If true, and the key does not exist, it will be created. - * @return True if the key exists, false if it does not and was not created. - */ -native bool KvJumpToKey(Handle kv, const char[] key, bool create=false); - -/** - * Sets the current position in the KeyValues tree to the given key. - * - * @param kv KeyValues Handle. - * @param id KeyValues id. - * @return True if the key exists, false if it does not. - */ -native bool KvJumpToKeySymbol(Handle kv, int id); - -/** - * Sets the current position in the KeyValues tree to the first sub key. - * This native adds to the internal traversal stack. - * - * @param kv KeyValues Handle. - * @param keyOnly If false, non-keys will be traversed (values). - * @return True on success, false if there was no first sub key. - * @error Invalid Handle. - */ -native bool KvGotoFirstSubKey(Handle kv, bool keyOnly=true); - -/** - * Sets the current position in the KeyValues tree to the next sub key. - * This native does NOT add to the internal traversal stack, and thus - * KvGoBack() is not needed for each successive call to this function. - * - * @param kv KeyValues Handle. - * @param keyOnly If false, non-keys will be traversed (values). - * @return True on success, false if there was no next sub key. - * @error Invalid Handle. - */ -native bool KvGotoNextKey(Handle kv, bool keyOnly=true); - -/** - * Saves the current position in the traversal stack onto the traversal - * stack. This can be useful if you wish to use KvGotoNextKey() and - * have the previous key saved for backwards traversal. - * - * @param kv KeyValues Handle. - * @error Invalid Handle. - */ -native void KvSavePosition(Handle kv); - -/** - * Removes the given key from the current position. - * - * @param kv KeyValues Handle. - * @param key Name of the key. - * @return True on success, false if key did not exist. - * @error Invalid Handle. - */ -native bool KvDeleteKey(Handle kv, const char[] key); - -/** - * Removes the current sub-key and attempts to set the position - * to the sub-key after the removed one. If no such sub-key exists, - * the position will be the parent key in the traversal stack. - * Given the sub-key having position "N" in the traversal stack, the - * removal will always take place from position "N-1." - * - * @param kv KeyValues Handle. - * @return 1 if removal succeeded and there was another key. - * 0 if the current node was not contained in the - * previous node, or no previous node exists. - * -1 if removal succeeded and there were no more keys, - * thus the state is as if KvGoBack() was called. - * @error Invalid Handle. - */ -native int KvDeleteThis(Handle kv); - -/** - * Jumps back to the previous position. Returns false if there are no - * previous positions (i.e., at the root node). This should be called - * once for each successful Jump call, in order to return to the top node. - * This function pops one node off the internal traversal stack. - * - * @param kv KeyValues Handle. - * @return True on success, false if there is no higher node. - * @error Invalid Handle. - */ -native bool KvGoBack(Handle kv); - -/** - * Sets the position back to the top node, emptying the entire node - * traversal history. This can be used instead of looping KvGoBack() - * if recursive iteration is not important. - * - * @param kv KeyValues Handle. - * @error Invalid Handle. - */ -native void KvRewind(Handle kv); - -/** - * Retrieves the current section name. - * - * @param kv KeyValues Handle. - * @param section Buffer to store the section name. - * @param maxlength Maximum length of the name buffer. - * @return True on success, false on failure. - * @error Invalid Handle. - */ -native bool KvGetSectionName(Handle kv, char[] section, int maxlength); - -/** - * Sets the current section name. - * - * @param kv KeyValues Handle. - * @param section Section name. - * @error Invalid Handle. - */ -native void KvSetSectionName(Handle kv, const char[] section); - -/** - * Returns the data type at a key. - * - * @param kv KeyValues Handle. - * @param key Key name. - * @return KvDataType value of the key. - * @error Invalid Handle. - */ -native KvDataTypes KvGetDataType(Handle kv, const char[] key); - -/** - * Converts a KeyValues tree to a file. The tree is dumped - * from the current position. - * - * @param kv KeyValues Handle. - * @param file File to dump write to. - * @return True on success, false otherwise. - * @error Invalid Handle. - */ -native bool KeyValuesToFile(Handle kv, const char[] file); - -/** - * Converts a file to a KeyValues tree. The file is read into - * the current position of the tree. - * - * @param kv KeyValues Handle. - * @param file File to read from. - * @return True on success, false otherwise. - * @error Invalid Handle. - */ -native bool FileToKeyValues(Handle kv, const char[] file); - -/** - * Converts a given string to a KeyValues tree. The string is read into - * the current postion of the tree. - * - * @param kv KeyValues Handle. - * @param buffer String buffer to load into the KeyValues. - * @param resourceName The resource name of the KeyValues, used for error tracking purposes. - * @return True on success, false otherwise. - * @error Invalid Handle. - */ -native bool StringToKeyValues(Handle kv, const char[] buffer, const char[] resourceName="StringToKeyValues"); - -/** - * Sets whether or not the KeyValues parser will read escape sequences. - * For example, \n would be read as a literal newline. This defaults - * to false for new KeyValues structures. - * - * @param kv KeyValues Handle. - * @param useEscapes Whether or not to read escape sequences. - * @error Invalid Handle. - */ -native void KvSetEscapeSequences(Handle kv, bool useEscapes); - -/** - * Returns the position in the jump stack; I.e. the number of calls - * required for KvGoBack to return to the root node. If at the root node, - * 0 is returned. - * - * @param kv KeyValues Handle. - * @return Number of non-root nodes in the jump stack. - * @error Invalid Handle. - */ -native int KvNodesInStack(Handle kv); - -/** - * Makes a new copy of all subkeys in the origin KeyValues to - * the destination KeyValues. - * NOTE: All KeyValues are processed from the current location not the root one. - * - * @param origin Origin KeyValues Handle. - * @param dest Destination KeyValues Handle. - * @error Invalid Handle. - */ -native void KvCopySubkeys(Handle origin, Handle dest); - -/** - * Finds a KeyValues name by id. - * - * @param kv KeyValues Handle. - * @param id KeyValues id. - * @param name Buffer to store the name. - * @param maxlength Maximum length of the value buffer. - * @return True on success, false if id not found. - * @error Invalid Handle. - */ -native bool KvFindKeyById(Handle kv, int id, char[] name, int maxlength); - -/** - * Finds a KeyValues id inside a KeyValues tree. - * - * @param kv KeyValues Handle. - * @param key Key name. - * @param id Id of the found KeyValue. - * @return True on success, false if key not found. - * @error Invalid Handle. - */ -native bool KvGetNameSymbol(Handle kv, const char[] key, int &id); - -/** - * Retrieves the current section id. - * - * @param kv KeyValues Handle. - * @param id Id of the current section. - * @return True on success, false on failure. - * @error Invalid Handle. - */ -native bool KvGetSectionSymbol(Handle kv, int &id); diff --git a/scripting/include/lang.inc b/scripting/include/lang.inc deleted file mode 100644 index b92bdb3..0000000 --- a/scripting/include/lang.inc +++ /dev/null @@ -1,134 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _lang_included - #endinput -#endif -#define _lang_included - -#define LANG_SERVER 0 /**< Translate using the server's language */ - -/** - * Loads a translation file for the plugin calling this native. - * If no extension is specified, .txt is assumed. - * - * @param file Translation file. - */ -native void LoadTranslations(const char[] file); - -/** - * Sets the global language target. This is useful for creating functions - * that will be compatible with the %t format specifier. Note that invalid - * indexes can be specified but the error will occur during translation, - * not during this function call. - * - * @param client Client index or LANG_SERVER. - */ -native void SetGlobalTransTarget(int client); - -/** - * Retrieves the language number of a client. - * - * @param client Client index. - * @return Language number client is using. - * @error Invalid client index or client not connected. - */ -native int GetClientLanguage(int client); - -/** - * Retrieves the server's language. - * - * @return Language number server is using. - */ -native int GetServerLanguage(); - -/** - * Returns the number of languages known in languages.cfg. - * - * @return Language count. - */ -native int GetLanguageCount(); - -/** - * Retrieves info about a given language number. - * - * @param language Language number. - * @param code Language code buffer (2-3 characters usually). - * @param codeLen Maximum length of the language code buffer. - * @param name Language name buffer. - * @param nameLen Maximum length of the language name buffer. - * @error Invalid language number. - */ -native void GetLanguageInfo(int language, char[] code="", int codeLen=0, char[] name="", int nameLen=0); - -/** - * Sets the language number of a client. - * - * @param client Client index. - * @param language Language number. - * @error Invalid client index or client not connected. - */ -native void SetClientLanguage(int client, int language); - -/** - * Retrieves the language number from a language code. - * - * @param code Language code (2-3 characters usually). - * @return Language number. -1 if not found. - */ -native int GetLanguageByCode(const char[] code); - -/** - * Retrieves the language number from a language name. - * - * @param name Language name (case insensitive). - * @return Language number. -1 if not found. - */ -native int GetLanguageByName(const char[] name); - -/** - * Determines if the specified phrase exists within the plugin's - * translation cache. - * - * @param phrase Phrase to look for. - * @return True if phrase exists. - */ -native bool TranslationPhraseExists(const char[] phrase); - -/** - * Determines if there is a translation for the specified language. - * - * @param phrase Phrase to check. - * @param language Language number. - * @return True if translation exists. - */ -native bool IsTranslatedForLanguage(const char[] phrase, int language); diff --git a/scripting/include/logging.inc b/scripting/include/logging.inc deleted file mode 100644 index 2683dda..0000000 --- a/scripting/include/logging.inc +++ /dev/null @@ -1,135 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sm_logging_included - #endinput -#endif -#define _sm_logging_included - -/** - * Logs a plugin message to the SourceMod logs. The log message will be - * prefixed by the plugin's logtag (filename). - * - * @param format String format. - * @param ... Format arguments. - */ -native void LogMessage(const char[] format, any ...); - -/** - * Logs a message to any file. The log message will be in the normal - * SourceMod format, with the plugin logtag prepended. - * - * @param file File to write the log message in. - * @param format String format. - * @param ... Format arguments. - * @error File could not be opened/written. - */ -native void LogToFile(const char[] file, const char[] format, any ...); - -/** - * Same as LogToFile(), except no plugin logtag is prepended. - * - * @param file File to write the log message in. - * @param format String format. - * @param ... Format arguments. - * @error File could not be opened/written. - */ -native void LogToFileEx(const char[] file, const char[] format, any ...); - -/** - * Logs an action from a command or event whereby interception and routing may - * be important. This is intended to be a logging version of ShowActivity(). - * - * @param client Client performing the action, 0 for server, or -1 if not - * applicable. - * @param target Client being targetted, or -1 if not applicable. - * @param message Message format. - * @param ... Message formatting parameters. - */ -native void LogAction(int client, int target, const char[] message, any ...); - -/** - * Logs a plugin error message to the SourceMod logs. - * - * @param format String format. - * @param ... Format arguments. - */ -native void LogError(const char[] format, any ...); - -/** - * Called when an action is going to be logged. - * - * @param source Handle to the object logging the action, or INVALID_HANDLE - * if Core is logging the action. - * @param ident Type of object logging the action (plugin, ext, or core). - * @param client Client the action is from; 0 for server, -1 if not applicable. - * @param target Client the action is targetting, or -1 if not applicable. - * @param message Message that is being logged. - * @return Plugin_Continue will perform the default logging behavior. - * Plugin_Handled will stop Core from logging the message. - * Plugin_Stop is the same as Handled, but prevents any other - * plugins from handling the message. - */ -forward Action OnLogAction(Handle source, - Identity ident, - int client, - int target, - const char[] message); - -/** - * Called when a game log message is received. - * - * Any Log*() functions called within this callback will not recursively - * pass through. That is, they will log directly, bypassing this callback. - * - * Note that this does not capture log messages from the engine. It only - * captures log messages being sent from the game/mod itself. - * - * @param message Message contents. - * @return Plugin_Handled or Plugin_Stop will prevent the message - * from being written to the log file. - */ -typedef GameLogHook = function Action (const char[] message); - -/** - * Adds a game log hook. - * - * @param hook Hook function. - */ -native void AddGameLogHook(GameLogHook hook); - -/** - * Removes a game log hook. - * - * @param hook Hook function. - */ -native void RemoveGameLogHook(GameLogHook hook); diff --git a/scripting/include/mapchooser.inc b/scripting/include/mapchooser.inc deleted file mode 100644 index 173faf2..0000000 --- a/scripting/include/mapchooser.inc +++ /dev/null @@ -1,159 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ -#if defined _mapchooser_included_ - #endinput -#endif -#define _mapchooser_included_ - -enum NominateResult -{ - Nominate_Added, /** The map was added to the nominate list */ - Nominate_Replaced, /** A clients existing nomination was replaced */ - Nominate_AlreadyInVote, /** Specified map was already in the vote */ - Nominate_InvalidMap, /** Mapname specified wasn't a valid map */ - Nominate_VoteFull, /** This will only occur if force was set to false */ -}; - -enum MapChange -{ - MapChange_Instant, /** Change map as soon as the voting results have come in */ - MapChange_RoundEnd, /** Change map at the end of the round */ - MapChange_MapEnd, /** Change the sm_nextmap cvar */ -}; - -/** - * Attempt to add a map to the mapchooser map list. - * - * @param map Map to add. - * @param force Should we force the map in even if it requires overwriting an existing nomination? - * @param owner Client index of the nominator. If the client disconnects the nomination will be removed. Use 0 for constant nominations - * @return Nominate Result of the outcome - */ -native NominateResult NominateMap(const char[] map, bool force, int owner); - -/** - * Attempt to remove a map from the mapchooser map list. - * - * @param map Map to remove. - * @return True if the nomination was found and removed, or false if the nomination was not found. - */ -native bool RemoveNominationByMap(const char[] map); - -/** - * Attempt to remove a map from the mapchooser map list. - * - * @param owner Client index of the nominator. - * @return True if the nomination was found and removed, or false if the nomination was not found. - */ -native bool RemoveNominationByOwner(int owner); - -/** - * Gets the current list of excluded maps. - * - * @param array An ADT array handle to add the map strings to. - */ -native void GetExcludeMapList(ArrayList array); - -/** - * Gets the current list of nominated maps. - * - * @param maparray An ADT array handle to add the map strings to. - * @param ownerarray An optional ADT array handle to add the nominator client indexes to. - */ -native void GetNominatedMapList(ArrayList maparray, ArrayList ownerarray = null); - -/** - * Checks if MapChooser will allow a vote - * - * @return True if a vote can be held, or false if mapchooser is already holding a vote. - */ -native bool CanMapChooserStartVote(); - -/** - * Initiates a MapChooser map vote - * - * Note: If no input array is specified mapchooser will use its internal list. This includes - * any nominations and excluded maps (as per mapchoosers convars). - * - * @param when MapChange consant of when the resulting mapchange should occur. - * @param inputarray ADT array list of maps to add to the vote. - */ -native void InitiateMapChooserVote(MapChange when, ArrayList inputarray=null); - -/** - * Checks if MapChooser's end of map vote has completed. - * - * @return True if complete, false otherwise. - */ -native bool HasEndOfMapVoteFinished(); - -/** - * Checks if MapChooser is set to run an end of map vote. - * - * @return True if enabled, false otherwise. - */ -native bool EndOfMapVoteEnabled(); - -/** - * Called when mapchooser removes a nomination from its list. - * Nominations cleared on map start will not trigger this forward - */ -forward void OnNominationRemoved(const char[] map, int owner); - -/** - * Called when mapchooser starts a Map Vote. - */ -forward void OnMapVoteStarted(); - -public SharedPlugin __pl_mapchooser = -{ - name = "mapchooser", - file = "mapchooser.smx", -#if defined REQUIRE_PLUGIN - required = 1, -#else - required = 0, -#endif -}; - -public void __pl_mapchooser_SetNTVOptional() -{ - MarkNativeAsOptional("NominateMap"); - MarkNativeAsOptional("RemoveNominationByMap"); - MarkNativeAsOptional("RemoveNominationByOwner"); - MarkNativeAsOptional("GetExcludeMapList"); - MarkNativeAsOptional("GetNominatedMapList"); - MarkNativeAsOptional("CanMapChooserStartVote"); - MarkNativeAsOptional("InitiateMapChooserVote"); - MarkNativeAsOptional("HasEndOfMapVoteFinished"); - MarkNativeAsOptional("EndOfMapVoteEnabled"); -} diff --git a/scripting/include/menus.inc b/scripting/include/menus.inc deleted file mode 100644 index 604502e..0000000 --- a/scripting/include/menus.inc +++ /dev/null @@ -1,1121 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _menus_included - #endinput -#endif -#define _menus_included - -/** - * Low-level drawing style of the menu. - */ -enum MenuStyle -{ - MenuStyle_Default = 0, /**< The "default" menu style for the mod */ - MenuStyle_Valve = 1, /**< The Valve provided menu style (Used on HL2DM) */ - MenuStyle_Radio = 2, /**< The simpler menu style commonly used on CS:S */ -}; - -/** - * Different actions for the menu "pump" callback - */ -enum MenuAction -{ - MenuAction_Start = (1<<0), /**< A menu has been started (nothing passed) */ - MenuAction_Display = (1<<1), /**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */ - MenuAction_Select = (1<<2), /**< An item was selected (param1=client, param2=item) */ - MenuAction_Cancel = (1<<3), /**< The menu was cancelled (param1=client, param2=reason) */ - MenuAction_End = (1<<4), /**< A menu display has fully ended. - param1 is the MenuEnd reason, and if it's MenuEnd_Cancelled, then - param2 is the MenuCancel reason from MenuAction_Cancel. - */ - MenuAction_VoteEnd = (1<<5), /**< (VOTE ONLY): A vote sequence has succeeded (param1=chosen item) - This is not called if SetVoteResultCallback has been used on the menu. */ - MenuAction_VoteStart = (1<<6), /**< (VOTE ONLY): A vote sequence has started (nothing passed) */ - MenuAction_VoteCancel = (1<<7), /**< (VOTE ONLY): A vote sequence has been cancelled (param1=reason) */ - MenuAction_DrawItem = (1<<8), /**< An item is being drawn; return the new style (param1=client, param2=item) */ - MenuAction_DisplayItem = (1<<9),/**< Item text is being drawn to the display (param1=client, param2=item) - To change the text, use RedrawMenuItem(). - If you do so, return its return value. Otherwise, return 0. - */ -}; - -/** Default menu actions */ -#define MENU_ACTIONS_DEFAULT MenuAction_Select|MenuAction_Cancel|MenuAction_End -/** All menu actions */ -#define MENU_ACTIONS_ALL view_as(0xFFFFFFFF) - -#define MENU_NO_PAGINATION 0 /**< Menu should not be paginated (10 items max) */ -#define MENU_TIME_FOREVER 0 /**< Menu should be displayed as long as possible */ - -#define ITEMDRAW_DEFAULT (0) /**< Item should be drawn normally */ -#define ITEMDRAW_DISABLED (1<<0) /**< Item is drawn but not selectable */ -#define ITEMDRAW_RAWLINE (1<<1) /**< Item should be a raw line, without a slot */ -#define ITEMDRAW_NOTEXT (1<<2) /**< No text should be drawn */ -#define ITEMDRAW_SPACER (1<<3) /**< Item should be drawn as a spacer, if possible */ -#define ITEMDRAW_IGNORE ((1<<1)|(1<<2)) /**< Item should be completely ignored (rawline + notext) */ -#define ITEMDRAW_CONTROL (1<<4) /**< Item is control text (back/next/exit) */ - -#define MENUFLAG_BUTTON_EXIT (1<<0) /**< Menu has an "exit" button (default if paginated) */ -#define MENUFLAG_BUTTON_EXITBACK (1<<1) /**< Menu has an "exit back" button */ -#define MENUFLAG_NO_SOUND (1<<2) /**< Menu will not have any select sounds */ -#define MENUFLAG_BUTTON_NOVOTE (1<<3) /**< Menu has a "No Vote" button at slot 1 */ - -#define VOTEINFO_CLIENT_INDEX 0 /**< Client index */ -#define VOTEINFO_CLIENT_ITEM 1 /**< Item the client selected, or -1 for none */ -#define VOTEINFO_ITEM_INDEX 0 /**< Item index */ -#define VOTEINFO_ITEM_VOTES 1 /**< Number of votes for the item */ - -#define VOTEFLAG_NO_REVOTES (1<<0) /**< Players cannot change their votes */ - -/** - * Reasons a menu can be cancelled (MenuAction_Cancel). - */ -enum -{ - MenuCancel_Disconnected = -1, /**< Client dropped from the server */ - MenuCancel_Interrupted = -2, /**< Client was interrupted with another menu */ - MenuCancel_Exit = -3, /**< Client exited via "exit" */ - MenuCancel_NoDisplay = -4, /**< Menu could not be displayed to the client */ - MenuCancel_Timeout = -5, /**< Menu timed out */ - MenuCancel_ExitBack = -6, /**< Client selected "exit back" on a paginated menu */ -}; - -/** - * Reasons a vote can be cancelled (MenuAction_VoteCancel). - */ -enum -{ - VoteCancel_Generic = -1, /**< Vote was generically cancelled. */ - VoteCancel_NoVotes = -2, /**< Vote did not receive any votes. */ -}; - -/** - * Reasons a menu ended (MenuAction_End). - */ -enum -{ - MenuEnd_Selected = 0, /**< Menu item was selected */ - MenuEnd_VotingDone = -1, /**< Voting finished */ - MenuEnd_VotingCancelled = -2, /**< Voting was cancelled */ - MenuEnd_Cancelled = -3, /**< Menu was cancelled (reason in param2) */ - MenuEnd_Exit = -4, /**< Menu was cleanly exited via "exit" */ - MenuEnd_ExitBack = -5, /**< Menu was cleanly exited via "back" */ -}; - -/** - * Describes a menu's source - */ -enum MenuSource -{ - MenuSource_None = 0, /**< No menu is being displayed */ - MenuSource_External = 1, /**< External menu */ - MenuSource_Normal = 2, /**< A basic menu is being displayed */ - MenuSource_RawPanel = 3, /**< A display is active, but it is not tied to a menu */ -}; - -/** - * Called when a menu action is completed. - * - * @param menu The menu being acted upon. - * @param action The action of the menu. - * @param param1 First action parameter (usually the client). - * @param param2 Second action parameter (usually the item). - */ -typedef MenuHandler = function int (Menu menu, MenuAction action, int param1, int param2); - -// Panels are used for drawing raw menus without any extra helper functions. -// Handles must be closed via delete or CloseHandle(). -methodmap Panel < Handle -{ - // Constructor for a new Panel. - // - // @param hStyle MenuStyle Handle, or null to use the default style. - public native Panel(Handle hStyle = null); - - // Sets the panel's title. - // - // @param text Text to set as the title. - // @param onlyIfEmpty If true, the title will only be set if no title is set. - public native void SetTitle(const char[] text, bool onlyIfEmpty=false); - - // Draws an item on a panel. If the item takes up a slot, the position - // is returned. - // - // @param text Display text to use. If not a raw line, - // the style may automatically add color markup. - // No numbering or newlines are needed. - // @param style ITEMDRAW style flags. - // @return A slot position, or 0 if item was a rawline or could not be drawn. - public native int DrawItem(const char[] text, int style=ITEMDRAW_DEFAULT); - - // Draws a raw line of text on a panel, without any markup other than a - // newline. - // - // @param text Display text to use. - // @return True on success, false if raw lines are not supported. - public native bool DrawText(const char[] text); - - // Returns whether or not the given drawing flags are supported by - // the menu style. - // - // @param style ITEMDRAW style flags. - // @return True if item is drawable, false otherwise. - public native bool CanDrawFlags(int style); - - // Sets the selectable key map of a panel. This is not supported by - // all styles (only by Radio, as of this writing). - // - // @param keys An integer where each bit N allows key - // N+1 to be selected. If no keys are selectable, - // then key 0 (bit 9) is automatically set. - // @return True if supported, false otherwise. - public native bool SetKeys(int keys); - - // Sends a panel to a client. Unlike full menus, the handler - // function will only receive the following actions, both of - // which will have null for a menu, and the client as param1. - // - // MenuAction_Select (param2 will be the key pressed) - // MenuAction_Cancel (param2 will be the reason) - // - // Also, if the menu fails to display, no callbacks will be called. - // - // @param client A client to draw to. - // @param handler The MenuHandler function to catch actions with. - // @param time Time to hold the menu for. - // @return True on success, false on failure. - public native bool Send(int client, MenuHandler handler, int time); - - // Returns the amount of text the menu can still hold. If this is - // limit is reached or overflowed, the text is silently truncated. - // - // Radio menus: Currently 511 characters (512 bytes). - // Valve menus: Currently -1 (no meaning). - property int TextRemaining { - public native get(); - } - - // Returns or sets the current key position, starting at 1. This cannot be - // used to traverse backwards. - property int CurrentKey { - public native get(); - public native set(int key); - } - - // Returns the panel's style. Style handles are global and cannot be closed. - property Handle Style { - public native get(); - } -}; - -// A menu is a helper object for managing in-game menus. -methodmap Menu < Handle -{ - // Creates a new, empty menu using the default style. - // - // @param handler Function which will receive menu actions. - // @param actions Optionally set which actions to receive. Select, - // Cancel, and End will always be received regardless - // of whether they are set or not. They are also - // the only default actions. - public native Menu(MenuHandler handler, MenuAction actions=MENU_ACTIONS_DEFAULT); - - // Displays a menu to a client. - // - // @param client Client index. - // @param time Maximum time to leave menu on the screen. - // @return True on success, false on failure. - // @error Client not in game. - public native bool Display(int client, int time); - - // Displays a menu to a client, starting from the given item. - // - // @param client Client index. - // @param first_item First item to begin drawing from. - // @param time Maximum time to leave menu on the screen. - // @return True on success, false on failure. - // @error Client not in game. - /// - public native bool DisplayAt(int client, int first_item, int time); - - // Appends a new item to the end of a menu. - // - // @param info Item information string. - // @param display Default item display string. - // @param style Drawing style flags. Anything other than DEFAULT or - // DISABLED will be completely ignored when paginating. - // @return True on success, false on failure. - // @error Item limit reached. - public native bool AddItem(const char[] info, const char[] display, int style=ITEMDRAW_DEFAULT); - - // Inserts an item into the menu before a certain position; the new item will - // be at the given position and all next items pushed forward. - // - // @param position Position, starting from 0. - // @param info Item information string. - // @param display Default item display string. - // @param style Drawing style flags. Anything other than DEFAULT or - // DISABLED will be completely ignored when paginating. - // @return True on success, false on failure. - // @error Invalid menu position. - public native bool InsertItem(int position, const char[] info, - const char[] display, int style=ITEMDRAW_DEFAULT); - - // Removes an item from the menu. - // - // @param position Position, starting from 0. - // @return True on success, false on failure. - // @error Invalid menu position. - public native bool RemoveItem(int position); - - // Removes all items from a menu. - public native void RemoveAllItems(); - - // Retrieves information about a menu item. - // - // @param position Position, starting from 0. - // @param infoBuf Info buffer. - // @param infoBufLen Maximum length of the info buffer. - // @param style By-reference variable to store drawing flags. - // @param dispBuf Display buffer. - // @param dispBufLen Maximum length of the display buffer. - // @return True on success, false if position is invalid. - public native bool GetItem(int position, char[] infoBuf, int infoBufLen, - int &style=0, char[] dispBuf="", int dispBufLen=0); - - // Sets the menu's default title/instruction message. - // - // @param fmt Message string format - // @param ... Message string arguments. - public native void SetTitle(const char[] fmt, any ...); - - // Returns the text of a menu's title. - // - // @param menu Menu Handle. - // @param buffer Buffer to store title. - // @param maxlength Maximum length of the buffer. - // @return Number of bytes written. - public native void GetTitle(char[] buffer, int maxlength); - - // Creates a raw MenuPanel based off the menu's style. - // The Handle must be freed with CloseHandle(). - // - // @param menu Menu Handle. - // @return A new MenuPanel Handle. - public native Panel ToPanel(); - - // Cancels a menu from displaying on all clients. While the - // cancellation is in progress, this menu cannot be re-displayed - // to any clients. - // - // The menu may still exist on the client's screen after this command. - // This simply verifies that the menu is not being used anywhere. - // - // If any vote is in progress on a menu, it will be cancelled. - public native void Cancel(); - - // Broadcasts a menu to a list of clients. The most selected item will be - // returned through MenuAction_End. On a tie, a random item will be returned - // from a list of the tied items. - // - // Note that MenuAction_VoteEnd and MenuAction_VoteStart are both - // default callbacks and do not need to be enabled. - // - // @param clients Array of clients to broadcast to. - // @param numClients Number of clients in the array. - // @param time Maximum time to leave menu on the screen. - // @param flags Optional voting flags. - // @return True on success, false if this menu already has a - // vote session in progress. - // @error A vote is already in progress. - public native bool DisplayVote(int[] clients, int numClients, int time, int flags=0); - - // Sends a vote menu to all clients. See VoteMenu() for more information. - // - // @param time Maximum time to leave menu on the screen. - // @param flags Optional voting flags. - // @return True on success, false if this menu already has a - // vote session in progress. - public bool DisplayVoteToAll(int time, int flags=0) { - int total = 0; - int[] players = new int[MaxClients]; - for (int i = 1; i <= MaxClients; i++) { - if (!IsClientInGame(i) || IsFakeClient(i)) - continue; - players[total++] = i; - } - return this.DisplayVote(players, total, time, flags); - } - - // Get or set the menu's pagination. - // - // If pagination is MENU_NO_PAGINATION, and the exit button flag is set, - // then the exit button flag is removed. It can be re-applied if desired. - property int Pagination { - public native get(); - public native set(int value); - } - - // Get or set the menu's option flags. - // - // If a certain bit is not supported, it will be stripped before being set. - property int OptionFlags { - public native get(); - public native set(int value); - } - - // Returns whether or not the menu has an exit button. By default, menus - // have an exit button. - property bool ExitButton { - public native get(); - public native set(bool value); - } - - // Controls whether or not the menu has an "exit back" button. By default, - // menus do not have an exit back button. - // - // Exit Back buttons appear as "Back" on page 1 of paginated menus and have - // functionality defined by the user in MenuEnd_ExitBack. - property bool ExitBackButton { - public native get(); - public native set(bool value); - } - - // Sets whether or not the menu has a "no vote" button in slot 1. - // By default, menus do not have a no vote button. - property bool NoVoteButton { - public native set(bool value); - } - - // Sets an advanced vote handling callback. If this callback is set, - // MenuAction_VoteEnd will not be called. - property VoteHandler VoteResultCallback { - public native set(VoteHandler handler); - } - - // Returns the number of items in a menu. - property int ItemCount { - public native get(); - } - - // Returns the menu style. The Handle is global and cannot be closed. - property Handle Style { - public native get(); - } - - // Returns the first item on the page of a currently selected menu. - // - // This is only valid inside a MenuAction_Select callback. - property int Selection { - public native get(); - } -} - -/** - * Creates a new, empty menu using the default style. - * - * @param handler Function which will receive menu actions. - * @param actions Optionally set which actions to receive. Select, - * Cancel, and End will always be received regardless - * of whether they are set or not. They are also - * the only default actions. - * @return A new menu Handle. - */ -native Menu CreateMenu(MenuHandler handler, MenuAction actions=MENU_ACTIONS_DEFAULT); - -/** - * Displays a menu to a client. - * - * @param menu Menu Handle. - * @param client Client index. - * @param time Maximum time to leave menu on the screen. - * @return True on success, false on failure. - * @error Invalid Handle or client not in game. - */ -native bool DisplayMenu(Handle menu, int client, int time); - -/** - * Displays a menu to a client, starting from the given item. - * - * @param menu Menu Handle. - * @param client Client index. - * @param first_item First item to begin drawing from. - * @param time Maximum time to leave menu on the screen. - * @return True on success, false on failure. - * @error Invalid Handle or client not in game. - */ -native bool DisplayMenuAtItem(Handle menu, int client, int first_item, int time); - -/** - * Appends a new item to the end of a menu. - * - * @param menu Menu Handle. - * @param info Item information string. - * @param display Default item display string. - * @param style Drawing style flags. Anything other than DEFAULT or - * DISABLED will be completely ignored when paginating. - * @return True on success, false on failure. - * @error Invalid Handle or item limit reached. - */ -native bool AddMenuItem(Handle menu, - const char[] info, - const char[] display, - int style=ITEMDRAW_DEFAULT); - -/** - * Inserts an item into the menu before a certain position; the new item will - * be at the given position and all next items pushed forward. - * - * @param menu Menu Handle. - * @param position Position, starting from 0. - * @param info Item information string. - * @param display Default item display string. - * @param style Drawing style flags. Anything other than DEFAULT or - * DISABLED will be completely ignored when paginating. - * @return True on success, false on failure. - * @error Invalid Handle or menu position. - */ -native bool InsertMenuItem(Handle menu, - position, - const char[] info, - const char[] display, - int style=ITEMDRAW_DEFAULT); - -/** - * Removes an item from the menu. - * - * @param menu Menu Handle. - * @param position Position, starting from 0. - * @return True on success, false on failure. - * @error Invalid Handle or menu position. - */ -native bool RemoveMenuItem(Handle menu, int position); - -/** - * Removes all items from a menu. - * - * @param menu Menu Handle. - * @error Invalid Handle or menu position. - */ -native void RemoveAllMenuItems(Handle menu); - -/** - * Retrieves information about a menu item. - * - * @param menu Menu Handle. - * @param position Position, starting from 0. - * @param infoBuf Info buffer. - * @param infoBufLen Maximum length of the info buffer. - * @param style By-reference variable to store drawing flags. - * @param dispBuf Display buffer. - * @param dispBufLen Maximum length of the display buffer. - * @return True on success, false if position is invalid. - * @error Invalid Handle. - */ -native bool GetMenuItem(Handle menu, - int position, - char[] infoBuf, - int infoBufLen, - int &style=0, - char[] dispBuf="", - int dispBufLen=0); - -/** - * Returns the first item on the page of a currently selected menu. - * - * This is only valid inside a MenuAction_Select callback. - * - * @return First item number on the page the client was viewing - * before selecting the item in the callback. This can - * be used to re-display the menu from the original - * position. - * @error Not called from inside a MenuAction_Select callback. - */ -native int GetMenuSelectionPosition(); - -/** - * Returns the number of items in a menu. - * - * @param menu Menu Handle. - * @return Number of items in the menu. - * @error Invalid Handle. - */ -native int GetMenuItemCount(Handle menu); - -/** - * Sets whether the menu should be paginated or not. - * - * If itemsPerPage is MENU_NO_PAGINATION, and the exit button flag is set, - * then the exit button flag is removed. It can be re-applied if desired. - * - * @param menu Handle to the menu. - * @param itemsPerPage Number of items per page, or MENU_NO_PAGINATION. - * @return True on success, false if pagination is too high or - * low. - * @error Invalid Handle. - */ -native bool SetMenuPagination(Handle menu, int itemsPerPage); - -/** - * Returns a menu's pagination setting. - * - * @param menu Handle to the menu. - * @return Pagination setting. - * @error Invalid Handle. - */ -native int GetMenuPagination(Handle menu); - -/** - * Returns a menu's MenuStyle Handle. The Handle - * is global and cannot be freed. - * - * @param menu Handle to the menu. - * @return Handle to the menu's draw style. - * @error Invalid Handle. - */ -native Handle GetMenuStyle(Handle menu); - -/** - * Sets the menu's default title/instruction message. - * - * @param menu Menu Handle. - * @param fmt Message string format - * @param ... Message string arguments. - * @error Invalid Handle. - */ -native void SetMenuTitle(Handle menu, const char[] fmt, any ...); - -/** - * Returns the text of a menu's title. - * - * @param menu Menu Handle. - * @param buffer Buffer to store title. - * @param maxlength Maximum length of the buffer. - * @return Number of bytes written. - * @error Invalid Handle/ - */ -native int GetMenuTitle(Handle menu, char[] buffer, int maxlength); - -/** - * Creates a raw MenuPanel based off the menu's style. - * The Handle must be freed with CloseHandle(). - * - * @param menu Menu Handle. - * @return A new MenuPanel Handle. - * @error Invalid Handle. - */ -native Panel CreatePanelFromMenu(Handle menu); - -/** - * Returns whether or not the menu has an exit button. - * By default, menus have an exit button. - * - * @param menu Menu Handle. - * @return True if the menu has an exit button; false otherwise. - * @error Invalid Handle. - */ -native bool GetMenuExitButton(Handle menu); - -/** - * Sets whether or not the menu has an exit button. By default, paginated menus - * have an exit button. - * - * If a menu's pagination is changed to MENU_NO_PAGINATION, and the pagination - * was previously a different value, then the Exit button status is changed to - * false. It must be explicitly re-enabled afterwards. - * - * If a non-paginated menu has an exit button, then at most 9 items will be - * displayed. - * - * @param menu Menu Handle. - * @param button True to enable the button, false to remove it. - * @return True if allowed; false on failure. - * @error Invalid Handle. - */ -native bool SetMenuExitButton(Handle menu, bool button); - -/** - * Returns whether or not the menu has an "exit back" button. By default, - * menus do not have an exit back button. - * - * Exit Back buttons appear as "Back" on page 1 of paginated menus and have - * functionality defined by the user in MenuEnd_ExitBack. - * - * @param menu Menu Handle. - * @return True if the menu has an exit back button; false otherwise. - * @error Invalid Handle. - */ -native bool GetMenuExitBackButton(Handle menu); - -/** - * Sets whether or not the menu has an "exit back" button. By default, menus - * do not have an exit back button. - * - * Exit Back buttons appear as "Back" on page 1 of paginated menus and have - * functionality defined by the user in MenuEnd_ExitBack. - * - * @param menu Menu Handle. - * @param button True to enable the button, false to remove it. - * @error Invalid Handle. - */ -native void SetMenuExitBackButton(Handle menu, bool button); - -/** - * Sets whether or not the menu has a "no vote" button in slot 1. - * By default, menus do not have a no vote button. - * - * @param menu Menu Handle. - * @param button True to enable the button, false to remove it. - * @return True if allowed; false on failure. - * @error Invalid Handle. - */ -native bool SetMenuNoVoteButton(Handle menu, bool button); - -/** - * Cancels a menu from displaying on all clients. While the - * cancellation is in progress, this menu cannot be re-displayed - * to any clients. - * - * The menu may still exist on the client's screen after this command. - * This simply verifies that the menu is not being used anywhere. - * - * If any vote is in progress on a menu, it will be cancelled. - * - * @param menu Menu Handle. - * @error Invalid Handle. - */ -native void CancelMenu(Handle menu); - -/** - * Retrieves a menu's option flags. - * - * @param menu Menu Handle. - * @return A bitstring of MENUFLAG bits. - * @error Invalid Handle. - */ -native int GetMenuOptionFlags(Handle menu); - -/** - * Sets a menu's option flags. - * - * If a certain bit is not supported, it will be stripped before being set. - * See SetMenuExitButton() for information on Exit buttons. - * See SetMenuExitBackButton() for information on Exit Back buttons. - * - * @param menu Menu Handle. - * @param flags A new bitstring of MENUFLAG bits. - * @error Invalid Handle. - */ -native void SetMenuOptionFlags(Handle menu, int flags); - -/** - * Returns whether a vote is in progress. - * - * @param menu Deprecated; no longer used. - * @return True if a vote is in progress, false otherwise. - */ -native bool IsVoteInProgress(Handle menu=INVALID_HANDLE); - -/** - * Cancels the vote in progress. - * - * @error If no vote is in progress. - */ -native void CancelVote(); - -/** - * Broadcasts a menu to a list of clients. The most selected item will be - * returned through MenuAction_End. On a tie, a random item will be returned - * from a list of the tied items. - * - * Note that MenuAction_VoteEnd and MenuAction_VoteStart are both - * default callbacks and do not need to be enabled. - * - * @param menu Menu Handle. - * @param clients Array of clients to broadcast to. - * @param numClients Number of clients in the array. - * @param time Maximum time to leave menu on the screen. - * @param flags Optional voting flags. - * @return True on success, false if this menu already has a vote session - * in progress. - * @error Invalid Handle, or a vote is already in progress. - */ -native bool VoteMenu(Handle menu, int[] clients, int numClients, int time, int flags=0); - -/** - * Sends a vote menu to all clients. See VoteMenu() for more information. - * - * @param menu Menu Handle. - * @param time Maximum time to leave menu on the screen. - * @param flags Optional voting flags. - * @return True on success, false if this menu already has a vote session - * in progress. - * @error Invalid Handle. - */ -stock bool VoteMenuToAll(Handle menu, int time, int flags=0) -{ - int total; - int[] players = new int[MaxClients]; - - for (int i=1; i<=MaxClients; i++) - { - if (!IsClientInGame(i) || IsFakeClient(i)) - { - continue; - } - players[total++] = i; - } - - return VoteMenu(menu, players, total, time, flags); -} - -/** - * Callback for when a vote has ended and results are available. - * - * @param menu The menu being voted on. - * @param num_votes Number of votes tallied in total. - * @param num_clients Number of clients who could vote. - * @param client_info Array of clients. Use VOTEINFO_CLIENT_ defines. - * @param num_items Number of unique items that were selected. - * @param item_info Array of items, sorted by count. Use VOTEINFO_ITEM - * defines. - */ -typeset VoteHandler -{ - // old style - function void( - Menu menu, - int num_votes, - int num_clients, - const int client_info[][2], - int num_items, - const int item_info[][2] - ); - - // new style - function void( - Menu menu, - int num_votes, - int num_clients, - const int[][] client_info, - int num_items, - const int[][] item_info - ); -}; - -/** - * Sets an advanced vote handling callback. If this callback is set, - * MenuAction_VoteEnd will not be called. - * - * @param menu Menu Handle. - * @param callback Callback function. - * @error Invalid Handle or callback. - */ -native void SetVoteResultCallback(Handle menu, VoteHandler callback); - -/** - * Returns the number of seconds you should "wait" before displaying - * a publicly invocable menu. This number is the time remaining until - * (last_vote + sm_vote_delay). - * - * @return Number of seconds to wait, or 0 for none. - */ -native int CheckVoteDelay(); - -/** - * Returns whether a client is in the pool of clients allowed - * to participate in the current vote. This is determined by - * the client list passed to VoteMenu(). - * - * @param client Client index. - * @return True if client is allowed to vote, false otherwise. - * @error If no vote is in progress or client index is invalid. - */ -native bool IsClientInVotePool(int client); - -/** - * Redraws the current vote menu to a client in the voting pool. - * - * @param client Client index. - * @param revotes True to allow revotes, false otherwise. - * @return True on success, false if the client is in the vote pool - * but cannot vote again. - * @error No vote in progress, int client is not in the voting pool, - * or client index is invalid. - */ -native bool RedrawClientVoteMenu(int client, bool revotes=true); - -/** - * Returns a style's global Handle. - * - * @param style Menu Style. - * @return A Handle, or INVALID_HANDLE if not found or unusable. - */ -native Handle GetMenuStyleHandle(MenuStyle style); - -/** - * Creates a MenuPanel from a MenuStyle. Panels are used for drawing raw - * menus without any extra helper functions. The Handle must be closed - * with CloseHandle(). - * - * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. - * @return A new MenuPanel Handle. - * @error Invalid Handle other than INVALID_HANDLE. - */ -native Panel CreatePanel(Handle hStyle=INVALID_HANDLE); - -/** - * Creates a Menu from a MenuStyle. The Handle must be closed with - * CloseHandle(). - * - * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. - * @param handler Function which will receive menu actions. - * @param actions Optionally set which actions to receive. Select, - * Cancel, and End will always be received regardless - * of whether they are set or not. They are also - * the only default actions. - * @return A new menu Handle. - * @error Invalid Handle other than INVALID_HANDLE. - */ -native Menu CreateMenuEx(Handle hStyle=INVALID_HANDLE, MenuHandler handler, MenuAction actions=MENU_ACTIONS_DEFAULT); - -/** - * Returns whether a client is viewing a menu. - * - * @param client Client index. - * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. - * @return A MenuSource value. - * @error Invalid Handle other than null. - */ -native MenuSource GetClientMenu(int client, Handle hStyle=null); - -/** - * Cancels a menu on a client. This will only affect non-external menus. - * - * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. - * @param client Client index. - * @param autoIgnore If true, no menus can be re-drawn on the client during - * the cancellation process. - * @return True if a menu was cancelled, false otherwise. - */ -native bool CancelClientMenu(int client, bool autoIgnore=false, Handle hStyle=INVALID_HANDLE); - -/** - * Returns a style's maximum items per page. - * - * @param hStyle MenuStyle Handle, or INVALID_HANDLE to use the default style. - * @return Maximum items per page. - * @error Invalid Handle other than INVALID_HANDLE. - */ -native int GetMaxPageItems(Handle hStyle=INVALID_HANDLE); - -/** - * Returns a MenuPanel's parent style. - * - * @param panel A MenuPanel Handle. - * @return The MenuStyle Handle that created the panel. - * @error Invalid Handle. - */ -native Handle GetPanelStyle(Handle panel); - -/** - * Sets the panel's title. - * - * @param panel A MenuPanel Handle. - * @param text Text to set as the title. - * @param onlyIfEmpty If true, the title will only be set if no title is set. - * @error Invalid Handle. - */ -native void SetPanelTitle(Handle panel, const char[] text, bool onlyIfEmpty=false); - -/** - * Draws an item on a panel. If the item takes up a slot, the position - * is returned. - * - * @param panel A MenuPanel Handle. - * @param text Display text to use. If not a raw line, - * the style may automatically add color markup. - * No numbering or newlines are needed. - * @param style ITEMDRAW style flags. - * @return A slot position, or 0 if item was a rawline or could not be drawn. - * @error Invalid Handle. - */ -native int DrawPanelItem(Handle panel, const char[] text, int style=ITEMDRAW_DEFAULT); - -/** - * Draws a raw line of text on a panel, without any markup other than a newline. - * - * @param panel A MenuPanel Handle, or INVALID_HANDLE if inside a - * MenuAction_DisplayItem callback. - * @param text Display text to use. - * @return True on success, false if raw lines are not supported. - * @error Invalid Handle. - */ -native bool DrawPanelText(Handle panel, const char[] text); - -/** - * Returns whether or not the given drawing flags are supported by - * the menu style. - * - * @param panel A MenuPanel Handle. - * @param style ITEMDRAW style flags. - * @return True if item is drawable, false otherwise. - * @error Invalid Handle. - */ -native bool CanPanelDrawFlags(Handle panel, int style); - -/** - * Sets the selectable key map of a panel. This is not supported by - * all styles (only by Radio, as of this writing). - * - * @param panel A MenuPanel Handle. - * @param keys An integer where each bit N allows key - * N+1 to be selected. If no keys are selectable, - * then key 0 (bit 9) is automatically set. - * @return True if supported, false otherwise. - */ -native bool SetPanelKeys(Handle panel, int keys); - -/** - * Sends a panel to a client. Unlike full menus, the handler - * function will only receive the following actions, both of - * which will have INVALID_HANDLE for a menu, and the client - * as param1. - * - * MenuAction_Select (param2 will be the key pressed) - * MenuAction_Cancel (param2 will be the reason) - * - * Also, if the menu fails to display, no callbacks will be called. - * - * @param panel A MenuPanel Handle. - * @param client A client to draw to. - * @param handler The MenuHandler function to catch actions with. - * @param time Time to hold the menu for. - * @return True on success, false on failure. - * @error Invalid Handle. - */ -native bool SendPanelToClient(Handle panel, int client, MenuHandler handler, int time); - -/** - * @brief Returns the amount of text the menu can still hold. If this is - * limit is reached or overflowed, the text is silently truncated. - * - * Radio menus: Currently 511 characters (512 bytes). - * Valve menus: Currently -1 (no meaning). - * - * @param panel A MenuPanel Handle. - * @return Number of characters that the menu can still hold, - * or -1 if there is no known limit. - * @error Invalid Handle. - */ -native int GetPanelTextRemaining(Handle panel); - -/** - * @brief Returns the current key position. - * - * @param panel A MenuPanel Handle. - * @return Current key position starting at 1. - * @error Invalid Handle. - */ -native int GetPanelCurrentKey(Handle panel); - -/** - * @brief Sets the next key position. This cannot be used - * to traverse backwards. - * - * @param panel A MenuPanel Handle. - * @param key Key that is greater or equal to - * GetPanelCurrentKey(). - * @return True on success, false otherwise. - * @error Invalid Handle. - */ -native bool SetPanelCurrentKey(Handle panel, int key); - -/** - * @brief Redraws menu text from inside a MenuAction_DisplayItem callback. - * - * @param text Menu text to draw. - * @return Item position; must be returned via the callback. - */ -native int RedrawMenuItem(const char[] text); - -/** - * This function is provided for legacy code only. Some older plugins may use - * network messages instead of the panel API. This function wraps the panel - * API for eased portability into the SourceMod menu system. - * - * This function is only usable with the Radio Menu style. You do not need to - * split up your menu into multiple packets; SourceMod will break the string - * up internally. - * - * @param client Client index. - * @param str Full menu string as would be passed over the network. - * @param time Time to hold the menu for. - * @param keys Selectable key bitstring. - * @param handler Optional handler function, with the same rules as - * SendPanelToClient(). - * @return True on success, false on failure. - * @error Invalid client index, or radio menus not supported. - */ -native bool InternalShowMenu(int client, const char[] str, int time, int keys=-1, MenuHandler handler=INVALID_FUNCTION); - -/** - * Retrieves voting information from MenuAction_VoteEnd. - * - * @param param2 Second parameter of MenuAction_VoteEnd. - * @param winningVotes Number of votes received by the winning option. - * @param totalVotes Number of total votes received. - */ -stock void GetMenuVoteInfo(int param2, int &winningVotes, int &totalVotes) -{ - winningVotes = param2 & 0xFFFF; - totalVotes = param2 >> 16; -} - -/** - * Quick stock to determine whether voting is allowed. This doesn't let you - * fine-tune a reason for not voting, so it's not recommended for lazily - * telling clients that voting isn't allowed. - * - * @return True if voting is allowed, false if voting is in progress - * or the cooldown is active. - */ -stock bool IsNewVoteAllowed() -{ - if (IsVoteInProgress() || CheckVoteDelay() != 0) - { - return false; - } - - return true; -} diff --git a/scripting/include/nextmap.inc b/scripting/include/nextmap.inc deleted file mode 100644 index cb86b71..0000000 --- a/scripting/include/nextmap.inc +++ /dev/null @@ -1,82 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _nextmap_included_ - #endinput -#endif -#define _nextmap_included_ - -/** - * Sets SourceMod's internal nextmap. - * Equivalent to changing sm_nextmap but with an added validity check. - * - * @param map Next map to set. - * @return True if the nextmap was set, false if map was invalid. - */ -native bool SetNextMap(const char[] map); - -/** - * Returns SourceMod's internal nextmap. - * - * @param map Buffer to store the nextmap name. - * @param maxlen Maximum length of the map buffer. - * @return True if a Map was found and copied, false if no nextmap is set (map will be unchanged). - */ -native bool GetNextMap(char[] map, int maxlen); - -/** - * Changes the current map and records the reason for the change with maphistory - * - * @param map Map to change to. - * @param reason Reason for change. - */ -native void ForceChangeLevel(const char[] map, const char[] reason); - -/** - * Gets the current number of maps in the map history - * - * @return Number of maps. - */ -native int GetMapHistorySize(); - -/** - * Retrieves a map from the map history list. - * - * @param item Item number. Must be 0 or greater and less than GetMapHistorySize(). - * @param map Buffer to store the map name. - * @param mapLen Length of map buffer. - * @param reason Buffer to store the change reason. - * @param reasonLen Length of the reason buffer. - * @param startTime Time the map started. - * @error Invalid item number. - */ -native void GetMapHistory(int item, char[] map, int mapLen, char[] reason, int reasonLen, int &startTime); diff --git a/scripting/include/profiler.inc b/scripting/include/profiler.inc deleted file mode 100644 index ed5a7ee..0000000 --- a/scripting/include/profiler.inc +++ /dev/null @@ -1,97 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _profiler_included - #endinput -#endif -#define _profiler_included - -/** - * ONLY AVAILABLE ON WINDOWS RIGHT NOW K. - */ - -/** - * Creates a new profile object. The Handle must be freed - * using CloseHandle(). - * - * @return Handle to the profiler object. - */ -native Handle CreateProfiler(); - -/** - * Starts profiling. - * - * @param prof Profiling object. - * @error Invalid Handle. - */ -native void StartProfiling(Handle prof); - -/** - * Stops profiling. - * - * @param prof Profiling object. - * @error Invalid Handle or profiling was never started. - */ -native void StopProfiling(Handle prof); - -/** - * Returns the amount of high-precision time in seconds - * that passed during the profiler's last start/stop - * cycle. - * - * @param prof Profiling object. - * @return Time elapsed in seconds. - * @error Invalid Handle. - */ -native float GetProfilerTime(Handle prof); - -/** - * Mark the start of a profiling event. - * - * @param group Budget group. This can be "all" for a default, or a short - * description like "Timers" or "Events". - * @param name A name to attribute to this profiling event. - */ -native void EnterProfilingEvent(const char[] group, const char[] name); - -/** - * Mark the end of the last profiling event. This must be called in the same - * stack frame as StartProfilingEvent(). Not doing so, or throwing errors, - * will make the resulting profile very wrong. - */ -native void LeaveProfilingEvent(); - -/** - * Returns true if the global profiler is enabled; false otherwise. It is - * not necessary to call this before Enter/LeaveProfilingEvent. - */ -native bool IsProfilingActive(); diff --git a/scripting/include/protobuf.inc b/scripting/include/protobuf.inc deleted file mode 100644 index 56bebc5..0000000 --- a/scripting/include/protobuf.inc +++ /dev/null @@ -1,572 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2013 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _protobuf_included -#endinput -#endif -#define _protobuf_included - -#define PB_FIELD_NOT_REPEATED -1 - -methodmap Protobuf < Handle -{ - // Reads an int32, uint32, sint32, fixed32, sfixed32, or enum value from a protobuf message. - // - // @param field Field name. - // @param index Index into repeated field. - // @return Integer value read. - // @error Non-existent field, or incorrect field type. - public native int ReadInt(const char[] field, int index = PB_FIELD_NOT_REPEATED); - - // Reads a float or downcasted double from a protobuf message. - // - // @param field Field name. - // @param index Index into repeated field. - // @return Float value read. - // @error Non-existent field, or incorrect field type. - public native float ReadFloat(const char[] field, int index = PB_FIELD_NOT_REPEATED); - - // Reads a bool from a protobuf message. - // - // @param field Field name. - // @param index Index into repeated field. - // @return Boolean value read. - // @error Non-existent field, or incorrect field type. - public native bool ReadBool(const char[] field, int index = PB_FIELD_NOT_REPEATED); - - // Reads a string from a protobuf message. - // - // @param field Field name. - // @param buffer Destination string buffer. - // @param maxlength Maximum length of output string buffer. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void ReadString(const char[] field, char[] buffer, int maxlength, int index = PB_FIELD_NOT_REPEATED); - - // Reads an RGBA color value from a protobuf message. - // - // @param field Field name. - // @param buffer Destination color buffer. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void ReadColor(const char[] field, int buffer[4], int index = PB_FIELD_NOT_REPEATED); - - // Reads an XYZ angle value from a protobuf message. - // - // @param field Field name. - // @param buffer Destination angle buffer. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void ReadAngle(const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); - - // Reads an XYZ vector value from a protobuf message. - // - // @param pb protobuf handle. - // @param field Field name. - // @param buffer Destination vector buffer. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void ReadVector(const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); - - // Reads an XY vector value from a protobuf message. - // - // @param field Field name. - // @param buffer Destination vector buffer. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void ReadVector2D(const char[] field, float buffer[2], int index = PB_FIELD_NOT_REPEATED); - - // Gets the number of elements in a repeated field of a protobuf message. - // - // @param field Field name. - // @return Number of elements in the field. - // @error Non-existent field, or incorrect field type. - public native int GetRepeatedFieldCount(const char[] field); - - // Sets an int32, uint32, sint32, fixed32, sfixed32, or enum value on a protobuf message. - // - // @param field Field name. - // @param value Integer value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native int SetInt(const char[] field, int value, int index = PB_FIELD_NOT_REPEATED); - - // Sets a float or double on a protobuf message. - // - // @param field Field name. - // @param value Float value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void SetFloat(const char[] field, float value, int index = PB_FIELD_NOT_REPEATED); - - // Sets a bool on a protobuf message. - // - // @param field Field name. - // @param value Boolean value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void SetBool(const char[] field, bool value, int index = PB_FIELD_NOT_REPEATED); - - // Sets a string on a protobuf message. - // - // @param field Field name. - // @param value String value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void SetString(const char[] field, const char[] value, int index = PB_FIELD_NOT_REPEATED); - - // Sets an RGBA color on a protobuf message. - // - // @param field Field name. - // @param color Color value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void SetColor(const char[] field, const int color[4], int index = PB_FIELD_NOT_REPEATED); - - // Sets an XYZ angle on a protobuf message. - // - // @param field Field name. - // @param angle Angle value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void SetAngle(const char[] field, const float angle[3], int index = PB_FIELD_NOT_REPEATED); - - // Sets an XYZ vector on a protobuf message. - // - // @param field Field name. - // @param vec Vector value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void SetVector(const char[] field, const float vec[3], int index = PB_FIELD_NOT_REPEATED); - - // Sets an XY vector on a protobuf message. - // - // @param field Field name. - // @param vec Vector value to set. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void SetVector2D(const char[] field, const float vec[2], int index = PB_FIELD_NOT_REPEATED); - - // Add an int32, uint32, sint32, fixed32, sfixed32, or enum value to a protobuf message repeated field. - // - // @param field Field name. - // @param value Integer value to add. - // @error Non-existent field, or incorrect field type. - public native void AddInt(const char[] field, int value); - - // Add a float or double to a protobuf message repeated field. - // - // @param field Field name. - // @param value Float value to add. - // @error Non-existent field, or incorrect field type. - public native void AddFloat(const char[] field, float value); - - // Add a bool to a protobuf message repeated field. - // - // @param field Field name. - // @param value Boolean value to add. - // @error Non-existent field, or incorrect field type. - public native void AddBool(const char[] field, bool value); - - // Add a string to a protobuf message repeated field. - // - // @param field Field name. - // @param value String value to add. - // @error Non-existent field, or incorrect field type. - public native void AddString(const char[] field, const char[] value); - - // Add an RGBA color to a protobuf message repeated field. - // - // @param field Field name. - // @param color Color value to add. - // @error Non-existent field, or incorrect field type. - public native void AddColor(const char[] field, const int color[4]); - - // Add an XYZ angle to a protobuf message repeated field. - // - // @param field Field name. - // @param angle Angle value to add. - // @error Non-existent field, or incorrect field type. - public native void AddAngle(const char[] field, const float angle[3]); - - // Add an XYZ vector to a protobuf message repeated field. - // - // @param field Field name. - // @param vec Vector value to add. - // @error Non-existent field, or incorrect field type. - public native void AddVector(const char[] field, const float vec[3]); - - // Add an XY vector to a protobuf message repeated field. - // - // @param field Field name. - // @param vec Vector value to add. - // @error Non-existent field, or incorrect field type. - public native void AddVector2D(const char[] field, const float vec[2]); - - // Removes a value by index from a protobuf message repeated field. - // - // @param field Field name. - // @param index Index into repeated field. - // @error Non-existent field, or incorrect field type. - public native void RemoveRepeatedFieldValue(const char[] field, int index); - - // Retrieve a handle to an embedded protobuf message in a protobuf message. - // - // @param field Field name. - // @return Protobuf handle to embedded message. - // @error Non-existent field, or incorrect field type. - public native Protobuf ReadMessage(const char[] field); - - // Retrieve a handle to an embedded protobuf message in a protobuf message - // repeated field. - // - // @param field Field name. - // @param index Index in the repeated field. - // @return Protobuf handle to embedded message. - // @error Non-existent field, or incorrect field type. - public native Protobuf ReadRepeatedMessage(const char[] field, int index); - - // Adds an embedded protobuf message to a protobuf message repeated field. - // - // @param field Field name. - // @return Protobuf handle to added, embedded message. - // @error Non-existent field, or incorrect field type. - public native Protobuf AddMessage(const char[] field); -}; - -/** - * Reads an int32, uint32, sint32, fixed32, sfixed32, or enum value from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param index Index into repeated field. - * @return Integer value read. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native int PbReadInt(Handle pb, const char[] field, int index = PB_FIELD_NOT_REPEATED); - -/** - * Reads a float or downcasted double from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param index Index into repeated field. - * @return Float value read. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native float PbReadFloat(Handle pb, const char[] field, int index = PB_FIELD_NOT_REPEATED); - -/** - * Reads a bool from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param index Index into repeated field. - * @return Boolean value read. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native bool PbReadBool(Handle pb, const char[] field, int index = PB_FIELD_NOT_REPEATED); - -/** - * Reads a string from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param buffer Destination string buffer. - * @param maxlength Maximum length of output string buffer. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbReadString(Handle pb, const char[] field, char[] buffer, int maxlength, int index = PB_FIELD_NOT_REPEATED); - -/** - * Reads an RGBA color value from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param buffer Destination color buffer. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbReadColor(Handle pb, const char[] field, int buffer[4], int index = PB_FIELD_NOT_REPEATED); - -/** - * Reads an XYZ angle value from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param buffer Destination angle buffer. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbReadAngle(Handle pb, const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); - -/** - * Reads an XYZ vector value from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param buffer Destination vector buffer. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbReadVector(Handle pb, const char[] field, float buffer[3], int index = PB_FIELD_NOT_REPEATED); - -/** - * Reads an XY vector value from a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param buffer Destination vector buffer. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbReadVector2D(Handle pb, const char[] field, float buffer[2], int index = PB_FIELD_NOT_REPEATED); - -/** - * Gets the number of elements in a repeated field of a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @return Number of elements in the field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native int PbGetRepeatedFieldCount(Handle pb, const char[] field); - -/** - * Sets an int32, uint32, sint32, fixed32, sfixed32, or enum value on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value Integer value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetInt(Handle pb, const char[] field, int value, int index = PB_FIELD_NOT_REPEATED); - -/** - * Sets a float or double on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value Float value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetFloat(Handle pb, const char[] field, float value, int index = PB_FIELD_NOT_REPEATED); - -/** - * Sets a bool on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value Boolean value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetBool(Handle pb, const char[] field, bool value, int index = PB_FIELD_NOT_REPEATED); - -/** - * Sets a string on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value String value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetString(Handle pb, const char[] field, const char[] value, int index = PB_FIELD_NOT_REPEATED); - -/** - * Sets an RGBA color on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param color Color value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetColor(Handle pb, const char[] field, const int color[4], int index = PB_FIELD_NOT_REPEATED); - -/** - * Sets an XYZ angle on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param angle Angle value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetAngle(Handle pb, const char[] field, const float angle[3], int index = PB_FIELD_NOT_REPEATED); - -/** - * Sets an XYZ vector on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param vec Vector value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetVector(Handle pb, const char[] field, const float vec[3], int index = PB_FIELD_NOT_REPEATED); - -/** - * Sets an XY vector on a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @param vec Vector value to set. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbSetVector2D(Handle pb, const char[] field, const float vec[2], int index = PB_FIELD_NOT_REPEATED); - -/** - * Add an int32, uint32, sint32, fixed32, sfixed32, or enum value to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value Integer value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddInt(Handle pb, const char[] field, int value); - -/** - * Add a float or double to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value Float value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddFloat(Handle pb, const char[] field, float value); - -/** - * Add a bool to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value Boolean value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddBool(Handle pb, const char[] field, bool value); - -/** - * Add a string to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param value String value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddString(Handle pb, const char[] field, const char[] value); - -/** - * Add an RGBA color to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param color Color value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddColor(Handle pb, const char[] field, const int color[4]); - -/** - * Add an XYZ angle to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param angle Angle value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddAngle(Handle pb, const char[] field, const float angle[3]); - -/** - * Add an XYZ vector to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param vec Vector value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddVector(Handle pb, const char[] field, const float vec[3]); - -/** - * Add an XY vector to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param vec Vector value to add. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbAddVector2D(Handle pb, const char[] field, const float vec[2]); - -/** - * Removes a value by index from a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param index Index into repeated field. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native void PbRemoveRepeatedFieldValue(Handle pb, const char[] field, int index); - -/** - * Retrieve a handle to an embedded protobuf message in a protobuf message. - * - * @param pb protobuf handle. - * @param field Field name. - * @return protobuf handle to embedded message. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native Handle PbReadMessage(Handle pb, const char[] field); - -/** - * Retrieve a handle to an embedded protobuf message in a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @param index Index in the repeated field. - * @return protobuf handle to embedded message. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native Handle PbReadRepeatedMessage(Handle pb, const char[] field, int index); - -/** - * Adds an embedded protobuf message to a protobuf message repeated field. - * - * @param pb protobuf handle. - * @param field Field name. - * @return protobuf handle to added, embedded message. - * @error Invalid or incorrect Handle, non-existent field, or incorrect field type. - */ -native Handle PbAddMessage(Handle pb, const char[] field); diff --git a/scripting/include/regex.inc b/scripting/include/regex.inc deleted file mode 100644 index d946659..0000000 --- a/scripting/include/regex.inc +++ /dev/null @@ -1,275 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _regex_included - #endinput -#endif -#define _regex_included - -/** - * @section Flags for compiling regex expressions. These come directly from the - * pcre library and can be used in MatchRegex and CompileRegex. - */ -#define PCRE_CASELESS 0x00000001 /* Ignore Case */ -#define PCRE_MULTILINE 0x00000002 /* Multilines (affects ^ and $ so that they match the start/end of a line rather than matching the start/end of the string). */ -#define PCRE_DOTALL 0x00000004 /* Single line (affects . so that it matches any character, even new line characters). */ -#define PCRE_EXTENDED 0x00000008 /* Pattern extension (ignore whitespace and # comments). */ -#define PCRE_ANCHORED 0x00000010 /* Force pattern anchoring. */ -#define PCRE_DOLLAR_ENDONLY 0x00000020 /* $ not to match newline at end. */ -#define PCRE_UNGREEDY 0x00000200 /* Invert greediness of quantifiers */ -#define PCRE_NOTEMPTY 0x00000400 /* An empty string is not a valid match. */ -#define PCRE_UTF8 0x00000800 /* Use UTF-8 Chars */ -#define PCRE_NO_UTF8_CHECK 0x00002000 /* Do not check the pattern for UTF-8 validity (only relevant if PCRE_UTF8 is set) */ -#define PCRE_UCP 0x20000000 /* Use Unicode properties for \ed, \ew, etc. */ - - -/** - * Regex expression error codes. - */ -enum RegexError -{ - REGEX_ERROR_NONE = 0, /* No error */ - - REGEX_ERROR_ASSERT = 1, /* internal error ? */ - REGEX_ERROR_BADBR, /* invalid repeat counts in {} */ - REGEX_ERROR_BADPAT, /* pattern error */ - REGEX_ERROR_BADRPT, /* ? * + invalid */ - REGEX_ERROR_EBRACE, /* unbalanced {} */ - REGEX_ERROR_EBRACK, /* unbalanced [] */ - REGEX_ERROR_ECOLLATE, /* collation error - not relevant */ - REGEX_ERROR_ECTYPE, /* bad class */ - REGEX_ERROR_EESCAPE, /* bad escape sequence */ - REGEX_ERROR_EMPTY, /* empty expression */ - REGEX_ERROR_EPAREN, /* unbalanced () */ - REGEX_ERROR_ERANGE, /* bad range inside [] */ - REGEX_ERROR_ESIZE, /* expression too big */ - REGEX_ERROR_ESPACE, /* failed to get memory */ - REGEX_ERROR_ESUBREG, /* bad back reference */ - REGEX_ERROR_INVARG, /* bad argument */ - - REGEX_ERROR_NOMATCH = -1, /* No match was found */ - REGEX_ERROR_NULL = -2, - REGEX_ERROR_BADOPTION = -3, - REGEX_ERROR_BADMAGIC = -4, - REGEX_ERROR_UNKNOWN_OPCODE = -5, - REGEX_ERROR_NOMEMORY = -6, - REGEX_ERROR_NOSUBSTRING = -7, - REGEX_ERROR_MATCHLIMIT = -8, - REGEX_ERROR_CALLOUT = -9, /* Never used by PCRE itself */ - REGEX_ERROR_BADUTF8 = -10, - REGEX_ERROR_BADUTF8_OFFSET = -11, - REGEX_ERROR_PARTIAL = -12, - REGEX_ERROR_BADPARTIAL = -13, - REGEX_ERROR_INTERNAL = -14, - REGEX_ERROR_BADCOUNT = -15, - REGEX_ERROR_DFA_UITEM = -16, - REGEX_ERROR_DFA_UCOND = -17, - REGEX_ERROR_DFA_UMLIMIT = -18, - REGEX_ERROR_DFA_WSSIZE = -19, - REGEX_ERROR_DFA_RECURSE = -20, - REGEX_ERROR_RECURSIONLIMIT = -21, - REGEX_ERROR_NULLWSLIMIT = -22, /* No longer actually used */ - REGEX_ERROR_BADNEWLINE = -23, - REGEX_ERROR_BADOFFSET = -24, - REGEX_ERROR_SHORTUTF8 = -25, - REGEX_ERROR_RECURSELOOP = -26, - REGEX_ERROR_JIT_STACKLIMIT = -27, - REGEX_ERROR_BADMODE = -28, - REGEX_ERROR_BADENDIANNESS = -29, - REGEX_ERROR_DFA_BADRESTART = -30, - REGEX_ERROR_JIT_BADOPTION = -31, - REGEX_ERROR_BADLENGTH = -32, -}; - -// Regular expression objects are used to match or decompose strings based on -// patterns. -methodmap Regex < Handle -{ - // Compile a regular expression. - // - // @param pattern The regular expression pattern. - // @param flags General flags for the regular expression. - // @param error Error message encountered, if applicable. - // @param maxLen Maximum string length of the error buffer. - // @param errcode Regex type error code encountered, if applicable. - public native Regex(const char[] pattern, int flags = 0, char[] error="", int maxLen = 0, RegexError &errcode = REGEX_ERROR_NONE); - - // Matches a string against a pre-compiled regular expression pattern. - // - // @param str The string to check. - // @param regex Regex Handle from CompileRegex() - // @param ret Error code, if applicable. - // @param offset Offset in the string to start searching from. MatchOffset returns the offset of the match. - // @return Number of captures found or -1 on failure. - // - // @note Use the regex handle passed to this function to extract - // matches with GetSubString(). - public native int Match(const char[] str, RegexError &ret = REGEX_ERROR_NONE, int offset = 0); - - // Gets all matches from a string against a pre-compiled regular expression pattern. - // - // @param str The string to check. - // @param regex Regex Handle from CompileRegex() - // @param ret Error code, if applicable. - // @return Number of matches found or -1 on failure. - // - // @note Use GetSubString() and loop from 0 -> totalmatches - 1. - public native int MatchAll(const char[] str, RegexError &ret = REGEX_ERROR_NONE); - - // Returns a matched substring from a regex handle. - // - // Substring ids start at 0 and end at captures-1, where captures is the - // number returned by Regex.Match or Regex.CaptureCount. - // - // @param regex The regex handle to extract data from. - // @param str_id The index of the expression to get - starts at 0, and ends at captures - 1. - // @param buffer The buffer to set to the matching substring. - // @param maxlen The maximum string length of the buffer. - // @param match Match to get the captures for - starts at 0, and ends at MatchCount() -1 - // @return True if a substring was found, False on fail/error - // - // @note str_id = 0 is the full captured string, anything else is the capture group index. - // if Regex.Match is used match can only be 0 - public native bool GetSubString(int str_id, char[] buffer, int maxlen, int match = 0); - - // Returns number of matches - // - // When using Match this is always 1 or 0 (unless an error occured) - // @return Total number of matches found. - public native int MatchCount(); - - // Returns number of captures for a match - // - // @param match Match to get the number of captures for. Match starts at 0, and ends at MatchCount() -1 - // @return Number of captures in the match. - // - // @note Use GetSubString() and loop from 1 -> captures -1 for str_id to get all captures - public native int CaptureCount(int match = 0); - - // Returns the string offset of a match. - // - // @param match Match to get the offset of. Match starts at 0, and ends at MatchCount() -1 - // @return Offset of the match in the string. - public native int MatchOffset(int match = 0) -}; - -/** - * Precompile a regular expression. Use this if you intend on using the - * same expression multiple times. Pass the regex handle returned here to - * MatchRegex to check for matches. - * - * @param pattern The regular expression pattern. - * @param flags General flags for the regular expression. - * @param error Error message encountered, if applicable. - * @param maxLen Maximum string length of the error buffer. - * @param errcode Regex type error code encountered, if applicable. - * @return Valid regex handle on success, INVALID_HANDLE on failure. - */ -native Regex CompileRegex(const char[] pattern, int flags = 0, char[] error="", int maxLen = 0, RegexError &errcode = REGEX_ERROR_NONE); - -/** - * Matches a string against a pre-compiled regular expression pattern. - * - * @param str The string to check. - * @param regex Regex Handle from CompileRegex() - * @param ret Error code, if applicable. - * @return Number of captures found or -1 on failure. - * - * @note Use the regex handle passed to this function to extract - * matches with GetRegexSubString(). - */ -native int MatchRegex(Handle regex, const char[] str, RegexError &ret = REGEX_ERROR_NONE); - -/** - * Returns a matched substring from a regex handle. - * Substring ids start at 0 and end at captures-1, where captures is the number returned - * by MatchRegex. - * - * @param regex The regex handle to extract data from. - * @param str_id The index of the expression to get - starts at 0, and ends at captures - 1. - * @param buffer The buffer to set to the matching substring. - * @param maxlen The maximum string length of the buffer. - * @return True if a substring was found, False on fail/error - * - * @note str_id = 0 is the full captured string, anything else is the capture group index. - * - */ -native bool GetRegexSubString(Handle regex, int str_id, char[] buffer, int maxlen); - -/** - * Matches a string against a regular expression pattern. - * - * @note If you intend on using the same regular expression pattern - * multiple times, consider using CompileRegex and MatchRegex - * instead of making this function reparse the expression each time. - * - * @param str The string to check. - * @param pattern The regular expression pattern. - * @param flags General flags for the regular expression. - * @param error Error message, if applicable. - * @param maxLen Maximum length of the error buffer. - * @return Number of substrings found or -1 on failure. - */ -stock int SimpleRegexMatch(const char[] str, const char[] pattern, int flags = 0, char[] error="", int maxLen = 0) -{ - Regex regex = new Regex(pattern, flags, error, maxLen); - if (!regex) - return -1; - - int substrings = regex.Match(str); - delete regex; - - return substrings; -} - -/** - * @endsection - */ - -/** - * Do not edit below this line! - */ -public Extension __ext_regex = -{ - name = "Regex Extension", - file = "regex.ext", -#if defined AUTOLOAD_EXTENSIONS - autoload = 1, -#else - autoload = 0, -#endif -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; diff --git a/scripting/include/sdkhooks.inc b/scripting/include/sdkhooks.inc deleted file mode 100644 index f58c128..0000000 --- a/scripting/include/sdkhooks.inc +++ /dev/null @@ -1,412 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2009-2013 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - */ - -#if defined _sdkhooks_included - #endinput -#endif -#define _sdkhooks_included - -// this is obviously _not_ a robust check, but it will solve most conflict and is clean -#if !defined DMG_GENERIC -#define DMG_GENERIC 0 /**< generic damage was done */ -#define DMG_CRUSH (1 << 0) /**< crushed by falling or moving object. - NOTE: It's assumed crush damage is occurring as a result of physics collision, so no extra physics force is generated by crush damage. - DON'T use DMG_CRUSH when damaging entities unless it's the result of a physics collision. You probably want DMG_CLUB instead. */ -#define DMG_BULLET (1 << 1) /**< shot */ -#define DMG_SLASH (1 << 2) /**< cut, clawed, stabbed */ -#define DMG_BURN (1 << 3) /**< heat burned */ -#define DMG_VEHICLE (1 << 4) /**< hit by a vehicle */ -#define DMG_FALL (1 << 5) /**< fell too far */ -#define DMG_BLAST (1 << 6) /**< explosive blast damage */ -#define DMG_CLUB (1 << 7) /**< crowbar, punch, headbutt */ -#define DMG_SHOCK (1 << 8) /**< electric shock */ -#define DMG_SONIC (1 << 9) /**< sound pulse shockwave */ -#define DMG_ENERGYBEAM (1 << 10) /**< laser or other high energy beam */ -#define DMG_PREVENT_PHYSICS_FORCE (1 << 11) /**< Prevent a physics force */ -#define DMG_NEVERGIB (1 << 12) /**< with this bit OR'd in, no damage type will be able to gib victims upon death */ -#define DMG_ALWAYSGIB (1 << 13) /**< with this bit OR'd in, any damage type can be made to gib victims upon death. */ -#define DMG_DROWN (1 << 14) /**< Drowning */ -#define DMG_PARALYZE (1 << 15) /**< slows affected creature down */ -#define DMG_NERVEGAS (1 << 16) /**< nerve toxins, very bad */ -#define DMG_POISON (1 << 17) /**< blood poisoning - heals over time like drowning damage */ -#define DMG_RADIATION (1 << 18) /**< radiation exposure */ -#define DMG_DROWNRECOVER (1 << 19) /**< drowning recovery */ -#define DMG_ACID (1 << 20) /**< toxic chemicals or acid burns */ -#define DMG_SLOWBURN (1 << 21) /**< in an oven */ -#define DMG_REMOVENORAGDOLL (1 << 22) /**< with this bit OR'd in, no ragdoll will be created, and the target will be quietly removed. - use this to kill an entity that you've already got a server-side ragdoll for */ -#define DMG_PHYSGUN (1 << 23) /**< Hit by manipulator. Usually doesn't do any damage. */ -#define DMG_PLASMA (1 << 24) /**< Shot by Cremator */ -#define DMG_AIRBOAT (1 << 25) /**< Hit by the airboat's gun */ -#define DMG_DISSOLVE (1 << 26) /**< Dissolving! */ -#define DMG_BLAST_SURFACE (1 << 27) /**< A blast on the surface of water that cannot harm things underwater */ -#define DMG_DIRECT (1 << 28) -#define DMG_BUCKSHOT (1 << 29) /**< not quite a bullet. Little, rounder, different. */ -#endif - -#if !defined DMG_CRIT - // TF2 crits and minicrits - #define DMG_CRIT DMG_ACID -#endif - -enum SDKHookType -{ - SDKHook_EndTouch, - SDKHook_FireBulletsPost, - SDKHook_OnTakeDamage, - SDKHook_OnTakeDamagePost, - SDKHook_PreThink, - SDKHook_PostThink, - SDKHook_SetTransmit, - SDKHook_Spawn, - SDKHook_StartTouch, - SDKHook_Think, - SDKHook_Touch, - SDKHook_TraceAttack, - SDKHook_TraceAttackPost, - SDKHook_WeaponCanSwitchTo, - SDKHook_WeaponCanUse, - SDKHook_WeaponDrop, - SDKHook_WeaponEquip, - SDKHook_WeaponSwitch, - SDKHook_ShouldCollide, - SDKHook_PreThinkPost, - SDKHook_PostThinkPost, - SDKHook_ThinkPost, - SDKHook_EndTouchPost, - SDKHook_GroundEntChangedPost, - SDKHook_SpawnPost, - SDKHook_StartTouchPost, - SDKHook_TouchPost, - SDKHook_VPhysicsUpdate, - SDKHook_VPhysicsUpdatePost, - SDKHook_WeaponCanSwitchToPost, - SDKHook_WeaponCanUsePost, - SDKHook_WeaponDropPost, - SDKHook_WeaponEquipPost, - SDKHook_WeaponSwitchPost, - SDKHook_Use, - SDKHook_UsePost, - SDKHook_Reload, - SDKHook_ReloadPost, - SDKHook_GetMaxHealth, /**< ep2v and later */ - SDKHook_Blocked, - SDKHook_BlockedPost, - SDKHook_OnTakeDamageAlive, - SDKHook_OnTakeDamageAlivePost, - SDKHook_CanBeAutobalanced, -}; - -/* - Alphabetized for easy readability - - SDKHook_Blocked, - SDKHook_BlockedPost, - - SDKHook_CanBeAutobalanced, - - SDKHook_EndTouch, - SDKHook_EndTouchPost, - - SDKHook_FireBulletsPost, - - SDKHook_GetMaxHealth, (ep2v and later) - - SDKHook_GroundEntChangedPost, - - SDKHook_OnTakeDamage, - SDKHook_OnTakeDamagePost, - - SDKHook_OnTakeDamageAlive, - SDKHook_OnTakeDamageAlivePost, - - SDKHook_PreThink, - SDKHook_PreThinkPost, - - SDKHook_PostThink, - SDKHook_PostThinkPost, - - SDKHook_Reload, - SDKHook_ReloadPost, - - SDKHook_SetTransmit, - - SDKHook_ShouldCollide, - - SDKHook_Spawn, - SDKHook_SpawnPost, - - SDKHook_StartTouch, - SDKHook_StartTouchPost, - - SDKHook_Think, - SDKHook_ThinkPost, - - SDKHook_Touch, - SDKHook_TouchPost, - - SDKHook_TraceAttack, - SDKHook_TraceAttackPost, - - SDKHook_Use, - SDKHook_UsePost, - - SDKHook_VPhysicsUpdate, - SDKHook_VPhysicsUpdatePost, - - SDKHook_WeaponCanSwitchTo, - SDKHook_WeaponCanSwitchToPost, - - SDKHook_WeaponCanUse, - SDKHook_WeaponCanUsePost, - - SDKHook_WeaponDrop, - SDKHook_WeaponDropPost, - - SDKHook_WeaponEquip, - SDKHook_WeaponEquipPost, - - SDKHook_WeaponSwitch, - SDKHook_WeaponSwitchPost -*/ - -enum UseType -{ - Use_Off, - Use_On, - Use_Set, - Use_Toggle -}; - -typeset SDKHookCB -{ - // PreThink/Post - // PostThink/Post - function void (int client); - - // Spawn - function Action (int entity); - - // GroundEntChanged - // SpawnPost - // Think/Post - // VPhysicsUpdate/Post - function void (int entity); - - // EndTouch - // StartTouch - // Touch - // Blocked - function Action (int entity, int other); - - // EndTouchPost - // StartTouchPost - // TouchPost - function void (int entity, int other); - - // SetTransmit - function Action (int entity, int client); - - // WeaponCanSwitchTo - // WeaponCanUse - // WeaponDrop - // WeaponEquip - // WeaponSwitch - function Action (int client, int weapon); - - // WeaponCanSwitchToPost - // WeaponCanUsePost - // WeaponDropPost - // WeaponEquipPost - // WeaponSwitchPost - function void (int client, int weapon); - - // GetMaxHealth (ep2v and later) - function Action (int entity, int &maxhealth); - - // OnTakeDamage - // OnTakeDamageAlive - // Note: The weapon parameter is not used by all games and damage sources. - // Note: Force application is dependent on game and damage type(s) - // SDKHooks 1.0+ - function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype); - // SDKHooks 2.0+ - function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3]); - // SDKHooks 2.1+ (can check for support at runtime using GetFeatureStatus on SDKHook_DmgCustomInOTD capability. - // DON'T attempt to access 'damagecustom' var if feature status != available - function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, - float damageForce[3], float damagePosition[3], int damagecustom); - - // OnTakeDamagePost - // OnTakeDamageAlivePost - function void (int victim, int attacker, int inflictor, float damage, int damagetype); - function void (int victim, int attacker, int inflictor, float damage, int damagetype, int weapon, const float damageForce[3], const float damagePosition[3]); - function void (int victim, int attacker, int inflictor, float damage, int damagetype, int weapon, - const float damageForce[3], const float damagePosition[3], int damagecustom); - - // FireBulletsPost - function void (int client, int shots, const char[] weaponname); - - // TraceAttack - function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &ammotype, int hitbox, int hitgroup); - - // TraceAttackPost - function void (int victim, int attacker, int inflictor, float damage, int damagetype, int ammotype, int hitbox, int hitgroup); - - // ShouldCollide - function bool (int entity, int collisiongroup, int contentsmask, bool originalResult); - - // Use - function Action (int entity, int activator, int caller, UseType type, float value); - - // UsePost - function void (int entity, int activator, int caller, UseType type, float value); - - // Reload - function Action (int weapon); - - // Reload post - function void (int weapon, bool bSuccessful); - - // CanBeAutobalanced - function bool (int client, bool origRet); -}; - - -/** - * @brief When an entity is created - * - * @param entity Entity index - * @param classname Class name - */ -forward void OnEntityCreated(int entity, const char[] classname); - -/** - * @brief When an entity is destroyed - * - * @param entity Entity index - */ -forward void OnEntityDestroyed(int entity); - -/** - * @brief When the game description is retrieved - * - * @note Not supported on ep2v. - * - * @param gameDesc Game description - * @return Plugin_Changed if gameDesc has been edited, else no change. - */ -forward Action OnGetGameDescription(char gameDesc[64]); - -/** - * @brief When the level is initialized - * - * @param mapName Name of the map - * @param mapEntities Entities of the map - * @return Plugin_Changed if mapEntities has been edited, else no change. - */ -forward Action OnLevelInit(const char[] mapName, char mapEntities[2097152]); - -/** - * @brief Hooks an entity - * - * @param entity Entity index - * @param type Type of function to hook - * @param callback Function to call when hook is called - */ -native void SDKHook(int entity, SDKHookType type, SDKHookCB callback); - -/** - * @brief Hooks an entity - * - * @param entity Entity index - * @param type Type of function to hook - * @param callback Function to call when hook is called - * @return bool Hook Successful - */ -native bool SDKHookEx(int entity, SDKHookType type, SDKHookCB callback); - -/** - * @brief Unhooks an entity - * - * @param entity Entity index - * @param type Type of function to unhook - * @param callback Callback function to unhook - */ -native void SDKUnhook(int entity, SDKHookType type, SDKHookCB callback); - -/** - * @brief Applies damage to an entity - * - * @note Force application is dependent on game and damage type(s) - * - * @param entity Entity index taking damage - * @param inflictor Inflictor entity index - * @param attacker Attacker entity index - * @param damage Amount of damage - * @param damageType Bitfield of damage types - * @param weapon Weapon index (orangebox and later) or -1 for unspecified - * @param damageForce Velocity of damage force - * @param damagePosition Origin of damage - */ -native void SDKHooks_TakeDamage(int entity, int inflictor, int attacker, - float damage, int damageType=DMG_GENERIC, int weapon=-1, - const float damageForce[3]=NULL_VECTOR, const float damagePosition[3]=NULL_VECTOR); - -/** - * @brief Forces a client to drop the specified weapon - * - * @param client Client index. - * @param weapon Weapon entity index. - * @param vecTarget Location to toss weapon to, or NULL_VECTOR for default. - * @param vecVelocity Velocity at which to toss weapon, or NULL_VECTOR for default. - * @error Invalid client or weapon entity, weapon not owned by client. - */ -native void SDKHooks_DropWeapon(int client, int weapon, const float vecTarget[3]=NULL_VECTOR, - const float vecVelocity[3]=NULL_VECTOR); - -/** - * Do not edit below this line! - */ -public Extension __ext_sdkhooks = -{ - name = "SDKHooks", - file = "sdkhooks.ext", -#if defined AUTOLOAD_EXTENSIONS - autoload = 1, -#else - autoload = 0, -#endif -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; diff --git a/scripting/include/sdktools.inc b/scripting/include/sdktools.inc deleted file mode 100644 index 15d5ffc..0000000 --- a/scripting/include/sdktools.inc +++ /dev/null @@ -1,229 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_included - #endinput -#endif -#define _sdktools_included - -#include -#include -#include -#if !defined SDKTOOLS_DISABLE_SOUNDAPI -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum SDKCallType -{ - SDKCall_Static, /**< Static call */ - SDKCall_Entity, /**< CBaseEntity call */ - SDKCall_Player, /**< CBasePlayer call */ - SDKCall_GameRules, /**< CGameRules call */ - SDKCall_EntityList, /**< CGlobalEntityList call */ - SDKCall_Raw, /**< |this| pointer with an arbitrary address */ -}; - -enum SDKLibrary -{ - SDKLibrary_Server, /**< server.dll/server_i486.so */ - SDKLibrary_Engine, /**< engine.dll/engine_*.so */ -}; - -enum SDKFuncConfSource -{ - SDKConf_Virtual = 0, /**< Read a virtual index from the Offsets section */ - SDKConf_Signature = 1, /**< Read a signature from the Signatures section */ - SDKConf_Address = 2, /**< Read an address from the Addresses section */ -}; - -enum SDKType -{ - SDKType_CBaseEntity, /**< CBaseEntity (always as pointer) */ - SDKType_CBasePlayer, /**< CBasePlayer (always as pointer) */ - SDKType_Vector, /**< Vector (pointer, byval, or byref) */ - SDKType_QAngle, /**< QAngles (pointer, byval, or byref) */ - SDKType_PlainOldData, /**< Integer/generic data <=32bit (any) */ - SDKType_Float, /**< Float (any) */ - SDKType_Edict, /**< edict_t (always as pointer) */ - SDKType_String, /**< NULL-terminated string (always as pointer) */ - SDKType_Bool, /**< Boolean (any) */ -}; - -enum SDKPassMethod -{ - SDKPass_Pointer, /**< Pass as a pointer */ - SDKPass_Plain, /**< Pass as plain data */ - SDKPass_ByValue, /**< Pass an object by value */ - SDKPass_ByRef, /**< Pass an object by reference */ -}; - -#define VDECODE_FLAG_ALLOWNULL (1<<0) /**< Allow NULL for pointers */ -#define VDECODE_FLAG_ALLOWNOTINGAME (1<<1) /**< Allow players not in game */ -#define VDECODE_FLAG_ALLOWWORLD (1<<2) /**< Allow World entity */ -#define VDECODE_FLAG_BYREF (1<<3) /**< Floats/ints by reference */ - -#define VENCODE_FLAG_COPYBACK (1<<0) /**< Copy back data once done */ - -/** - * Starts the preparation of an SDK call. - * - * @param type Type of function call this will be. - */ -native void StartPrepSDKCall(SDKCallType type); - -/** - * Sets the virtual index of the SDK call if it is virtual. - * - * @param vtblidx Virtual table index. - */ -native void PrepSDKCall_SetVirtual(int vtblidx); - -/** - * Finds an address in a library and sets it as the address to use for the SDK call. - * - * @param lib Library to use. - * @param signature Binary data to search for in the library. If it starts with '@', - * the bytes parameter is ignored and the signature is interpreted - * as a symbol lookup in the library. - * @param bytes Number of bytes in the binary search string. - * @return True on success, false if nothing was found. - */ -native bool PrepSDKCall_SetSignature(SDKLibrary lib, const char[] signature, int bytes); - -/** - * Uses the given function address for the SDK call. - * - * @param addr Address of function to use. - * @return True on success, false on failure. - */ -native bool PrepSDKCall_SetAddress(Address addr); - -/** - * Finds an address or virtual function index in a GameConfig file and sets it as - * the calling information for the SDK call. - * - * @param gameconf GameConfig Handle, or INVALID_HANDLE to use sdktools.games.txt. - * @param source Whether to look in Offsets or Signatures. - * @param name Name of the property to find. - * @return True on success, false if nothing was found. - */ -native bool PrepSDKCall_SetFromConf(Handle gameconf, SDKFuncConfSource source, const char[] name); - -/** - * Sets the return information of an SDK call. Do not call this if there is no return data. - * This must be called if there is a return value (i.e. it is not necessarily safe to ignore - * the data). - * - * @param type Data type to convert to/from. - * @param pass How the data is passed in C++. - * @param decflags Flags on decoding from the plugin to C++. - * @param encflags Flags on encoding from C++ to the plugin. - */ -native void PrepSDKCall_SetReturnInfo(SDKType type, SDKPassMethod pass, int decflags=0, int encflags=0); - -/** - * Adds a parameter to the calling convention. This should be called in normal ascending order. - * - * @param type Data type to convert to/from. - * @param pass How the data is passed in C++. - * @param decflags Flags on decoding from the plugin to C++. - * @param encflags Flags on encoding from C++ to the plugin. - */ -native void PrepSDKCall_AddParameter(SDKType type, SDKPassMethod pass, int decflags=0, int encflags=0); - -/** - * Finalizes an SDK call preparation and returns the resultant Handle. - * - * @return A new SDKCall Handle on success, or INVALID_HANDLE on failure. - */ -native Handle EndPrepSDKCall(); - -/** - * Calls an SDK function with the given parameters. - * - * If the call type is Entity or Player, the index MUST ALWAYS be the FIRST parameter passed. - * If the call type is GameRules, then nothing special needs to be passed. - * If the return value is a Vector or QAngles, the SECOND parameter must be a Float[3]. - * If the return value is a string, the THIRD parameter must be a String buffer, and the - * FOURTH parameter must be the maximum length. - * All parameters must be passed after the above is followed. Failure to follow these - * rules will result in crashes or wildly unexpected behavior! - * - * If the return value is a float or integer, the return value will be this value. - * If the return value is a CBaseEntity, CBasePlayer, or edict, the return value will - * always be the entity index, or -1 for NULL. - * - * @param call SDKCall Handle. - * @param ... Call Parameters. - * @return Simple return value, if any. - * @error Invalid Handle or internal decoding error. - */ -native any SDKCall(Handle call, any ...); - -/** - * Returns the entity index of the player resource/manager entity. - * - * @return Index of resource entity or -1 if not found. - */ -native int GetPlayerResourceEntity(); - -#include - -/** - * Do not edit below this line! - */ -public Extension __ext_sdktools = -{ - name = "SDKTools", - file = "sdktools.ext", -#if defined AUTOLOAD_EXTENSIONS - autoload = 1, -#else - autoload = 0, -#endif -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; diff --git a/scripting/include/sdktools_client.inc b/scripting/include/sdktools_client.inc deleted file mode 100644 index 0044634..0000000 --- a/scripting/include/sdktools_client.inc +++ /dev/null @@ -1,50 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_client_included - #endinput -#endif -#define _sdktools_client_included - -/** - * Sets the client to an inactive state waiting for a new map - * - * @param client The client index - */ -native void InactivateClient(int client); - -/** - * Reconnect a client without dropping the netchannel - * - * @param client The client index - */ -native void ReconnectClient(int client); diff --git a/scripting/include/sdktools_engine.inc b/scripting/include/sdktools_engine.inc deleted file mode 100644 index 280d970..0000000 --- a/scripting/include/sdktools_engine.inc +++ /dev/null @@ -1,66 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_engine_included - #endinput -#endif -#define _sdktools_engine_included - -#define MAX_LIGHTSTYLES 64 - -/** - * Sets a client's "viewing entity." - * - * @param client Client index. - * @param entity Entity index. - * @error Invalid client or entity, lack of mod support, or client not in - * game. - */ -native void SetClientViewEntity(int client, int entity); - -/** - * Sets a light style. - * - * @param style Light style (from 0 to MAX_LIGHTSTYLES-1) - * @param value Light value string (see world.cpp/light.cpp in dlls) - * @error Light style index is out of range. - */ -native void SetLightStyle(int style, const char[] value); - -/** - * Returns the client's eye position. - * - * @param client Player's index. - * @param pos Destination vector to store the client's eye position. - * @error Invalid client index, client not in game, or no mod support. - */ -native void GetClientEyePosition(int client, float pos[3]); diff --git a/scripting/include/sdktools_entinput.inc b/scripting/include/sdktools_entinput.inc deleted file mode 100644 index 0b502c2..0000000 --- a/scripting/include/sdktools_entinput.inc +++ /dev/null @@ -1,51 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_entinput_included - #endinput -#endif -#define _sdktools_entinput_included - -/** - * Invokes a named input method on an entity. - * - * After completion (successful or not), the current global variant is re-initialized. - * - * @param dest Destination entity index. - * @param input Input action. - * @param activator Entity index which initiated the sequence of actions (-1 for a NULL entity). - * @param caller Entity index from which this event is sent (-1 for a NULL entity). - * @param outputid Unknown. - * @return True if successful otherwise false. - * @error Invalid entity index or no mod support. - */ -native bool AcceptEntityInput(int dest, const char[] input, int activator=-1, int caller=-1, int outputid=0); \ No newline at end of file diff --git a/scripting/include/sdktools_entoutput.inc b/scripting/include/sdktools_entoutput.inc deleted file mode 100644 index 68931e1..0000000 --- a/scripting/include/sdktools_entoutput.inc +++ /dev/null @@ -1,108 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_entoutput_included - #endinput -#endif -#define _sdktools_entoutput_included - -/** - * Called when an entity output is fired. - * - * @param output Name of the output that fired. - * @param caller Entity index of the caller. - * @param activator Entity index of the activator. - * @param delay Delay in seconds? before the event gets fired. - * @return Anything other than Plugin_Continue will supress this event, - * returning Plugin_Continue will allow it to propagate the results - * of this output to any entity inputs. - */ -typeset EntityOutput -{ - function void (const char[] output, int caller, int activator, float delay); - function Action (const char[] output, int caller, int activator, float delay); -}; - -/** - * Add an entity output hook on a entity classname - * - * @param classname The classname to hook. - * @param output The output name to hook. - * @param callback An EntityOutput function pointer. - * @error Entity Outputs disabled. - */ -native void HookEntityOutput(const char[] classname, const char[] output, EntityOutput callback); - -/** - * Remove an entity output hook. - * @param classname The classname to hook. - * @param output The output name to hook. - * @param callback An EntityOutput function pointer. - * @return True on success, false if no valid hook was found. - * @error Entity Outputs disabled. - */ -native bool UnhookEntityOutput(const char[] classname, const char[] output, EntityOutput callback); - -/** - * Add an entity output hook on a single entity instance - * - * @param entity The entity on which to add a hook. - * @param output The output name to hook. - * @param callback An EntityOutput function pointer. - * @param once Only fire this hook once and then remove itself. - * @error Entity Outputs disabled or Invalid Entity index. - */ -native void HookSingleEntityOutput(int entity, const char[] output, EntityOutput callback, bool once=false); - -/** - * Remove a single entity output hook. - * - * @param entity The entity on which to remove the hook. - * @param output The output name to hook. - * @param callback An EntityOutput function pointer. - * @return True on success, false if no valid hook was found. - * @error Entity Outputs disabled or Invalid Entity index. - */ -native bool UnhookSingleEntityOutput(int entity, const char[] output, EntityOutput callback); - -/** - * Fire a named output on an entity. - * - * After completion (successful or not), the current global variant is re-initialized. - * - * @param caller Entity index from where the output is fired. - * @param output Output name. - * @param activator Entity index which initiated the sequence of actions (-1 for a NULL entity). - * @param delay Delay before firing the output. - * @error Invalid entity index or no mod support. - */ -native void FireEntityOutput(int caller, const char[] output, int activator=-1, float delay=0.0); \ No newline at end of file diff --git a/scripting/include/sdktools_functions.inc b/scripting/include/sdktools_functions.inc deleted file mode 100644 index c0e42e6..0000000 --- a/scripting/include/sdktools_functions.inc +++ /dev/null @@ -1,352 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_functions_included - #endinput -#endif -#define _sdktools_functions_included - -/** - * Removes a player's item. - * - * @param client Client index. - * @param item CBaseCombatWeapon entity index. - * @return True on success, false otherwise. - * @error Invalid client or entity, lack of mod support, or client not in - * game. - */ -native bool RemovePlayerItem(int client, int item); - -/** - * Gives a named item to a player. - * - * @param client Client index. - * @param item Item classname (such as weapon_ak47). - * @param iSubType Unknown. - * @return Entity index on success, or -1 on failure. - * @error Invalid client or client not in game, or lack of mod support. - */ -native int GivePlayerItem(int client, const char[] item, int iSubType=0); - -/** - * Returns the weapon in a player's slot. - * - * @param client Client index. - * @param slot Slot index (mod specific). - * @return Entity index on success, -1 if no weapon existed. - * @error Invalid client or client not in game, or lack of mod support. - */ -native int GetPlayerWeaponSlot(int client, int slot); - -/** - * Ignites an entity on fire. - * - * @param entity Entity index. - * @param time Number of seconds to set on fire. - * @param npc True to only affect NPCs. - * @param size Unknown. - * @param level Unknown. - * @error Invalid entity or client not in game, or lack of mod support. - */ -native void IgniteEntity(int entity, float time, bool npc=false, float size=0.0, bool level=false); - -/** - * Extinguishes an entity that is on fire. - * - * @param entity Entity index. - * @error Invalid entity or client not in game, or lack of mod support. - */ -native void ExtinguishEntity(int entity); - -/** - * Teleports an entity. - * - * @param entity Client index. - * @param origin New origin, or NULL_VECTOR for no change. - * @param angles New angles, or NULL_VECTOR for no change. - * @param velocity New velocity, or NULL_VECTOR for no change. - * @error Invalid entity or client not in game, or lack of mod support. - */ -native void TeleportEntity(int entity, const float origin[3], const float angles[3], const float velocity[3]); - -/** - * Forces a player to commit suicide. - * - * @param client Client index. - * @error Invalid client or client not in game, or lack of mod support. - */ -native void ForcePlayerSuicide(int client); - -/** - * Slaps a player in a random direction. - * - * @param client Client index. - * @param health Health to subtract. - * @param sound False to disable the sound effects. - * @error Invalid client or client not in game, or lack of mod support. - */ -native void SlapPlayer(int client, int health=5, bool sound=true); - -/** - * Searches for an entity by classname. - * - * @param startEnt The entity index after which to begin searching from. - * Use -1 to start from the first entity. - * @param classname Classname of the entity to find. - * @return Entity index >= 0 if found, -1 otherwise. - * @error Lack of mod support. - */ -native int FindEntityByClassname(int startEnt, const char[] classname); - -/** - * Returns the client's eye angles. - * - * @param client Player's index. - * @param ang Destination vector to store the client's eye angles. - * @return True on success, false on failure. - * @error Invalid client index, client not in game, or no mod support. - */ -native bool GetClientEyeAngles(int client, float ang[3]); - -/** - * Creates an entity by string name, but does not spawn it (see DispatchSpawn). - * If ForceEdictIndex is not -1, then it will use the edict by that index. If the index is - * invalid or there is already an edict using that index, it will error out. - * - * @param classname Entity classname. - * @param ForceEdictIndex Edict index used by the created entity (ignored on Orangebox and above). - * @return Entity index on success, or -1 on failure. - * @error Invalid edict index, or no mod support. - */ -native int CreateEntityByName(const char[] classname, int ForceEdictIndex=-1); - -/** - * Spawns an entity into the game. - * - * @param entity Entity index of the created entity. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. - */ -native bool DispatchSpawn(int entity); - -/** - * Dispatches a KeyValue into given entity using a string value. - * - * @param entity Destination entity index. - * @param keyName Name of the key. - * @param value String value. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. - */ -native bool DispatchKeyValue(int entity, const char[] keyName, const char[] value); - -/** - * Dispatches a KeyValue into given entity using a floating point value. - * - * @param entity Destination entity index. - * @param keyName Name of the key. - * @param value Floating point value. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. - */ -native bool DispatchKeyValueFloat(int entity, const char[] keyName, float value); - -/** - * Dispatches a KeyValue into given entity using a vector value. - * - * @param entity Destination entity index. - * @param keyName Name of the key. - * @param vec Vector value. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. - */ -native bool DispatchKeyValueVector(int entity, const char[] keyName, const float vec[3]); - -/** - * Returns the entity a client is aiming at. - * - * @param client Client performing the aiming. - * @param only_clients True to exclude all entities but clients. - * @return Entity index being aimed at. - * -1 if no entity is being aimed at. - * -2 if the function is not supported. - * @error Invalid client index or client not in game. - */ -native int GetClientAimTarget(int client, bool only_clients=true); - -/** - * Returns the total number of teams in a game. - * Note: This native should not be called before OnMapStart. - * - * @return Total number of teams. - */ -native int GetTeamCount(); - -/** - * Retrieves the team name based on a team index. - * Note: This native should not be called before OnMapStart. - * - * @param index Team index. - * @param name Buffer to store string in. - * @param maxlength Maximum length of string buffer. - * @error Invalid team index. - */ -native void GetTeamName(int index, char[] name, int maxlength); - -/** - * Returns the score of a team based on a team index. - * Note: This native should not be called before OnMapStart. - * - * @param index Team index. - * @return Score. - * @error Invalid team index. - */ -native int GetTeamScore(int index); - -/** - * Sets the score of a team based on a team index. - * Note: This native should not be called before OnMapStart. - * - * @param index Team index. - * @param value New score value. - * @error Invalid team index. - */ -native void SetTeamScore(int index, int value); - -/** - * Retrieves the number of players in a certain team. - * Note: This native should not be called before OnMapStart. - * - * @param index Team index. - * @return Number of players in the team. - * @error Invalid team index. - */ -native int GetTeamClientCount(int index); - -/** - * Returns the entity index of a team. - * - * @param teamIndex Team index. - * @return Entity index of team. - * @error Invalid team index. - */ -native int GetTeamEntity(int teamIndex); - -/** - * Sets the model to a given entity. - * - * @param entity Entity index. - * @param model Model name. - * @error Invalid entity index, or no mod support. - */ -native void SetEntityModel(int entity, const char[] model); - -/** - * Retrieves the decal file name associated with a given client. - * - * @param client Player's index. - * @param hex Buffer to store the logo filename. - * @param maxlength Maximum length of string buffer. - * @return True on success, otherwise false. - * @error Invalid client or client not in game. - */ -native bool GetPlayerDecalFile(int client, char[] hex, int maxlength); - -/** - * Retrieves the jingle file name associated with a given client. - * - * @param client Player's index. - * @param hex Buffer to store the jingle filename. - * @param maxlength Maximum length of string buffer. - * @return True on success, otherwise false. - * @error Invalid client or client not in game. - */ -native bool GetPlayerJingleFile(int client, char[] hex, int maxlength); - -/** - * Returns the average server network traffic in bytes/sec. - * - * @param in Buffer to store the input traffic velocity. - * @param out Buffer to store the output traffic velocity. - */ -native void GetServerNetStats(float &inAmount, float &outAmout); - -/** - * Equip's a player's weapon. - * - * @param client Client index. - * @param weapon CBaseCombatWeapon entity index. - * @error Invalid client or entity, lack of mod support, or client not in - * game. - */ -native void EquipPlayerWeapon(int client, int weapon); - -/** - * Activates an entity (CBaseAnimating::Activate) - * - * @param entity Entity index. - * @error Invalid entity or lack of mod support. - */ -native void ActivateEntity(int entity); - -/** - * Sets values to client info buffer keys and notifies the engine of the change. - * The change does not get propagated to mods until the next frame. - * - * @param client Player's index. - * @param key Key string. - * @param value Value string. - * @error Invalid client index, or client not connected. - */ -native void SetClientInfo(int client, const char[] key, const char[] value); - -/** - * Changes a client's name. - * - * @param client Player's index. - * @param name New name. - * @error Invalid client index, or client not connected. - */ -native void SetClientName(int client, const char[] name); - -/** - * Gives ammo of a certain type to a player. - * This natives obeys the maximum amount of ammo a player can carry per ammo type. - * - * @param client The client index. - * @param amount Amount of ammo to give. Is capped at ammotype's limit. - * @param ammotype Type of ammo to give to player. - * @param suppressSound If true, don't play the ammo pickup sound. - * - * @return Amount of ammo actually given. - */ -native int GivePlayerAmmo(int client, int amount, int ammotype, bool suppressSound=false); diff --git a/scripting/include/sdktools_gamerules.inc b/scripting/include/sdktools_gamerules.inc deleted file mode 100644 index 30527fc..0000000 --- a/scripting/include/sdktools_gamerules.inc +++ /dev/null @@ -1,197 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_gamerules_included - #endinput -#endif -#define _sdktools_gamerules_included - -enum RoundState { - // initialize the game, create teams - RoundState_Init, - - //Before players have joined the game. Periodically checks to see if enough players are ready - //to start a game. Also reverts to this when there are no active players - RoundState_Pregame, - - //The game is about to start, wait a bit and spawn everyone - RoundState_StartGame, - - //All players are respawned, frozen in place - RoundState_Preround, - - //Round is on, playing normally - RoundState_RoundRunning, - - //Someone has won the round - RoundState_TeamWin, - - //Noone has won, manually restart the game, reset scores - RoundState_Restart, - - //Noone has won, restart the game - RoundState_Stalemate, - - //Game is over, showing the scoreboard etc - RoundState_GameOver, - - //Game is over, doing bonus round stuff - RoundState_Bonus, - - //Between rounds - RoundState_BetweenRounds, -}; - -/** - * Retrieves an integer value from a property of the gamerules entity. - * - * @param prop Property name. - * @param size Number of bytes to read (valid values are 1, 2, or 4). - * This value is auto-detected, and the size parameter is - * only used as a fallback in case detection fails. - * @param element Element # (starting from 0) if property is an array. - * @return Value at the given property offset. - * @error Not supported. - */ -native int GameRules_GetProp(const char[] prop, int size=4, int element=0); - -/** - * Sets an integer value for a property of the gamerules entity. - * - * @param prop Property name. - * @param value Value to set. - * @param size Number of bytes to write (valid values are 1, 2, or 4). - * This value is auto-detected, and the size parameter is - * only used as a fallback in case detection fails. - * @param element Element # (starting from 0) if property is an array. - * @param changeState This parameter is ignored. - * @error Not supported. - */ -native void GameRules_SetProp(const char[] prop, any value, int size=4, int element=0, bool changeState=false); - -/** - * Retrieves a float value from a property of the gamerules entity. - * - * @param prop Property name. - * @param element Element # (starting from 0) if property is an array. - * @return Value at the given property offset. - * @error Not supported. - */ -native float GameRules_GetPropFloat(const char[] prop, int element=0); - -/** - * Sets a float value for a property of the gamerules entity. - * - * @param prop Property name. - * @param value Value to set. - * @param element Element # (starting from 0) if property is an array. - * @param changeState This parameter is ignored. - * @error Not supported. - */ -native void GameRules_SetPropFloat(const char[] prop, float value, int element=0, bool changeState=false); - -/** - * Retrieves a entity index from a property of the gamerules entity. - * - * @param prop Property name. - * @param element Element # (starting from 0) if property is an array. - * @return Entity index at the given property. - * If there is no entity, or the entity is not valid, - * then -1 is returned. - * @error Not supported. - */ -native int GameRules_GetPropEnt(const char[] prop, int element=0); - -/** - * Sets an entity index for a property of the gamerules entity. - * - * @param prop Property name. - * @param other Entity index to set, or -1 to unset. - * @param element Element # (starting from 0) if property is an array. - * @param changeState This parameter is ignored. - * @error Not supported. - */ -native void GameRules_SetPropEnt(const char[] prop, int other, int element=0, bool changeState=false); - -/** - * Retrieves a vector of floats from the gamerules entity, given a named network property. - * - * @param prop Property name. - * @param vec Vector buffer to store data in. - * @param element Element # (starting from 0) if property is an array. - * @error Not supported. - */ -native void GameRules_GetPropVector(const char[] prop, float vec[3], int element=0); - -/** - * Sets a vector of floats in the gamerules entity, given a named network property. - * - * @param prop Property name. - * @param vec Vector to set. - * @param element Element # (starting from 0) if property is an array. - * @param changeState This parameter is ignored. - * @error Not supported. - */ -native void GameRules_SetPropVector(const char[] prop, const float vec[3], int element=0, bool changeState=false); - -/** - * Gets a gamerules property as a string. - * - * @param prop Property to use. - * @param buffer Destination string buffer. - * @param maxlen Maximum length of output string buffer. - * @return Number of non-null bytes written. - * @error Not supported. - */ -native int GameRules_GetPropString(const char[] prop, char[] buffer, int maxlen); - -/** - * Sets a gamerules property as a string. - * - * @param prop Property to use. - * @param buffer String to set. - * @param changeState This parameter is ignored. - * @return Number of non-null bytes written. - * @error Not supported. - */ -native int GameRules_SetPropString(const char[] prop, const char[] buffer, bool changeState=false); - -/** - * Gets the current round state. - * - * @return Round state. - * @error Game doesn't support round state. - */ -stock RoundState GameRules_GetRoundState() -{ - return view_as(GameRules_GetProp("m_iRoundState")); -} diff --git a/scripting/include/sdktools_hooks.inc b/scripting/include/sdktools_hooks.inc deleted file mode 100644 index fc0f14a..0000000 --- a/scripting/include/sdktools_hooks.inc +++ /dev/null @@ -1,96 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2009 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_hooks_included - #endinput -#endif -#define _sdktools_hooks_included - -#define FEATURECAP_PLAYERRUNCMD_11PARAMS "SDKTools PlayerRunCmd 11Params" - -/** - * @brief Called when a clients movement buttons are being processed - * - * @param client Index of the client. - * @param buttons Copyback buffer containing the current commands (as bitflags - see entity_prop_stocks.inc). - * @param impulse Copyback buffer containing the current impulse command. - * @param vel Players desired velocity. - * @param angles Players desired view angles. - * @param weapon Entity index of the new weapon if player switches weapon, 0 otherwise. - * @param subtype Weapon subtype when selected from a menu. - * @param cmdnum Command number. Increments from the first command sent. - * @param tickcount Tick count. A client's prediction based on the server's GetGameTickCount value. - * @param seed Random seed. Used to determine weapon recoil, spread, and other predicted elements. - * @param mouse Mouse direction (x, y). - * @return Plugin_Handled to block the commands from being processed, Plugin_Continue otherwise. - * - * @note To see if all 11 params are available, use FeatureType_Capability and - * FEATURECAP_PLAYERRUNCMD_11PARAMS. - */ -forward Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]); - -/** - * @brief Called after a clients movement buttons were processed. - * - * @param client Index of the client. - * @param buttons The current commands (as bitflags - see entity_prop_stocks.inc). - * @param impulse The current impulse command. - * @param vel Players desired velocity. - * @param angles Players desired view angles. - * @param weapon Entity index of the new weapon if player switches weapon, 0 otherwise. - * @param subtype Weapon subtype when selected from a menu. - * @param cmdnum Command number. Increments from the first command sent. - * @param tickcount Tick count. A client's prediction based on the server's GetGameTickCount value. - * @param seed Random seed. Used to determine weapon recoil, spread, and other predicted elements. - * @param mouse Mouse direction (x, y). - */ -forward void OnPlayerRunCmdPost(int client, int buttons, int impulse, const float vel[3], const float angles[3], int weapon, int subtype, int cmdnum, int tickcount, int seed, const int mouse[2]); - -/** - * @brief Called when a client requests a file from the server. - * - * @param client Client index. - * @param sFile Requested file path. - * - * @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed. - */ -forward Action OnFileSend(int client, const char[] sFile); - -/** - * @brief Called when a client sends a file to the server. - * - * @param client Client index. - * @param sFile Requested file path. - * - * @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed. - */ -forward Action OnFileReceive(int client, const char[] sFile); diff --git a/scripting/include/sdktools_sound.inc b/scripting/include/sdktools_sound.inc deleted file mode 100644 index aceeafd..0000000 --- a/scripting/include/sdktools_sound.inc +++ /dev/null @@ -1,725 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_sound_included - #endinput -#endif -#define _sdktools_sound_included - -/** - * Sound should be from the target client. - */ -#define SOUND_FROM_PLAYER -2 - -/** - * Sound should be from the listen server player. - */ -#define SOUND_FROM_LOCAL_PLAYER -1 - -/** - * Sound is from the world. - */ -#define SOUND_FROM_WORLD 0 - -/** - * Sound channels. - */ -enum -{ - SNDCHAN_REPLACE = -1, /**< Unknown */ - SNDCHAN_AUTO = 0, /**< Auto */ - SNDCHAN_WEAPON = 1, /**< Weapons */ - SNDCHAN_VOICE = 2, /**< Voices */ - SNDCHAN_ITEM = 3, /**< Items */ - SNDCHAN_BODY = 4, /**< Player? */ - SNDCHAN_STREAM = 5, /**< "Stream channel from the static or dynamic area" */ - SNDCHAN_STATIC = 6, /**< "Stream channel from the static area" */ - SNDCHAN_VOICE_BASE = 7, /**< "Channel for network voice data" */ - SNDCHAN_USER_BASE = 135 /**< Anything >= this is allocated to game code */ -}; - -/** - * Sound flags for the sound emitter system. - */ -enum -{ - SND_NOFLAGS= 0, /**< Nothing */ - SND_CHANGEVOL = 1, /**< Change sound volume */ - SND_CHANGEPITCH = 2, /**< Change sound pitch */ - SND_STOP = 3, /**< Stop the sound */ - SND_SPAWNING = 4, /**< Used in some cases for ambients */ - SND_DELAY = 5, /**< Sound has an initial delay */ - SND_STOPLOOPING = 6, /**< Stop looping all sounds on the entity */ - SND_SPEAKER = 7, /**< Being played by a mic through a speaker */ - SND_SHOULDPAUSE = 8, /**< Pause if game is paused */ -}; - -/** - * Various predefined sound levels in dB. - */ -enum -{ - SNDLEVEL_NONE = 0, /**< None */ - SNDLEVEL_RUSTLE = 20, /**< Rustling leaves */ - SNDLEVEL_WHISPER = 25, /**< Whispering */ - SNDLEVEL_LIBRARY = 30, /**< In a library */ - SNDLEVEL_FRIDGE = 45, /**< Refrigerator */ - SNDLEVEL_HOME = 50, /**< Average home (3.9 attn) */ - SNDLEVEL_CONVO = 60, /**< Normal conversation (2.0 attn) */ - SNDLEVEL_DRYER = 60, /**< Clothes dryer */ - SNDLEVEL_DISHWASHER = 65, /**< Dishwasher/washing machine (1.5 attn) */ - SNDLEVEL_CAR = 70, /**< Car or vacuum cleaner (1.0 attn) */ - SNDLEVEL_NORMAL = 75, /**< Normal sound level */ - SNDLEVEL_TRAFFIC = 75, /**< Busy traffic (0.8 attn) */ - SNDLEVEL_MINIBIKE = 80, /**< Mini-bike, alarm clock (0.7 attn) */ - SNDLEVEL_SCREAMING = 90, /**< Screaming child (0.5 attn) */ - SNDLEVEL_TRAIN = 100, /**< Subway train, pneumatic drill (0.4 attn) */ - SNDLEVEL_HELICOPTER = 105, /**< Helicopter */ - SNDLEVEL_SNOWMOBILE = 110, /**< Snow mobile */ - SNDLEVEL_AIRCRAFT = 120, /**< Auto horn, aircraft */ - SNDLEVEL_RAIDSIREN = 130, /**< Air raid siren */ - SNDLEVEL_GUNFIRE = 140, /**< Gunshot, jet engine (0.27 attn) */ - SNDLEVEL_ROCKET = 180, /**< Rocket launching (0.2 attn) */ -}; - -#define SNDVOL_NORMAL 1.0 /**< Normal volume */ -#define SNDPITCH_NORMAL 100 /**< Normal pitch */ -#define SNDPITCH_LOW 95 /**< A low pitch */ -#define SNDPITCH_HIGH 120 /**< A high pitch */ -#define SNDATTN_NONE 0.0 /**< No attenuation */ -#define SNDATTN_NORMAL 0.8 /**< Normal attenuation */ -#define SNDATTN_STATIC 1.25 /**< Static attenuation? */ -#define SNDATTN_RICOCHET 1.5 /**< Ricochet effect */ -#define SNDATTN_IDLE 2.0 /**< Idle attenuation? */ - -/** - * Prefetches a sound. - * - * @param name Sound file name relative to the "sounds" folder. - */ -native void PrefetchSound(const char[] name); - -/** - * This function is not known to work, and may crash. You should - * not use it. It is provided for backwards compatibility only. - * - * @param name Sound file name relative to the "sounds" folder. - * @return Duration in seconds. - */ -#pragma deprecated Does not work, may crash. -native float GetSoundDuration(const char[] name); - -/** - * Emits an ambient sound. - * - * @param name Sound file name relative to the "sounds" folder. - * @param pos Origin of sound. - * @param entity Entity index to associate sound with. - * @param level Sound level (from 0 to 255). - * @param flags Sound flags. - * @param vol Volume (from 0.0 to 1.0). - * @param pitch Pitch (from 0 to 255). - * @param delay Play delay. - */ -native void EmitAmbientSound(const char[] name, - const float pos[3], - int entity = SOUND_FROM_WORLD, - int level = SNDLEVEL_NORMAL, - int flags = SND_NOFLAGS, - float vol = SNDVOL_NORMAL, - int pitch = SNDPITCH_NORMAL, - float delay = 0.0); - -/** - * Fades a client's volume level toward silence or a given percentage. - * - * @param client Client index. - * @param percent Fade percentage. - * @param outtime Fade out time, in seconds. - * @param holdtime Hold time, in seconds. - * @param intime Fade in time, in seconds. - * @error Invalid client index or client not in game. - */ -native void FadeClientVolume(int client, float percent, float outtime, float holdtime, float intime); - -/** - * Stops a sound. - * - * @param entity Entity index. - * @param channel Channel number. - * @param name Sound file name relative to the "sounds" folder. - */ -native void StopSound(int entity, int channel, const char[] name); - -/** - * Emits a sound to a list of clients. - * - * @param clients Array of client indexes. - * @param numClients Number of clients in the array. - * @param sample Sound file name relative to the "sounds" folder. - * @param entity Entity to emit from. - * @param channel Channel to emit with. - * @param level Sound level. - * @param flags Sound flags. - * @param volume Sound volume. - * @param pitch Sound pitch. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @param ... Optional list of Float[3] arrays to specify additional origins. - * @error Invalid client index. - */ -native void EmitSound(const int[] clients, - int numClients, - const char[] sample, - int entity = SOUND_FROM_PLAYER, - int channel = SNDCHAN_AUTO, - int level = SNDLEVEL_NORMAL, - int flags = SND_NOFLAGS, - float volume = SNDVOL_NORMAL, - int pitch = SNDPITCH_NORMAL, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0, - any ...); - -/** - * Emits a sound or game sound to a list of clients using the latest version of the engine sound interface. - * This native is only available in engines that are greater than or equal to Portal 2. - * - * @param clients Array of client indexes. - * @param numClients Number of clients in the array. - * @param soundEntry Sound entry name. - * @param sample Sound file name relative to the "sounds" folder. - * @param entity Entity to emit from. - * @param channel Channel to emit with. - * @param level Sound level. - * @param seed Sound seed. - * @param flags Sound flags. - * @param volume Sound volume. - * @param pitch Sound pitch. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @param ... Optional list of Float[3] arrays to specify additional origins. - * @error Invalid client index. - */ -native void EmitSoundEntry(const int[] clients, - int numClients, - const char[] soundEntry, - const char[] sample, - int entity = SOUND_FROM_PLAYER, - int channel = SNDCHAN_AUTO, - int level = SNDLEVEL_NORMAL, - int seed = 0, - int flags = SND_NOFLAGS, - float volume = SNDVOL_NORMAL, - int pitch = SNDPITCH_NORMAL, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0, - any ...); - -/** - * Emits a sentence to a list of clients. - * - * @param clients Array of client indexes. - * @param numClients Number of clients in the array. - * @param sentence Sentence index (from PrecacheSentenceFile). - * @param entity Entity to emit from. - * @param channel Channel to emit with. - * @param level Sound level. - * @param flags Sound flags. - * @param volume Sound volume. - * @param pitch Sound pitch. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @param ... Optional list of Float[3] arrays to specify additional origins. - * @error Invalid client index. - */ -native void EmitSentence(const int[] clients, - int numClients, - int sentence, - int entity, - int channel = SNDCHAN_AUTO, - int level = SNDLEVEL_NORMAL, - int flags = SND_NOFLAGS, - float volume = SNDVOL_NORMAL, - int pitch = SNDPITCH_NORMAL, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0, - any ...); - -/** - * Calculates gain of sound on given distance with given sound level in decibel - * - * @param soundlevel decibel of sound, like SNDLEVEL_NORMAL or integer value - * @param distance distance of sound to calculate, not meter or feet, but Source Engine`s normal Coordinate unit - * @return gain of sound. you can multiply this with original sound`s volume to calculate volume on given distance - */ -native float GetDistGainFromSoundLevel(int soundlevel, float distance); - -/** - * Called when an ambient sound is about to be emitted to one or more clients. - * - * NOTICE: all parameters can be overwritten to modify the default behavior. - * - * @param sample Sound file name relative to the "sounds" folder. - * @param entity Entity index associated to the sound. - * @param volume Volume (from 0.0 to 1.0). - * @param level Sound level (from 0 to 255). - * @param pitch Pitch (from 0 to 255). - * @param pos Origin of sound. - * @param flags Sound flags. - * @param delay Play delay. - * @return Plugin_Continue to allow the sound to be played, Plugin_Stop to block it, - * Plugin_Changed when any parameter has been modified. - */ -typedef AmbientSHook = function Action ( - char sample[PLATFORM_MAX_PATH], - int &entity, - float &volume, - int &level, - int &pitch, - float pos[3], - int &flags, - float &delay -); - -typeset NormalSHook -{ - // Called when a sound is going to be emitted to one or more clients. - // NOTICE: all params can be overwritten to modify the default behavior. - // - // @param clients Array of client indexes. - // @param numClients Number of clients in the array (modify this value if you add/remove elements from the client array). - // @param sample Sound file name relative to the "sounds" folder. - // @param entity Entity emitting the sound. - // @param channel Channel emitting the sound. - // @param volume Sound volume. - // @param level Sound level. - // @param pitch Sound pitch. - // @param flags Sound flags. - // @param soundEntry Game sound entry name. (Used in engines newer than Portal 2) - // @param seed Sound seed. (Used in engines newer than Portal 2) - // @return Plugin_Continue to allow the sound to be played, Plugin_Stop to block it, - // Plugin_Changed when any parameter has been modified. - function Action (int clients[MAXPLAYERS], int &numClients, char sample[PLATFORM_MAX_PATH], - int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, - char soundEntry[PLATFORM_MAX_PATH], int &seed); - - // Deprecated. Use other prototype. - function Action (int clients[64], int &numClients, char sample[PLATFORM_MAX_PATH], - int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, - char soundEntry[PLATFORM_MAX_PATH], int &seed); - - // Deprecated. Use other prototype. - function Action (int clients[64], int &numClients, char sample[PLATFORM_MAX_PATH], - int &entity, int &channel, float &volume, int &level, int &pitch, int &flags); -}; - -/** - * Hooks all played ambient sounds. - * - * @param hook Function to use as a hook. - * @error Invalid function hook. - */ -native void AddAmbientSoundHook(AmbientSHook hook); - -/** - * Hooks all played normal sounds. - * - * @param hook Function to use as a hook. - * @error Invalid function hook. - */ -native void AddNormalSoundHook(NormalSHook hook); - -/** - * Unhooks all played ambient sounds. - * - * @param hook Function used for the hook. - * @error Invalid function hook. - */ -native void RemoveAmbientSoundHook(AmbientSHook hook); - -/** - * Unhooks all played normal sounds. - * - * @param hook Function used for the hook. - * @error Invalid function hook. - */ -native void RemoveNormalSoundHook(NormalSHook hook); - -/** - * Wrapper to emit sound to one client. - * - * @param client Client index. - * @param sample Sound file name relative to the "sounds" folder. - * @param entity Entity to emit from. - * @param channel Channel to emit with. - * @param level Sound level. - * @param flags Sound flags. - * @param volume Sound volume. - * @param pitch Sound pitch. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @error Invalid client index. - */ -stock void EmitSoundToClient(int client, - const char[] sample, - int entity = SOUND_FROM_PLAYER, - int channel = SNDCHAN_AUTO, - int level = SNDLEVEL_NORMAL, - int flags = SND_NOFLAGS, - float volume = SNDVOL_NORMAL, - int pitch = SNDPITCH_NORMAL, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0) -{ - int clients[1]; - clients[0] = client; - /* Save some work for SDKTools and remove SOUND_FROM_PLAYER references */ - entity = (entity == SOUND_FROM_PLAYER) ? client : entity; - EmitSound(clients, 1, sample, entity, channel, - level, flags, volume, pitch, speakerentity, - origin, dir, updatePos, soundtime); -} - -/** - * Wrapper to emit sound to all clients. - * - * @param sample Sound file name relative to the "sounds" folder. - * @param entity Entity to emit from. - * @param channel Channel to emit with. - * @param level Sound level. - * @param flags Sound flags. - * @param volume Sound volume. - * @param pitch Sound pitch. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @error Invalid client index. - */ -stock void EmitSoundToAll(const char[] sample, - int entity = SOUND_FROM_PLAYER, - int channel = SNDCHAN_AUTO, - int level = SNDLEVEL_NORMAL, - int flags = SND_NOFLAGS, - float volume = SNDVOL_NORMAL, - int pitch = SNDPITCH_NORMAL, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0) -{ - int[] clients = new int[MaxClients]; - int total = 0; - - for (int i=1; i<=MaxClients; i++) - { - if (IsClientInGame(i)) - { - clients[total++] = i; - } - } - - if (!total) - { - return; - } - - EmitSound(clients, total, sample, entity, channel, - level, flags, volume, pitch, speakerentity, - origin, dir, updatePos, soundtime); -} - -/** - * Converts an attenuation value to a sound level. - * This function is from the HL2SDK. - * - * @param attn Attenuation value. - * @return Integer sound level. - */ -stock int ATTN_TO_SNDLEVEL(float attn) -{ - if (attn > 0.0) - { - return RoundFloat(50.0 + (20.0 / attn)); - } - return 0; -} - -/** - * Retrieves the parameters for a game sound. - * - * Game sounds are found in a game's scripts/game_sound.txt or other files - * referenced from it - * - * Note that if a game sound has a rndwave section, one of them will be returned - * at random. - * - * @param gameSound Name of game sound. - * @param channel Channel to emit with. - * @param level Sound level. - * @param volume Sound volume. - * @param pitch Sound pitch. - * @param sample Sound file name relative to the "sounds" folder. - * @param maxlength Maximum length of sample string buffer. - * @param entity Entity the sound is being emitted from. - * @return True if the sound was successfully retrieved, false if it - * was not found - */ -native bool GetGameSoundParams(const char[] gameSound, - int &channel, - int &soundLevel, - float &volume, - int &pitch, - char[] sample, - int maxlength, - int entity=SOUND_FROM_PLAYER); - -/** - * Emits a game sound to a list of clients. - * - * Game sounds are found in a game's scripts/game_sound.txt or other files - * referenced from it - * - * Note that if a game sound has a rndwave section, one of them will be returned - * at random. - * - * @param clients Array of client indexes. - * @param numClients Number of clients in the array. - * @param gameSound Name of game sound. - * @param entity Entity to emit from. - * @param flags Sound flags. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @return True if the sound was played successfully, false if it failed - * @error Invalid client index. - */ -stock bool EmitGameSound(const int[] clients, - int numClients, - const char[] gameSound, - int entity = SOUND_FROM_PLAYER, - int flags = SND_NOFLAGS, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0) -{ - int channel; - int level; - float volume; - int pitch; - char sample[PLATFORM_MAX_PATH]; - - if (GetGameSoundParams(gameSound, channel, level, volume, pitch, sample, sizeof(sample), entity)) - { - EmitSound(clients, numClients, sample, entity, channel, level, flags, volume, pitch, speakerentity, origin, dir, updatePos, soundtime); - return true; - } - else - { - return false; - } -} - -/** - * Emits an ambient game sound. - * - * Game sounds are found in a game's scripts/game_sound.txt or other files - * referenced from it - * - * Note that if a game sound has a rndwave section, one of them will be returned - * at random. - * - * @param gameSound Name of game sound. - * @param pos Origin of sound. - * @param entity Entity index to associate sound with. - * @param flags Sound flags. - * @param delay Play delay. - */ -stock bool EmitAmbientGameSound(const char[] gameSound, - const float pos[3], - int entity = SOUND_FROM_WORLD, - int flags = SND_NOFLAGS, - float delay = 0.0) -{ - int channel; // This is never actually used for Ambients, but it's a mandatory field to GetGameSoundParams - int level; - float volume; - int pitch; - char sample[PLATFORM_MAX_PATH]; - - if (GetGameSoundParams(gameSound, channel, level, volume, pitch, sample, sizeof(sample), entity)) - { - EmitAmbientSound(sample, pos, entity, level, flags, volume, pitch, delay); - return true; - } - else - { - return false; - } -} - -/** - * Wrapper to emit a game sound to one client. - * - * Game sounds are found in a game's scripts/game_sound.txt or other files - * referenced from it - * - * Note that if a game sound has a rndwave section, one of them will be returned - * at random. - * - * @param client Client index. - * @param gameSound Name of game sound. - * @param entity Entity to emit from. - * @param flags Sound flags. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @error Invalid client index. - */ -stock bool EmitGameSoundToClient(int client, - const char[] gameSound, - int entity = SOUND_FROM_PLAYER, - int flags = SND_NOFLAGS, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0) -{ - int clients[1]; - clients[0] = client; - /* Save some work for SDKTools and remove SOUND_FROM_PLAYER references */ - entity = (entity == SOUND_FROM_PLAYER) ? client : entity; - return EmitGameSound(clients, 1, gameSound, entity, flags, - speakerentity, origin, dir, updatePos, soundtime); -} - -/** - * Wrapper to emit game sound to all clients. - * - * Game sounds are found in a game's scripts/game_sound.txt or other files - * referenced from it - * - * Note that if a game sound has a rndwave section, one of them will be returned - * at random. - * - * @param gameSound Name of game sound. - * @param entity Entity to emit from. - * @param flags Sound flags. - * @param speakerentity Unknown. - * @param origin Sound origin. - * @param dir Sound direction. - * @param updatePos Unknown (updates positions?) - * @param soundtime Alternate time to play sound for. - * @error Invalid client index. - */ -stock bool EmitGameSoundToAll(const char[] gameSound, - int entity = SOUND_FROM_PLAYER, - int flags = SND_NOFLAGS, - int speakerentity = -1, - const float origin[3] = NULL_VECTOR, - const float dir[3] = NULL_VECTOR, - bool updatePos = true, - float soundtime = 0.0) -{ - int[] clients = new int[MaxClients]; - int total = 0; - - for (int i=1; i<=MaxClients; i++) - { - if (IsClientInGame(i)) - { - clients[total++] = i; - } - } - - if (!total) - { - return false; - } - - return EmitGameSound(clients, total, gameSound, entity, flags, - speakerentity, origin, dir, updatePos, soundtime); -} - -/** - * Precache a game sound. - * - * Most games will precache all game sounds on map start, but this is not guaranteed... - * Team Fortress 2 is known to not pre-cache MvM game mode sounds on non-MvM maps. - * - * Due to the above, this native should be called before any calls to GetGameSoundParams, - * EmitGameSound*, or EmitAmbientGameSound. - * - * It should be safe to pass already precached game sounds to this function. - * - * Note: It precaches all files for a game sound. - * - * @param soundname Game sound to precache - * - * @return True if the game sound was found, false if sound did not exist - * or had no files - */ -native bool PrecacheScriptSound(const char[] soundname); diff --git a/scripting/include/sdktools_stocks.inc b/scripting/include/sdktools_stocks.inc deleted file mode 100644 index 2af01a8..0000000 --- a/scripting/include/sdktools_stocks.inc +++ /dev/null @@ -1,75 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_stocks_included - #endinput -#endif -#define _sdktools_stocks_included - -/** - * Given a partial team name, attempts to find a matching team. - * - * The search is performed case insensitively and only against the - * first N characters of the team names, where N is the number of - * characters in the search pattern. - * - * @param name Partial or full team name. - * @return A valid team index on success. - * -1 if no team matched. - * -2 if more than one team matched. - */ -stock int FindTeamByName(const char[] name) -{ - int name_len = strlen(name); - int num_teams = GetTeamCount(); - char team_name[32]; - int found_team = -1; - - for (int i = 0; i < num_teams; i++) - { - GetTeamName(i, team_name, sizeof(team_name)); - - if (strncmp(team_name, name, name_len, false) == 0) - { - if (found_team >= 0) - { - return -2; - } - else - { - found_team = i; - } - } - } - - return found_team; -} diff --git a/scripting/include/sdktools_stringtables.inc b/scripting/include/sdktools_stringtables.inc deleted file mode 100644 index 59e13f1..0000000 --- a/scripting/include/sdktools_stringtables.inc +++ /dev/null @@ -1,180 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_stringtables_included - #endinput -#endif -#define _sdktools_stringtables_included - -#define INVALID_STRING_TABLE -1 /**< An invalid string table index */ -#define INVALID_STRING_INDEX -1 /**< An invalid string index in a table */ - -/** - * Searches for a string table. - * - * @param name Name of string table to find. - * @return A string table index number if found, INVALID_STRING_TABLE otherwise. - */ -native int FindStringTable(const char[] name); - -/** - * Returns the number of string tables that currently exist. - * - * @return Number of string tables that currently exist. - */ -native int GetNumStringTables(); - -/** - * Returns the number of strings that currently exist in a given string table. - * - * @param tableidx A string table index. - * @return Number of strings that currently exist. - * @error Invalid string table index. - */ -native int GetStringTableNumStrings(int tableidx); - -/** - * Returns the maximum number of strings that are allowed in a given string table. - * - * @param tableidx A string table index. - * @return Maximum number of strings allowed. - * @error Invalid string table index. - */ -native int GetStringTableMaxStrings(int tableidx); - -/** - * Retrieves the name of a string table. - * - * @param tableidx A string table index. - * @param name Buffer to store the name of the string table. - * @param maxlength Maximum length of string buffer. - * @return Number of bytes written to the buffer (UTF-8 safe). - * @error Invalid string table index. - */ -native int GetStringTableName(int tableidx, char[] name, int maxlength); - -/** - * Searches for the index of a given string in a string table. - * - * @param tableidx A string table index. - * @param str String to find. - * @return String index if found, INVALID_STRING_INDEX otherwise. - * @error Invalid string table index. - */ -native int FindStringIndex(int tableidx, const char[] str); - -/** - * Retrieves the string at a given index of a string table. - * - * @param tableidx A string table index. - * @param stringidx A string index. - * @param str Buffer to store the string value. - * @param maxlength Maximum length of string buffer. - * @return Number of bytes written to the buffer (UTF-8 safe). - * @error Invalid string table index or string index. - */ -native int ReadStringTable(int tableidx, int stringidx, char[] str, int maxlength); - -/** - * Returns the length of the user data associated with a given string index. - * - * @param tableidx A string table index. - * @param stringidx A string index. - * @return Length of user data. This will be 0 if there is no user data. - * @error Invalid string table index or string index. - */ -native int GetStringTableDataLength(int tableidx, int stringidx); - -/** - * Retrieves the user data associated with a given string index. - * - * @param tableidx A string table index. - * @param stringidx A string index. - * @param userdata Buffer to store the user data. This will be set to "" if there is no user data. - * @param maxlength Maximum length of string buffer. - * @return Number of bytes written to the buffer (UTF-8 safe). - * @error Invalid string table index or string index. - */ -native int GetStringTableData(int tableidx, int stringidx, char[] userdata, int maxlength); - -/** - * Sets the user data associated with a given string index. - * - * @param tableidx A string table index. - * @param stringidx A string index. - * @param userdata User data string that will be set. - * @param length Length of user data string. This should include the null terminator. - * @return Number of bytes written to the buffer (UTF-8 safe). - * @error Invalid string table index or string index. - */ -native int SetStringTableData(int tableidx, int stringidx, const char[] userdata, int length); - -/** - * Adds a string to a given string table. - * - * @param tableidx A string table index. - * @param str String to add. - * @param userdata An optional user data string. - * @param length Length of user data string. This should include the null terminator. - * If set to -1, then user data will be not be altered if the specified string - * already exists in the string table. - */ -native void AddToStringTable(int tableidx, const char[] str, const char[] userdata="", int length=-1); - -/** - * Locks or unlocks the network string tables. - * - * @param lock Determines whether network string tables should be locked. - * True means the tables should be locked for writing; false means unlocked. - * @return Previous lock state. - */ -native bool LockStringTables(bool lock); - -/** - * Adds a file to the downloadables network string table. - * This forces a client to download the file if they do not already have it. - * - * @param filename File that will be added to downloadables table. - */ -stock void AddFileToDownloadsTable(const char[] filename) -{ - static int table = INVALID_STRING_TABLE; - - if (table == INVALID_STRING_TABLE) - { - table = FindStringTable("downloadables"); - } - - bool save = LockStringTables(false); - AddToStringTable(table, filename); - LockStringTables(save); -} diff --git a/scripting/include/sdktools_tempents.inc b/scripting/include/sdktools_tempents.inc deleted file mode 100644 index 41c2f33..0000000 --- a/scripting/include/sdktools_tempents.inc +++ /dev/null @@ -1,232 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_tempents_included - #endinput -#endif -#define _sdktools_tempents_included - -/** - * Called when a temp entity is going to be sent. - * - * @param te_name TE name. - * @param Players Array containing target player indexes. - * @param numClients Number of players in the array. - * @param delay Delay in seconds to send the TE. - * @return Plugin_Continue to allow the transmission of the TE, Plugin_Stop to block it. - */ -typedef TEHook = function Action (const char[] te_name, const int[] Players, int numClients, float delay); - -/** - * Hooks a temp entity. - * - * @param te_name TE name to hook. - * @param hook Function to use as a hook. - * @error Temp Entity name not available or invalid function hook. - */ -native void AddTempEntHook(const char[] te_name, TEHook hook); - -/** - * Removes a temp entity hook. - * - * @param te_name TE name to unhook. - * @param hook Function used for the hook. - * @error Temp Entity name not available or invalid function hook. - */ -native void RemoveTempEntHook(const char[] te_name, TEHook hook); - -/** - * Starts a temp entity transmission. - * - * @param te_name TE name. - * @error Temp Entity name not available. - */ -native void TE_Start(const char[] te_name); - -/** - * Checks if a certain TE property exists. - * - * @param prop Property to use. - * @return True if the property exists, otherwise false. - */ -native bool TE_IsValidProp(const char[] prop); - -/** - * Sets an integer value in the current temp entity. - * - * @param prop Property to use. - * @param value Integer value to set. - * @error Property not found. - */ -native void TE_WriteNum(const char[] prop, int value); - -/** - * Reads an integer value in the current temp entity. - * - * @param prop Property to use. - * @return Property value. - * @error Property not found. - */ -native int TE_ReadNum(const char[] prop); - -/** - * Sets a floating point number in the current temp entity. - * - * @param prop Property to use. - * @param value Floating point number to set. - * @error Property not found. - */ -native void TE_WriteFloat(const char[] prop, float value); - -/** - * Reads a floating point number in the current temp entity. - * - * @param prop Property to use. - * @return Property value. - * @error Property not found. - */ -native float TE_ReadFloat(const char[] prop); - -/** - * Sets a vector in the current temp entity. - * - * @param prop Property to use. - * @param vector Vector to set. - * @error Property not found. - */ -native void TE_WriteVector(const char[] prop, const float vector[3]); - -/** - * Reads a vector in the current temp entity. - * - * @param prop Property to use. - * @param vector Vector to read. - * @error Property not found. - */ -native void TE_ReadVector(const char[] prop, float vector[3]); - -/** - * Sets a QAngle in the current temp entity. - * - * @param prop Property to use. - * @param angles Angles to set. - * @error Property not found. - */ -native void TE_WriteAngles(const char[] prop, const float angles[3]); - -/** - * Sets an array of floats in the current temp entity. - * - * @param prop Property to use. - * @param array Array of values to copy. - * @param arraySize Number of values to copy. - * @error Property not found. - */ -native void TE_WriteFloatArray(const char[] prop, const float[] array, int arraySize); - -/** - * Sends the current temp entity to one or more clients. - * - * @param clients Array containing player indexes to broadcast to. - * @param numClients Number of players in the array. - * @param delay Delay in seconds to send the TE. - * @error Invalid client index or client not in game. - */ -native void TE_Send(const int[] clients, int numClients, float delay=0.0); - -/** - * Sets an encoded entity index in the current temp entity. - * (This is usually used for m_nStartEntity and m_nEndEntity). - * - * @param prop Property to use. - * @param value Value to set. - * @error Property not found. - */ -stock void TE_WriteEncodedEnt(const char[] prop, int value) -{ - int encvalue = (value & 0x0FFF) | ((1 & 0xF)<<12); - TE_WriteNum(prop, encvalue); -} - -/** - * Broadcasts the current temp entity to all clients. - * @note See TE_Start(). - * - * @param delay Delay in seconds to send the TE. - */ -stock void TE_SendToAll(float delay=0.0) -{ - int total = 0; - int[] clients = new int[MaxClients]; - for (int i=1; i<=MaxClients; i++) - { - if (IsClientInGame(i)) - { - clients[total++] = i; - } - } - TE_Send(clients, total, delay); -} - -/** - * Sends the current TE to only a client. - * @note See TE_Start(). - * - * @param client Client to send to. - * @param delay Delay in seconds to send the TE. - * @error Invalid client index or client not in game. - */ -stock void TE_SendToClient(int client, float delay=0.0) -{ - int players[1]; - - players[0] = client; - - TE_Send(players, 1, delay); -} - -/** - * Sends the current TE to all clients that are in - * visible or audible range of the origin. - * @note See TE_Start(). - * @note See GetClientsInRange() - * - * @param origin Coordinates from which to test range. - * @param rangeType Range type to use for filtering clients. - * @param delay Delay in seconds to send the TE. - */ -stock void TE_SendToAllInRange(float origin[3], ClientRangeType rangeType, float delay=0.0) -{ - int[] clients = new int[MaxClients]; - int total = GetClientsInRange(origin, rangeType, clients, MaxClients); - TE_Send(clients, total, delay); -} diff --git a/scripting/include/sdktools_tempents_stocks.inc b/scripting/include/sdktools_tempents_stocks.inc deleted file mode 100644 index 853e464..0000000 --- a/scripting/include/sdktools_tempents_stocks.inc +++ /dev/null @@ -1,443 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _te_stocks_included - #endinput -#endif -#define _te_stocks_included - -/** - * @section TE Explosion flags. - */ -#define TE_EXPLFLAG_NONE 0x0 /**< all flags clear makes default Half-Life explosion */ -#define TE_EXPLFLAG_NOADDITIVE 0x1 /**< sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) */ -#define TE_EXPLFLAG_NODLIGHTS 0x2 /**< do not render dynamic lights */ -#define TE_EXPLFLAG_NOSOUND 0x4 /**< do not play client explosion sound */ -#define TE_EXPLFLAG_NOPARTICLES 0x8 /**< do not draw particles */ -#define TE_EXPLFLAG_DRAWALPHA 0x10 /**< sprite will be drawn alpha */ -#define TE_EXPLFLAG_ROTATE 0x20 /**< rotate the sprite randomly */ -#define TE_EXPLFLAG_NOFIREBALL 0x40 /**< do not draw a fireball */ -#define TE_EXPLFLAG_NOFIREBALLSMOKE 0x80 /**< do not draw smoke with the fireball */ - -/** - * @endsection - */ - -/** - * @section TE Beam flags. - */ -#define FBEAM_STARTENTITY 0x00000001 -#define FBEAM_ENDENTITY 0x00000002 -#define FBEAM_FADEIN 0x00000004 -#define FBEAM_FADEOUT 0x00000008 -#define FBEAM_SINENOISE 0x00000010 -#define FBEAM_SOLID 0x00000020 -#define FBEAM_SHADEIN 0x00000040 -#define FBEAM_SHADEOUT 0x00000080 -#define FBEAM_ONLYNOISEONCE 0x00000100 /**< Only calculate our noise once */ -#define FBEAM_NOTILE 0x00000200 -#define FBEAM_USE_HITBOXES 0x00000400 /**< Attachment indices represent hitbox indices instead when this is set. */ -#define FBEAM_STARTVISIBLE 0x00000800 /**< Has this client actually seen this beam's start entity yet? */ -#define FBEAM_ENDVISIBLE 0x00001000 /**< Has this client actually seen this beam's end entity yet? */ -#define FBEAM_ISACTIVE 0x00002000 -#define FBEAM_FOREVER 0x00004000 -#define FBEAM_HALOBEAM 0x00008000 /**< When drawing a beam with a halo, don't ignore the segments and endwidth */ - -/** - * @endsection - */ - -/** - * Sets up a sparks effect. - * - * @param pos Position of the sparks. - * @param dir Direction of the sparks. - * @param Magnitude Sparks size. - * @param TrailLength Trail lenght of the sparks. - */ -stock void TE_SetupSparks(const float pos[3], const float dir[3], int Magnitude, int TrailLength) -{ - TE_Start("Sparks"); - TE_WriteVector("m_vecOrigin[0]", pos); - TE_WriteVector("m_vecDir", dir); - TE_WriteNum("m_nMagnitude", Magnitude); - TE_WriteNum("m_nTrailLength", TrailLength); -} - -/** - * Sets up a smoke effect. - * - * @param pos Position of the smoke. - * @param Model Precached model index. - * @param Scale Scale of the smoke. - * @param FrameRate Frame rate of the smoke. - */ -stock void TE_SetupSmoke(const float pos[3], int Model, float Scale, int FrameRate) -{ - TE_Start("Smoke"); - TE_WriteVector("m_vecOrigin", pos); - TE_WriteNum("m_nModelIndex", Model); - TE_WriteFloat("m_fScale", Scale); - TE_WriteNum("m_nFrameRate", FrameRate); -} - -/** - * Sets up a dust cloud effect. - * - * @param pos Position of the dust. - * @param dir Direction of the dust. - * @param Size Dust cloud size. - * @param Speed Dust cloud speed. - */ -stock void TE_SetupDust(const float pos[3], const float dir[3], float Size, float Speed) -{ - TE_Start("Dust"); - TE_WriteVector("m_vecOrigin[0]", pos); - TE_WriteVector("m_vecDirection", dir); - TE_WriteFloat("m_flSize", Size); - TE_WriteFloat("m_flSpeed", Speed); -} - -/** - * Sets up a muzzle flash effect. - * - * @param pos Position of the muzzle flash. - * @param angles Rotation angles of the muzzle flash. - * @param Scale Scale of the muzzle flash. - * @param Type Muzzle flash type to render (Mod specific). - */ -stock void TE_SetupMuzzleFlash(const float pos[3], const float angles[3], float Scale, int Type) -{ - TE_Start("MuzzleFlash"); - TE_WriteVector("m_vecOrigin", pos); - TE_WriteVector("m_vecAngles", angles); - TE_WriteFloat("m_flScale", Scale); - TE_WriteNum("m_nType", Type); -} - -/** - * Sets up a metal sparks effect. - * - * @param pos Position of the metal sparks. - * @param dir Direction of the metal sparks. - */ -stock void TE_SetupMetalSparks(const float pos[3], const float dir[3]) -{ - TE_Start("Metal Sparks"); - TE_WriteVector("m_vecPos", pos); - TE_WriteVector("m_vecDir", dir); -} - -/** - * Sets up an energy splash effect. - * - * @param pos Position of the energy splash. - * @param dir Direction of the energy splash. - * @param Explosive Makes the effect explosive. - */ -stock void TE_SetupEnergySplash(const float pos[3], const float dir[3], bool Explosive) -{ - TE_Start("Energy Splash"); - TE_WriteVector("m_vecPos", pos); - TE_WriteVector("m_vecDir", dir); - TE_WriteNum("m_bExplosive", Explosive); -} - -/** - * Sets up an armor ricochet effect. - * - * @param pos Position of the armor ricochet. - * @param dir Direction of the armor ricochet. - */ -stock void TE_SetupArmorRicochet(const float pos[3], const float dir[3]) -{ - TE_Start("Armor Ricochet"); - TE_WriteVector("m_vecPos", pos); - TE_WriteVector("m_vecDir", dir); -} - -/** - * Sets up a glowing sprite effect. - * - * @param pos Position of the sprite. - * @param Model Precached model index. - * @param Life Time duration of the sprite. - * @param Size Sprite size. - * @param Brightness Sprite brightness. - */ -stock void TE_SetupGlowSprite(const float pos[3], int Model, float Life, float Size, int Brightness) -{ - TE_Start("GlowSprite"); - TE_WriteVector("m_vecOrigin", pos); - TE_WriteNum("m_nModelIndex", Model); - TE_WriteFloat("m_fScale", Size); - TE_WriteFloat("m_fLife", Life); - TE_WriteNum("m_nBrightness", Brightness); -} - -/** - * Sets up a explosion effect. - * - * @param pos Explosion position. - * @param Model Precached model index. - * @param Scale Explosion scale. - * @param Framerate Explosion frame rate. - * @param Flags Explosion flags. - * @param Radius Explosion radius. - * @param Magnitude Explosion size. - * @param normal Normal vector to the explosion. - * @param MaterialType Exploded material type. - */ -stock void TE_SetupExplosion(const float pos[3], int Model, float Scale, int Framerate, int Flags, int Radius, int Magnitude, const float normal[3]={0.0, 0.0, 1.0}, int MaterialType='C') -{ - TE_Start("Explosion"); - TE_WriteVector("m_vecOrigin[0]", pos); - TE_WriteVector("m_vecNormal", normal); - TE_WriteNum("m_nModelIndex", Model); - TE_WriteFloat("m_fScale", Scale); - TE_WriteNum("m_nFrameRate", Framerate); - TE_WriteNum("m_nFlags", Flags); - TE_WriteNum("m_nRadius", Radius); - TE_WriteNum("m_nMagnitude", Magnitude); - TE_WriteNum("m_chMaterialType", MaterialType); -} - -/** - * Sets up a blood sprite effect. - * - * @param pos Position of the sprite. - * @param dir Sprite direction. - * @param color Color array (r, g, b, a). - * @param Size Sprite size. - * @param SprayModel Precached model index. - * @param BloodDropModel Precached model index. - */ -stock void TE_SetupBloodSprite(const float pos[3], const float dir[3], const int color[4], int Size, int SprayModel, int BloodDropModel) -{ - TE_Start("Blood Sprite"); - TE_WriteVector("m_vecOrigin", pos); - TE_WriteVector("m_vecDirection", dir); - TE_WriteNum("r", color[0]); - TE_WriteNum("g", color[1]); - TE_WriteNum("b", color[2]); - TE_WriteNum("a", color[3]); - TE_WriteNum("m_nSize", Size); - TE_WriteNum("m_nSprayModel", SprayModel); - TE_WriteNum("m_nDropModel", BloodDropModel); -} - -/** - * Sets up a beam ring point effect. - * - * @param center Center position of the ring. - * @param Start_Radius Initial ring radius. - * @param End_Radius Final ring radius. - * @param ModelIndex Precached model index. - * @param HaloIndex Precached model index. - * @param StartFrame Initial frame to render. - * @param FrameRate Ring frame rate. - * @param Life Time duration of the ring. - * @param Width Beam width. - * @param Amplitude Beam amplitude. - * @param Color Color array (r, g, b, a). - * @param Speed Speed of the beam. - * @param Flags Beam flags. - */ -stock void TE_SetupBeamRingPoint(const float center[3], float Start_Radius, float End_Radius, int ModelIndex, int HaloIndex, int StartFrame, - int FrameRate, float Life, float Width, float Amplitude, const int Color[4], int Speed, int Flags) -{ - TE_Start("BeamRingPoint"); - TE_WriteVector("m_vecCenter", center); - TE_WriteFloat("m_flStartRadius", Start_Radius); - TE_WriteFloat("m_flEndRadius", End_Radius); - TE_WriteNum("m_nModelIndex", ModelIndex); - TE_WriteNum("m_nHaloIndex", HaloIndex); - TE_WriteNum("m_nStartFrame", StartFrame); - TE_WriteNum("m_nFrameRate", FrameRate); - TE_WriteFloat("m_fLife", Life); - TE_WriteFloat("m_fWidth", Width); - TE_WriteFloat("m_fEndWidth", Width); - TE_WriteFloat("m_fAmplitude", Amplitude); - TE_WriteNum("r", Color[0]); - TE_WriteNum("g", Color[1]); - TE_WriteNum("b", Color[2]); - TE_WriteNum("a", Color[3]); - TE_WriteNum("m_nSpeed", Speed); - TE_WriteNum("m_nFlags", Flags); - TE_WriteNum("m_nFadeLength", 0); -} - -/** - * Sets up a point to point beam effect. - * - * @param start Start position of the beam. - * @param end End position of the beam. - * @param ModelIndex Precached model index. - * @param HaloIndex Precached model index. - * @param StartFrame Initial frame to render. - * @param FrameRate Beam frame rate. - * @param Life Time duration of the beam. - * @param Width Initial beam width. - * @param EndWidth Final beam width. - * @param FadeLength Beam fade time duration. - * @param Amplitude Beam amplitude. - * @param Color Color array (r, g, b, a). - * @param Speed Speed of the beam. - */ -stock void TE_SetupBeamPoints(const float start[3], const float end[3], int ModelIndex, int HaloIndex, int StartFrame, int FrameRate, float Life, - float Width, float EndWidth, int FadeLength, float Amplitude, const int Color[4], int Speed) -{ - TE_Start("BeamPoints"); - TE_WriteVector("m_vecStartPoint", start); - TE_WriteVector("m_vecEndPoint", end); - TE_WriteNum("m_nModelIndex", ModelIndex); - TE_WriteNum("m_nHaloIndex", HaloIndex); - TE_WriteNum("m_nStartFrame", StartFrame); - TE_WriteNum("m_nFrameRate", FrameRate); - TE_WriteFloat("m_fLife", Life); - TE_WriteFloat("m_fWidth", Width); - TE_WriteFloat("m_fEndWidth", EndWidth); - TE_WriteFloat("m_fAmplitude", Amplitude); - TE_WriteNum("r", Color[0]); - TE_WriteNum("g", Color[1]); - TE_WriteNum("b", Color[2]); - TE_WriteNum("a", Color[3]); - TE_WriteNum("m_nSpeed", Speed); - TE_WriteNum("m_nFadeLength", FadeLength); -} - -/** - * Sets up an entity to entity laser effect. - * - * @param StartEntity Entity index from where the beam starts. - * @param EndEntity Entity index from where the beam ends. - * @param ModelIndex Precached model index. - * @param HaloIndex Precached model index. - * @param StartFrame Initial frame to render. - * @param FrameRate Beam frame rate. - * @param Life Time duration of the beam. - * @param Width Initial beam width. - * @param EndWidth Final beam width. - * @param FadeLength Beam fade time duration. - * @param Amplitude Beam amplitude. - * @param Color Color array (r, g, b, a). - * @param Speed Speed of the beam. - */ -stock void TE_SetupBeamLaser(int StartEntity, int EndEntity, int ModelIndex, int HaloIndex, int StartFrame, int FrameRate, float Life, - float Width, float EndWidth, int FadeLength, float Amplitude, const int Color[4], int Speed) -{ - TE_Start("BeamLaser"); - TE_WriteEncodedEnt("m_nStartEntity", StartEntity); - TE_WriteEncodedEnt("m_nEndEntity", EndEntity); - TE_WriteNum("m_nModelIndex", ModelIndex); - TE_WriteNum("m_nHaloIndex", HaloIndex); - TE_WriteNum("m_nStartFrame", StartFrame); - TE_WriteNum("m_nFrameRate", FrameRate); - TE_WriteFloat("m_fLife", Life); - TE_WriteFloat("m_fWidth", Width); - TE_WriteFloat("m_fEndWidth", EndWidth); - TE_WriteFloat("m_fAmplitude", Amplitude); - TE_WriteNum("r", Color[0]); - TE_WriteNum("g", Color[1]); - TE_WriteNum("b", Color[2]); - TE_WriteNum("a", Color[3]); - TE_WriteNum("m_nSpeed", Speed); - TE_WriteNum("m_nFadeLength", FadeLength); -} - -/** - * Sets up a beam ring effect. - * - * @param StartEntity Entity index from where the ring starts. - * @param EndEntity Entity index from where the ring ends. - * @param ModelIndex Precached model index. - * @param HaloIndex Precached model index. - * @param StartFrame Initial frame to render. - * @param FrameRate Ring frame rate. - * @param Life Time duration of the ring. - * @param Width Beam width. - * @param Amplitude Beam amplitude. - * @param Color Color array (r, g, b, a). - * @param Speed Speed of the beam. - * @param Flags Beam flags. - */ -stock void TE_SetupBeamRing(int StartEntity, int EndEntity, int ModelIndex, int HaloIndex, int StartFrame, int FrameRate, float Life, float Width, float Amplitude, const int Color[4], int Speed, int Flags) -{ - TE_Start("BeamRing"); - TE_WriteEncodedEnt("m_nStartEntity", StartEntity); - TE_WriteEncodedEnt("m_nEndEntity", EndEntity); - TE_WriteNum("m_nModelIndex", ModelIndex); - TE_WriteNum("m_nHaloIndex", HaloIndex); - TE_WriteNum("m_nStartFrame", StartFrame); - TE_WriteNum("m_nFrameRate", FrameRate); - TE_WriteFloat("m_fLife", Life); - TE_WriteFloat("m_fWidth", Width); - TE_WriteFloat("m_fEndWidth", Width); - TE_WriteFloat("m_fAmplitude", Amplitude); - TE_WriteNum("r", Color[0]); - TE_WriteNum("g", Color[1]); - TE_WriteNum("b", Color[2]); - TE_WriteNum("a", Color[3]); - TE_WriteNum("m_nSpeed", Speed); - TE_WriteNum("m_nFadeLength", 0); - TE_WriteNum("m_nFlags", Flags); -} - -/** - * Sets up a follow beam effect. - * - * @param EntIndex Entity index from where the beam starts. - * @param ModelIndex Precached model index. - * @param HaloIndex Precached model index. - * @param Life Time duration of the beam. - * @param Width Initial beam width. - * @param EndWidth Final beam width. - * @param FadeLength Beam fade time duration. - * @param Color Color array (r, g, b, a). - */ -stock void TE_SetupBeamFollow(int EntIndex, int ModelIndex, int HaloIndex, float Life, float Width, float EndWidth, int FadeLength, const int Color[4]) -{ - TE_Start("BeamFollow"); - TE_WriteEncodedEnt("m_iEntIndex", EntIndex); - TE_WriteNum("m_nModelIndex", ModelIndex); - TE_WriteNum("m_nHaloIndex", HaloIndex); - TE_WriteNum("m_nStartFrame", 0); - TE_WriteNum("m_nFrameRate", 0); - TE_WriteFloat("m_fLife", Life); - TE_WriteFloat("m_fWidth", Width); - TE_WriteFloat("m_fEndWidth", EndWidth); - TE_WriteNum("m_nFadeLength", FadeLength); - TE_WriteNum("r", Color[0]); - TE_WriteNum("g", Color[1]); - TE_WriteNum("b", Color[2]); - TE_WriteNum("a", Color[3]); -} diff --git a/scripting/include/sdktools_trace.inc b/scripting/include/sdktools_trace.inc deleted file mode 100644 index 3b9d5ee..0000000 --- a/scripting/include/sdktools_trace.inc +++ /dev/null @@ -1,368 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_trace_included - #endinput -#endif -#define _sdktools_trace_included - -#define CONTENTS_EMPTY 0 /**< No contents. */ -#define CONTENTS_SOLID 0x1 /**< an eye is never valid in a solid . */ -#define CONTENTS_WINDOW 0x2 /**< translucent, but not watery (glass). */ -#define CONTENTS_AUX 0x4 -#define CONTENTS_GRATE 0x8 /**< alpha-tested "grate" textures. Bullets/sight pass through, but solids don't. */ -#define CONTENTS_SLIME 0x10 -#define CONTENTS_WATER 0x20 -#define CONTENTS_MIST 0x40 -#define CONTENTS_OPAQUE 0x80 /**< things that cannot be seen through (may be non-solid though). */ -#define LAST_VISIBLE_CONTENTS 0x80 -#define ALL_VISIBLE_CONTENTS (LAST_VISIBLE_CONTENTS | (LAST_VISIBLE_CONTENTS-1)) -#define CONTENTS_TESTFOGVOLUME 0x100 -#define CONTENTS_UNUSED5 0x200 -#define CONTENTS_UNUSED6 0x4000 -#define CONTENTS_TEAM1 0x800 /**< per team contents used to differentiate collisions. */ -#define CONTENTS_TEAM2 0x1000 /**< between players and objects on different teams. */ -#define CONTENTS_IGNORE_NODRAW_OPAQUE 0x2000 /**< ignore CONTENTS_OPAQUE on surfaces that have SURF_NODRAW. */ -#define CONTENTS_MOVEABLE 0x4000 /**< hits entities which are MOVETYPE_PUSH (doors, plats, etc) */ -#define CONTENTS_AREAPORTAL 0x8000 /**< remaining contents are non-visible, and don't eat brushes. */ -#define CONTENTS_PLAYERCLIP 0x10000 -#define CONTENTS_MONSTERCLIP 0x20000 - -/** - * @section currents can be added to any other contents, and may be mixed - */ -#define CONTENTS_CURRENT_0 0x40000 -#define CONTENTS_CURRENT_90 0x80000 -#define CONTENTS_CURRENT_180 0x100000 -#define CONTENTS_CURRENT_270 0x200000 -#define CONTENTS_CURRENT_UP 0x400000 -#define CONTENTS_CURRENT_DOWN 0x800000 - -/** - * @endsection - */ - -#define CONTENTS_ORIGIN 0x1000000 /**< removed before bsp-ing an entity. */ -#define CONTENTS_MONSTER 0x2000000 /**< should never be on a brush, only in game. */ -#define CONTENTS_DEBRIS 0x4000000 -#define CONTENTS_DETAIL 0x8000000 /**< brushes to be added after vis leafs. */ -#define CONTENTS_TRANSLUCENT 0x10000000 /**< auto set if any surface has trans. */ -#define CONTENTS_LADDER 0x20000000 -#define CONTENTS_HITBOX 0x40000000 /**< use accurate hitboxes on trace. */ - -/** - * @section Trace masks. - */ -#define MASK_ALL (0xFFFFFFFF) -#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) /**< everything that is normally solid */ -#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) /**< everything that blocks player movement */ -#define MASK_NPCSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) /**< blocks npc movement */ -#define MASK_WATER (CONTENTS_WATER|CONTENTS_MOVEABLE|CONTENTS_SLIME) /**< water physics in these contents */ -#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_OPAQUE) /**< everything that blocks line of sight for AI, lighting, etc */ -#define MASK_OPAQUE_AND_NPCS (MASK_OPAQUE|CONTENTS_MONSTER) /**< everything that blocks line of sight for AI, lighting, etc, but with monsters added. */ -#define MASK_VISIBLE (MASK_OPAQUE|CONTENTS_IGNORE_NODRAW_OPAQUE) /**< everything that blocks line of sight for players */ -#define MASK_VISIBLE_AND_NPCS (MASK_OPAQUE_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE) /**< everything that blocks line of sight for players, but with monsters added. */ -#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_HITBOX) /**< bullets see these as solid */ -#define MASK_SHOT_HULL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_GRATE) /**< non-raycasted weapons see this as solid (includes grates) */ -#define MASK_SHOT_PORTAL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW) /**< hits solids (not grates) and passes through everything else */ -#define MASK_SOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_GRATE) /**< everything normally solid, except monsters (world+brush only) */ -#define MASK_PLAYERSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_PLAYERCLIP|CONTENTS_GRATE) /**< everything normally solid for player movement, except monsters (world+brush only) */ -#define MASK_NPCSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) /**< everything normally solid for npc movement, except monsters (world+brush only) */ -#define MASK_NPCWORLDSTATIC (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) /**< just the world, used for route rebuilding */ -#define MASK_SPLITAREAPORTAL (CONTENTS_WATER|CONTENTS_SLIME) /**< These are things that can split areaportals */ - -/** - * @endsection - */ - -enum RayType -{ - RayType_EndPoint, /**< The trace ray will go from the start position to the end position. */ - RayType_Infinite /**< The trace ray will go from the start position to infinity using a direction vector. */ -}; - -typeset TraceEntityFilter -{ - /** - * Called on entity filtering. - * - * @param entity Entity index. - * @param contentsMask Contents Mask. - * @return True to allow the current entity to be hit, otherwise false. - */ - function bool (int entity, int contentsMask); - - /** - * Called on entity filtering. - * - * @param entity Entity index. - * @param contentsMask Contents Mask. - * @param data Data value, if used. - * @return True to allow the current entity to be hit, otherwise false. - */ - function bool (int entity, int contentsMask, any data); -}; - -/** - * Get the contents mask and the entity index at the given position. - * - * @param pos World position to test. - * @param entindex Entity index found at the given position (by reference). - * @return Contents mask. - */ -native int TR_GetPointContents(const float pos[3], int &entindex=-1); - -/** - * Get the point contents testing only the given entity index. - * - * @param entindex Entity index to test. - * @param pos World position. - * @return Contents mask. - */ -native int TR_GetPointContentsEnt(int entindex, const float pos[3]); - -/** - * Starts up a new trace ray using a global trace result. - * - * @param pos Starting position of the ray. - * @param vec Depending on RayType, it will be used as the - * ending point, or the direction angle. - * @param flags Trace flags. - * @param rtype Method to calculate the ray direction. - */ -native void TR_TraceRay(const float pos[3], - const float vec[3], - int flags, - RayType rtype); - -/** - * Starts up a new trace hull using a global trace result. - * - * @param pos Starting position of the ray. - * @param vec Ending position of the ray. - * @param mins Hull minimum size. - * @param maxs Hull maximum size. - * @param flags Trace flags. - */ -native void TR_TraceHull(const float pos[3], - const float vec[3], - const float mins[3], - const float maxs[3], - int flags); - -/** - * Starts up a new trace ray using a global trace result and a customized - * trace ray filter. - * - * Calling TR_Trace*Filter or TR_Trace*FilterEx from inside a filter - * function is currently not allowed and may not work. - * - * @param pos Starting position of the ray. - * @param vec Depending on RayType, it will be used as the ending - * point, or the direction angle. - * @param flags Trace flags. - * @param rtype Method to calculate the ray direction. - * @param filter Function to use as a filter. - * @param data Arbitrary data value to pass through to the filter - * function. - */ -native void TR_TraceRayFilter(const float pos[3], - const float vec[3], - int flags, - RayType rtype, - TraceEntityFilter filter, - any data=0); - -/** - * Starts up a new trace hull using a global trace result and a customized - * trace ray filter. - * - * Calling TR_Trace*Filter or TR_Trace*FilterEx from inside a filter - * function is currently not allowed and may not work. - * - * @param pos Starting position of the ray. - * @param vec Depending on RayType, it will be used as the ending - * point, or the direction angle. - * @param mins Hull minimum size. - * @param maxs Hull maximum size. - * @param flags Trace flags. - * @param filter Function to use as a filter. - * @param data Arbitrary data value to pass through to the filter - * function. - */ -native void TR_TraceHullFilter(const float pos[3], - const float vec[3], - const float mins[3], - const float maxs[3], - int flags, - TraceEntityFilter filter, - any data=0); - -/** - * Starts up a new trace ray using a new trace result. - * - * @param pos Starting position of the ray. - * @param vec Depending on RayType, it will be used as the ending - * point, or the direction angle. - * @param flags Trace flags. - * @param rtype Method to calculate the ray direction. - * @return Ray trace handle, which must be closed via CloseHandle(). - */ -native Handle TR_TraceRayEx(const float pos[3], - const float vec[3], - int flags, - RayType rtype); - -/** - * Starts up a new trace hull using a new trace result. - * - * @param pos Starting position of the ray. - * @param vec Ending position of the ray. - * @param mins Hull minimum size. - * @param maxs Hull maximum size. - * @param flags Trace flags. - * @return Ray trace handle, which must be closed via CloseHandle(). - */ -native Handle TR_TraceHullEx(const float pos[3], - const float vec[3], - const float mins[3], - const float maxs[3], - int flags); - -/** - * Starts up a new trace ray using a new trace result and a customized - * trace ray filter. - * - * Calling TR_Trace*Filter or TR_TraceRay*Ex from inside a filter - * function is currently not allowed and may not work. - * - * @param pos Starting position of the ray. - * @param vec Depending on RayType, it will be used as the ending - * point, or the direction angle. - * @param flags Trace flags. - * @param rtype Method to calculate the ray direction. - * @param filter Function to use as a filter. - * @param data Arbitrary data value to pass through to the filter function. - * @return Ray trace handle, which must be closed via CloseHandle(). - */ -native Handle TR_TraceRayFilterEx(const float pos[3], - const float vec[3], - int flags, - RayType rtype, - TraceEntityFilter filter, - any data=0); - -/** - * Starts up a new trace hull using a new trace result and a customized - * trace ray filter. - * - * Calling TR_Trace*Filter or TR_Trace*FilterEx from inside a filter - * function is currently not allowed and may not work. - * - * @param pos Starting position of the ray. - * @param vec Ending position of the ray. - * @param mins Hull minimum size. - * @param maxs Hull maximum size. - * @param flags Trace flags. - * @param filter Function to use as a filter. - * @param data Arbitrary data value to pass through to the filter function. - * @return Ray trace handle, which must be closed via CloseHandle(). - */ -native Handle TR_TraceHullFilterEx(const float pos[3], - const float vec[3], - const float mins[3], - const float maxs[3], - int flags, - TraceEntityFilter filter, - any data=0); - -/** - * Returns the time fraction from a trace result (1.0 means no collision). - * - * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. - * @return Time fraction value of the trace. - * @error Invalid Handle. - */ -native float TR_GetFraction(Handle hndl=INVALID_HANDLE); - -/** - * Returns the collision position of a trace result. - * - * @param pos Vector buffer to store data in. - * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. - * @error Invalid Handle. - */ -native void TR_GetEndPosition(float pos[3], Handle hndl=INVALID_HANDLE); - -/** - * Returns the entity index that collided with the trace. - * - * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. - * @return Entity index or -1 for no collision. - * @error Invalid Handle. - */ -native int TR_GetEntityIndex(Handle hndl=INVALID_HANDLE); - -/** - * Returns if there was any kind of collision along the trace ray. - * - * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. - * @return True if any collision found, otherwise false. - * @error Invalid Handle. - */ -native bool TR_DidHit(Handle hndl=INVALID_HANDLE); - -/** - * Returns in which body hit group the trace collided if any. - * - * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. - * @return Body hit group. - * @error Invalid Handle. - */ -native int TR_GetHitGroup(Handle hndl=INVALID_HANDLE); - -/** - * Find the normal vector to the collision plane of a trace. - * - * @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result. - * @param normal Vector buffer to store the vector normal to the collision plane - * @error Invalid Handle - */ -native void TR_GetPlaneNormal(Handle hndl, float normal[3]); - -/** - * Tests a point to see if it's outside any playable area - * - * @param pos Vector buffer to store data in. - * @return True if outside world, otherwise false. - */ -native bool TR_PointOutsideWorld(float pos[3]); diff --git a/scripting/include/sdktools_variant_t.inc b/scripting/include/sdktools_variant_t.inc deleted file mode 100644 index 9934816..0000000 --- a/scripting/include/sdktools_variant_t.inc +++ /dev/null @@ -1,93 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2017 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_variant_t_included - #endinput -#endif -#define _sdktools_variant_t_included - -/** - * Sets a bool value in the global variant object. - * - * @param val Input value. - */ -native void SetVariantBool(bool val); - -/** - * Sets a string in the global variant object. - * - * @param str Input string. - */ -native void SetVariantString(const char[] str); - -/** - * Sets an integer value in the global variant object. - * - * @param val Input value. - */ -native void SetVariantInt(int val); - -/** - * Sets a floating point value in the global variant object. - * - * @param val Input value. - */ -native void SetVariantFloat(float val); - -/** - * Sets a 3D vector in the global variant object. - * - * @param vec Input vector. - */ -native void SetVariantVector3D(const float vec[3]); - -/** - * Sets a 3D position vector in the global variant object. - * - * @param vec Input position vector. - */ -native void SetVariantPosVector3D(const float vec[3]); - -/** - * Sets a color in the global variant object. - * - * @param color Input color. - */ -native void SetVariantColor(const int color[4]); - -/** - * Sets an entity in the global variant object. - * - * @param entity Entity index. - * @error Invalid entity index. - */ -native void SetVariantEntity(int entity); \ No newline at end of file diff --git a/scripting/include/sdktools_voice.inc b/scripting/include/sdktools_voice.inc deleted file mode 100644 index 505a0ab..0000000 --- a/scripting/include/sdktools_voice.inc +++ /dev/null @@ -1,122 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sdktools_voice_included - #endinput -#endif -#define _sdktools_voice_included - -/** - * @section voice flags. - */ -#define VOICE_NORMAL 0 /**< Allow the client to listen and speak normally. */ -#define VOICE_MUTED 1 /**< Mutes the client from speaking to everyone. */ -#define VOICE_SPEAKALL 2 /**< Allow the client to speak to everyone. */ -#define VOICE_LISTENALL 4 /**< Allow the client to listen to everyone. */ -#define VOICE_TEAM 8 /**< Allow the client to always speak to team, even when dead. */ -#define VOICE_LISTENTEAM 16 /**< Allow the client to always hear teammates, including dead ones. */ - -/** - * @endsection - */ - -enum ListenOverride -{ - Listen_Default = 0, /**< Leave it up to the game */ - Listen_No, /**< Can't hear */ - Listen_Yes, /**< Can hear */ -}; - -/** - * Set the client listening flags. - * - * @param client The client index - * @param flags The voice flags - */ -native void SetClientListeningFlags(int client, int flags); - -/** - * Retrieve the client current listening flags. - * - * @param client The client index - * @return The current voice flags - */ -native int GetClientListeningFlags(int client); - -/** - * Set the receiver ability to listen to the sender. - * - * @param iReceiver The listener index. - * @param iSender The sender index. - * @param bListen True if the receiver can listen to the sender, false otherwise. - * @return True if successful otherwise false. - */ -#pragma deprecated Use SetListenOverride() instead -native bool SetClientListening(int iReceiver, int iSender, bool bListen); - -/** - * Retrieves if the receiver can listen to the sender. - * - * @param iReceiver The listener index. - * @param iSender The sender index. - * @return True if successful otherwise false. - */ -#pragma deprecated GetListenOverride() instead -native bool GetClientListening(int iReceiver, int iSender); - -/** - * Override the receiver's ability to listen to the sender. - * - * @param iReceiver The listener index. - * @param iSender The sender index. - * @param override The override of the receiver's ability to listen to the sender. - * @return True if successful otherwise false. - */ -native bool SetListenOverride(int iReceiver, int iSender, ListenOverride override); - -/** - * Retrieves the override of the receiver's ability to listen to the sender. - * - * @param iReceiver The listener index. - * @param iSender The sender index. - * @return The override value. - */ -native ListenOverride GetListenOverride(int iReceiver, int iSender); - -/** - * Retrieves if the muter has muted the mutee. - * - * @param iMuter The muter index. - * @param iMutee The mutee index. - * @return True if muter has muted mutee, false otherwise. - */ -native bool IsClientMuted(int iMuter, int iMutee); diff --git a/scripting/include/sorting.inc b/scripting/include/sorting.inc deleted file mode 100644 index b7e8bf8..0000000 --- a/scripting/include/sorting.inc +++ /dev/null @@ -1,169 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - - -#if defined _sorting_included - #endinput -#endif -#define _sorting_included - -/** - * Contains sorting orders. - */ -enum SortOrder -{ - Sort_Ascending = 0, /**< Ascending order */ - Sort_Descending = 1, /**< Descending order */ - Sort_Random = 2 /**< Random order */ -}; - -/** - * Data types for ADT Array Sorts - */ -enum SortType -{ - Sort_Integer = 0, - Sort_Float, - Sort_String, -}; - -/** - * Sorts an array of integers. - * - * @param array Array of integers to sort in-place. - * @param array_size Size of the array. - * @param order Sorting order to use. - */ -native void SortIntegers(int[] array, int array_size, SortOrder order = Sort_Ascending); - -/** - * Sorts an array of float point numbers. - * - * @param array Array of floating point numbers to sort in-place. - * @param array_size Size of the array. - * @param order Sorting order to use. - */ -native void SortFloats(float[] array, int array_size, SortOrder order = Sort_Ascending); - -/** - * Sorts an array of strings. - * - * @param array Array of strings to sort in-place. - * @param array_size Size of the array. - * @param order Sorting order to use. - */ -native void SortStrings(char[][] array, int array_size, SortOrder order = Sort_Ascending); - -/** - * Sort comparison function for 1D array elements. - * @note You may need to use explicit tags in order to use data properly. - * - * @param elem1 First element to compare. - * @param elem2 Second element to compare. - * @param array Array that is being sorted (order is undefined). - * @param hndl Handle optionally passed in while sorting. - * @return -1 if first should go before second - * 0 if first is equal to second - * 1 if first should go after second - */ -typedef SortFunc1D = function int (int elem1, int elem2, const int[] array, Handle hndl); - -/** - * Sorts a custom 1D array. You must pass in a comparison function. - * - * @param array Array to sort. - * @param array_size Size of the array to sort. - * @param sortfunc Sort function. - * @param hndl Optional Handle to pass through the comparison calls. - */ -native void SortCustom1D(int[] array, int array_size, SortFunc1D sortfunc, Handle hndl=INVALID_HANDLE); - -/** - * Sort comparison function for 2D array elements (sub-arrays). - * @note You may need to use explicit tags in order to use data properly. - * - * @param elem1 First array to compare. - * @param elem2 Second array to compare. - * @param array Array that is being sorted (order is undefined). - * @param hndl Handle optionally passed in while sorting. - * @return -1 if first should go before second - * 0 if first is equal to second - * 1 if first should go after second - */ -typeset SortFunc2D -{ - function int (int[] elem1, int[] elem2, const int[][] array, Handle hndl); - function int (char[] elem1, char[] elem2, const char[][] array, Handle hndl); -}; - -/** - * Sorts a custom 2D array. You must pass in a comparison function. - * - * @param array Array to sort. - * @param array_size Size of the major array to sort (first index, outermost). - * @param sortfunc Sort comparison function to use. - * @param hndl Optional Handle to pass through the comparison calls. - */ -native void SortCustom2D(any[][] array, int array_size, SortFunc2D sortfunc, Handle hndl=INVALID_HANDLE); - -/** - * Sort an ADT Array. Specify the type as Integer, Float, or String. - * - * @param array Array Handle to sort - * @param order Sort order to use, same as other sorts. - * @param type Data type stored in the ADT Array - */ -native void SortADTArray(Handle array, SortOrder order, SortType type); - -/** - * Sort comparison function for ADT Array elements. Function provides you with - * indexes currently being sorted, use ADT Array functions to retrieve the - * index values and compare. - * - * @param index1 First index to compare. - * @param index2 Second index to compare. - * @param array Array that is being sorted (order is undefined). - * @param hndl Handle optionally passed in while sorting. - * @return -1 if first should go before second - * 0 if first is equal to second - * 1 if first should go after second - */ -typedef SortFuncADTArray = function int (int index1, int index2, Handle array, Handle hndl); - -/** - * Custom sorts an ADT Array. You must pass in a comparison function. - * - * @param array Array Handle to sort - * @param sortfunc Sort comparison function to use - * @param hndl Optional Handle to pass through the comparison calls. - */ -native void SortADTArrayCustom(Handle array, SortFuncADTArray sortfunc, Handle hndl=INVALID_HANDLE); diff --git a/scripting/include/sourcemod.inc b/scripting/include/sourcemod.inc deleted file mode 100644 index 3b18863..0000000 --- a/scripting/include/sourcemod.inc +++ /dev/null @@ -1,681 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _sourcemod_included - #endinput -#endif -#define _sourcemod_included - -/** - * Plugin public information. - */ -struct Plugin -{ - public const char[] name; /**< Plugin Name */ - public const char[] description; /**< Plugin Description */ - public const char[] author; /**< Plugin Author */ - public const char[] version; /**< Plugin Version */ - public const char[] url; /**< Plugin URL */ -}; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum APLRes -{ - APLRes_Success = 0, /**< Plugin should load */ - APLRes_Failure, /**< Plugin shouldn't load and should display an error */ - APLRes_SilentFailure /**< Plugin shouldn't load but do so silently */ -}; - -/** - * Called when the plugin is fully initialized and all known external references - * are resolved. This is only called once in the lifetime of the plugin, and is - * paired with OnPluginEnd(). - * - * If any run-time error is thrown during this callback, the plugin will be marked - * as failed. - */ -forward void OnPluginStart(); - -/** - * @deprecated Use AskPluginLoad2() instead. - * If a plugin contains both AskPluginLoad() and AskPluginLoad2(), the former will - * not be called, but old plugins with only AskPluginLoad() will work. - */ -#pragma deprecated Use AskPluginLoad2() instead -forward bool AskPluginLoad(Handle myself, bool late, char[] error, int err_max); - -/** - * Called before OnPluginStart, in case the plugin wants to check for load failure. - * This is called even if the plugin type is "private." Any natives from modules are - * not available at this point. Thus, this forward should only be used for explicit - * pre-emptive things, such as adding dynamic natives, setting certain types of load - * filters (such as not loading the plugin for certain games). - * - * @note It is not safe to call externally resolved natives until OnPluginStart(). - * @note Any sort of RTE in this function will cause the plugin to fail loading. - * @note If you do not return anything, it is treated like returning success. - * @note If a plugin has an AskPluginLoad2(), AskPluginLoad() will not be called. - * - * - * @param myself Handle to the plugin. - * @param late Whether or not the plugin was loaded "late" (after map load). - * @param error Error message buffer in case load failed. - * @param err_max Maximum number of characters for error message buffer. - * @return APLRes_Success for load success, APLRes_Failure or APLRes_SilentFailure otherwise - */ -forward APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max); - -/** - * Called when the plugin is about to be unloaded. - * - * It is not necessary to close any handles or remove hooks in this function. - * SourceMod guarantees that plugin shutdown automatically and correctly releases - * all resources. - */ -forward void OnPluginEnd(); - -/** - * Called when the plugin's pause status is changing. - * - * @param pause True if the plugin is being paused, false otherwise. - */ -forward void OnPluginPauseChange(bool pause); - -/** - * Called before every server frame. Note that you should avoid - * doing expensive computations or declaring large local arrays. - */ -forward void OnGameFrame(); - -/** - * Called when the map is loaded. - * - * @note This used to be OnServerLoad(), which is now deprecated. - * Plugins still using the old forward will work. - */ -forward void OnMapStart(); - -/** - * Called right before a map ends. - */ -forward void OnMapEnd(); - -/** - * Called when the map has loaded, servercfgfile (server.cfg) has been - * executed, and all plugin configs are done executing. This is the best - * place to initialize plugin functions which are based on cvar data. - * - * @note This will always be called once and only once per map. It will be - * called after OnMapStart(). - */ -forward void OnConfigsExecuted(); - -/** - * This is called once, right after OnMapStart() but any time before - * OnConfigsExecuted(). It is called after the "exec sourcemod.cfg" - * command and all AutoExecConfig() exec commands have been added to - * the ServerCommand() buffer. - * - * If you need to load per-map settings that override default values, - * adding commands to the ServerCommand() buffer here will guarantee - * that they're set before OnConfigsExecuted(). - * - * Unlike OnMapStart() and OnConfigsExecuted(), this is not called on - * late loads that occur after OnMapStart(). - */ -forward void OnAutoConfigsBuffered(); - -/** - * @deprecated Use OnConfigsExecuted() instead. - */ -#pragma deprecated Use OnConfigsExecuted() instead -forward void OnServerCfg(); - -/** - * Called after all plugins have been loaded. This is called once for - * every plugin. If a plugin late loads, it will be called immediately - * after OnPluginStart(). - */ -forward void OnAllPluginsLoaded(); - -/** - * Returns the calling plugin's Handle. - * - * @return Handle of the calling plugin. - */ -native Handle GetMyHandle(); - -/** - * Returns an iterator that can be used to search through plugins. - * - * @return Handle to iterate with. Must be closed via - * CloseHandle(). - * @error Invalid Handle. - */ -native Handle GetPluginIterator(); - -/** - * Returns whether there are more plugins available in the iterator. - * - * @param iter Handle to the plugin iterator. - * @return True on more plugins, false otherwise. - * @error Invalid Handle. - */ -native bool MorePlugins(Handle iter); - -/** - * Returns the current plugin in the iterator and advances the iterator. - * - * @param iter Handle to the plugin iterator. - * @return Current plugin the iterator is at, before - * the iterator is advanced. - * @error Invalid Handle. - */ -native Handle ReadPlugin(Handle iter); - -/** - * Returns a plugin's status. - * - * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). - * @return Status code for the plugin. - * @error Invalid Handle. - */ -native PluginStatus GetPluginStatus(Handle plugin); - -/** - * Retrieves a plugin's file name relative to the plugins folder. - * - * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). - * @param buffer Buffer to the store the file name. - * @param maxlength Maximum length of the name buffer. - * @error Invalid Handle. - */ -native void GetPluginFilename(Handle plugin, char[] buffer, int maxlength); - -/** - * Retrieves whether or not a plugin is being debugged. - * - * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). - * @return True if being debugged, false otherwise. - * @error Invalid Handle. - */ -native bool IsPluginDebugging(Handle plugin); - -/** - * Retrieves a plugin's public info. - * - * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). - * @param info Plugin info property to retrieve. - * @param buffer Buffer to store info in. - * @param maxlength Maximum length of buffer. - * @return True on success, false if property is not available. - * @error Invalid Handle. - */ -native bool GetPluginInfo(Handle plugin, PluginInfo info, char[] buffer, int maxlength); - -/** - * Finds a plugin by its order in the list from the "plugins list" server - * "sm" command. You should not use this function to loop through all plugins, - * use the iterator instead. Looping through all plugins using this native - * is O(n^2), whereas using the iterator is O(n). - * - * @param order_num Number of the plugin as it appears in "sm plugins list". - * @return Plugin Handle on success, INVALID_HANDLE if no plugin - * matches the given number. - */ -native Handle FindPluginByNumber(int order_num); - -/** - * Causes the plugin to enter a failed state. An error will be thrown and - * the plugin will be paused until it is unloaded or reloaded. - * - * For backwards compatibility, if no extra arguments are passed, no - * formatting is applied. If one or more additional arguments is passed, - * the string is formatted using Format(). If any errors are encountered - * during formatting, both the format specifier string and an additional - * error message are written. - * - * This function does not return, and no further code in the plugin is - * executed. - * - * @param string Format specifier string. - * @param ... Formatting arguments. - * @error Always throws SP_ERROR_ABORT. - */ -native void SetFailState(const char[] string, any ...); - -/** - * Aborts the current callback and throws an error. This function - * does not return in that no code is executed following it. - * - * @param fmt String format. - * @param ... Format arguments. - * @error Always! - */ -native void ThrowError(const char[] fmt, any ...); - -/** - * Gets the system time as a unix timestamp. - * - * @param bigStamp Optional array to store the 64bit timestamp in. - * @return 32bit timestamp (number of seconds since unix epoch). - */ -native int GetTime(int bigStamp[2]={0,0}); - -/** - * Produces a date and/or time string value for a timestamp. - * - * See this URL for valid parameters: - * http://cplusplus.com/reference/clibrary/ctime/strftime.html - * - * @param buffer Destination string buffer. - * @param maxlength Maximum length of output string buffer. - * @param format Formatting rules (passing NULL_STRING will use the rules defined in sm_datetime_format). - * @param stamp Optional time stamp. - * @error Buffer too small or invalid time format. - */ -native void FormatTime(char[] buffer, int maxlength, const char[] format, int stamp=-1); - -/** - * Loads a game config file. - * - * @param file File to load. The path must be relative to the 'gamedata' folder under the config folder - * and the extension should be omitted. - * @return A handle to the game config file or INVALID_HANDLE in failure. - */ -native Handle LoadGameConfigFile(const char[] file); - -/** - * Returns an offset value. - * - * @param gc Game config handle. - * @param key Key to retrieve from the offset section. - * @return An offset, or -1 on failure. - */ -native int GameConfGetOffset(Handle gc, const char[] key); - -/** - * Gets the value of a key from the "Keys" section. - * - * @param gc Game config handle. - * @param key Key to retrieve from the Keys section. - * @param buffer Destination string buffer. - * @param maxlen Maximum length of output string buffer. - * @return True if key existed, false otherwise. - */ -native bool GameConfGetKeyValue(Handle gc, const char[] key, char[] buffer, int maxlen); - -/** - * Finds an address calculation in a GameConfig file, - * performs LoadFromAddress on it as appropriate, then returns the final address. - * - * @param gameconf GameConfig Handle, or INVALID_HANDLE to use sdktools.games.txt. - * @param name Name of the property to find. - * @return An address calculated on success, or 0 on failure. - */ -native Address GameConfGetAddress(Handle gameconf, const char[] name); - -/** - * Returns the operating system's "tick count," which is a number of - * milliseconds since the operating system loaded. This can be used - * for basic benchmarks. - * - * @return Tick count in milliseconds. - */ -native int GetSysTickCount(); - -/** - * Specifies that the given config file should be executed after plugin load. - * OnConfigsExecuted() will not be called until the config file has executed, - * but it will be called if the execution fails. - * - * @param autoCreate If true, and the config file does not exist, such a config - * file will be automatically created and populated with - * information from the plugin's registered cvars. - * @param name Name of the config file, excluding the .cfg extension. - * If empty, is assumed. - * @param folder Folder under cfg/ to use. By default this is "sourcemod." - */ -native void AutoExecConfig(bool autoCreate=true, const char[] name="", const char[] folder="sourcemod"); - -/** - * Registers a library name for identifying as a dependency to - * other plugins. - * - * @param name Library name. - */ -native void RegPluginLibrary(const char[] name); - -/** - * Returns whether a library exists. This function should be considered - * expensive; it should only be called on plugin to determine availability - * of resources. Use OnLibraryAdded()/OnLibraryRemoved() to detect changes - * in optional resources. - * - * @param name Library name of a plugin or extension. - * @return True if exists, false otherwise. - */ -native bool LibraryExists(const char[] name); - -/** - * Returns the status of an extension, by filename. - * - * @param name Extension name (like "sdktools.ext"). - * @param error Optional error message buffer. - * @param maxlength Length of optional error message buffer. - * @return -2 if the extension was not found. - * -1 if the extension was found but failed to load. - * 0 if the extension loaded but reported an error. - * 1 if the extension is running without error. - */ -native int GetExtensionFileStatus(const char[] name, char[] error="", int maxlength=0); - -/** - * Called after a library is added that the current plugin references - * optionally. A library is either a plugin name or extension name, as - * exposed via its include file. - * - * @param name Library name. - */ -forward void OnLibraryAdded(const char[] name); - -/** - * Called right before a library is removed that the current plugin references - * optionally. A library is either a plugin name or extension name, as - * exposed via its include file. - * - * @param name Library name. - */ -forward void OnLibraryRemoved(const char[] name); - -#define MAPLIST_FLAG_MAPSFOLDER (1<<0) /**< On failure, use all maps in the maps folder. */ -#define MAPLIST_FLAG_CLEARARRAY (1<<1) /**< If an input array is specified, clear it before adding. */ -#define MAPLIST_FLAG_NO_DEFAULT (1<<2) /**< Do not read "default" or "mapcyclefile" on failure. */ - -/** - * Loads a map list to an ADT Array. - * - * A map list is a list of maps from a file. SourceMod allows easy configuration of - * maplists through addons/sourcemod/configs/maplists.cfg. Each entry is given a - * name and a file (for example, "rtv" => "rtv.cfg"), or a name and a redirection - * (for example, "rtv" => "default"). This native will read a map list entry, - * cache the file, and return the list of maps it holds. - * - * Serial change numbers are used to identify if a map list has changed. Thus, if - * you pass a serial change number and it's equal to what SourceMod currently knows - * about the map list, then SourceMod won't re-parse the file. - * - * If the maps end up being read from the maps folder (MAPLIST_FLAG_MAPSFOLDER), they - * are automatically sorted in alphabetical, ascending order. - * - * Arrays created by this function are temporary and must be freed via CloseHandle(). - * Modifying arrays created by this function will not affect future return values or - * or the contents of arrays returned to other plugins. - * - * @param array Array to store the map list. If INVALID_HANDLE, a new blank - * array will be created. The blocksize should be at least 16; - * otherwise results may be truncated. Items are added to the array - * as strings. The array is never checked for duplicates, and it is - * not read beforehand. Only the serial number is used to detect - * changes. - * @param serial Serial number to identify last known map list change. If -1, the - * the value will not be checked. If the map list has since changed, - * the serial is updated (even if -1 was passed). If there is an error - * finding a valid maplist, then the serial is set to -1. - * @param str Config name, or "default" for the default map list. Config names - * should be somewhat descriptive. For example, the admin menu uses - * a config name of "admin menu". The list names can be configured - * by users in addons/sourcemod/configs/maplists.cfg. - * @param flags MAPLIST_FLAG flags. - * @return On failure: - * INVALID_HANDLE is returned, the serial is set to -1, and the input - * array (if any) is left unchanged. - * On no change: - INVALID_HANDLE is returned, the serial is unchanged, and the input - array (if any) is left unchanged. - * On success: - * A valid array Handle is returned, containing at least one map string. - * If an array was passed, the return value is equal to the passed Array - * Handle. If the passed array was not cleared, it will have grown by at - * least one item. The serial number is updated to a positive number. - * @error Invalid array Handle that is not INVALID_HANDLE. - */ -native Handle ReadMapList(Handle array=INVALID_HANDLE, - int &serial=-1, - const char[] str="default", - int flags=MAPLIST_FLAG_CLEARARRAY); - -/** - * Makes a compatibility binding for map lists. For example, if a function previously used - * "clam.cfg" for map lists, this function will insert a "fake" binding to "clam.cfg" that - * will be overridden if it's in the maplists.cfg file. - * - * @param name Configuration name that would be used with ReadMapList(). - * @param file Default file to use. - */ -native void SetMapListCompatBind(const char[] name, const char[] file); - -/** - * Called when a client has sent chat text. This must return either true or - * false to indicate that a client is or is not spamming the server. - * - * The return value is a hint only. Core or another plugin may decide - * otherwise. - * - * @param client Client index. The server (0) will never be passed. - * @return True if client is spamming the server, false otherwise. - */ -forward bool OnClientFloodCheck(int client); - -/** - * Called after a client's flood check has been computed. This can be used - * by antiflood algorithms to decay/increase flooding weights. - * - * Since the result from "OnClientFloodCheck" isn't guaranteed to be the - * final result, it is generally a good idea to use this to play with other - * algorithms nicely. - * - * @param client Client index. The server (0) will never be passed. - * @param blocked True if client flooded last "say", false otherwise. - */ -forward void OnClientFloodResult(int client, bool blocked); - -/** - * Feature types. - */ -enum FeatureType -{ - /** - * A native function call. - */ - FeatureType_Native, - - /** - * A named capability. This is distinctly different from checking for a - * native, because the underlying functionality could be enabled on-demand - * to improve loading time. Thus a native may appear to exist, but it might - * be part of a set of features that are not compatible with the current game - * or version of SourceMod. - */ - FeatureType_Capability -}; - -/** - * Feature statuses. - */ -enum FeatureStatus -{ - /** - * Feature is available for use. - */ - FeatureStatus_Available, - - /** - * Feature is not available. - */ - FeatureStatus_Unavailable, - - /** - * Feature is not known at all. - */ - FeatureStatus_Unknown -}; - -/** - * Returns whether "GetFeatureStatus" will work. Using this native - * or this function will not cause SourceMod to fail loading on older versions, - * however, GetFeatureStatus will only work if this function returns true. - * - * @return True if GetFeatureStatus will work, false otherwise. - */ -stock bool CanTestFeatures() -{ - return LibraryExists("__CanTestFeatures__"); -} - -/** - * Returns whether a feature exists, and if so, whether it is usable. - * - * @param type Feature type. - * @param name Feature name. - * @return Feature status. - */ -native FeatureStatus GetFeatureStatus(FeatureType type, const char[] name); - -/** - * Requires that a given feature is available. If it is not, SetFailState() - * is called with the given message. - * - * @param type Feature type. - * @param name Feature name. - * @param fmt Message format string, or empty to use default. - * @param ... Message format parameters, if any. - */ -native void RequireFeature(FeatureType type, const char[] name, - const char[] fmt="", any ...); - -/** - * Represents how many bytes we can read from an address with one load - */ -enum NumberType -{ - NumberType_Int8, - NumberType_Int16, - NumberType_Int32 -}; - -enum Address -{ - Address_Null = 0, // a typical invalid result when an address lookup fails -}; - -/** - * Load up to 4 bytes from a memory address. - * - * @param addr Address to a memory location. - * @param size How many bytes should be read. - * @return The value that is stored at that address. - */ -native int LoadFromAddress(Address addr, NumberType size); - -/** - * Store up to 4 bytes to a memory address. - * - * @param addr Address to a memory location. - * @param data Value to store at the address. - * @param size How many bytes should be written. - */ -native void StoreToAddress(Address addr, int data, NumberType size); - -methodmap FrameIterator < Handle { - // Creates a stack frame iterator to build your own stack traces. - // @return New handle to a FrameIterator. - public native FrameIterator(); - - // Advances the iterator to the next stack frame. - // @return True if another frame was fetched and data can be successfully read. - // @error No next element exception. - public native bool Next(); - - // Resets the iterator back to it's starting position. - public native void Reset(); - - // Returns the line number of the current function call. - property bool LineNumber { - public native get(); - } - - // Gets the name of the current function in the call stack. - // - // @param buffer Buffer to copy to. - // @param maxlen Max size of the buffer. - public native void GetFunctionName(char[] buffer, int maxlen); - - // Gets the file path to the current call in the call stack. - // - // @param buffer Buffer to copy to. - // @param maxlen Max size of the buffer. - public native void GetFilePath(char[] buffer, int maxlen); -} - -#include -#include -#include diff --git a/scripting/include/string.inc b/scripting/include/string.inc deleted file mode 100644 index a4febcd..0000000 --- a/scripting/include/string.inc +++ /dev/null @@ -1,548 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _string_included - #endinput -#endif -#define _string_included - -/** - * @global Unless otherwise noted, all string functions which take in a - * writable buffer and maximum length should have the null terminator INCLUDED - * in the length. This means that this is valid: - * strcopy(string, sizeof(string), ...) - */ - -/** - * Calculates the length of a string. - * - * @param str String to check. - * @return Number of valid character bytes in the string. - */ -native int strlen(const char[] str); - -/** - * Tests whether a string is found inside another string. - * - * @param str String to search in. - * @param substr Substring to find inside the original string. - * @param caseSensitive If true (default), search is case sensitive. - * If false, search is case insensitive. - * @return -1 on failure (no match found). Any other value - * indicates a position in the string where the match starts. - */ -native int StrContains(const char[] str, const char[] substr, bool caseSensitive=true); - -/** - * Compares two strings lexographically. - * - * @param str1 First string (left). - * @param str2 Second string (right). - * @param caseSensitive If true (default), comparison is case sensitive. - * If false, comparison is case insensitive. - * @return -1 if str1 < str2 - * 0 if str1 == str2 - * 1 if str1 > str2 - */ -native int strcmp(const char[] str1, const char[] str2, bool caseSensitive=true); - -/** - * Compares two strings parts lexographically. - * - * @param str1 First string (left). - * @param str2 Second string (right). - * @param num Number of characters to compare. - * @param caseSensitive If true (default), comparison is case sensitive. - * If false, comparison is case insensitive. - * @return -1 if str1 < str2 - * 0 if str1 == str2 - * 1 if str1 > str2 - */ -native int strncmp(const char[] str1, const char[] str2, int num, bool caseSensitive=true); - -/** - * Backwards compatible stock - StrCompare is now strcmp - * @deprecated Renamed to strcmp - */ -#pragma deprecated Use strcmp() instead -stock int StrCompare(const char[] str1, const char[] str2, bool caseSensitive=true) -{ - return strcmp(str1, str2, caseSensitive); -} - -/** - * Returns whether two strings are equal. - * - * @param str1 First string (left). - * @param str2 Second string (right). - * @param caseSensitive If true (default), comparison is case sensitive. - * If false, comparison is case insensitive. - * @return True if equal, false otherwise. - */ -stock bool StrEqual(const char[] str1, const char[] str2, bool caseSensitive=true) -{ - return (strcmp(str1, str2, caseSensitive) == 0); -} - -/** - * Copies one string to another string. - * @note If the destination buffer is too small to hold the source string, the - * destination will be truncated. - * - * @param dest Destination string buffer to copy to. - * @param destLen Destination buffer length (includes null terminator). - * @param source Source string buffer to copy from. - * @return Number of cells written. - */ -native int strcopy(char[] dest, int destLen, const char[] source); - -/** - * Backwards compatibility stock - use strcopy - * @deprecated Renamed to strcopy - */ -#pragma deprecated Use strcopy() instead -stock int StrCopy(char[] dest, int destLen, const char[] source) -{ - return strcopy(dest, destLen, source); -} - -/** - * Formats a string according to the SourceMod format rules (see documentation). - * - * @param buffer Destination string buffer. - * @param maxlength Maximum length of output string buffer. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @return Number of cells written. - */ -native int Format(char[] buffer, int maxlength, const char[] format, any ...); - -/** - * Formats a string according to the SourceMod format rules (see documentation). - * @note This is the same as Format(), except none of the input buffers can - * overlap the same memory as the output buffer. Since this security - * check is removed, it is slightly faster. - * - * @param buffer Destination string buffer. - * @param maxlength Maximum length of output string buffer. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @return Number of cells written. - */ -native int FormatEx(char[] buffer, int maxlength, const char[] format, any ...); - -/** - * Formats a string according to the SourceMod format rules (see documentation). - * @note This is the same as Format(), except it grabs parameters from a - * parent parameter stack, rather than a local. This is useful for - * implementing your own variable argument functions. - * - * @param buffer Destination string buffer. - * @param maxlength Maximum length of output string buffer. - * @param format Formatting rules. - * @param varpos Argument number which contains the '...' symbol. - * Note: Arguments start at 1. - * @return Number of bytes written. - */ -native int VFormat(char[] buffer, int maxlength, const char[] format, int varpos); - -/** - * Converts a string to an integer. - * - * @param str String to convert. - * @param nBase Numerical base to use. 10 is default. - * @return Integer conversion of string, or 0 on failure. - */ -native int StringToInt(const char[] str, int nBase=10); - -/** - * Converts a string to an integer with some more options. - * - * @param str String to convert. - * @param result Variable to store the result in. - * @param nBase Numerical base to use. 10 is default. - * @return Number of characters consumed. - */ -native int StringToIntEx(const char[] str, int &result, int nBase=10); - -/** - * Converts an integer to a string. - * - * @param num Integer to convert. - * @param str Buffer to store string in. - * @param maxlength Maximum length of string buffer. - * @return Number of cells written to buffer. - */ -native int IntToString(int num, char[] str, int maxlength); - -/** - * Converts a string to a floating point number. - * - * @param str String to convert to a float. - * @return Floating point result, or 0.0 on error. - */ -native float StringToFloat(const char[] str); - -/** - * Converts a string to a floating point number with some more options. - * - * @param str String to convert to a float. - * @param result Variable to store result in. - * @return Number of characters consumed. - */ -native int StringToFloatEx(const char[] str, float &result); - -/** - * Converts a floating point number to a string. - * - * @param num Floating point number to convert. - * @param str Buffer to store string in. - * @param maxlength Maximum length of string buffer. - * @return Number of cells written to buffer. - */ -native int FloatToString(float num, char[] str, int maxlength); - -/** - * Finds the first "argument" in a string; either a set of space - * terminated characters, or a fully quoted string. After the - * argument is found, whitespace is read until the next portion - * of the string is reached. If nothing remains, -1 is returned. - * Otherwise, the index to the first character is returned. - * - * @param source Source input string. - * @param arg Stores argument read from string. - * @param argLen Maximum length of argument buffer. - * @return Index to next piece of string, or -1 if none. - */ -native int BreakString(const char[] source, char[] arg, int argLen); - -/** - * Backwards compatibility stock - use BreakString - * @deprecated Renamed to BreakString. - */ -#pragma deprecated Use BreakString() instead -stock int StrBreak(const char[] source, char[] arg, int argLen) -{ - return BreakString(source, arg, argLen); -} - -/** - * Removes whitespace characters from the beginning and end of a string. - * - * @param str The string to trim. - * @return Number of bytes written (UTF-8 safe). - */ -native int TrimString(char[] str); - -/** - * Returns text in a string up until a certain character sequence is reached. - * - * @param source Source input string. - * @param split A string which specifies a search point to break at. - * @param part Buffer to store string part. - * @param partLen Maximum length of the string part buffer. - * @return -1 if no match was found; otherwise, an index into source - * marking the first index after the searched text. The - * index is always relative to the start of the input string. - */ -native int SplitString(const char[] source, const char[] split, char[] part, int partLen); - -/** - * Given a string, replaces all occurrences of a search string with a - * replacement string. - * - * @param text String to perform search and replacements on. - * @param maxlength Maximum length of the string buffer. - * @param search String to search for. - * @param replace String to replace the search string with. - * @param caseSensitive If true (default), search is case sensitive. - * @return Number of replacements that were performed. - */ -native int ReplaceString(char[] text, int maxlength, const char[] search, const char[] replace, bool caseSensitive=true); - -/** - * Given a string, replaces the first occurrence of a search string with a - * replacement string. - * - * @param text String to perform search and replacements on. - * @param maxlength Maximum length of the string buffer. - * @param search String to search for. - * @param replace String to replace the search string with. - * @param searchLen If higher than -1, its value will be used instead of - * a strlen() call on the search parameter. - * @param replaceLen If higher than -1, its value will be used instead of - * a strlen() call on the replace parameter. - * @param caseSensitive If true (default), search is case sensitive. - * @return Index into the buffer (relative to the start) from where - * the last replacement ended, or -1 if no replacements were - * made. - */ -native int ReplaceStringEx(char[] text, int maxlength, const char[] search, const char[] replace, int searchLen=-1, int replaceLen=-1, bool caseSensitive=true); - -/** - * Returns the number of bytes a character is using. This is - * for multi-byte characters (UTF-8). For normal ASCII characters, - * this will return 1. - * - * @param source Source input string. - * @return Number of bytes the current character uses. - */ -native int GetCharBytes(const char[] source); - -/** - * Returns whether a character is an ASCII alphabet character. - * - * @note Multi-byte characters will always return false. - * - * @param chr Character to test. - * @return True if character is alphabetical, otherwise false. - */ -native bool IsCharAlpha(int chr); - -/** - * Returns whether a character is numeric. - * - * @note Multi-byte characters will always return false. - * - * @param chr Character to test. - * @return True if character is numeric, otherwise false. - */ -native bool IsCharNumeric(int chr); - -/** - * Returns whether a character is whitespace. - * - * @note Multi-byte characters will always return false. - * - * @param chr Character to test. - * @return True if character is whitespace, otherwise false. - */ -native bool IsCharSpace(int chr); - -/** - * Returns if a character is multi-byte or not. - * - * @param chr Character to test. - * @return 0 for a normal 7-bit ASCII character, - * otherwise number of bytes in multi-byte character. - */ -native int IsCharMB(int chr); - -/** - * Returns whether an alphabetic character is uppercase. - * - * @note Multi-byte characters will always return false. - * - * @param chr Character to test. - * @return True if character is uppercase, otherwise false. - */ -native bool IsCharUpper(int chr); - -/** - * Returns whether an alphabetic character is lowercase. - * - * @note Multi-byte characters will always return false. - * - * @param chr Character to test. - * @return True if character is lowercase, otherwise false. - */ -native bool IsCharLower(int chr); - -/** - * Strips a quote pair off a string if it exists. That is, the following - * replace rule is applied once: ^"(.*)"$ -> ^\1$ - * - * Note that the leading and trailing quotes will only be removed if both - * exist. Otherwise, the string is left unmodified. This function should - * be considered O(k) (all characters get shifted down). - * - * @param text String to modify (in place). - * @return True if string was modified, false if there was no - * set of quotes. - */ -native bool StripQuotes(char[] text); - -/** - * Returns a lowercase character to an uppercase character. - * - * @param chr Character to convert. - * @return Uppercase character on success, - * no change on failure. - */ -stock int CharToUpper(int chr) -{ - if (IsCharLower(chr)) - { - return (chr & ~(1<<5)); - } - return chr; -} - -/** - * Returns an uppercase character to a lowercase character. - * - * @param chr Character to convert. - * @return Lowercase character on success, - * no change on failure. - */ -stock int CharToLower(int chr) -{ - if (IsCharUpper(chr)) - { - return (chr | (1<<5)); - } - return chr; -} - -/** - * Finds the first occurrence of a character in a string. - * - * @param str String. - * @param c Character to search for. - * @param reverse False (default) to search forward, true to search - * backward. - * @return The index of the first occurrence of the character - * in the string, or -1 if the character was not found. - */ -stock int FindCharInString(const char[] str, char c, bool reverse = false) -{ - int len = strlen(str); - - if (!reverse) { - for (int i = 0; i < len; i++) { - if (str[i] == c) - return i; - } - } else { - for (int i = len - 1; i >= 0; i--) { - if (str[i] == c) - return i; - } - } - - return -1; -} - -/** - * Concatenates one string onto another. - * - * @param buffer String to append to. - * @param maxlength Maximum length of entire buffer. - * @param source Source string to concatenate. - * @return Number of bytes written. - */ -stock int StrCat(char[] buffer, int maxlength, const char[] source) -{ - int len = strlen(buffer); - if (len >= maxlength) - { - return 0; - } - - return Format(buffer[len], maxlength-len, "%s", source); -} - -/** - * Breaks a string into pieces and stores each piece into an array of buffers. - * - * @param text The string to split. - * @param split The string to use as a split delimiter. - * @param buffers An array of string buffers (2D array). - * @param maxStrings Number of string buffers (first dimension size). - * @param maxStringLength Maximum length of each string buffer. - * @param copyRemainder False (default) discard excess pieces, true to ignore - * delimiters after last piece. - * @return Number of strings retrieved. - */ -stock int ExplodeString(const char[] text, const char[] split, char[][] buffers, int maxStrings, - int maxStringLength, bool copyRemainder = false) -{ - int reloc_idx, idx, total; - - if (maxStrings < 1 || !split[0]) - { - return 0; - } - - while ((idx = SplitString(text[reloc_idx], split, buffers[total], maxStringLength)) != -1) - { - reloc_idx += idx; - if (++total == maxStrings) - { - if (copyRemainder) - { - strcopy(buffers[total-1], maxStringLength, text[reloc_idx-idx]); - } - return total; - } - } - - strcopy(buffers[total++], maxStringLength, text[reloc_idx]); - - return total; -} - -/** - * Joins an array of strings into one string, with a "join" string inserted in - * between each given string. This function complements ExplodeString. - * - * @param strings An array of strings. - * @param numStrings Number of strings in the array. - * @param join The join string to insert between each string. - * @param buffer Output buffer to write the joined string to. - * @param maxLength Maximum length of the output buffer. - * @return Number of bytes written to the output buffer. - */ -stock int ImplodeStrings(const char[][] strings, int numStrings, const char[] join, char[] buffer, int maxLength) -{ - int total, length, part_length; - int join_length = strlen(join); - for (int i=0; i. - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -static int TestNumber = 0; -static char TestContext[255]; - -stock void SetTestContext(const char[] context) -{ - strcopy(TestContext, sizeof(TestContext), context); -} - -stock void AssertEq(const char[] text, int cell1, int cell2) -{ - TestNumber++; - if (cell1 == cell2) { - PrintToServer("[%d] %s: %s == %d OK", TestNumber, TestContext, text, cell2); - } else { - PrintToServer("[%d] %s FAIL: %s should be %d, got %d", TestNumber, TestContext, text, cell2, cell1); - ThrowError("test %d (%s in %s) failed", TestNumber, text, TestContext); - } -} - -stock void AssertFalse(const char[] text, bool value) -{ - TestNumber++; - if (!value) { - PrintToServer("[%d] %s: %s == false OK", TestNumber, TestContext, text, value); - } else { - PrintToServer("[%d] %s FAIL: %s should be false, got true", TestNumber, TestContext, text); - ThrowError("test %d (%s in %s) failed", TestNumber, text, TestContext); - } -} - -stock void AssertTrue(const char[] text, bool value) -{ - TestNumber++; - if (value) { - PrintToServer("[%d] %s: %s == true OK", TestNumber, TestContext, text, value); - } else { - PrintToServer("[%d] %s FAIL: %s should be true, got false", TestNumber, TestContext, text); - ThrowError("test %d (%s in %s) failed", TestNumber, text, TestContext); - } -} diff --git a/scripting/include/textparse.inc b/scripting/include/textparse.inc deleted file mode 100644 index 4680179..0000000 --- a/scripting/include/textparse.inc +++ /dev/null @@ -1,243 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod (C)2004-2014 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _textparse_included - #endinput -#endif -#define _textparse_included - - -/******************************** - * Everything below describes the SMC Parse, or "SourceMod Configuration" format. - * This parser is entirely event based. You must hook events to receive data. - * The file format itself is nearly identical to Valve's KeyValues format. - ********************************/ - -/** - * Parse result directive. - */ -enum SMCResult -{ - SMCParse_Continue, /**< Continue parsing */ - SMCParse_Halt, /**< Stop parsing here */ - SMCParse_HaltFail /**< Stop parsing and return failure */ -}; - -/** - * Parse error codes. - */ -enum SMCError -{ - SMCError_Okay = 0, /**< No error */ - SMCError_StreamOpen, /**< Stream failed to open */ - SMCError_StreamError, /**< The stream died... somehow */ - SMCError_Custom, /**< A custom handler threw an error */ - SMCError_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */ - SMCError_InvalidSection2, /**< A section was declared without any header */ - SMCError_InvalidSection3, /**< A section ending was declared with too many unknown tokens */ - SMCError_InvalidSection4, /**< A section ending has no matching beginning */ - SMCError_InvalidSection5, /**< A section beginning has no matching ending */ - SMCError_InvalidTokens, /**< There were too many unidentifiable strings on one line */ - SMCError_TokenOverflow, /**< The token buffer overflowed */ - SMCError_InvalidProperty1, /**< A property was declared outside of any section */ -}; - -// Called when parsing is started. -// -// @param smc The SMC Parse Handle. -typedef SMC_ParseStart = function void (SMCParser smc); - -// Called when the parser is entering a new section or sub-section. -// -// Note: Enclosing quotes are always stripped. -// -// @param smc The SMC Parser. -// @param name String containing section name. -// @param opt_quotes True if the section name was quote-enclosed in the file. -// @return An SMCResult action to take. -typedef SMC_NewSection = function SMCResult (SMCParser smc, const char[] name, bool opt_quotes); - -// Called when the parser finds a new key/value pair. -// -// Note: Enclosing quotes are always stripped. -// -// @param smc The SMCParser. -// @param key String containing key name. -// @param value String containing value name. -// @param key_quotes Whether or not the key was enclosed in quotes. -// @param value_quotes Whether or not the value was enclosed in quotes. -// @return An SMCResult action to take. -typedef SMC_KeyValue = function SMCResult (SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes); - -// Called when the parser finds the end of the current section. -// -// @param smc The SMCParser. -// @return An SMCResult action to take. -typedef SMC_EndSection = function SMCResult (SMCParser smc); - -// Called when parsing is halted. -// -// @param smc The SMCParser. -// @param halted True if abnormally halted, false otherwise. -// @param failed True if parsing failed, false otherwise. -typedef SMC_ParseEnd = function void (SMCParser smc, bool halted, bool failed); - -// Callback for whenever a new line of text is about to be parsed. -// -// @param smc The SMCParser. -// @param line A string containing the raw line from the file. -// @param lineno The line number it occurs on. -// @return An SMCResult action to take. -typedef SMC_RawLine = function SMCResult (SMCParser smc, const char[] line, int lineno); - -// An SMCParser is a callback-driven parser for SourceMod configuration files. -// SMC files are similar to Valve KeyValues format, with two key differences: -// (1) SMC cannot handle single-item entries (that is, a key with no value). -// (2) SMC files can have multi-line comment blocks, whereas KeyValues cannot. -methodmap SMCParser < Handle -{ - // Create a new SMC file format parser. - public native SMCParser(); - - // Parses an SMC file. - // - // @param file A string containing the file path. - // @param line An optional variable to store the last line number read. - // @param col An optional variable to store the last column number read. - // @return An SMCParseError result. - public native SMCError ParseFile(const char[] file, int &line = 0, int &col = 0); - - // Sets the callback for receiving SMC_ParseStart events. - property SMC_ParseStart OnStart { - public native set(SMC_ParseStart func); - } - - // Sets the callback for receiving SMC_ParseEnd events. - property SMC_ParseEnd OnEnd { - public native set(SMC_ParseEnd func); - } - - // Sets the callback for receiving SMC_NewSection events. - property SMC_NewSection OnEnterSection { - public native set(SMC_NewSection func); - } - - // Sets the callback for receiving SMC_EndSection events. - property SMC_EndSection OnLeaveSection { - public native set(SMC_EndSection func); - } - - // Sets the callback for receiving SMC_KeyValue events. - property SMC_KeyValue OnKeyValue { - public native set(SMC_KeyValue func); - } - - // Sets the callback for receiving SMC_RawLine events. - property SMC_RawLine OnRawLine { - public native set(SMC_RawLine func); - } - - // Gets an error string for an SMCError code. - // - // @param error The SMCParseError code. - // @param buffer A string buffer for the error (contents undefined on failure). - // @param buf_max The maximum size of the buffer. - // @return The number of characters written to buffer. - public native void GetErrorString(SMCError error, char[] buffer, int buf_max); -}; - -/** - * Creates a new SMC file format parser. This is used to set parse hooks. - * - * @return A new Handle to an SMC Parse structure. - */ -native SMCParser SMC_CreateParser(); - -/** - * Parses an SMC file. - * - * @param smc A Handle to an SMC Parse structure. - * @param file A string containing the file path. - * @param line An optional by reference cell to store the last line number read. - * @param col An optional by reference cell to store the last column number read. - * @return An SMCParseError result. - * @error Invalid or corrupt Handle. - */ -native SMCError SMC_ParseFile(Handle smc, const char[] file, int &line=0, int &col=0); - -/** - * Gets an error string for an SMCError code. - * @note SMCError_Okay returns false. - * @note SMCError_Custom (which is thrown on SMCParse_HaltFail) returns false. - * - * @param error The SMCParseError code. - * @param buffer A string buffer for the error (contents undefined on failure). - * @param buf_max The maximum size of the buffer. - * @return True on success, false otherwise. - */ -native bool SMC_GetErrorString(SMCError error, char[] buffer, int buf_max); - -/** - * Sets the SMC_ParseStart function of a parse Handle. - * - * @param smc Handle to an SMC Parse. - * @param func SMC_ParseStart function. - * @error Invalid or corrupt Handle. - */ -native void SMC_SetParseStart(Handle smc, SMC_ParseStart func); - -/** - * Sets the SMC_ParseEnd of a parse handle. - * - * @param smc Handle to an SMC Parse. - * @param func SMC_ParseEnd function. - * @error Invalid or corrupt Handle. - */ -native void SMC_SetParseEnd(Handle smc, SMC_ParseEnd func); - -/** - * Sets the three main reader functions. - * - * @param smc An SMC parse Handle. - * @param ns An SMC_NewSection function pointer. - * @param kv An SMC_KeyValue function pointer. - * @param es An SMC_EndSection function pointer. - */ -native void SMC_SetReaders(Handle smc, SMC_NewSection ns, SMC_KeyValue kv, SMC_EndSection es); - -/** - * Sets a raw line reader on an SMC parser Handle. - * - * @param smc Handle to an SMC Parse. - * @param func SMC_RawLine function. - */ -native void SMC_SetRawLine(Handle smc, SMC_RawLine func); diff --git a/scripting/include/tf2.inc b/scripting/include/tf2.inc deleted file mode 100644 index f93d5da..0000000 --- a/scripting/include/tf2.inc +++ /dev/null @@ -1,493 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _tf2_included - #endinput -#endif -#define _tf2_included - -#define TF_STUNFLAG_SLOWDOWN (1 << 0) /**< activates slowdown modifier */ -#define TF_STUNFLAG_BONKSTUCK (1 << 1) /**< bonk sound, stuck */ -#define TF_STUNFLAG_LIMITMOVEMENT (1 << 2) /**< disable forward/backward movement */ -#define TF_STUNFLAG_CHEERSOUND (1 << 3) /**< cheering sound */ -#define TF_STUNFLAG_NOSOUNDOREFFECT (1 << 5) /**< no sound or particle */ -#define TF_STUNFLAG_THIRDPERSON (1 << 6) /**< panic animation */ -#define TF_STUNFLAG_GHOSTEFFECT (1 << 7) /**< ghost particles */ -#define TF_STUNFLAG_SOUND (1 << 8) /**< sound */ - -#define TF_STUNFLAGS_LOSERSTATE TF_STUNFLAG_SLOWDOWN|TF_STUNFLAG_NOSOUNDOREFFECT|TF_STUNFLAG_THIRDPERSON -#define TF_STUNFLAGS_GHOSTSCARE TF_STUNFLAG_GHOSTEFFECT|TF_STUNFLAG_THIRDPERSON -#define TF_STUNFLAGS_SMALLBONK TF_STUNFLAG_THIRDPERSON|TF_STUNFLAG_SLOWDOWN -#define TF_STUNFLAGS_NORMALBONK TF_STUNFLAG_BONKSTUCK -#define TF_STUNFLAGS_BIGBONK TF_STUNFLAG_CHEERSOUND|TF_STUNFLAG_BONKSTUCK - -enum TFClassType -{ - TFClass_Unknown = 0, - TFClass_Scout, - TFClass_Sniper, - TFClass_Soldier, - TFClass_DemoMan, - TFClass_Medic, - TFClass_Heavy, - TFClass_Pyro, - TFClass_Spy, - TFClass_Engineer -}; - -enum TFTeam -{ - TFTeam_Unassigned = 0, - TFTeam_Spectator = 1, - TFTeam_Red = 2, - TFTeam_Blue = 3 -}; - -enum TFCond -{ - TFCond_Slowed = 0, - TFCond_Zoomed, - TFCond_Disguising, - TFCond_Disguised, - TFCond_Cloaked, - TFCond_Ubercharged, - TFCond_TeleportedGlow, - TFCond_Taunting, - TFCond_UberchargeFading, - TFCond_Unknown1, //9 - TFCond_CloakFlicker = 9, - TFCond_Teleporting, - TFCond_Kritzkrieged, - TFCond_Unknown2, //12 - TFCond_TmpDamageBonus = 12, - TFCond_DeadRingered, - TFCond_Bonked, - TFCond_Dazed, - TFCond_Buffed, - TFCond_Charging, - TFCond_DemoBuff, - TFCond_CritCola, - TFCond_InHealRadius, - TFCond_Healing, - TFCond_OnFire, - TFCond_Overhealed, - TFCond_Jarated, - TFCond_Bleeding, - TFCond_DefenseBuffed, - TFCond_Milked, - TFCond_MegaHeal, - TFCond_RegenBuffed, - TFCond_MarkedForDeath, - TFCond_NoHealingDamageBuff, - TFCond_SpeedBuffAlly, // 32 - TFCond_HalloweenCritCandy, - TFCond_CritCanteen, - TFCond_CritDemoCharge, - TFCond_CritHype, - TFCond_CritOnFirstBlood, - TFCond_CritOnWin, - TFCond_CritOnFlagCapture, - TFCond_CritOnKill, - TFCond_RestrictToMelee, - TFCond_DefenseBuffNoCritBlock, - TFCond_Reprogrammed, - TFCond_CritMmmph, - TFCond_DefenseBuffMmmph, - TFCond_FocusBuff, - TFCond_DisguiseRemoved, - TFCond_MarkedForDeathSilent, - TFCond_DisguisedAsDispenser, - TFCond_Sapped, - TFCond_UberchargedHidden, - TFCond_UberchargedCanteen, - TFCond_HalloweenBombHead, - TFCond_HalloweenThriller, - TFCond_RadiusHealOnDamage, - TFCond_CritOnDamage, - TFCond_UberchargedOnTakeDamage, - TFCond_UberBulletResist, - TFCond_UberBlastResist, - TFCond_UberFireResist, - TFCond_SmallBulletResist, - TFCond_SmallBlastResist, - TFCond_SmallFireResist, - TFCond_Stealthed, // 64 - TFCond_MedigunDebuff, - TFCond_StealthedUserBuffFade, - TFCond_BulletImmune, - TFCond_BlastImmune, - TFCond_FireImmune, - TFCond_PreventDeath, - TFCond_MVMBotRadiowave, - TFCond_HalloweenSpeedBoost, - TFCond_HalloweenQuickHeal, - TFCond_HalloweenGiant, - TFCond_HalloweenTiny, - TFCond_HalloweenInHell, - TFCond_HalloweenGhostMode, - TFCond_MiniCritOnKill, - TFCond_DodgeChance, //79 - TFCond_ObscuredSmoke = 79, - TFCond_Parachute, - TFCond_BlastJumping, - TFCond_HalloweenKart, - TFCond_HalloweenKartDash, - TFCond_BalloonHead, - TFCond_MeleeOnly, - TFCond_SwimmingCurse, - TFCond_HalloweenKartNoTurn, //87 - TFCond_FreezeInput = 87, - TFCond_HalloweenKartCage, - TFCond_HasRune, - TFCond_RuneStrength, - TFCond_RuneHaste, - TFCond_RuneRegen, - TFCond_RuneResist, - TFCond_RuneVampire, - TFCond_RuneWarlock, - TFCond_RunePrecision, // 96 - TFCond_RuneAgility, - TFCond_GrapplingHook, - TFCond_GrapplingHookSafeFall, - TFCond_GrapplingHookLatched, - TFCond_GrapplingHookBleeding, - TFCond_AfterburnImmune, - TFCond_RuneKnockout, - TFCond_RuneImbalance, - TFCond_CritRuneTemp, - TFCond_PasstimeInterception, - TFCond_SwimmingNoEffects, - TFCond_EyeaductUnderworld, - TFCond_KingRune, - TFCond_PlagueRune, - TFCond_SupernovaRune, - TFCond_Plague, - TFCond_KingAura, - TFCond_SpawnOutline, //114 - TFCond_KnockedIntoAir, - TFCond_CompetitiveWinner, - TFCond_CompetitiveLoser, - TFCond_NoTaunting_DEPRECATED, - TFCond_HealingDebuff = 118, - TFCond_PasstimePenaltyDebuff, - TFCond_GrappledToPlayer, - TFCond_GrappledByPlayer, - TFCond_ParachuteDeployed, - TFCond_Gas, - TFCond_BurningPyro, - TFCond_RocketPack, - TFCond_LostFooting, - TFCond_AirCurrent, -}; - -const float TFCondDuration_Infinite = -1.0; - -enum TFHoliday -{ - TFHoliday_Invalid = -1 -}; - -public const TFHoliday TFHoliday_Birthday; -public const TFHoliday TFHoliday_Halloween; -public const TFHoliday TFHoliday_Christmas; -public const TFHoliday TFHoliday_EndOfTheLine; -public const TFHoliday TFHoliday_CommunityUpdate; -public const TFHoliday TFHoliday_ValentinesDay; -public const TFHoliday TFHoliday_MeetThePyro; -public const TFHoliday TFHoliday_FullMoon; -public const TFHoliday TFHoliday_HalloweenOrFullMoon; -public const TFHoliday TFHoliday_HalloweenOrFullMoonOrValentines; -public const TFHoliday TFHoliday_AprilFools; - -enum TFObjectType -{ - TFObject_CartDispenser = 0, - TFObject_Dispenser = 0, - TFObject_Teleporter = 1, - TFObject_Sentry = 2, - TFObject_Sapper = 3 -}; - -enum TFObjectMode -{ - TFObjectMode_None = 0, - TFObjectMode_Entrance = 0, - TFObjectMode_Exit = 1 -}; - -/** - * Sets a client on fire for 10 seconds. - * - * @param client Player's index. - * @param attacker Attacker's index. - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_IgnitePlayer(int client, int attacker); - -/** - * Respawns a client - * - * @param client Player's index. - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_RespawnPlayer(int client); - -/** - * Regenerates a client's health and ammunition - * - * @param client Player's index. - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_RegeneratePlayer(int client); - -/** - * Adds a condition to a player - * - * @param client Player's index. - * @param condition Integer identifier of condition to apply. - * @param duration Duration of condition (does not apply to all conditions). - * Pass TFCondDuration_Infinite to apply until manually removed. - * @param inflictor Condition inflictor's index (0 for no inflictor). - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_AddCondition(int client, TFCond condition, float duration=TFCondDuration_Infinite, int inflictor=0); - -/** - * Removes a condition from a player - * - * @param client Player's index. - * @param condition Integer identifier of condition to remove. - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_RemoveCondition(int client, TFCond condition); - -/** - * Enables/disables PowerPlay mode on a player. - * - * @param client Player's index. - * @param enabled Whether to enable or disable PowerPlay on player. - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_SetPlayerPowerPlay(int client, bool enabled); - -/** - * Disguises a client to the given model and team. Only has an effect on spies. - * - * Note: This only starts the disguise process and a delay occurs before the spy is fully disguised - * - * @param client Player's index. - * @param team Team to disguise the player as (only TFTeam_Red and TFTeam_Blue have an effect) - * @param classType TFClassType class to disguise the player as - * @param target Specific target player to disguise as (0 for any) - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_DisguisePlayer(int client, TFTeam team, TFClassType classType, int target=0); - -/** - * Removes the current disguise from a client. Only has an effect on spies. - * - * @param client Player's index. - * @error Invalid client index, client not in game, or no mod support. - */ -native void TF2_RemovePlayerDisguise(int client); - -/** - * Stuns a client - * - * @param client Player's index. - * @param duration Duration of stun. - * @param slowdown Slowdown percent (as decimal, 0.00-1.00) - * Ignored if TF_STUNFLAG_SLOWDOWN is not set. - * @param stunflags Stun flags. - * @param attacker Attacker's index (0 is allowed for world). - */ -native void TF2_StunPlayer(int client, float duration, float slowdown=0.0, int stunflags, int attacker=0); - -/** - * Induces the bleed effect on a client - * - * @param client Player's index. - * @param attacker Attacker's index. - * @param duration Duration of bleeding (in seconds). - */ -native void TF2_MakeBleed(int client, int attacker, float duration); - -/** - * Retrieves the entity index of the CPlayerResource entity - * - * @return The current resource entity index. - */ -#pragma deprecated Use GetPlayerResourceEntity instead -native int TF2_GetResourceEntity(); - -/** - * Finds the TFClassType for a given class name. - * - * @param classname A classname string such as "sniper" or "demoman" - * @return A TFClassType constant. - */ -native TFClassType TF2_GetClass(const char[] classname); - -/** - * Called on weapon fire to decide if the current shot should be critical. - * Return Plugin_Continue to let the original calculation or return a higher - * action to override the decision with the value of 'result' - * - * @note Since critical shots are also calculated client side any changes made with - * this will not show for the shooter. Projectile weapons such as the rocketlauncher - * and demoman weapons will show a critical bullet but no critical sound effect. - * Bullet hits should appear as expected. - * - * @param client Client Index. - * @param weapon Weapon entity Index. - * @param weaponname Classname of the weapon. - * @param result Buffer param for the result of the decision. - */ -forward Action TF2_CalcIsAttackCritical(int client, int weapon, char[] weaponname, bool &result); - -/** - * @deprecated No longer called. Use TF2_OnIsHolidayActive. - */ -#pragma deprecated No longer called. Use TF2_OnIsHolidayActive. -forward Action TF2_OnGetHoliday(TFHoliday &holiday); - -/** - * Called at various times when the game checks to see if the given holiday is active. - * Return Plugin_Continue to let the original calculation or return a higher - * action to override the decision with the value of 'result' - * - * @param holiday Holiday being checked. - * @param result Buffer param for the result of the decision. - * @return Plugin_Continue for original calculation, higher value to use 'result'. - */ -forward Action TF2_OnIsHolidayActive(TFHoliday holiday, bool &result); - -/** - * Returns whether or not a holiday is active - * - * @param holiday Holiday being checked. - * @return Boolean of whether or not the holiday is active. - */ -native bool TF2_IsHolidayActive(TFHoliday holiday); - -/** - * Returns whether or not a client (Player) is in a duel. - * - * @param client Client Index. - * @return Boolean of whether or not the client/player is dueling. - */ -native bool TF2_IsPlayerInDuel(int client); - -/** - * Removes an econ wearable (hat, misc, etc) from a player. - * This also deletes the wearable entity. - * - * @param client Client index. - * @param wearable Index of the wearable entity. - * @error Invalid client index, client not in game, invalid wearable entity, or no mod support. -*/ -native void TF2_RemoveWearable(int client, int wearable); - -/** - * Called after a condition is added to a player - * - * @param client Index of the client to which the condition is being added. - * @param condition Condition that is being added. - */ -forward void TF2_OnConditionAdded(int client, TFCond condition); - -/** - * Called after a condition is removed from a player - * - * @param client Index of the client to which the condition is being removed. - * @param condition Condition that is being removed. - */ -forward void TF2_OnConditionRemoved(int client, TFCond condition); - -/** - * Called when the server enters the Waiting for Players round state - */ -forward void TF2_OnWaitingForPlayersStart(); - -/** - * Called when the server exits the Waiting for Players round state - */ -forward void TF2_OnWaitingForPlayersEnd(); - -/** - * Called when a player attempts to use a teleporter to decide if the player should be allowed to teleport. - * Return Plugin_Continue to let the original calculation or return a higher - * action to override the decision with the value of 'result' - * - * @param client Client index. - * @param teleporter Teleporter entity index. - * @param result Buffer param for the result of the decision. - * This is prepopulated with the game's original decision to let a player teleport. - * @return Plugin_Continue for original calculation, higher value to use 'result'. - */ -forward Action TF2_OnPlayerTeleport(int client, int teleporter, bool &result); - -/** - * Do not edit below this line! - */ -public Extension __ext_tf2 = -{ - name = "TF2 Tools", - file = "game.tf2.ext", - autoload = 0, -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_EXTENSIONS -public void __ext_tf2_SetNTVOptional() -{ - MarkNativeAsOptional("TF2_IgnitePlayer"); - MarkNativeAsOptional("TF2_RespawnPlayer"); - MarkNativeAsOptional("TF2_RegeneratePlayer"); - MarkNativeAsOptional("TF2_AddCondition"); - MarkNativeAsOptional("TF2_RemoveCondition"); - MarkNativeAsOptional("TF2_SetPlayerPowerPlay"); - MarkNativeAsOptional("TF2_DisguisePlayer"); - MarkNativeAsOptional("TF2_RemovePlayerDisguise"); - MarkNativeAsOptional("TF2_StunPlayer"); - MarkNativeAsOptional("TF2_MakeBleed"); - MarkNativeAsOptional("TF2_GetResourceEntity"); - MarkNativeAsOptional("TF2_GetClass"); - MarkNativeAsOptional("TF2_IsPlayerInDuel"); - MarkNativeAsOptional("TF2_IsHolidayActive"); - MarkNativeAsOptional("TF2_RemoveWearable"); -} -#endif diff --git a/scripting/include/tf2_stocks.inc b/scripting/include/tf2_stocks.inc deleted file mode 100644 index 0d68e11..0000000 --- a/scripting/include/tf2_stocks.inc +++ /dev/null @@ -1,637 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _tf2_stocks_included - #endinput -#endif -#define _tf2_stocks_included - -#include -#include - -#define TF_CONDFLAG_NONE 0 -#define TF_CONDFLAG_SLOWED (1 << 0) -#define TF_CONDFLAG_ZOOMED (1 << 1) -#define TF_CONDFLAG_DISGUISING (1 << 2) -#define TF_CONDFLAG_DISGUISED (1 << 3) -#define TF_CONDFLAG_CLOAKED (1 << 4) -#define TF_CONDFLAG_UBERCHARGED (1 << 5) -#define TF_CONDFLAG_TELEPORTGLOW (1 << 6) -#define TF_CONDFLAG_TAUNTING (1 << 7) -#define TF_CONDFLAG_UBERCHARGEFADE (1 << 8) -#define TF_CONDFLAG_CLOAKFLICKER (1 << 9) -#define TF_CONDFLAG_TELEPORTING (1 << 10) -#define TF_CONDFLAG_KRITZKRIEGED (1 << 11) -#define TF_CONDFLAG_DEADRINGERED (1 << 13) -#define TF_CONDFLAG_BONKED (1 << 14) -#define TF_CONDFLAG_DAZED (1 << 15) -#define TF_CONDFLAG_BUFFED (1 << 16) -#define TF_CONDFLAG_CHARGING (1 << 17) -#define TF_CONDFLAG_DEMOBUFF (1 << 18) -#define TF_CONDFLAG_CRITCOLA (1 << 19) -#define TF_CONDFLAG_INHEALRADIUS (1 << 20) -#define TF_CONDFLAG_HEALING (1 << 21) -#define TF_CONDFLAG_ONFIRE (1 << 22) -#define TF_CONDFLAG_OVERHEALED (1 << 23) -#define TF_CONDFLAG_JARATED (1 << 24) -#define TF_CONDFLAG_BLEEDING (1 << 25) -#define TF_CONDFLAG_DEFENSEBUFFED (1 << 26) -#define TF_CONDFLAG_MILKED (1 << 27) -#define TF_CONDFLAG_MEGAHEAL (1 << 28) -#define TF_CONDFLAG_REGENBUFFED (1 << 29) -#define TF_CONDFLAG_MARKEDFORDEATH (1 << 30) - -#define TF_DEATHFLAG_KILLERDOMINATION (1 << 0) -#define TF_DEATHFLAG_ASSISTERDOMINATION (1 << 1) -#define TF_DEATHFLAG_KILLERREVENGE (1 << 2) -#define TF_DEATHFLAG_ASSISTERREVENGE (1 << 3) -#define TF_DEATHFLAG_FIRSTBLOOD (1 << 4) -#define TF_DEATHFLAG_DEADRINGER (1 << 5) -#define TF_DEATHFLAG_INTERRUPTED (1 << 6) -#define TF_DEATHFLAG_GIBBED (1 << 7) -#define TF_DEATHFLAG_PURGATORY (1 << 8) -#define TF_DEATHFLAG_MINIBOSS (1 << 9) -#define TF_DEATHFLAG_AUSTRALIUM (1 << 10) - -// Custom kill identifiers for the customkill property on the player_death event -enum { - TF_CUSTOM_HEADSHOT = 1, - TF_CUSTOM_BACKSTAB, - TF_CUSTOM_BURNING, - TF_CUSTOM_WRENCH_FIX, - TF_CUSTOM_MINIGUN, - TF_CUSTOM_SUICIDE, - TF_CUSTOM_TAUNT_HADOUKEN, - TF_CUSTOM_BURNING_FLARE, - TF_CUSTOM_TAUNT_HIGH_NOON, - TF_CUSTOM_TAUNT_GRAND_SLAM, - TF_CUSTOM_PENETRATE_MY_TEAM, - TF_CUSTOM_PENETRATE_ALL_PLAYERS, - TF_CUSTOM_TAUNT_FENCING, - TF_CUSTOM_PENETRATE_HEADSHOT, - TF_CUSTOM_TAUNT_ARROW_STAB, - TF_CUSTOM_TELEFRAG, - TF_CUSTOM_BURNING_ARROW, - TF_CUSTOM_FLYINGBURN, - TF_CUSTOM_PUMPKIN_BOMB, - TF_CUSTOM_DECAPITATION, - TF_CUSTOM_TAUNT_GRENADE, - TF_CUSTOM_BASEBALL, - TF_CUSTOM_CHARGE_IMPACT, - TF_CUSTOM_TAUNT_BARBARIAN_SWING, - TF_CUSTOM_AIR_STICKY_BURST, - TF_CUSTOM_DEFENSIVE_STICKY, - TF_CUSTOM_PICKAXE, - TF_CUSTOM_ROCKET_DIRECTHIT, - TF_CUSTOM_TAUNT_UBERSLICE, - TF_CUSTOM_PLAYER_SENTRY, - TF_CUSTOM_STANDARD_STICKY, - TF_CUSTOM_SHOTGUN_REVENGE_CRIT, - TF_CUSTOM_TAUNT_ENGINEER_SMASH, - TF_CUSTOM_BLEEDING, - TF_CUSTOM_GOLD_WRENCH, - TF_CUSTOM_CARRIED_BUILDING, - TF_CUSTOM_COMBO_PUNCH, - TF_CUSTOM_TAUNT_ENGINEER_ARM, - TF_CUSTOM_FISH_KILL, - TF_CUSTOM_TRIGGER_HURT, - TF_CUSTOM_DECAPITATION_BOSS, - TF_CUSTOM_STICKBOMB_EXPLOSION, - TF_CUSTOM_AEGIS_ROUND, - TF_CUSTOM_FLARE_EXPLOSION, - TF_CUSTOM_BOOTS_STOMP, - TF_CUSTOM_PLASMA, - TF_CUSTOM_PLASMA_CHARGED, - TF_CUSTOM_PLASMA_GIB, - TF_CUSTOM_PRACTICE_STICKY, - TF_CUSTOM_EYEBALL_ROCKET, - TF_CUSTOM_HEADSHOT_DECAPITATION, - TF_CUSTOM_TAUNT_ARMAGEDDON, - TF_CUSTOM_FLARE_PELLET, - TF_CUSTOM_CLEAVER, - TF_CUSTOM_CLEAVER_CRIT, - TF_CUSTOM_SAPPER_RECORDER_DEATH, - TF_CUSTOM_MERASMUS_PLAYER_BOMB, - TF_CUSTOM_MERASMUS_GRENADE, - TF_CUSTOM_MERASMUS_ZAP, - TF_CUSTOM_MERASMUS_DECAPITATION, - TF_CUSTOM_CANNONBALL_PUSH, - TF_CUSTOM_TAUNT_ALLCLASS_GUITAR_RIFF, - TF_CUSTOM_THROWABLE, - TF_CUSTOM_THROWABLE_KILL, - TF_CUSTOM_SPELL_TELEPORT, - TF_CUSTOM_SPELL_SKELETON, - TF_CUSTOM_SPELL_MIRV, - TF_CUSTOM_SPELL_METEOR, - TF_CUSTOM_SPELL_LIGHTNING, - TF_CUSTOM_SPELL_FIREBALL, - TF_CUSTOM_SPELL_MONOCULUS, - TF_CUSTOM_SPELL_BLASTJUMP, - TF_CUSTOM_SPELL_BATS, - TF_CUSTOM_SPELL_TINY, - TF_CUSTOM_KART, - TF_CUSTOM_GIANT_HAMMER, - TF_CUSTOM_RUNE_REFLECT, - TF_CUSTOM_DRAGONS_FURY_IGNITE, - TF_CUSTOM_DRAGONS_FURY_BONUS_BURNING, - TF_CUSTOM_SLAP_KILL, - TF_CUSTOM_CROC, - TF_CUSTOM_TAUNTATK_GASBLAST, -}; - -// Weapon codes as used in some events, such as player_death -// (not to be confused with Item Definition Indexes) -enum { - TF_WEAPON_NONE = 0, - TF_WEAPON_BAT, - TF_WEAPON_BAT_WOOD, - TF_WEAPON_BOTTLE, - TF_WEAPON_FIREAXE, - TF_WEAPON_CLUB, - TF_WEAPON_CROWBAR, - TF_WEAPON_KNIFE, - TF_WEAPON_FISTS, - TF_WEAPON_SHOVEL, - TF_WEAPON_WRENCH, - TF_WEAPON_BONESAW, - TF_WEAPON_SHOTGUN_PRIMARY, - TF_WEAPON_SHOTGUN_SOLDIER, - TF_WEAPON_SHOTGUN_HWG, - TF_WEAPON_SHOTGUN_PYRO, - TF_WEAPON_SCATTERGUN, - TF_WEAPON_SNIPERRIFLE, - TF_WEAPON_MINIGUN, - TF_WEAPON_SMG, - TF_WEAPON_SYRINGEGUN_MEDIC, - TF_WEAPON_TRANQ, - TF_WEAPON_ROCKETLAUNCHER, - TF_WEAPON_GRENADELAUNCHER, - TF_WEAPON_PIPEBOMBLAUNCHER, - TF_WEAPON_FLAMETHROWER, - TF_WEAPON_GRENADE_NORMAL, - TF_WEAPON_GRENADE_CONCUSSION, - TF_WEAPON_GRENADE_NAIL, - TF_WEAPON_GRENADE_MIRV, - TF_WEAPON_GRENADE_MIRV_DEMOMAN, - TF_WEAPON_GRENADE_NAPALM, - TF_WEAPON_GRENADE_GAS, - TF_WEAPON_GRENADE_EMP, - TF_WEAPON_GRENADE_CALTROP, - TF_WEAPON_GRENADE_PIPEBOMB, - TF_WEAPON_GRENADE_SMOKE_BOMB, - TF_WEAPON_GRENADE_HEAL, - TF_WEAPON_GRENADE_STUNBALL, - TF_WEAPON_GRENADE_JAR, - TF_WEAPON_GRENADE_JAR_MILK, - TF_WEAPON_PISTOL, - TF_WEAPON_PISTOL_SCOUT, - TF_WEAPON_REVOLVER, - TF_WEAPON_NAILGUN, - TF_WEAPON_PDA, - TF_WEAPON_PDA_ENGINEER_BUILD, - TF_WEAPON_PDA_ENGINEER_DESTROY, - TF_WEAPON_PDA_SPY, - TF_WEAPON_BUILDER, - TF_WEAPON_MEDIGUN, - TF_WEAPON_GRENADE_MIRVBOMB, - TF_WEAPON_FLAMETHROWER_ROCKET, - TF_WEAPON_GRENADE_DEMOMAN, - TF_WEAPON_SENTRY_BULLET, - TF_WEAPON_SENTRY_ROCKET, - TF_WEAPON_DISPENSER, - TF_WEAPON_INVIS, - TF_WEAPON_FLAREGUN, - TF_WEAPON_LUNCHBOX, - TF_WEAPON_JAR, - TF_WEAPON_COMPOUND_BOW, - TF_WEAPON_BUFF_ITEM, - TF_WEAPON_PUMPKIN_BOMB, - TF_WEAPON_SWORD, - TF_WEAPON_DIRECTHIT, - TF_WEAPON_LIFELINE, - TF_WEAPON_LASER_POINTER, - TF_WEAPON_DISPENSER_GUN, - TF_WEAPON_SENTRY_REVENGE, - TF_WEAPON_JAR_MILK, - TF_WEAPON_HANDGUN_SCOUT_PRIMARY, - TF_WEAPON_BAT_FISH, - TF_WEAPON_CROSSBOW, - TF_WEAPON_STICKBOMB, - TF_WEAPON_HANDGUN_SCOUT_SEC, - TF_WEAPON_SODA_POPPER, - TF_WEAPON_SNIPERRIFLE_DECAP, - TF_WEAPON_RAYGUN, - TF_WEAPON_PARTICLE_CANNON, - TF_WEAPON_MECHANICAL_ARM, - TF_WEAPON_DRG_POMSON, - TF_WEAPON_BAT_GIFTWRAP, - TF_WEAPON_GRENADE_ORNAMENT, - TF_WEAPON_RAYGUN_REVENGE, - TF_WEAPON_PEP_BRAWLER_BLASTER, - TF_WEAPON_CLEAVER, - TF_WEAPON_GRENADE_CLEAVER, - TF_WEAPON_STICKY_BALL_LAUNCHER, - TF_WEAPON_GRENADE_STICKY_BALL, - TF_WEAPON_SHOTGUN_BUILDING_RESCUE, - TF_WEAPON_CANNON, - TF_WEAPON_THROWABLE, - TF_WEAPON_GRENADE_THROWABLE, - TF_WEAPON_PDA_SPY_BUILD, - TF_WEAPON_GRENADE_WATERBALLOON, - TF_WEAPON_HARVESTER_SAW, - TF_WEAPON_SPELLBOOK, - TF_WEAPON_SPELLBOOK_PROJECTILE, - TF_WEAPON_SNIPERRIFLE_CLASSIC, - TF_WEAPON_PARACHUTE, - TF_WEAPON_GRAPPLINGHOOK, - TF_WEAPON_PASSTIME_GUN, - TF_WEAPON_CHARGED_SMG, - TF_WEAPON_BREAKABLE_SIGN, - TF_WEAPON_ROCKETPACK, - TF_WEAPON_SLAP, - TF_WEAPON_JAR_GAS, - TF_WEAPON_GRENADE_JAR_GAS, - TF_WEAPON_FLAME_BALL, -}; - -// TF2 Weapon Loadout Slots -enum -{ - TFWeaponSlot_Primary, - TFWeaponSlot_Secondary, - TFWeaponSlot_Melee, - TFWeaponSlot_Grenade, - TFWeaponSlot_Building, - TFWeaponSlot_PDA, - TFWeaponSlot_Item1, - TFWeaponSlot_Item2 -}; - -// Identifiers for the eventtype property on the teamplay_flag_event event -enum { - TF_FLAGEVENT_PICKEDUP = 1, - TF_FLAGEVENT_CAPTURED, - TF_FLAGEVENT_DEFENDED, - TF_FLAGEVENT_DROPPED, - TF_FLAGEVENT_RETURNED -}; - -enum TFResourceType -{ - TFResource_Ping, - TFResource_Score, - TFResource_Deaths, - TFResource_TotalScore, - TFResource_Captures, - TFResource_Defenses, - TFResource_Dominations, - TFResource_Revenge, - TFResource_BuildingsDestroyed, - TFResource_Headshots, - TFResource_Backstabs, - TFResource_HealPoints, - TFResource_Invulns, - TFResource_Teleports, - TFResource_ResupplyPoints, - TFResource_KillAssists, - TFResource_MaxHealth, - TFResource_PlayerClass -}; - -static const char TFResourceNames[TFResourceType][] = -{ - "m_iPing", - "m_iScore", - "m_iDeaths", - "m_iTotalScore", - "m_iCaptures", - "m_iDefenses", - "m_iDominations", - "m_iRevenge", - "m_iBuildingsDestroyed", - "m_iHeadshots", - "m_iBackstabs", - "m_iHealPoints", - "m_iInvulns", - "m_iTeleports", - "m_iResupplyPoints", - "m_iKillAssists", - "m_iMaxHealth", - "m_iPlayerClass" -}; - -/** - * Gets a client's current team. - * - * @param client Client index. - * @return Current TFTeam of client. - * @error Invalid client index. - */ -stock TFTeam TF2_GetClientTeam(int client) -{ - return view_as(GetClientTeam(client)); -} - -/** - * Changes a client's current team. - * - * @param client Client index. - * @param team TFTeam team symbol. - * @error Invalid client index. - */ -stock void TF2_ChangeClientTeam(int client, TFTeam team) -{ - ChangeClientTeam(client, view_as(team)); -} - -/** - * Gets a client's current class. - * - * @param client Player's index. - * @return Current TFClassType of player. - * @error Invalid client index. - */ -stock TFClassType TF2_GetPlayerClass(int client) -{ - return view_as(GetEntProp(client, Prop_Send, "m_iClass")); -} - -/** - * Sets a client's class. - * - * Note: If setting player class in a player spawn hook weapons should be set to false. - * - * @param client Player's index. - * @param classType TFClassType class symbol. - * @param weapons This parameter is ignored. - * @param persistent If true, changes the player's desired class so the change stays after death. - * @error Invalid client index. - */ -stock void TF2_SetPlayerClass(int client, TFClassType classType, bool weapons=true, bool persistent=true) -{ - SetEntProp(client, Prop_Send, "m_iClass", view_as(classType)); - - if (persistent) - { - SetEntProp(client, Prop_Send, "m_iDesiredPlayerClass", view_as(classType)); - } -} - -/** - * Retrieves client data from the resource entity - * - * @param client Player's index. - * @param type ResourceType constant - * @return Value or -1 on failure. - * @error Invalid client index, client not in game or failed to find resource entity. - */ -#pragma deprecated Use GetPlayerResourceEntity and GetEntProp instead -stock int TF2_GetPlayerResourceData(int client, TFResourceType type) -{ - if (!IsClientConnected(client)) - { - return -1; - } - - int offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); - - if (offset < 1) - { - return -1; - } - - int entity = TF2_GetResourceEntity(); - - if (entity == -1) - { - return -1; - } - - return GetEntData(entity, offset + (client*4)); -} - -/** - * Sets client data in the resource entity - * - * Note: The game overwrites these values every frame, so changing them will have very little effect. - * - * @param client Player's index. - * @param type ResourceType constant - * @param value Value to set. - * @return Value or -1 on failure. - * @error Invalid client index, client not in game or failed to find resource entity. - */ -#pragma deprecated Use GetPlayerResourceEntity and SetEntProp instead -stock bool TF2_SetPlayerResourceData(int client, TFResourceType type, any value) -{ - if (!IsClientConnected(client)) - { - return false; - } - - int offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); - - if (offset < 1) - { - return false; - } - - int entity = TF2_GetResourceEntity(); - - if (entity == -1) - { - return false; - } - - SetEntData(entity, offset + (client*4), value); - - return true; -} - -/** - * Removes all weapons from a client's weapon slot - * - * @param client Player's index. - * @param slot Slot index (0-5) - * @error Invalid client, invalid slot or lack of mod support - */ -stock void TF2_RemoveWeaponSlot(int client, int slot) -{ - int weaponIndex; - while ((weaponIndex = GetPlayerWeaponSlot(client, slot)) != -1) - { - // bug #6206 - // papering over a valve bug where a weapon's extra wearables aren't properly removed from the weapon's owner - int extraWearable = GetEntPropEnt(weaponIndex, Prop_Send, "m_hExtraWearable"); - if (extraWearable != -1) - { - TF2_RemoveWearable(client, extraWearable); - } - - extraWearable = GetEntPropEnt(weaponIndex, Prop_Send, "m_hExtraWearableViewModel"); - if (extraWearable != -1) - { - TF2_RemoveWearable(client, extraWearable); - } - - RemovePlayerItem(client, weaponIndex); - AcceptEntityInput(weaponIndex, "Kill"); - } -} - -/** - * Removes all weapons from a client - * - * @param client Player's index. - */ -stock void TF2_RemoveAllWeapons(int client) -{ - for (int i = 0; i <= 5; i++) - { - TF2_RemoveWeaponSlot(client, i); - } -} - -/** - * Gets a player's condition bits - * - * @param client Player's index. - * @return Player's condition bits - */ -#pragma deprecated Use TF2_IsPlayerInCondition instead. -stock int TF2_GetPlayerConditionFlags(int client) -{ - return GetEntProp(client, Prop_Send, "m_nPlayerCond")|GetEntProp(client, Prop_Send, "_condition_bits"); -} - -/** - * Check whether or not a condition is set on a player - * - * @param client Player's index. - * @param cond TFCond constant - * @return True if set, false otherwise - */ -stock bool TF2_IsPlayerInCondition(int client, TFCond cond) -{ - // Conditions are stored across multiple netprops now, one for each 32-bit segment. - int iCond = view_as(cond); - switch (iCond / 32) - { - case 0: - { - int bit = 1 << iCond; - if ((GetEntProp(client, Prop_Send, "m_nPlayerCond") & bit) == bit) - { - return true; - } - - if ((GetEntProp(client, Prop_Send, "_condition_bits") & bit) == bit) - { - return true; - } - } - case 1: - { - int bit = (1 << (iCond - 32)); - if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx") & bit) == bit) - { - return true; - } - } - case 2: - { - int bit = (1 << (iCond - 64)); - if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx2") & bit) == bit) - { - return true; - } - } - case 3: - { - int bit = (1 << (iCond - 96)); - if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx3") & bit) == bit) - { - return true; - } - } - case 4: - { - int bit = (1 << (iCond - 128)); - if ((GetEntProp(client, Prop_Send, "m_nPlayerCondEx4") & bit) == bit) - { - return true; - } - } - default: - ThrowError("Invalid TFCond value %d", iCond); - } - - return false; -} - -/** - * Gets an entity's object type. - * - * @param entity Entity index. - * @return Current TFObjectType of entity. - * @error Invalid entity index. - */ -stock TFObjectType TF2_GetObjectType(int entity) -{ - int offset = GetEntSendPropOffs(entity, "m_iObjectType"); - - if (offset <= 0) - { - ThrowError("Entity index %d is not an object", entity); - } - - return view_as(GetEntData(entity, offset)); -} - -/** - * Gets an entity's object mode. - * - * @param entity Entity index. - * @return Current TFObjectMode of entity. - * @error Invalid entity index. - */ -stock TFObjectMode TF2_GetObjectMode(int entity) -{ - int offset = GetEntSendPropOffs(entity, "m_iObjectMode"); - - if (offset <= 0) - { - ThrowError("Entity index %d is not an object", entity); - } - - return view_as(GetEntData(entity, offset)); -} diff --git a/scripting/include/timers.inc b/scripting/include/timers.inc deleted file mode 100644 index 1676263..0000000 --- a/scripting/include/timers.inc +++ /dev/null @@ -1,209 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _timers_included - #endinput -#endif -#define _timers_included - -#include - -#define TIMER_REPEAT (1<<0) /**< Timer will repeat until it returns Plugin_Stop */ -#define TIMER_FLAG_NO_MAPCHANGE (1<<1) /**< Timer will not carry over mapchanges */ -#define TIMER_HNDL_CLOSE (1<<9) /**< Deprecated define, replaced by below */ -#define TIMER_DATA_HNDL_CLOSE (1<<9) /**< Timer will automatically call CloseHandle() on its data when finished */ - -/** - * Any of the following prototypes will work for a timed function. - */ -typeset Timer -{ - /** - * Called when the timer interval has elapsed. - * - * @param timer Handle to the timer object. - * @param hndl Handle passed to CreateTimer() when timer was created. - * @return Plugin_Stop to stop a repeating timer, any other value for - * default behavior. - */ - function Action(Handle timer, Handle hndl); - - /** - * Called when the timer interval has elapsed. - * - * @param timer Handle to the timer object. - * @param data Data passed to CreateTimer() when timer was created. - * @return Plugin_Stop to stop a repeating timer, any other value for - * default behavior. - */ - function Action(Handle timer, any data); - - /** - * Called when the timer interval has elapsed. - * - * @param timer Handle to the timer object. - * @return Plugin_Stop to stop a repeating timer, any other value for - * default behavior. - */ - function Action(Handle timer); -}; - -/** - * Creates a basic timer. Calling CloseHandle() on a timer will end the timer. - * - * @param interval Interval from the current game time to execute the given function. - * @param func Function to execute once the given interval has elapsed. - * @param data Handle or value to pass through to the timer callback function. - * @param flags Flags to set (such as repeatability or auto-Handle closing). - * @return Handle to the timer object. You do not need to call CloseHandle(). - * If the timer could not be created, INVALID_HANDLE will be returned. - */ -native Handle CreateTimer(float interval, Timer func, any data=INVALID_HANDLE, int flags=0); - -/** - * Kills a timer. Use this instead of CloseHandle() if you need more options. - * - * @param timer Timer Handle to kill. - * @param autoClose If autoClose is true, the data that was passed to CreateTimer() will - * be closed as a handle if TIMER_DATA_HNDL_CLOSE was not specified. - * @error Invalid handles will cause a run time error. - */ -native void KillTimer(Handle timer, bool autoClose=false); - -/** - * Manually triggers a timer so its function will be called. - * - * @param timer Timer Handle to trigger. - * @param reset If reset is true, the elapsed time counter is reset - * so the full interval must pass again. - */ -native void TriggerTimer(Handle timer, bool reset=false); - -/** - * Returns the simulated game time. - * - * This time is internally maintained by SourceMod and is based on the game - * tick count and tick rate. Unlike GetGameTime(), it will increment past - * map changes and while no players are connected. Unlike GetEngineTime(), - * it will not increment based on the system clock (i.e. it is still bound - * to the ticking process). - * - * @return Time based on the game tick count. - */ -native float GetTickedTime(); - -/** - * Returns an estimate of the time left before the map ends. If the server - * has not processed any frames yet (i.e. no players have joined the map yet), - * then the time left returned will always be infinite. - * - * @param timeleft Variable to store the time, in seconds. If the - * value is less than 0, the time limit is infinite. - * @return True if the operation is supported, false otherwise. - */ -native bool GetMapTimeLeft(int &timeleft); - -/** - * Retrieves the current map time limit. If the server has not processed any - * frames yet (i.e. no players have joined the map yet), then the time limit - * returned will always be 0. - * - * @param time Set to the number of total seconds in the map time - * limit, or 0 if there is no time limit set. - * @return True on success, false if operation is not supported. - */ -native bool GetMapTimeLimit(int &time); - -/** - * Extends the map time limit in a way that will notify all plugins. - * - * @param time Number of seconds to extend map time limit by. - * The number can be negative to decrease the time limit. - * If 0, the map will be set to have no time limit. - * @return True on success, false if operation is not supported. - */ -native bool ExtendMapTimeLimit(int time); - -/** - * Returns the number of seconds in between game server ticks. - * - * Note: A tick, in this context, is a frame. - * - * @return Number of seconds in between ticks. - */ -native float GetTickInterval(); - -/** - * Notification that the map's time left has changed via a change in the time - * limit or a change in the game rules (such as mp_restartgame). This is useful - * for plugins trying to create timers based on the time left in the map. - * - * Calling ExtendMapTimeLimit() from here, without proper precaution, will - * cause infinite recursion. - * - * If the operation is not supported, this will never be called. - - * If the server has not yet processed any frames (i.e. no players have joined - * the map yet), then this will be called once the server begins ticking, even - * if there is no time limit set. - */ -forward void OnMapTimeLeftChanged(); - -/** - * Returns whether or not the server is processing frames or not. - * - * The server does not process frames until at least one client joins the game. - * Once the first player has in, even if that player, leaves, the server's - * timers and entities will work. - * - * @return True if the server is ticking, false otherwise. - */ -native bool IsServerProcessing(); - -/** - * Creates a timer associated with a new datapack, and returns the datapack. - * @note The datapack is automatically freed when the timer ends. - * @note The position of the datapack is not reset or changed for the timer function. - * - * @param interval Interval from the current game time to execute the given function. - * @param func Function to execute once the given interval has elapsed. - * @param datapack The newly created datapack is passed though this by-reference - * parameter to the timer callback function. - * @param flags Timer flags. - * @return Handle to the timer object. You do not need to call CloseHandle(). - */ -stock Handle CreateDataTimer(float interval, Timer func, Handle &datapack, int flags=0) -{ - datapack = new DataPack(); - flags |= TIMER_DATA_HNDL_CLOSE; - return CreateTimer(interval, func, datapack, flags); -} diff --git a/scripting/include/topmenus.inc b/scripting/include/topmenus.inc deleted file mode 100644 index a4cb793..0000000 --- a/scripting/include/topmenus.inc +++ /dev/null @@ -1,434 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet: - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _topmenus_included - #endinput -#endif -#define _topmenus_included - -#include - -/** - * Actions a top menu will take on an topobj. - */ -enum TopMenuAction -{ - /** - * An option is being drawn for a menu (or for sorting purposes). - * - * INPUT : TopMenu Handle, topobj ID, client index. - * OUTPUT: Buffer for rendering, maxlength of buffer. - */ - TopMenuAction_DisplayOption = 0, - - /** - * The title of a menu is being drawn for a given topobj. - * - * Note: The Object ID will be INVALID_TOPMENUOBJECT if drawing the - * root title. Otherwise, the Object ID is a category. - * - * INPUT : TopMenu Handle, topobj ID, client index. - * OUTPUT: Buffer for rendering, maxlength of buffer. - */ - TopMenuAction_DisplayTitle = 1, - - /** - * A menu option has been selected. - * - * The Object ID will always be an item (not a category). - * - * INPUT : TopMenu Handle, topobj ID, client index. - */ - TopMenuAction_SelectOption = 2, - - /** - * A menu option is being drawn and its flags can be overridden. - * - * INPUT : TopMenu Handle, topobj ID, client index. - * OUTPUT: The first byte of the 'buffer' string should be set - * to the desired flags. By default, it will contain - * ITEMDRAW_DEFAULT. - */ - TopMenuAction_DrawOption = 3, - - /** - * Called when an topobj is being removed from the menu. - * This can be used to clean up data stored in the info string. - * - * INPUT : TopMenu Handle, topobj ID. - */ - TopMenuAction_RemoveObject = 4, -}; - -/** - * Top menu topobj types. - */ -enum TopMenuObjectType -{ - TopMenuObject_Category = 0, /**< Category (sub-menu branching from root) */ - TopMenuObject_Item = 1 /**< Item on a sub-menu */ -}; - -/** - * Top menu starting positions for display. - */ -enum TopMenuPosition -{ - TopMenuPosition_Start = 0, /**< Start/root of the menu */ - TopMenuPosition_LastRoot = 1, /**< Last position in the root menu */ - TopMenuPosition_LastCategory = 3, /**< Last position in their last category */ -}; - -/** - * Top menu topobj tag for type checking. - */ -enum TopMenuObject -{ - INVALID_TOPMENUOBJECT = 0, -}; - -/** - * TopMenu callback prototype. - * - * @param topmenu Handle to the TopMenu. - * @param action TopMenuAction being performed. - * @param topobj_id The topobj ID (if used). - * @param param Extra parameter (if used). - * @param buffer Output buffer (if used). - * @param maxlength Output buffer (if used). - */ -typedef TopMenuHandler = function void ( - TopMenu topmenu, - TopMenuAction action, - TopMenuObject topobj_id, - int param, - char[] buffer, - int maxlength -); - -// TopMenu objects are used for constructing multi-layer menus. Currently, they -// support at most two levels. The first level of items are called "categories". -methodmap TopMenu < Handle -{ - // Creates a new TopMenu. - // - // @param handler Handler to use for drawing the root title. - // @return A new TopMenu. - public native TopMenu(TopMenuHandler handler); - - // Returns a TopMenu handle from a generic handle. If the given handle is - // a TopMenu, the handle is simply casted back. Otherwise, an error is - // raised. - public static native TopMenu FromHandle(Handle handle); - - // Re-sorts the items in a TopMenu via a configuration file. - // - // The format of the configuration file should be a Valve Key-Values - // formatted file that SourceMod can parse. There should be one root - // section, and one sub-section for each category. Each sub-section's - // name should match the category name. - // - // Each sub-section may only contain key/value pairs in the form of: - // key: "item" - // value: Name of the item as passed to AddToTopMenu(). - // - // The TopMenu will draw items in the order declared in the configuration - // file. If items do not appear in the configuration file, they are sorted - // per-player based on how the handler function renders for that player. - // These items appear after the configuration sorted items. - // - // @param topmenu TopMenu Handle. - // @param file File path. - // @param error Error buffer. - // @param maxlength Maximum size of the error buffer. Error buffer - // will be filled with a zero-terminated string if - // false is returned. - // @return True on success, false on failure. - public native bool LoadConfig(const char[] file, char[] error, int maxlength); - - // Adds a category to a TopMenu. - // - // @param name Object name (MUST be unique). - // @param handler Handler for topobj. - // @param cmdname Command name (for access overrides). - // @param flags Default access flags. - // @param info_string Arbitrary storage (max 255 bytes). - // @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on failure. - public native TopMenuObject AddCategory(const char[] name, TopMenuHandler handler, - const char[] cmdname = "", int flags = 0, - const char[] info_string = ""); - - // Adds an item to a TopMenu category. - // - // @param name Object name (MUST be unique). - // @param handler Handler for topobj. - // @param category The object of the parent category for the item. - // @param cmdname Command name (for access overrides). - // @param flags Default access flags. - // @param info_string Arbitrary storage (max 255 bytes). - // @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on failure. - public native TopMenuObject AddItem(const char[] name, TopMenuHandler handler, - TopMenuObject parent, const char[] cmdname = "", - int flags = 0, const char[] info_string = ""); - - // Retrieves the info string of a top menu item. - // - // @param parent TopMenuObject ID. - // @param buffer Buffer to store info string. - // @param maxlength Maximum size of info string. - // @return Number of bytes written, not including the null terminator. - public native int GetInfoString(TopMenuObject parent, char[] buffer, int maxlength); - - // Retrieves the name string of a top menu item. - // - // @param topobj TopMenuObject ID. - // @param buffer Buffer to store info string. - // @param maxlength Maximum size of info string. - // @return Number of bytes written, not including the null terminator. - public native int GetObjName(TopMenuObject topobj, char[] buffer, int maxlength); - - // Removes an topobj from a TopMenu. - // - // Plugins' topobjs are automatically removed all TopMenus when the given - // plugin unloads or pauses. In the case of unpausing, all items are restored. - // - // @param topobj TopMenuObject ID. - public native void Remove(TopMenuObject topobj); - - // Displays a TopMenu to a client. - // - // @param client Client index. - // @param position Position to display from. - // @return True on success, false on failure. - public native bool Display(int client, TopMenuPosition position); - - // Displays a TopMenu category to a client. - // - // @param category Category topobj id. - // @param client Client index. - // @return True on success, false on failure. - public native bool DisplayCategory(TopMenuObject category, int client); - - // Finds a category's topobj ID in a TopMenu. - // - // @param name Object's unique name. - // @return TopMenuObject ID on success, or - // INVALID_TOPMENUOBJECT on failure. - public native TopMenuObject FindCategory(const char[] name); - - // Set the menu title caching behavior of the TopMenu. By default titles - // are cached to reduce overhead. If you need dynamic menu titles which - // change each time the menu is displayed to a user, set this to false. - property bool CacheTitles { - public native set(bool value); - } -}; - -/** - * Creates a TopMenu. - * - * @param handler Handler to use for drawing the root title. - * @return A new TopMenu Handle, or INVALID_HANDLE on failure. - */ -native TopMenu CreateTopMenu(TopMenuHandler handler); - -/** - * Re-sorts the items in a TopMenu via a configuration file. - * - * The format of the configuration file should be a Valve Key-Values - * formatted file that SourceMod can parse. There should be one root - * section, and one sub-section for each category. Each sub-section's - * name should match the category name. - * - * Each sub-section may only contain key/value pairs in the form of: - * key: "item" - * value: Name of the item as passed to AddToTopMenu(). - * - * The TopMenu will draw items in the order declared in the configuration - * file. If items do not appear in the configuration file, they are sorted - * per-player based on how the handler function renders for that player. - * These items appear after the configuration sorted items. - * - * @param topmenu TopMenu Handle. - * @param file File path. - * @param error Error buffer. - * @param maxlength Maximum size of the error buffer. - * Error buffer will be filled with a - * zero-terminated string if false is - * returned. - * @return True on success, false on failure. - * @error Invalid TopMenu Handle. - */ -native bool LoadTopMenuConfig(Handle topmenu, const char[] file, char[] error, int maxlength); - -/** - * Adds an topobj to a TopMenu. - * - * @param topmenu TopMenu Handle. - * @param name Object name (MUST be unique). - * @param type Object type. - * @param handler Handler for topobj. - * @param parent Parent topobj ID, or INVALID_TOPMENUOBJECT for none. - * Items must have a category parent. - * Categories must not have a parent. - * @param cmdname Command name (for access overrides). - * @param flags Default access flags. - * @param info_string Arbitrary storage (max 255 bytes). - * @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on - * failure. - * @error Invalid TopMenu Handle. - */ -native TopMenuObject AddToTopMenu(Handle topmenu, - const char[] name, - TopMenuObjectType type, - TopMenuHandler handler, - TopMenuObject parent, - const char[] cmdname="", - int flags=0, - const char[] info_string=""); - -/** - * Retrieves the info string of a top menu item. - * - * @param topmenu TopMenu Handle. - * @param parent TopMenuObject ID. - * @param buffer Buffer to store info string. - * @param maxlength Maximum size of info string. - * @return Number of bytes written, not including the - * null terminator. - * @error Invalid TopMenu Handle or TopMenuObject ID. - */ -native int GetTopMenuInfoString(Handle topmenu, TopMenuObject parent, char[] buffer, int maxlength); - -/** - * Retrieves the name string of a top menu item. - * - * @param topmenu TopMenu Handle. - * @param topobj TopMenuObject ID. - * @param buffer Buffer to store info string. - * @param maxlength Maximum size of info string. - * @return Number of bytes written, not including the - * null terminator. - * @error Invalid TopMenu Handle or TopMenuObject ID. - */ -native int GetTopMenuObjName(Handle topmenu, TopMenuObject topobj, char[] buffer, int maxlength); - -/** - * Removes an topobj from a TopMenu. - * - * Plugins' topobjs are automatically removed all TopMenus when the given - * plugin unloads or pauses. In the case of unpausing, all items are restored. - * - * @param topmenu TopMenu Handle. - * @param topobj TopMenuObject ID. - * @error Invalid TopMenu Handle. - */ -native void RemoveFromTopMenu(Handle topmenu, TopMenuObject topobj); - -/** - * Displays a TopMenu to a client. - * - * @param topmenu TopMenu Handle. - * @param client Client index. - * @param position Position to display from. - * @return True on success, false on failure. - * @error Invalid TopMenu Handle or client not in game. - */ -native bool DisplayTopMenu(Handle topmenu, int client, TopMenuPosition position); - -/** - * Displays a TopMenu category to a client. - * - * @param topmenu TopMenu Handle. - * @param category Category topobj id. - * @param client Client index. - * @return True on success, false on failure. - * @error Invalid TopMenu Handle or client not in game. - */ -native bool DisplayTopMenuCategory(Handle topmenu, TopMenuObject category, int client); - -/** - * Finds a category's topobj ID in a TopMenu. - * - * @param topmenu TopMenu Handle. - * @param name Object's unique name. - * @return TopMenuObject ID on success, or - * INVALID_TOPMENUOBJECT on failure. - * @error Invalid TopMenu Handle. - */ -native TopMenuObject FindTopMenuCategory(Handle topmenu, const char[] name); - -/** - * Change the menu title caching behavior of the TopMenu. By default the - * titles are cached to reduce overhead. If you need dynamic menu titles, which - * can change everytime the menu is displayed to a user, set this to false. - * - * @param topmenu TopMenu Handle. - * @param cache_titles Cache the menu titles and don't call the handler with - * TopMenuAction_DisplayTitle everytime the menu is drawn? - * @error Invalid TopMenu Handle - */ -native void SetTopMenuTitleCaching(Handle topmenu, bool cache_titles); - - -/** - * Do not edit below this line! - */ -public Extension __ext_topmenus = -{ - name = "TopMenus", - file = "topmenus.ext", -#if defined AUTOLOAD_EXTENSIONS - autoload = 1, -#else - autoload = 0, -#endif -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_EXTENSIONS -public void __ext_topmenus_SetNTVOptional() -{ - MarkNativeAsOptional("CreateTopMenu"); - MarkNativeAsOptional("LoadTopMenuConfig"); - MarkNativeAsOptional("AddToTopMenu"); - MarkNativeAsOptional("RemoveFromTopMenu"); - MarkNativeAsOptional("DisplayTopMenu"); - MarkNativeAsOptional("DisplayTopMenuCategory"); - MarkNativeAsOptional("FindTopMenuCategory"); - MarkNativeAsOptional("SetTopMenuTitleCaching"); -} -#endif diff --git a/scripting/include/usermessages.inc b/scripting/include/usermessages.inc deleted file mode 100644 index baf3d8f..0000000 --- a/scripting/include/usermessages.inc +++ /dev/null @@ -1,257 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _eventsmsgs_included - #endinput -#endif -#define _eventsmsgs_included - -/** - * UserMsg helper values. - */ -enum UserMsg -{ - INVALID_MESSAGE_ID = -1, -}; - -/** - * UserMsg message serialization formats - */ -enum UserMessageType -{ - UM_BitBuf = 0, - UM_Protobuf, -}; - -/** - * @section Message Flags. - */ -#define USERMSG_RELIABLE (1<<2) /**< Message will be set on the reliable stream */ -#define USERMSG_INITMSG (1<<3) /**< Message will be considered to be an initmsg */ -#define USERMSG_BLOCKHOOKS (1<<7) /**< Prevents the message from triggering SourceMod and Metamod hooks */ - -/** - * @endsection - */ - -/** - * Returns usermessage serialization type used for the current engine - * - * @return The supported usermessage type. - */ -native UserMessageType GetUserMessageType(); - -stock Protobuf UserMessageToProtobuf(Handle msg) -{ - if (GetUserMessageType() != UM_Protobuf) - return null; - return view_as(msg); -} - -// Make sure to only call this on writable buffers (eg from StartMessage). -stock BfWrite UserMessageToBfWrite(Handle msg) -{ - if (GetUserMessageType() == UM_Protobuf) - return null; - return view_as(msg); -} - -// Make sure to only call this on readable buffers (eg from a message hook). -stock BfRead UserMessageToBfRead(Handle msg) -{ - if (GetUserMessageType() == UM_Protobuf) - return null; - return view_as(msg); -} - -/** - * Returns the ID of a given message, or -1 on failure. - * - * @param msg String containing message name (case sensitive). - * @return A message index, or INVALID_MESSAGE_ID on failure. - */ -native UserMsg GetUserMessageId(const char[] msg); - -/** - * Retrieves the name of a message by ID. - * - * @param msg_id Message index. - * @param msg Buffer to store the name of the message. - * @param maxlength Maximum length of string buffer. - * @return True if message index is valid, false otherwise. - */ -native bool GetUserMessageName(UserMsg msg_id, char[] msg, int maxlength); - -/** - * Starts a usermessage (network message). - * @note Only one message can be active at a time. - * @note It is illegal to send any message while a non-intercept hook is in progress. - * - * @param msgname Message name to start. - * @param clients Array containing player indexes to broadcast to. - * @param numClients Number of players in the array. - * @param flags Optional flags to set. - * @return A handle to a bf_write bit packing structure, or - * INVALID_HANDLE on failure. - * @error Invalid message name, unable to start a message, invalid client, - * or client not connected. - */ -native Handle StartMessage(const char[] msgname, const int[] clients, int numClients, int flags=0); - -/** - * Starts a usermessage (network message). - * @note Only one message can be active at a time. - * @note It is illegal to send any message while a non-intercept hook is in progress. - * - * @param msg Message index to start. - * @param clients Array containing player indexes to broadcast to. - * @param numClients Number of players in the array. - * @param flags Optional flags to set. - * @return A handle to a bf_write bit packing structure, or - * INVALID_HANDLE on failure. - * @error Invalid message name, unable to start a message, invalid client, - * or client not connected. - */ -native Handle StartMessageEx(UserMsg msg, const int[] clients, int numClients, int flags=0); - -/** - * Ends a previously started user message (network message). - */ -native void EndMessage(); - -/** - * Hook function types for user messages. -*/ -typeset MsgHook -{ - /** - * Called when a bit buffer based usermessage is hooked - * - * @param msg_id Message index. - * @param msg Handle to the input bit buffer. - * @param players Array containing player indexes. - * @param playersNum Number of players in the array. - * @param reliable True if message is reliable, false otherwise. - * @param init True if message is an initmsg, false otherwise. - * @return Ignored for normal hooks. For intercept hooks, Plugin_Handled - * blocks the message from being sent, and Plugin_Continue - * resumes normal functionality. - */ - function Action (UserMsg msg_id, BfRead msg, const int[] players, int playersNum, bool reliable, bool init); - /** - * Called when a protobuf based usermessage is hooked - * - * @param msg_id Message index. - * @param msg Handle to the input protobuf. - * @param players Array containing player indexes. - * @param playersNum Number of players in the array. - * @param reliable True if message is reliable, false otherwise. - * @param init True if message is an initmsg, false otherwise. - * @return Ignored for normal hooks. For intercept hooks, Plugin_Handled - * blocks the message from being sent, and Plugin_Continue - * resumes normal functionality. - */ - function Action (UserMsg msg_id, Protobuf msg, const int[] players, int playersNum, bool reliable, bool init); -}; - -/** - * Called when a message hook has completed. - * - * @param msg_id Message index. - * @param sent True if message was sent, false if blocked. - */ -typedef MsgPostHook = function void (UserMsg msg_id, bool sent); - -/** - * Hooks a user message. - * - * @param msg_id Message index. - * @param hook Function to use as a hook. - * @param intercept If intercept is true, message will be fully intercepted, - * allowing the user to block the message. Otherwise, - * the hook is normal and ignores the return value. - * @param post Notification function. - * @error Invalid message index. - */ -native void HookUserMessage(UserMsg msg_id, MsgHook hook, bool intercept=false, MsgPostHook post=INVALID_FUNCTION); - -/** - * Removes one usermessage hook. - * - * @param msg_id Message index. - * @param hook Function used for the hook. - * @param intercept Specifies whether the hook was an intercept hook or not. - * @error Invalid message index. - */ -native void UnhookUserMessage(UserMsg msg_id, MsgHook hook, bool intercept=false); - -/** - * Starts a usermessage (network message) that broadcasts to all clients. - * @note See StartMessage or StartMessageEx(). - * - * @param msgname Message name to start. - * @param flags Optional flags to set. - * @return A handle to a bf_write bit packing structure, or - * INVALID_HANDLE on failure. - */ -stock Handle StartMessageAll(const char[] msgname, int flags=0) -{ - int total = 0; - int[] clients = new int[MaxClients]; - for (int i=1; i<=MaxClients; i++) - { - if (IsClientConnected(i)) - { - clients[total++] = i; - } - } - return StartMessage(msgname, clients, total, flags); -} - -/** - * Starts a simpler usermessage (network message) for one client. - * @note See StartMessage or StartMessageEx(). - * - * @param msgname Message name to start. - * @param client Client to send to. - * @param flags Optional flags to set. - * @return A handle to a bf_write bit packing structure, or - * INVALID_HANDLE on failure. - */ -stock Handle StartMessageOne(const char[] msgname, int client, int flags=0) -{ - int players[1]; - - players[0] = client; - - return StartMessage(msgname, players, 1, flags); -} diff --git a/scripting/include/vector.inc b/scripting/include/vector.inc deleted file mode 100644 index a6aea08..0000000 --- a/scripting/include/vector.inc +++ /dev/null @@ -1,179 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _vector_included - #endinput -#endif -#define _vector_included - -/** - * Calculates a vector's length. - * - * @param vec Vector. - * @param squared If true, the result will be squared (for optimization). - * @return Vector length (magnitude). - */ -native float GetVectorLength(const float vec[3], bool squared=false); - -/** - * Calculates the distance between two vectors. - * - * @param vec1 First vector. - * @param vec2 Second vector. - * @param squared If true, the result will be squared (for optimization). - * @return Vector distance. - */ -native float GetVectorDistance(const float vec1[3], const float vec2[3], bool squared=false); - -/** - * Calculates the dot product of two vectors. - * - * @param vec1 First vector. - * @param vec2 Second vector. - * @return Dot product of the two vectors. - */ -native float GetVectorDotProduct(const float vec1[3], const float vec2[3]); - -/** - * Computes the cross product of two vectors. Any input array can be the same - * as the output array. - * - * @param vec1 First vector. - * @param vec2 Second vector. - * @param result Resultant vector. - */ -native void GetVectorCrossProduct(const float vec1[3], const float vec2[3], float result[3]); - -/** - * Normalizes a vector. The input array can be the same as the output array. - * - * @param vec Vector. - * @param result Resultant vector. - * @return Vector length. - */ -native float NormalizeVector(const float vec[3], float result[3]); - -/** - * Returns vectors in the direction of an angle. - * - * @param angle Angle. - * @param fwd Forward vector buffer or NULL_VECTOR. - * @param right Right vector buffer or NULL_VECTOR. - * @param up Up vector buffer or NULL_VECTOR. - */ -native void GetAngleVectors(const float angle[3], float fwd[3], float right[3], float up[3]); - -/** - * Returns angles from a vector. - * - * @param vec Vector. - * @param angle Angle buffer. - */ -native void GetVectorAngles(const float vec[3], float angle[3]); - -/** - * Returns direction vectors from a vector. - * - * @param vec Vector. - * @param right Right vector buffer or NULL_VECTOR. - * @param up Up vector buffer or NULL_VECTOR. - */ -native void GetVectorVectors(const float vec[3], float right[3], float up[3]); - -/** - * Adds two vectors. It is safe to use either input buffer as an output - * buffer. - * - * @param vec1 First vector. - * @param vec2 Second vector. - * @param result Result buffer. - */ -stock void AddVectors(const float vec1[3], const float vec2[3], float result[3]) -{ - result[0] = vec1[0] + vec2[0]; - result[1] = vec1[1] + vec2[1]; - result[2] = vec1[2] + vec2[2]; -} - -/** - * Subtracts a vector from another vector. It is safe to use either input - * buffer as an output buffer. - * - * @param vec1 First vector. - * @param vec2 Second vector to subtract from first. - * @param result Result buffer. - */ -stock void SubtractVectors(const float vec1[3], const float vec2[3], float result[3]) -{ - result[0] = vec1[0] - vec2[0]; - result[1] = vec1[1] - vec2[1]; - result[2] = vec1[2] - vec2[2]; -} - -/** - * Scales a vector. - * - * @param vec Vector. - * @param scale Scale value. - */ -stock void ScaleVector(float vec[3], float scale) -{ - vec[0] *= scale; - vec[1] *= scale; - vec[2] *= scale; -} - -/** - * Negatives a vector. - * - * @param vec Vector. - */ -stock void NegateVector(float vec[3]) -{ - vec[0] = -vec[0]; - vec[1] = -vec[1]; - vec[2] = -vec[2]; -} - -/** - * Builds a vector from two points by subtracting the points. - * - * @param pt1 First point (to be subtracted from the second). - * @param pt2 Second point. - * @param output Output vector buffer. - */ -stock void MakeVectorFromPoints(const float pt1[3], const float pt2[3], float output[3]) -{ - output[0] = pt2[0] - pt1[0]; - output[1] = pt2[1] - pt1[1]; - output[2] = pt2[2] - pt1[2]; -} diff --git a/scripting/include/version.inc b/scripting/include/version.inc deleted file mode 100644 index 8519560..0000000 --- a/scripting/include/version.inc +++ /dev/null @@ -1,49 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This file is part of the SourceMod/SourcePawn SDK. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#if defined _version_included - #endinput -#endif -#define _version_included - -#tryinclude - -#if !defined _auto_version_included -#define SOURCEMOD_V_TAG "manual" -#define SOURCEMOD_V_REV 0 -#define SOURCEMOD_V_CSET "0" -#define SOURCEMOD_V_MAJOR 1 /**< SourceMod Major version */ -#define SOURCEMOD_V_MINOR 8 /**< SourceMod Minor version */ -#define SOURCEMOD_V_RELEASE 0 /**< SourceMod Release version */ - -#define SOURCEMOD_VERSION "1.8.0-manual" /**< SourceMod version string (major.minor.release-tag) */ -#endif diff --git a/scripting/include/version_auto.inc b/scripting/include/version_auto.inc deleted file mode 100644 index 32281ec..0000000 --- a/scripting/include/version_auto.inc +++ /dev/null @@ -1,15 +0,0 @@ - -#if defined _auto_version_included - #endinput -#endif -#define _auto_version_included - -#define SOURCEMOD_V_TAG "" -#define SOURCEMOD_V_CSET "50b5bb1" -#define SOURCEMOD_V_MAJOR 1 -#define SOURCEMOD_V_MINOR 9 -#define SOURCEMOD_V_RELEASE 0 -#define SOURCEMOD_V_REV 6245 - -#define SOURCEMOD_VERSION "1.9.0.6245" - \ No newline at end of file From 1108c91b34404f991c1720be2797564be9a9c853 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:53:48 -0800 Subject: [PATCH 08/29] Utilize Timber + Mind Media support --- plugins/ngs_proxychecker.smx | Bin 33093 -> 35270 bytes scripting/ngs_proxychecker.sp | 118 ++++++++++++++++++---------------- updater/ngs_proxychecker.txt | 6 +- 3 files changed, 67 insertions(+), 57 deletions(-) diff --git a/plugins/ngs_proxychecker.smx b/plugins/ngs_proxychecker.smx index c75b9e25a442502ee266b01d18c40326cb16dbdc..4dadb8663477845e3f39ba0d739b38ac4cd06594 100644 GIT binary patch literal 35270 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 perDay) { vpnToUse++; - PrintToServerDebug("Rolling vpnList to %d as perDaySoFar of %d is >= %s\'s perDay of %d", vpnToUse, perDaySoFar, buffer, perDay); + Timber.d("Rolling vpnList to %d as perDaySoFar of %d is >= %s\'s perDay of %d", vpnToUse, perDaySoFar, buffer, perDay); if (vpnToUse == vpnList.Length) { - PrintToServerDebug("Just totally invalidating vpnToUse as all are taken up. List length is %d", vpnList.Length); + Timber.d("Just totally invalidating vpnToUse as all are taken up. List length is %d", vpnList.Length); vpnToUse = -1; } } - PrintToServerDebug("Setting %s perDaySoFar to %d!", buffer, kv.GetNum("perDaySoFar")); + Timber.d("Setting %s perDaySoFar to %d!", buffer, kv.GetNum("perDaySoFar")); } kv.GoBack(); } @@ -287,7 +287,7 @@ void ReadProxyConfigFile(const char[] configPath, const char[] cachePath, bool s processQueue = new SMQueue(); } processQueueTimer = new SMTimer(time, OnProcessQueueTimer, _, TIMER_REPEAT); // saved for later delete/reuse if needed - PrintToServerDebug("Set process queue timer to %0.2f with lowestPerMin at %0.2f and " ... + Timber.d("Set process queue timer to %0.2f with lowestPerMin at %0.2f and " ... "totalPerDay at %d", time, lowestPerMin, totalPerDay); } @@ -335,7 +335,7 @@ public void OnClientPutInServer(int client) if (requestCache != null && requestCache.GetValue(ip, isSafe) && isSafe) { - PrintToServerDebug("Retrieved notion that client %L is safe", client); + Timber.d("Retrieved notion that client %L is safe", client); return; } @@ -360,15 +360,15 @@ public Action OnProcessQueueTimer(Handle timer) pack.Reset(); pack.ReadCell(); pack.ReadString(ip, sizeof(ip)); - PrintToServerDebug("ProcessQueue is not empty, processing %s.", ip); + Timber.d("ProcessQueue is not empty, processing %s.", ip); if (requestCache.GetValue(ip, dummy)) { - PrintToServerDebug("Got ip %s from cache, already processed.", ip); + Timber.d("Got ip %s from cache, already processed.", ip); delete pack; // already cached } else { - PrintToServerDebug("Ip %s not in cache, sending request.", ip); + Timber.d("Ip %s not in cache, sending request.", ip); SendCheckRequest(pack); break; } @@ -386,7 +386,7 @@ void SendCheckRequest(DataPack pack) } else if (now - twentyFourHourTimeStamp >= 86400) { - PrintToServerDebug("now: %d minus priortimestamp: %d is greater than a day, reseting daily values.", now, twentyFourHourTimeStamp); + Timber.d("now: %d minus priortimestamp: %d is greater than a day, reseting daily values.", now, twentyFourHourTimeStamp); for (int i = 0; i < vpnList.Length; i++) { VPN vpn = vpnList.Get(i); @@ -422,22 +422,22 @@ void SendCheckRequest(DataPack pack) vpn.GetValue("perDay", allowedPerDay); if (soFarToday + 1 == allowedPerDay) { - PrintToServerDebug("soFarToday + 1 == allowedPerDay for service %s!", type); + Timber.d("soFarToday + 1 == allowedPerDay for service %s!", type); if (vpnToUse + 1 == vpnList.Length) { - PrintToServerDebug("vpnToUse runs off the end of the list, invalidating vpnToUse"); + Timber.d("vpnToUse runs off the end of the list, invalidating vpnToUse"); vpnToUse = -1; // wait to cycle back } else { - PrintToServerDebug("vpnToUse is being iterated by 1 to %d.", vpnToUse + 1); + Timber.d("vpnToUse is being iterated by 1 to %d.", vpnToUse + 1); vpnToUse++; } } } else { - PrintToServerDebug("vpnToUse is -1 requeuing datapack at beginning"); + Timber.d("vpnToUse is -1 requeuing datapack at beginning"); processQueue.EnqueueAt(0, pack); } } @@ -452,7 +452,7 @@ void SendGetIPIntelRequest(DataPack pack) cvarContactEmail.GetString(contactAddr, sizeof(contactAddr)); if (StrEqual("dummy@dummy.dummy", contactAddr)) { - LogError("SPAMMY ERRORS! Please change the email used with the proxy checker to something valid!"); + Timber.e("Please change the email used with the proxy checker to something valid!"); delete pack; return; } @@ -462,7 +462,7 @@ void SendGetIPIntelRequest(DataPack pack) request.SetContextValue(pack); request.SetCallbacks(OnGetIPIntelRequestDone); request.Send(); - PrintToServerDebug("Sending getipintel request at url %s .", formatURL); + Timber.d("Sending getipintel request at url %s .", formatURL); } public void OnGetIPIntelRequestDone(SWHTTPRequest hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, DataPack pack) @@ -479,46 +479,42 @@ public void OnGetIPIntelRequestDone(SWHTTPRequest hRequest, bool bFailure, bool hRequest.GetBodyData(buffer, hRequest.ResponseSize); float response = StringToFloat(buffer); switch(response) { - case -1: { - LogError("Get IP Intel request failed for userid %d! Invalid no input!", userid); + case -1.0: { + Timber.e("Get IP Intel request failed for userid %d! No input!", userid); } - case -2: { - LogError("Get IP Intel request failed for userid %d! Invalid IP address!", userid); + case -2.0: { + Timber.e("Get IP Intel request failed for userid %d! Invalid IP address!", userid); } - case -3: { - LogError("Get IP Intel request failed for userid %d! Unroutable address / private address!", userid); + case -3.0: { + Timber.e("Get IP Intel request failed for userid %d! Unroutable address / private address!", userid); } - case -4: { - LogError("Get IP Intel request failed for userid %d! Unable to reach database, most likely the database is being updated. Keep an eye on twitter for more information!", userid); + case -4.0: { + Timber.e("Get IP Intel request failed for userid %d! Unable to reach database, most likely the database is being updated. Keep an eye on twitter for more information!", userid); } - case -5: { - LogError("Get IP Intel request failed for userid %d! Your connecting IP has been banned from the system or you do not have permission to access a particular service. Did you exceed your query limits? Did you use an invalid email address? If you want more information, contact GetIPIntel using the links at http://getipintel.net/#Contact . Rolling over to next VPN.", userid); + case -5.0: { + Timber.e("Get IP Intel request failed for userid %d! Your connecting IP has been banned from the system or you do not have permission to access a particular service. Did you exceed your query limits? Did you use an invalid email address? If you want more information, contact GetIPIntel using the links at http://getipintel.net/#Contact . Rolling over to next VPN.", userid); // Apply the maxed out queries to the VPN in case of caching - VPN vpn = vpnList.Get(vpnToUse); - int allowedPerDay; - vpn.GetValue("perDay", allowedPerDay); - vpn.SetValue("perDaySoFar", allowedPerDay); - vpnToUse++; + RollOverVPN(); } - case -6: { - LogError("Get IP Intel request failed for userid %d! You did not provide any contact information with your query or the contact information is invalid! Rolling over!", userid); - vpnToUse++; + case -6.0: { + Timber.e("Get IP Intel request failed for userid %d! You did not provide any contact information with your query or the contact information is invalid! Rolling over!", userid); + RollOverVPN(); } default: { - LogError("Get IP Intel request failed for userid %d! Check GetIPIntel for error code %.0f with status 400!", userid, response); + Timber.e("Get IP Intel request failed for userid %d! Check GetIPIntel for error code %.0f with status 400!", userid, response); } } delete pack; } else if (eStatusCode == k_EHTTPStatusCode429TooManyRequests) { - LogError("Get IP Intel request failed for userid %d! There were too many requests, please investigate this!", userid); + Timber.e("Get IP Intel request failed for userid %d! There were too many requests, please investigate this!", userid); processQueue.Enqueue(pack); - vpnToUse++; + RollOverVPN(); } else { - LogError("Get IP Intel request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); + Timber.e("Get IP Intel request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); delete pack; } delete hRequest; @@ -537,7 +533,7 @@ public void OnGetIPIntelRequestDone(SWHTTPRequest hRequest, bool bFailure, bool delete pack; float probability = StringToFloat(buffer); - PrintToServerDebug("Probability for proxy is %.2f for ip %s!", probability, ip); + Timber.d("Probability for proxy is %.2f for ip %s!", probability, ip); if (probability >= getIpIntelProbability) { ServerCommand("sm_banip %s 0 Suspicion of proxy with probability %.2f", ip, probability); @@ -551,7 +547,7 @@ public void OnGetIPIntelRequestDone(SWHTTPRequest hRequest, bool bFailure, bool { requestCache.SetValue(ip, true); // TODO: Make cache erase after a while } - PrintToServerDebug("Caching probability %.02f for client %L.", probability, client); + Timber.d("Caching probability %.02f for client %L.", probability, client); } void SendProxyCheckIORequest(DataPack pack) @@ -566,7 +562,7 @@ void SendProxyCheckIORequest(DataPack pack) request.SetContextValue(pack); request.SetCallbacks(OnProxyCheckIORequestDone); request.Send(); - PrintToServerDebug("Sending proxycheckio request at url %s .", formatURL); + Timber.d("Sending proxycheckio request at url %s .", formatURL); } public void OnProxyCheckIORequestDone(SWHTTPRequest hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, DataPack pack) @@ -577,7 +573,7 @@ public void OnProxyCheckIORequestDone(SWHTTPRequest hRequest, bool bFailure, boo pack.ReadString(ip, sizeof(ip)); if(eStatusCode != k_EHTTPStatusCode200OK || !bRequestSuccessful) { - LogError("ProxyCheck.io request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); + Timber.e("ProxyCheck.io request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); processQueue.Enqueue(pack); // deprioritize this delete hRequest; return; @@ -594,7 +590,7 @@ public void OnProxyCheckIORequestDone(SWHTTPRequest hRequest, bool bFailure, boo delete hRequest; delete pack; - PrintToServerDebug("ProxyCheck.io request returned %s", buffer); + Timber.d("ProxyCheck.io request returned %s", buffer); JSON_Object reponse = new JSON_Object(); reponse.Decode(buffer); @@ -606,11 +602,11 @@ public void OnProxyCheckIORequestDone(SWHTTPRequest hRequest, bool bFailure, boo reponse.GetString("message", message, sizeof(message)); if (StrEqual("warning", status)) { - LogMessage("ProxyCheck.io error: %s", message); + Timber.w("ProxyCheck.io warning: %s", message); } else { - LogError("ProxyCheck.io error: %s", message); + Timber.e("ProxyCheck.io error: %s", message); } } else @@ -618,7 +614,7 @@ public void OnProxyCheckIORequestDone(SWHTTPRequest hRequest, bool bFailure, boo char isProxy[8], proxyType[24]; JSON_Object ipObj = reponse.GetObject(ip); ipObj.GetString("proxy", isProxy, sizeof(isProxy)); - PrintToServerDebug("Result for proxy is %s <%s> for ip %s!", isProxy, (isProxy[0] == 'y') ? proxyType : "none", ip); + Timber.d("Result for proxy is %s <%s> for ip %s!", isProxy, (isProxy[0] == 'y') ? proxyType : "none", ip); if (StrEqual(isProxy, "yes")) { ipObj.GetString("type", proxyType, sizeof(proxyType)); @@ -633,7 +629,7 @@ public void OnProxyCheckIORequestDone(SWHTTPRequest hRequest, bool bFailure, boo { requestCache.SetValue(ip, true); // TODO: Make cache erase after a while } - PrintToServerDebug("Caching suspicion of %s for ip %s.", isProxy, ip); + Timber.d("Caching suspicion of %s for ip %s.", isProxy, ip); } reponse.Cleanup(); delete reponse; @@ -651,7 +647,7 @@ void SendMindMediaRequest(DataPack pack) request.SetContextValue(pack); request.SetCallbacks(OnMindMediaRequestDone); request.Send(); - PrintToServerDebug("Sending mindmedia request at url %s .", formatURL); + Timber.d("Sending mindmedia request at url %s .", formatURL); } public void OnMindMediaRequestDone(SWHTTPRequest hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, DataPack pack) @@ -662,7 +658,7 @@ public void OnMindMediaRequestDone(SWHTTPRequest hRequest, bool bFailure, bool b pack.ReadString(ip, sizeof(ip)); if(eStatusCode != k_EHTTPStatusCode200OK || !bRequestSuccessful) { - LogError("Mind-Media request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); + Timber.e("Mind-Media request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); processQueue.Enqueue(pack); // deprioritize this delete hRequest; return; @@ -679,13 +675,13 @@ public void OnMindMediaRequestDone(SWHTTPRequest hRequest, bool bFailure, bool b delete hRequest; TrimString(buffer); - PrintToServerDebug("Mind-Media request returned %s", buffer); + Timber.d("Mind-Media request returned %s", buffer); int bufferLen = strlen(buffer); // retrieving new size after trim if (bufferLen == 0 || bufferLen > 1 || buffer[0] == 'X') { - LogError("Mind-Media errored with response %s!", buffer); + Timber.e("Mind-Media errored with response %s!", buffer); processQueue.Enqueue(pack); } else @@ -703,7 +699,19 @@ public void OnMindMediaRequestDone(SWHTTPRequest hRequest, bool bFailure, bool b { requestCache.SetValue(ip, true); // TODO: Make cache erase after a while } - PrintToServerDebug("Caching suspicion of %s for ip %s.", buffer, ip); + Timber.d("Caching suspicion of %s for ip %s.", buffer, ip); delete pack; } +} + +void RollOverVPN(bool setUsed = true) +{ + if (setUsed) + { + VPN vpn = vpnList.Get(vpnToUse); + int allowedPerDay; + vpn.GetValue("perDay", allowedPerDay); + vpn.SetValue("perDaySoFar", allowedPerDay); + } + vpnToUse++; } \ No newline at end of file diff --git a/updater/ngs_proxychecker.txt b/updater/ngs_proxychecker.txt index f9ca472..f0a7984 100644 --- a/updater/ngs_proxychecker.txt +++ b/updater/ngs_proxychecker.txt @@ -4,10 +4,12 @@ { "Version" { - "Latest" "1.3.3" + "Latest" "1.3.4" } - "Notes" "Added a whitelist/blacklist feature, minor additional refactors!" + "Notes" "Added MindMedia support to check against proxy lists!" + "Notes" "Added rollover support to roll over to next VPN on error." + "Notes" "Changed logging to use Timber library." } "Files" From fbf802fca591356716c7ca253cc6766bca432a31 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:56:40 -0800 Subject: [PATCH 09/29] Target Non-AFK --- plugins/ngs_randomfilter.smx | Bin 7719 -> 9905 bytes scripting/ngs_randomfilter.sp | 39 ++++++++++++++++++++++++++++++++-- updater/ngs_randomfilter.txt | 5 ++--- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/plugins/ngs_randomfilter.smx b/plugins/ngs_randomfilter.smx index 1c06090e56356d047d9de87e4876921fcdb4c2cd..385ad06eb1bd558a8b778539c420c63ec69229fb 100644 GIT binary patch literal 9905 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 delta 7659 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 diff --git a/scripting/ngs_randomfilter.sp b/scripting/ngs_randomfilter.sp index e97b33f..951bb69 100644 --- a/scripting/ngs_randomfilter.sp +++ b/scripting/ngs_randomfilter.sp @@ -6,7 +6,7 @@ * addons/sourcemod/plugins/ngs_randomfilter.smx * * Dependencies: -* tf2_stocks.inc, ngsutils.inc, ngsupdater.inc +* tf2_stocks.inc, afk_manager.inc, ngsutils.inc, ngsupdater.inc */ #pragma newdecls required #pragma semicolon 1 @@ -15,6 +15,7 @@ #define RELOAD_ON_UPDATE 1 #include +#include #include #include @@ -24,7 +25,7 @@ public Plugin myinfo = { name = "[NGS] Random Filter", author = "TheXeon", description = "Adds a filter to target random people.", - version = "1.1.1", + version = "1.1.2", url = "https://www.neogenesisnetwork.net" } @@ -32,6 +33,10 @@ public void OnPluginStart() { AddMultiTargetFilter("@random", TargetRandom, "Random player", false); AddMultiTargetFilter("@r", TargetRandom, "Random player", false); + AddMultiTargetFilter("@randomafk", TargetRandomAFK, "Random afk player", false); + AddMultiTargetFilter("@randomnonafk", TargetRandomNonAFK, "Random nonafk player", false); + AddMultiTargetFilter("@rafk", TargetRandomAFK, "Random afk player", false); + AddMultiTargetFilter("@rnonafk", TargetRandomNonAFK, "Random nonafk player", false); AddMultiTargetFilter("@randomred", TargetRandomRed, "Random player on red", false); AddMultiTargetFilter("@rred", TargetRandomRed, "Random player on red", false); AddMultiTargetFilter("@randomblue", TargetRandomBlue, "Random player on blue", false); @@ -42,6 +47,10 @@ public void OnPluginEnd() { RemoveMultiTargetFilter("@random", TargetRandom); RemoveMultiTargetFilter("@r", TargetRandom); + RemoveMultiTargetFilter("@randomafk", TargetRandomAFK); + RemoveMultiTargetFilter("@randomnonafk", TargetRandomNonAFK); + RemoveMultiTargetFilter("@rafk", TargetRandomAFK); + RemoveMultiTargetFilter("@rnonafk", TargetRandomNonAFK); RemoveMultiTargetFilter("@randomred", TargetRandomRed); RemoveMultiTargetFilter("@rred", TargetRandomRed); RemoveMultiTargetFilter("@randomblue", TargetRandomBlue); @@ -62,6 +71,32 @@ public bool TargetRandom(const char[] pattern, Handle clients) return true; } +public bool TargetRandomAFK(const char[] pattern, Handle clients) +{ + if (GetClientCount() < 1) return false; + int client; + do + { + client = GetRandomInt(1, MaxClients); + } + while(!IsClientInGame(client) && !AFKM_IsClientAFK(client)); + PushArrayCell(clients, client); + return true; +} + +public bool TargetRandomNonAFK(const char[] pattern, Handle clients) +{ + if (GetClientCount() < 1) return false; + int client; + do + { + client = GetRandomInt(1, MaxClients); + } + while(!IsValidClient(client, _, _, _, _, true)); + PushArrayCell(clients, client); + return true; +} + public bool TargetRandomBlue(const char[] pattern, Handle clients) { if (GetTeamClientCount(view_as(TFTeam_Blue)) < 1) return false; diff --git a/updater/ngs_randomfilter.txt b/updater/ngs_randomfilter.txt index 8e686db..f97322d 100644 --- a/updater/ngs_randomfilter.txt +++ b/updater/ngs_randomfilter.txt @@ -4,11 +4,10 @@ { "Version" { - "Latest" "1.1.1" + "Latest" "1.1.2" } - "Notes" "Add updater support!" - "Notes" "Remove extra spaces from sp." + "Notes" "Added targetting random AFK and non-AFK!" } "Files" From 616316869daa28e4e5fb6abe6428bf7489a7bcc9 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 18:59:32 -0800 Subject: [PATCH 10/29] Restart map instead of entire server --- plugins/ngs_autorestart.smx | Bin 25179 -> 26591 bytes scripting/ngs_autorestart.sp | 33 +++++++++++++++++---------------- updater/ngs_autorestart.txt | 6 +++--- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/plugins/ngs_autorestart.smx b/plugins/ngs_autorestart.smx index a3a307bf5c4ccccf36b20059a130b076efd0b213..dfd34b11c4f8ecb274bea2c5ec0c36b289b33188 100644 GIT binary patch literal 26591 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 diff --git a/scripting/ngs_autorestart.sp b/scripting/ngs_autorestart.sp index 4e710f1..62895f4 100644 --- a/scripting/ngs_autorestart.sp +++ b/scripting/ngs_autorestart.sp @@ -27,7 +27,7 @@ public Plugin myinfo = { name = "[NGS] Timed Restart", author = "TheXeon", - description = "Restart the server automagically :D", + description = "Restart the server's map automagically :D", version = "1.0.7", url = "https://www.neogenesisnetwork.net/" } @@ -43,6 +43,7 @@ public void OnPluginStart() AutoExecConfig_SetFile("autorestart"); AutoExecConfig_SetCreateFile(true); bool appended; + Timber.plantToFile(appended); cvarEnabled = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsar_enabled", "1", "Enable autorestart on no players.", 0, true, 0.0, true, 1.0); cvarUptimeRequirement = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsar_uptime_requirement", "960.0", "Minutes the server should have since first connection to allow a restart."); cvarForcedRestartTime = AutoExecConfig_CreateConVarCheckAppend(appended, "ngsar_forced_requirement", "1920.0", "Minutes the server should have since first connection to go to forced restart. Set to 0.0 to disable."); @@ -54,9 +55,9 @@ public void OnPluginStart() public void OnConfigsExecuted() { - if (GetEngineVersion() == Engine_TF2 && (FindConVar("tf_allow_server_hibernation").BoolValue)) + if (GetEngineVersion() == Engine_TF2 && FindConVar("tf_allow_server_hibernation").BoolValue) { - LogMessage("Warning! Timers will be messed up as tf_allow_server_hibernation is enabled!"); + Timber.w("Timers will be messed up as tf_allow_server_hibernation is enabled!"); } } @@ -72,7 +73,7 @@ public Action CommandStartRestartTimer(int client, int args) status = StringToInt(arg1); } autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, status); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} A %srestart timer has been started, server %s be restarting in 30 seconds!", + CPrintToChatAll("{GREEN}[SM]{DEFAULT} A %srestart timer has been started, server map %s be restarting in 30 seconds!", (status == 1) ? "forced " : "", (status == 1) ? "will" : "may"); } else @@ -84,8 +85,8 @@ public Action CommandStartRestartTimer(int client, int args) public Action CommandCheckRestartTimer(int client, int args) { - CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There is %sa restart timer going on!", - (autoRestartTimer == null) ? "not " : ""); + CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} There is %sa restart timer going on at uptime %f!", + (autoRestartTimer == null) ? "not " : "", GetGameTime()); return Plugin_Handled; } @@ -94,7 +95,7 @@ public void OnClientPostAdminCheck(int client) if (autoRestartTimer != null && !IsFakeClient(client) && !IsValidForcedTime()) { delete autoRestartTimer; - CPrintToChatAll("{GREEN}[SM]{DEFAULT} Server restart aborted (someone joined)!"); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} Map restart aborted (someone joined)!"); } } @@ -106,13 +107,13 @@ public void OnClientDisconnect_Post(int client) if (IsValidForcedTime()) { autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, 1); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server has been up for %f hours, forcing a restart in 30 seconds!", time / 3600.0); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server has been up for %d hours, forcing a map restart in 30 seconds!", RoundToNearest(time / 3600.0)); } else if ((GetClientCount(false) == 0 || !NonAFKPlayersExist()) && (time / 60.0) > cvarUptimeRequirement.FloatValue) { autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, 0); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server will attempt a restart in 30 seconds!"); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server will attempt a map restart in 30 seconds!"); } } } @@ -120,22 +121,22 @@ public void OnClientDisconnect_Post(int client) public Action AutoRestartTimer(Handle timer, any status) { autoRestartTimer = null; - #if defined DEBUG - PrintToServer("Status is %d, GetClientCount(false) = %d, !NonAFKPlayersExist() = %u in AutoRestartTimer callback", status, GetClientCount(false), !NonAFKPlayersExist()); - #endif + Timber.d("Status is %d, GetClientCount(false) = %d, !NonAFKPlayersExist() = %u in AutoRestartTimer callback", status, GetClientCount(false), !NonAFKPlayersExist()); // status: 0 for regular, 1 for forced all the way if (status == 1 || GetClientCount(false) == 0 || !NonAFKPlayersExist()) { #if defined DEBUG PrintToServer("Fake doing a restart!"); #else - LogMessage("Server is restarting at Unix Timestamp %d!", GetTime()); - ServerCommand("_restart"); + Timber.i("Server is restarting map at Unix Timestamp %d!", GetTime()); + char mapName[MAX_BUFFER_LENGTH]; + GetCurrentMap(mapName, sizeof(mapName)); + ForceChangeLevel(mapName, "Having a quick map refresh, sit tight!"); #endif } else { - CPrintToChatAll("{GREEN}[SM]{DEFAULT} Restart aborted!"); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} Map restart aborted!"); } } @@ -154,5 +155,5 @@ stock bool NonAFKPlayersExist() stock bool IsValidForcedTime() { float forcedTime = cvarForcedRestartTime.FloatValue; - return forcedTime != 0.0 && (GetGameTime() / 60.0) > forcedTime; + return forcedTime != 0.0 && (GetGameTime() / 60.0) >= forcedTime; } diff --git a/updater/ngs_autorestart.txt b/updater/ngs_autorestart.txt index 9afabd2..8454df6 100644 --- a/updater/ngs_autorestart.txt +++ b/updater/ngs_autorestart.txt @@ -4,11 +4,11 @@ { "Version" { - "Latest" "1.0.6" + "Latest" "1.0.7" } - "Notes" "Fix to use delete instead of SMTimer.Close()" - "Notes" "Allow float values for time, so half hours or exact is possible." + "Notes" "Changed to restart map instead of sending _restart command" + "Notes" "Changed to utilize Timber logging library, logs to file." } "Files" From 47c8b5c47175d0a10cda4789e64a8bc1874e5afa Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 26 Jan 2019 19:10:29 -0800 Subject: [PATCH 11/29] Fixed request messages, added cvar autoupdating --- plugins/ngs_djsuite.smx | Bin 19887 -> 25090 bytes scripting/ngs_djsuite.sp | 25 ++++++++++++++----------- updater/ngs_djsuite.txt | 7 +++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/plugins/ngs_djsuite.smx b/plugins/ngs_djsuite.smx index 6d352260bb7fe47c2837c0919e8efdd27bbdcca8..dbd329431604415766cdb4d9e0a96ce8a4f273bc 100644 GIT binary patch literal 25090 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 diff --git a/scripting/ngs_djsuite.sp b/scripting/ngs_djsuite.sp index 5d79931..51002e7 100644 --- a/scripting/ngs_djsuite.sp +++ b/scripting/ngs_djsuite.sp @@ -8,7 +8,7 @@ * cfg/sourcemod/plugin.ngs_djsuite.cfg * * Dependencies: -* sourcemod.inc, multicolors.inc, ngsutils.inc, ngsupdater.inc, basecomms.inc, +* autoexecconfig.inc, multicolors.inc, ngsutils.inc, ngsupdater.inc, basecomms.inc, * sourcecomms.inc */ #pragma newdecls required @@ -19,7 +19,7 @@ #define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" #define RELOAD_ON_UPDATE 1 -#include +#include #include #include #include @@ -33,7 +33,7 @@ public Plugin myinfo = { name = "[NGS] RDJ Suite", author = "Luki / TheXeon", description = "Adds a special chat and features for DJ's!", - version = "1.0.6", + version = "1.0.7", url = "https://neogenesisnetwork.net" } @@ -43,7 +43,7 @@ bool djChatToggledOn[MAXPLAYERS + 1] = { false, ... }; ConVar cvarDisableDJForNonDJs; ConVar sv_allow_voice_from_file; -char logfile[255]; +char logfile[PLATFORM_MAX_PATH]; public void OnPluginStart() { @@ -56,14 +56,19 @@ public void OnPluginStart() AddCommandListener(CommandSay, "say"); AddCommandListener(CommandSay, "say_team"); - cvarDisableDJForNonDJs = CreateConVar("sm_djsuite_nondj_disabled", "1", "Disable the ability for nonDJS to play music."); - cvarDisableDJForNonDJs.AddChangeHook(OnDJDisableChange); sv_allow_voice_from_file = FindConVar("sv_allow_voice_from_file"); if (sv_allow_voice_from_file == null) { SetFailState("Unsupported game: sv_allow_voice_from_file does not exist!"); } + AutoExecConfig_SetCreateDirectory(true); + AutoExecConfig_SetCreateFile(true); + bool appended; + cvarDisableDJForNonDJs = AutoExecConfig_CreateConVarCheckAppend(appended, "djsuite_nondj_disabled", "1", "Disable the ability for nonDJS to play music."); + cvarDisableDJForNonDJs.AddChangeHook(OnDJDisableChange); + AutoExecConfig_ExecAndClean(appended); + BuildPath(Path_SM, logfile, sizeof(logfile), "logs/djchat.log"); for (int i = 1; i <= MaxClients; i++) @@ -73,8 +78,6 @@ public void OnPluginStart() OnClientPostAdminCheck(i); } } - - AutoExecConfig(); } public void OnDJDisableChange(ConVar convar, char[] oldValue, char[] newValue) @@ -111,7 +114,7 @@ public void OnLibAdded(const char[] name) { basecommExists = true; } - else if (StrEqual(name, "sourcecomms", false)) + else if (StrContains(name, "sourcecomms", false) != -1) { sourcecommsExists = true; } @@ -123,7 +126,7 @@ public void OnLibRemoved(const char[] name) { basecommExists = false; } - else if (StrEqual(name, "sourcecomms", false)) + else if (StrContains(name, "sourcecomms", false) != -1) { sourcecommsExists = false; } @@ -175,7 +178,7 @@ public Action CommandSongRequest(int client, int args) for (int i = 1; i <= MaxClients; i++) { - if (IsValidClient(i) && CheckCommandAccess(client, "sm_djsuite_allowaudio_override", ADMFLAG_ROOT)) + if (IsValidClient(i) && CheckCommandAccess(i, "sm_djsuite_allowaudio_override", ADMFLAG_ROOT)) { djExists = true; break; diff --git a/updater/ngs_djsuite.txt b/updater/ngs_djsuite.txt index 1a033d9..78ab4fe 100644 --- a/updater/ngs_djsuite.txt +++ b/updater/ngs_djsuite.txt @@ -4,12 +4,11 @@ { "Version" { - "Latest" "1.0.6" + "Latest" "1.0.7" } - "Notes" "Convert to use CommandListeners for chat!" - "Notes" "Add extra checks for replicating convars!" - "Notes" "Optimize DJ chat checks (take less cycles)." + "Notes" "Added automated CVar updating through AutoExecConfig include!" + "Notes" "Fix using incorrect request client checking. Messages should now show up!" } "Files" From 1eaa327d2228c7a71914330b5e41f8344fba2e40 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 14:08:42 -0800 Subject: [PATCH 12/29] MathType First Version with math.js --- plugins/ngs_mathtype.smx | Bin 0 -> 24387 bytes scripting/ngs_mathtype.sp | 113 ++++++++++++++++++++++++++++++++++++++ updater/ngs_mathtype.txt | 19 +++++++ 3 files changed, 132 insertions(+) create mode 100644 plugins/ngs_mathtype.smx create mode 100644 scripting/ngs_mathtype.sp create mode 100644 updater/ngs_mathtype.txt diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx new file mode 100644 index 0000000000000000000000000000000000000000..2cee3b88738596ddeba873bab66623d67c86949b GIT binary patch literal 24387 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 BPPhO7 literal 0 HcmV?d00001 diff --git a/scripting/ngs_mathtype.sp b/scripting/ngs_mathtype.sp new file mode 100644 index 0000000..a26e470 --- /dev/null +++ b/scripting/ngs_mathtype.sp @@ -0,0 +1,113 @@ +/** +* TheXeon +* ngs_mathtype.sp +* +* Files: +* addons/sourcemod/plugins/ngs_mathtype.smx +* +* Dependencies: +* SteamWorks.inc, multicolors.inc, ngsutils.inc, ngsupdater.inc +*/ +#pragma newdecls required +#pragma semicolon 1 + +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 + +// #define DEBUG + +#tryinclude +#tryinclude +#tryinclude +#tryinclude + +#define MATHJSURL "http://api.mathjs.org/v4/" + +public Plugin myinfo = { + name = "[NGS] Math Type", + author = "TheXeon", + description = "Process math equations through math.js", + version = "1.0.0", + url = "https://www.neogenesisnetwork.net" +} + +ConVar digitsPrecision; +int cooldownNum; + +public void OnPluginStart() { + AutoExecConfig_SetCreateDirectory(true); + AutoExecConfig_SetCreateFile(true); + bool appended; + Timber.plantToFile(appended); + digitsPrecision = AutoExecConfig_CreateConVarCheckAppend(appended, "mathtype_precision", "-1", "How many digits precision should be returned by math.js.\n-1 to disable, otherwise number precision"); + AutoExecConfig_ExecAndClean(appended); + + cooldownNum = GetTime(); + + AddCommandListener(OnClientSayMessage, "say"); + AddCommandListener(OnClientSayMessage, "say_team"); +} + +public Action OnClientSayMessage(int client, const char[] command, int argc) { + if (!IsValidClient(client)) return Plugin_Continue; + + // Might cause lag, unsure + char buffer[MAX_BUFFER_LENGTH]; + GetCmdArgString(buffer, sizeof(buffer)); + StripQuotes(buffer); + TrimString(buffer); + + if (buffer[0] == '=') { + int cooldownAmt = GetTime() - cooldownNum; + if (cooldownAmt < 10) { + buffer[0] = ' '; + CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Sorry! We can't process this right now, please wait {LIGHTGREEN}%d{DEFAULT} more seconds and for the previous request to process. For reference, you asked{YELLOW}%s{DEFAULT}.", 10 - cooldownAmt, buffer); + return Plugin_Continue; + } + + SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodGET, MATHJSURL); + mathRequest.SetParam("expr", buffer); + + char precision[24]; + digitsPrecision.GetString(precision, sizeof(precision)); + + if (digitsPrecision.IntValue >= 0) { + mathRequest.SetParam("precision", precision); + } + + mathRequest.SetContextValue(GetClientUserId(client)); + mathRequest.SetCallbacks(OnMathJSReceived); + mathRequest.Send(); + Timber.d("Sending math.js HTTP request for %L", client); + return Plugin_Handled; + } + return Plugin_Continue; +} + +public void OnMathJSReceived(SWHTTPRequest hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, any userid) { + cooldownNum = GetTime(); + + int client = 0; + if (userid != 0) + { + client = GetClientOfUserId(userid); + } + + if(eStatusCode != k_EHTTPStatusCode200OK || !bRequestSuccessful) { + if (client != 0) { + CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Could not complete request, sorry!"); + } + + Timber.e("Math.js request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); + delete hRequest; + return; + } + + char[] buffer = new char[hRequest.ResponseSize + 1]; + hRequest.GetBodyData(buffer, hRequest.ResponseSize); + delete hRequest; + + if (client != 0) { + CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Answer is: %s", buffer); + } +} \ No newline at end of file diff --git a/updater/ngs_mathtype.txt b/updater/ngs_mathtype.txt new file mode 100644 index 0000000..8ff70f3 --- /dev/null +++ b/updater/ngs_mathtype.txt @@ -0,0 +1,19 @@ +"Updater" +{ + "Information" + { + "Version" + { + "Latest" "1.0.0" + } + + "Notes" "First push! Implements =equation handling and cooldown." + } + + "Files" + { + "Plugin" "Path_SM/plugins/ngs_mathtype.smx" + + "Source" "Path_SM/scripting/ngs_mathtype.sp" + } +} \ No newline at end of file From e2d4c4aad01f8328a6582852cf551115b47e8fd2 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 14:25:59 -0800 Subject: [PATCH 13/29] Log properly --- plugins/ngs_mathtype.smx | Bin 24387 -> 24394 bytes scripting/include/timber.inc | 12 +++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx index 2cee3b88738596ddeba873bab66623d67c86949b..a73bc9d06d2cbf4f4b1031c237ae1f3c98414c69 100644 GIT binary patch delta 24121 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 delta 24073 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 diff --git a/scripting/include/timber.inc b/scripting/include/timber.inc index 821d4a4..58bddca 100644 --- a/scripting/include/timber.inc +++ b/scripting/include/timber.inc @@ -5,6 +5,8 @@ // Name from the wonderful Timber library by JakeWharton +#tryinclude + enum TimberLogLevel { Log_Error = 0, Log_Warning, @@ -53,7 +55,7 @@ methodmap Timber { char logLine[8192]; VFormat(logLine, sizeof(logLine), log, 2); - this.log(Log_Verbose, log); + this.log(Log_Verbose, logLine); } } @@ -63,7 +65,7 @@ methodmap Timber { char logLine[8192]; VFormat(logLine, sizeof(logLine), log, 2); - Timber.log(Log_Debug, log); + Timber.log(Log_Debug, logLine); } } @@ -73,7 +75,7 @@ methodmap Timber { char logLine[8192]; VFormat(logLine, sizeof(logLine), log, 2); - Timber.log(Log_Error, log); + Timber.log(Log_Error, logLine); } } @@ -83,7 +85,7 @@ methodmap Timber { char logLine[8192]; VFormat(logLine, sizeof(logLine), log, 2); - Timber.log(Log_Warning, log); + Timber.log(Log_Warning, logLine); } } @@ -93,7 +95,7 @@ methodmap Timber { char logLine[8192]; VFormat(logLine, sizeof(logLine), log, 2); - Timber.log(Log_Verbose, log); + Timber.log(Log_Verbose, logLine); } } From dcfac8ad5015818feac94305f5eebdfc67730597 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 14:51:28 -0800 Subject: [PATCH 14/29] Properly log to file if needed --- plugins/ngs_mathtype.smx | Bin 24394 -> 24401 bytes scripting/include/timber.inc | 2 ++ scripting/ngs_mathtype.sp | 16 ++++++---------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx index a73bc9d06d2cbf4f4b1031c237ae1f3c98414c69..e088a87622f66b70ead19d39975f735d8015458a 100644 GIT binary patch literal 24401 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 diff --git a/scripting/include/timber.inc b/scripting/include/timber.inc index 58bddca..d536918 100644 --- a/scripting/include/timber.inc +++ b/scripting/include/timber.inc @@ -103,6 +103,7 @@ methodmap Timber { char pluginName[128], cvarName[256]; GetPluginFilename(null, pluginName, sizeof(pluginName)); + ReplaceString(pluginName, sizeof(pluginName), ".smx", ""); Format(cvarName, sizeof(cvarName), "%s_log_level", pluginName); #if defined _autoexecconfig_included timber__cvarLogThroughTimber = AutoExecConfig_CreateConVarCheckAppend(appended, cvarName, "0", "-1: None\n0: Errors\n1: Warnings\n2: Info\n3: Debug\n4: Verbose"); @@ -115,6 +116,7 @@ methodmap Timber { char pluginName[128], cvarName[256]; GetPluginFilename(null, pluginName, sizeof(pluginName)); + ReplaceString(pluginName, sizeof(pluginName), ".smx", ""); Format(cvarName, sizeof(cvarName), "%s_log_file", pluginName); #if defined _autoexecconfig_included timber__cvarLogToFile = AutoExecConfig_CreateConVarCheckAppend(appended, cvarName, "0", "0: Don't log to file.\n1: Log to file."); diff --git a/scripting/ngs_mathtype.sp b/scripting/ngs_mathtype.sp index a26e470..c07ee8a 100644 --- a/scripting/ngs_mathtype.sp +++ b/scripting/ngs_mathtype.sp @@ -92,22 +92,18 @@ public void OnMathJSReceived(SWHTTPRequest hRequest, bool bFailure, bool bReques { client = GetClientOfUserId(userid); } + + char[] buffer = new char[hRequest.ResponseSize + 1]; + hRequest.GetBodyData(buffer, hRequest.ResponseSize); + delete hRequest; if(eStatusCode != k_EHTTPStatusCode200OK || !bRequestSuccessful) { if (client != 0) { CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Could not complete request, sorry!"); } - Timber.e("Math.js request failed for userid %d! Status code is %d, success was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false"); - delete hRequest; - return; - } - - char[] buffer = new char[hRequest.ResponseSize + 1]; - hRequest.GetBodyData(buffer, hRequest.ResponseSize); - delete hRequest; - - if (client != 0) { + Timber.e("Math.js request failed for userid %d! Status code is %d, success was %s, response was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false", buffer); + } else if (client != 0) { CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Answer is: %s", buffer); } } \ No newline at end of file From e925f9729e4bfeecc0a0776a59a9851e296ed60f Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 15:03:52 -0800 Subject: [PATCH 15/29] Fix file logging --- plugins/ngs_mathtype.smx | Bin 24401 -> 24451 bytes scripting/include/timber.inc | 1 + scripting/ngs_mathtype.sp | 2 ++ 3 files changed, 3 insertions(+) diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx index e088a87622f66b70ead19d39975f735d8015458a..326cdcc0a66005a138a8ac27bbdfc19d19d44334 100644 GIT binary patch delta 24190 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

LR9F+ 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 diff --git a/scripting/include/timber.inc b/scripting/include/timber.inc index d536918..c1a3f18 100644 --- a/scripting/include/timber.inc +++ b/scripting/include/timber.inc @@ -36,6 +36,7 @@ methodmap Timber char pluginName[128]; GetPluginFilename(null, pluginName, sizeof(pluginName)); + ReplaceString(pluginName, sizeof(pluginName), ".smx", ""); char logPrefixes[][] = {"[ERROR]", "[WARNING]", "[INFO]", "[DEBUG]", "[VERBOSE]"}; if (timber__cvarLogToFile != null && timber__cvarLogToFile.BoolValue) { diff --git a/scripting/ngs_mathtype.sp b/scripting/ngs_mathtype.sp index c07ee8a..bbd3dc9 100644 --- a/scripting/ngs_mathtype.sp +++ b/scripting/ngs_mathtype.sp @@ -65,6 +65,8 @@ public Action OnClientSayMessage(int client, const char[] command, int argc) { return Plugin_Continue; } + Timber.d("Received %s from user %L.", buffer, client); + SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodGET, MATHJSURL); mathRequest.SetParam("expr", buffer); From ad98282c469146d44dc86100ded3ce422bdc15a0 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 15:44:43 -0800 Subject: [PATCH 16/29] Encode Url and trim equals --- plugins/ngs_mathtype.smx | Bin 24451 -> 24972 bytes scripting/include/ngsutils.inc | 25 +++++++++++++++++++++++++ scripting/ngs_mathtype.sp | 10 ++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx index 326cdcc0a66005a138a8ac27bbdfc19d19d44334..a72dd09bd8f0dca9a617b96fe297c4cdcf100b8c 100644 GIT binary patch literal 24972 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%0AF6EPTz?%< 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�!6Qv~Ilg?iDho?buNIp2b^ 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 literal 24451 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 Jy^oh_{|6<(Z~y=R diff --git a/scripting/include/ngsutils.inc b/scripting/include/ngsutils.inc index ffdda2a..65aa1a4 100644 --- a/scripting/include/ngsutils.inc +++ b/scripting/include/ngsutils.inc @@ -1243,3 +1243,28 @@ stock ConVar AutoExecConfig_ExecAndClean(bool appended, bool exec=true) } } #endif + +/** + * Encodes a URL or parameter to HTML5 encoding. + * + * @param buffer Buffer to store encoding in. + * @param buffersize Size of buffer. + * @param encodestr String to percent-encode. + * @noreturn + */ +stock ConVar EncodeURL(char[] buffer, int buffersize, char[] encodestr) { + int len = strlen(encodestr); + for (int i = 0; i < len; i++) { + if (IsCharAlpha(encodestr[i]) || IsCharNumeric(encodestr[i])) { + StrCat(buffer, buffersize, encodestr[i]); + } else if (encodestr[i] == ' ') { + char hex[8]; + Format(hex, sizeof(hex), "%20"); + StrCat(buffer, buffersize, hex); + } else { + char hex[8]; + Format(hex, sizeof(hex), "%02x", encodestr[i]); + StrCat(buffer, buffersize, hex); + } + } +} diff --git a/scripting/ngs_mathtype.sp b/scripting/ngs_mathtype.sp index bbd3dc9..9603180 100644 --- a/scripting/ngs_mathtype.sp +++ b/scripting/ngs_mathtype.sp @@ -65,10 +65,16 @@ public Action OnClientSayMessage(int client, const char[] command, int argc) { return Plugin_Continue; } + buffer[0] = ' '; // replace equal sign + TrimString(buffer); + Timber.d("Received %s from user %L.", buffer, client); - SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodGET, MATHJSURL); - mathRequest.SetParam("expr", buffer); + char encodeBuffer[MAX_BUFFER_LENGTH * 3 + 1]; + EncodeURL(encodeBuffer, sizeof(encodeBuffer), buffer); + + SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodPOST, MATHJSURL); + mathRequest.SetParam("expr", encodeBuffer); char precision[24]; digitsPrecision.GetString(precision, sizeof(precision)); From b0ad41ea94f83e2f62a7ecb4d79649e8279390af Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 16:32:13 -0800 Subject: [PATCH 17/29] Switch to Post method for encoding --- plugins/ngs_mathtype.smx | Bin 24972 -> 35351 bytes scripting/ngs_mathtype.sp | 42 +++++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx index a72dd09bd8f0dca9a617b96fe297c4cdcf100b8c..c657680649b98bfe4ee72fd05dd3dbb5b7321eb6 100644 GIT binary patch literal 35351 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 literal 24972 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%0AF6EPTz?%< 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�!6Qv~Ilg?iDho?buNIp2b^ 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 diff --git a/scripting/ngs_mathtype.sp b/scripting/ngs_mathtype.sp index 9603180..e09db0d 100644 --- a/scripting/ngs_mathtype.sp +++ b/scripting/ngs_mathtype.sp @@ -16,10 +16,11 @@ // #define DEBUG -#tryinclude -#tryinclude -#tryinclude -#tryinclude +#include +#include +#include +#include +#include #define MATHJSURL "http://api.mathjs.org/v4/" @@ -70,19 +71,19 @@ public Action OnClientSayMessage(int client, const char[] command, int argc) { Timber.d("Received %s from user %L.", buffer, client); - char encodeBuffer[MAX_BUFFER_LENGTH * 3 + 1]; - EncodeURL(encodeBuffer, sizeof(encodeBuffer), buffer); - - SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodPOST, MATHJSURL); - mathRequest.SetParam("expr", encodeBuffer); - - char precision[24]; - digitsPrecision.GetString(precision, sizeof(precision)); + JSON_Object obj = new JSON_Object(); + obj.SetString("expr", buffer); if (digitsPrecision.IntValue >= 0) { - mathRequest.SetParam("precision", precision); + obj.SetInt("precision", digitsPrecision.IntValue); } + char jsonEncode[MAX_BUFFER_LENGTH * 3 + 1]; + obj.Encode(jsonEncode, sizeof(jsonEncode)); + delete obj; + + SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodPOST, MATHJSURL); + mathRequest.SetRawPostBody("application/json", jsonEncode, sizeof(jsonEncode)); mathRequest.SetContextValue(GetClientUserId(client)); mathRequest.SetCallbacks(OnMathJSReceived); mathRequest.Send(); @@ -104,14 +105,23 @@ public void OnMathJSReceived(SWHTTPRequest hRequest, bool bFailure, bool bReques char[] buffer = new char[hRequest.ResponseSize + 1]; hRequest.GetBodyData(buffer, hRequest.ResponseSize); delete hRequest; + + JSON_Object obj = new JSON_Object(); + obj.Decode(buffer); - if(eStatusCode != k_EHTTPStatusCode200OK || !bRequestSuccessful) { + if(eStatusCode != k_EHTTPStatusCode200OK || !bRequestSuccessful || obj.GetKeyType("error") != Type_Null) { if (client != 0) { CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Could not complete request, sorry!"); } - Timber.e("Math.js request failed for userid %d! Status code is %d, success was %s, response was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false", buffer); + char error[MAX_BUFFER_LENGTH]; + obj.GetString("error", error, sizeof(error)); + Timber.e("Math.js request failed for userid %d! Status code is %d, success was %s, error response was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false", error); } else if (client != 0) { - CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Answer is: %s", buffer); + char answer[MAX_BUFFER_LENGTH]; + obj.GetString("answer", answer, sizeof(answer)); + CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Answer is: %s", answer); } + obj.Cleanup(); + delete obj; } \ No newline at end of file From 77ea75b58269daf1c4c9d6e7b7baad415df76532 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 16:33:29 -0800 Subject: [PATCH 18/29] Clean up json obj --- plugins/ngs_mathtype.smx | Bin 35351 -> 35360 bytes scripting/ngs_mathtype.sp | 1 + 2 files changed, 1 insertion(+) diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx index c657680649b98bfe4ee72fd05dd3dbb5b7321eb6..565765ca46ac19d390ed5a9a8822460785f4a9bb 100644 GIT binary patch delta 24203 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 Ndx75t{$H{S9ijQ?gkt~z delta 24157 zcmXVWWmFtX*DkKX-QC^Y-4dMO76@*^Wg2%05-hj}4ess`90CU$T!Rm8ciy|cAG_+Q zUE51~R!xRFkGAN1JlI_ z1M}g3{6`oVX#^M;0w{KUg@Mt8_LNZSh2nUqE)x{1y~Ds*QNX}(LU9c_EKC8k7lD!n z1uRUcI1G#;6wesKa>59+!N6!i2gnhyFmISJFlJDUm<9`j4YlG3#RQ#D4DG$3#86lR z3p>|X3){#5q#qWT@g)LvO&^eAct5k7_|KF@hkngu}UWf&}6-FZ*9HNh)#DeEGuZg(>gBz zdMk+++N9~$&~tLqF|iWAO#F=#0JeLs*L(Elc`^ijeRv(}emTe*2}=C7WcB_=p%AIM z`tn>KnxE$r|ML4b=G3EM<2LIo4$N~P)jT2`c}(=K>GS4<;}R_n)+zo6-)p^!T+6db z7y0A?_?AsqEix_HE}p3_?uw~*)U=ozthMmQ2^`|p9gFWr`?eVV%U=z03^Y%83lgZh zxMM(Py1+kfd^mXekM!#)?8g(kx-FTqCC8IaOm@YJ$k91y>>w|ZzQ`Nu=y9gwHg2Y2W0(ybsoq2`>J{IJOUcK3y3aqJt6Q~ z6Hq(cmyu!X1uAL*+U}0JS-OXq8QdHAtAH7H)<&fW^>6aIV>zYEdRrJT~W-ogkT57~~Z{4H)1?#+HSa}Skv_o|Utd&+hgQ!zNX^bf$f%D7wN z04PJo!lTCG<+EZwG+V=Q2UDhd`)eQN(mH_#j*);#TCMd}E3W|#ynuh#;8^KEzdj<@ zSft9`ts!h58;8 zXWa~x-!CRlg0vpZOsQf=}$5)0LN@n{y;zG9i8LK-8l>2sJBjWa;y@V^ENhLbCgh1mLk+ zh>n@(vlwc@p}R}SWY)3{q{oD3l(*`WKPJ6l+Ap-|$i#IsT#dOJ3IBlJBx?YqQabiV za60x91pWP;;NMPQH&O7S?`fQ*wCswZ<7qO8FR^@6a@rBe@>FY8IZd{^c-uoQ6H?hi z)59B|Rpw(AvZ+#dWV-D7)Xk0?3&;cMTPr;5&74;SXlG=|pFwQgFVjyodYNUAF$Y_(QBR zn*(47T@`Qd-2WH}J8khnHzSPUVV0zdQy6G|lQtcq`n>lmY!jF=Ai|QD*j8T03-{dV zKkE+$@5cGju1O-D9K^^=oo5{jMIclBhZzFjR|UqqRFEUhO6HthM{$RpnwE}Z z8gU$Mj;X_R&{^4COJuiLmwzqXsgC21c-cPP!S*AMNMX-MZJI4Xl*^3tT35NY_?vO! z+qVou7n{p-+YP|r770XF&o)jM~Wj#;Dywe8g%x(yW;ywJo%N zDK`9ok?>>Nv_})WgcwbBJiwPwoG;9YH;R$d>|$3)d_I@WB)8y#fYuPD;+7OXg6F{-a(cW4iEp zhF=TPD149zHMkYJR}v|zlt+E!4y#L`Cxd<5 zu&w*0$?ta6Yd_D%k!`uQs%N2*w@ZRJvi}zoehj~Vivpb({5BjCNj17tvG+PrXuJ%6 zj~j(8_B!BuSzFe3{zOeR!Us0hkUSQAkamQPq* zqSJv1ub0lgtYa)MA;0u!%F+KD1uwo8cCrzpA{L}kyLQgC*cjv4U7jl=+_p|1Vhthk z2r^yS6`+zWc08ddPmc1TaM5gf4PSP{;!?M=r~|vEnXT6{tZmz8g=6Q^X|zM&dJDVq z%r(WIq=nPF0sJd4OL0rh58PsZF5=G99*2Dhz&NNfjfDGt`@Mw?_Mo}oCrXsK``p`} zT$!s)7*evt=Z64#{B;8C@E4y&B1Oyj0E(tX2xWvx5!vnlJv-s$IQ@~(gyI*YXAa)- z7XWh%%&pd2#ey5J;%~_KCS6d^LwvwHaKAE5NLeMd(r3NPIkc1X;G^7*lpREqws&X2 z|C@t!Zy(DeN|yS^DrF3kmHWi`o!#DU=INP+*KK_P*1D$h1SvRqnWD!+xP=2Z0S0N_ zK^Adciz;R~BGQV4y4#4bf&2@J^0r$m1Aq-DU~wyHXF&7zq%1tUgLTPJ_@tcENQNK~ zJ7VtwPau4RuGH?b^^7^D>}Eh8i!<5q;nCajX7Z5wn&KgP=?2_6$oq=jRA`Cqh7LsS zgjsF$NDNGJ;IC_OdFA$^510CAi@w$JuoBO?Ss8U9FZ!tG^u`VBUC4$UnHo?(0UT&X z&oyk{pTr7Y6OrMH_8wf5n>ByS49#KB?qYp2IFW2(!AX;r>!WgV&@?8A(dvS5I)=V% ztl&F;U}+Mi+iBIu8@f>Z=VN1rve29lO1-m=5kh#iEd9LYBWy+#(URRey2CMtQpbmp z+#zbtJ~mlj$Y4fQO}Byi?ENT72+$}*_|(Q(@;F9nhyUg2^X>i`ZvrevIUY5fr>b=@ ziMT>S2w6I&0d&x%Y0cz=@gWi*^kfwHJzvom>*3^t%<^BbFZJrsvxL?%nOxJsJn?^L z8Mj8Nq9?^(((yPeuE}TK{PR1hKZFi$p5Yk?E>JN z9$zT@>Hb+4By2_qs8yD%w){HFUM(9Q(B)d3*Vo10ROxfC(3`!T&+Mi|!zYecA`Nt} z*sUc0IneO6|DO6{Eqg$to)HDDTY{_Cw17-FBiZ@z{0W9Ca4a#cvmWUvm?Tvo!(_s| zbcJb!_KuWCCn1w-{e8g89Zi#u-qyKc?7Cit$oU-f z#ivU$R!lPCHlcOIl@mfpFwIqz+RvK=JKLzm2Z8_ad<+gYM*DFVhTq_vswG4Zi<0Us z#0eL0lv*Yv1t*4*dMHEljkSl7^AcB7!9UL<1;umEySYA=^VO2gANTwbFg^CX|5Ls&p8k~O z*+BJbE4o2+opkJZuupXC>AjolDcYMO8h_3;MxuCVh!#0#_=98cNIkVvm=xt=v=@sL zbRU$uA@rUJ+f@>zbO;< zq)9{Sk=L?#t$0)98ChS|?O);Lq-SVcaD-5P3)}-Wz-v2h(P5ic*DhrajqvT5)JO|U+pinsQELlzg?is}ExC5|OtzYg9=%9RJ5kKAj74?-!{CUd{H;?YJ>%$Dz)}x5H>%dL^WtR})bB%4b$M8z_ z?T;VLO9H1Bw(=Kb6B$d@rlSsymh*a5#3I;z92vuG`9EW*){9^_$>f?nN(`$KQpt=$ zxz8*Szjc3$>q2bRt25QKa=fsOc_Y7|Yt$Q5)z9Q!aMWKeS(|gu(B8X4SX3Z1 zr~H@3nMb2Fi)aUg{)YtF-K=&4hqtQMl>eMEFGWqsR(x=BS*< zw8_HK3dElnOPC#QN;wk3de0L9u%V;mKbocDr}ry#b5mi2;WpPWK_(cmGBGJyL&0R;lDl2cXx$&7G;WDBT zuA(}c^hPh#sN2c!cNP=oe0Hnb`M^NvkNOj3ohDArqgzh-4-g9xfU}YVeS3!-xeIZ` zYr}{c!jO=lsa-&)Q7Bvv*Z;FZ^RdXTtuu$W`FF*NqnZw3yvK7DA$<;(gDovRs}a0n z3NE{tIX|bTjWe-!a84+07F_y`fMhaq0rSTKYJGVQ*6cXFa3VKnzZI%A;-R-1yYtYZ z@GfhXaZODZ)R&tUK&Hf47w$N8MYF%n?{R{g9**+nFx1yEv<-8B$PBi>R+k#|VhUGE z53<(Pj8fZk)ns&%j*C4c@Wc45Ay02&@G z)aO+jBrpP*7ZHC;q^p&RCU9P#ynbv686f>a50`Cjf-@!yOGkT+)s?D%n}_#T9<~;{ z~#4<946kmn#OPFfGArB$rBd8n@0;lO;!CEHhK_^ zg@zZ_UcM?n6tJpUfW^uR+iAb?`d*GTNGQ>z9Mo^Zg3-r(h8QvIFQYl3`Qoo!Uw~mz zPg1>)_Pb!LD!{GSawt|kvxGy-jYMYLgr;I;+M+mQ2@%~!1|{ym$YoA_TlM#bkguvG zJ3Bk?qgxC+dzw}HZ|undzk^I=LG(io?nKlypG$!xEr2z!Uaw*ZohTDYg3Ve@6KS!K zlRv2~T|lAO<0G{)VRqyh|K35~q{F1o_QA7*Ih`vyNnJwGNc6Wf$H7@-t*ID2+0w9S zJLgPNxFdxxpE?CiNY)8&6^zp#Vq{-RQpr%ZLcz{U9;kRQv8nSl+iMKXWVA9;sRa7k zm*SRMnSjIuZRg<1htH35uD!gs19?^&Q<2RHZF{J%0t8ys)62x)ZKev#e&fim)%d3D z2V~+X`qW+xhg31}aNJ>p*trFuQyTpcBgZy1m7_Bz86*sp;P=%Em*w`t&GqrJW@bJl zQI78n?ZP4$)M{?EvLdD)Q@MTc^%-v=u8RM6sQ?tN*;||zlwZo}P{#JzSu(Vo&?1yC zfwap0@(W1Uo)U)$;E)?l`jD#W3{ELY?ZL(lVi8<@RFBgCEKAG7@MUG0xGHJLOPRJZ zg;bk&v=FgioVj7z=O9gU#a;f#H>9Fxt ze@y%gs~6_a;7-}5W0FKV_@G-vQZM)-okJ$%4!7lS=ABE4RpstcnY`3>Sai=&IO0#m zhQ3vchV?s9Y0z9DQf9~>lp%;H_r_}HS^sg?uC|K=T#7$Ac;yvxCXnpW9^S;;vfc{t zQIGhVAntI}^fAUU;;6O7a64EN9EpFtpeETb_x{_Ey_OlncPo0>7Q)pSTaIu#Cyj^R zcVf|VBo(e}bAuUfHOsU!*BtGGN1M(N7#A&+!ckD}ujnv~Oa7z1zn8v4&R(6=)it(H zIYegdFSUinp;qoM?b(awHAL-6-{nML?P+qqrDwH=mmlqW=R@F@66PvQU)5F#Yj|@! zN8u&gBW$xT`a*|NwQelTZL#K30Rb!v)|`rNAq#n(XGPvi#1o@aWu_f(I=qH-i>b+# zFbx0;TQl+lX^}k9;f9r+behzGT#&UutqW3uCe2sU%@>by64MLIFS)nY|2Gs+ln(=` zs=R$(M$oFkkNVO!6KhxU3rBtuK1D5JoNsu}rl;dcnjn!>|7>87+az9QcgBmV;kT|j z>ts4-gs6r(dxRhxu0ne{2S*&zT$=H`o;B6C02_^OZP_h^!*%;T7AP}#SA+{nr8+J6 z=;2(Qv;@qS#Nov;xYUy0=V1N-U_mPN1a8$_cHD%zgdG`-z+I9dqQ$~?n^nicw~mtP zNUW#Nwx+?BNAF-uMzlIk#h zHW+x!%v1EY$nT-(0`fXGWi@m{gP5duTBV0A&P!LC}!&+Lo>4)x`XS=%Xo+jKOCWw zi7=xeZIBYKqKx_GV3L_>qWK{PpD>{GLv@x3cU|V;+NswxeJZ&kIw00Mo2YV*I=$`} zp`h-R_w6((KZYx9N|~lAPDy)g!fKCtRRZLTZ75bvs;-X){>Z=~DAgK68`15MQgw2l-S3J!x+d?hqfJkRtOTSIVjv0U(0+RSa_#0k zfF<`&HQ7UNPJ)HkCdO(aU!7-ypm&XgRE`FeOS|8(qTwHR^wS8$O8~)QNjdZkvHAym ze`^xkkE@rpJ>3U z1t62$#6sWV1^^b{wJva!*cjr^UZ`VeJH1VVP{Fr8LB(euY zGR8{WOir975*r<9@>*suUfPwCoq6FH{V+S7z z0?)oE56-~%xWbjb&s+Rb`|rOm9Fa#n92gnWJb4C4WT&4-<;VV`N4qNS=e@JW8(aM_ zrxUinjF-fGbZYdE0&aNaeRv3V$F3$40__Hl#(`6xHmNnVv87w;|{M# z{IB(`RTD^e$%?9maLdb7vTr>75;e+XeU89I z2D>5!`=$wpzjTWesm*9!dcIuCiPOLI*g{i~d+;i&JbT9Urq5t!;UPMwY0x{?oc%*X z->Iw5pIXgPKbj*hf0s$$FTNc`Q%go`TuUBeHSsN~qJ6dI(K7l`jy@K}$b+`SE;>F4 zIAw1*m51mj2pY>|U?nrG^Tj!};+Qg6ReUYS_sk_6bVuB%DD{32ZFo}jj8j~zEqJ5x zU=LGHk`9w=!Znyh(jdiEupiQx*OXhA2w&|rt$y`y5K?N=V~bJ^u@b+>;<;PSxPf5j z&ugELFUX18sd(!+yE!P2t4@9SP8CI1rD}%*6xzSq;$h zfNDRIwuGI!@Z}$o?ScxTe7WP5Co29f^dY=Z8a_sJ^}&(=(Q_VluH8sH4l(wMoqM?P zGpf5z_TM<7Srt@ywPs&Y1Snf*c%d-7O=Bpv-{jj-31X3Bvu`GJ)83Z(X5#K(av;z; z(+(+V(3DW+*OiX1J>m580Tj{a%BhWHG1ola+3se=PXbx|^XB;FNZg1_@%$pGY4| z{<=DpOu8dPs-%Q=yoc!lNslSUgl?fX9W_IR_X_utq99Tw)~ApW9NMo4qP`X63YE-x z-)R1)nLy⩔L#-pzGo3LYXTeo5+YM;NhwGaFx{pbvsR3IVFtG4^*h@D4<78_~P_` z`xux`w=>0E0JJ)gtKf^U3b~g=e*WdYm;I@{{ClwgV`Apz?k*CC4Z&;lNOG*plCbvN z8L3kAmI{ZwPpq#G*=*)WvV3weA)b;$bO3)MA<@Dk*WQsNo{||fV9Hr-{kc!}St@qLduVfIeEpB)+~-AqqfYBaOzmuVs>3|>V0n176`B;w#?Oyn1;lBh z!3Uj!fQ4hnoZD(L-&F%fh+u9H2^y}>tkV3kV^c8m5niy_-Vr6@aH@|4xwEdOc%#Cu zd2eV>+Q;1{eEpIFDdqBdMb=3|W)EM{4PoGZFlB{HHb*6+lvS&THQ9w-Phf~FbJF0q z`ZO5H2+`9EM*9$B{B?)k=juwoQ5SxTDuCRJ3g={l)OD- zLFAK@6cWa6mRzsUTwS@zJz3ea`(q9}om9N@9=FJdlfkU}V9A#|bo{TwsZryiE#^RB zuAus~1;fN>@nA_8XHN{Ta7$u+g9925@{9kb{8XjZtb#A;wT5I>h_C~K|0(xQMP4(U zzkY!l_p&Q3mmXS2AaM}B;155<*!8-lw(^ug@;p46%Bb-MMTD6#tId3pvh>?g0qCj| z&}7MwU!g(#aFTF>w3H9YdY+ze9y^)GT5x&i-dEX+3Xu&tjKUh9153Xd%yKpOVU~dfp)8kcFakT3^LX~PQ!^?pJLY-bdo4GF?Y0# zsqTA_RTqpURLiO+wfVebxQfNy^1w(;vLRD1A!u^96GT zHOmF(PcoZOZC#uQ@)I^yKssxe=DDlG$Y9d@CC<%7K`VdgHXb7XXtFsJLb^k6DJJ`@ zN`*L8ffvMCkQ)q2d4!dq1!i@EDfb`8@t8;6@Hp_pA%5; z{L7FiB-dZn^+QIspS}#2T}RmAOcEO8esF(9PvKqIB+*0{GBaqy#-PPmv2cw7$j}x$W2mt#%G!|JRl@)?7#eqzPO|%1U9{i7w}( z*Mt{+G4d1lofiI~c2=@;AAP`d;Cw%C@2~#ehhiF+}ql<5*RJDN2cCnLdo4qA&og)RYMRRFRl5Gg8$8l8{+`=lbGKY-v|H>gKX;Xb4F!{8QfFG@>I3c;ED^^H6vq5J= zCCv+7tBvxNPHm5stR6Q}kSc~YR105fi_WtDFihMFs`DDW_PC_9pWHVb5c&VSADI~t zKM>hD4`(dJ&ajxF*|-?(pmG(OVFvXs@?W9cpXvfHpqfY1y_!p!?a?(ncI!k+-B~G^ z)yX+Q#2}v%_D)hn4HAaQ+M7wwI25X-_!Ju=T;_u>|CkNE`A22ZSPr8w5 zwF4kry4@uyg<;T6zT{!aQ9M<=BY)wQHk)ed;0`YDKNS{%gp{C!L@rNS~NZ+Y&HfClH0@2qGR3Fq*dc2;1-u#adH{1o4_X<3IA(Kymm0>QAdQ+brq51t29Zdt^iz7 zru{>JAQ#*8Ru|PJq&sS{#Oe>=3yDcPB%76TY?t3_l1A=~xeJD+*e|;h{Ih0m>vZZaJKACY19_|$y$MX< zI2?KhBL?Rw0H(vgNE8_z)ebQKI|q=rnt=Z+Drj79>Pem8MU3TbPsU=MZ>o1&_JLr3 zTTdbSb43_3z2K`gXS|L-Xr%ux(V-MG^RfZiD4@ytSoFi?1WV_G-H)G7a&%{kt&5BV z8~@VN;aNMTI5?2$CzhAiPfn8OxXuL=avx`aES7cH zsSAXA;}^P$hq@H7jD}H~*#(wYFIN)J^y<|COVg)e@*Zx*H3@9y{N^N{I}?X!gOM?b z6;kP)@*#gyq#%YTynoRD63Nb@KTZ|68kaW+hFm{o^%IFBE%-G0H0}cL)ltmT1$7mC z`tP4aJDBBab8;jUgxoB}C;9d!P_LSm9xS7mNK&|BXw6S~;{$)uNT$eu`y)tiL>E{2 z(jq^pg}qEn&l>p8xkjCjE)TZ8As9vGYddX!X#Waa3&`@k+C{qCw%-d#$g3eOy~~Iz zDZn{T6+8j0utD5%cZ>k*Q~L+QFg*wxiAS!gLT|DRol{Uw0{YicUORFnz`ZNTew@mHqB7@Yp>oYv74Q%Am(Ggnn+%h|ECBr?c;a;iZwUd7`_x|+ZuYb z+%Q&V8*NJvcI49-O)J-^Ap`kp_{F@;ILkd~hW3=Q?7u^5QQw^3zvtQWuqlKR*?Tf= zLxxYUg=3vFY;hv(hJ{rPTfJqPymNkIEml8ZJCib1AM+cF$loX6d4sZ@sfx@gl>}ot z1&rn7p$O2n$+n?%Egy+7HFL%yntLZ_x{GNxwUB=v{Xb6imDRi9nyDf`(6zF^bmxY{ zLBZwS+HC45FO*1>PMEESP_%tDAS>HwEDh^xB0Ie;$WZ9{(i0yi_VjbsB#a&F1Epg*Uof?(ZBU<4*00pEwl1!YO3L zz}*wfKbV_Xj%EV+8f<%F59UtJ*k_YvxoP~)QiyYwc+4i*Es{xgcL+tw3*MaAxd4Wp z#CtmZ2(|I=VZ1NsF@+0Fw|-_)eO!Af0m3O^7hpYRSCnBvwW2~) z{yeq)^+|}2V?Du@NYu&wI4Um&d2;zxuW->wSCBtkLb%DQFUlO32J|yg=e>lZR>s+Y zY{7#AgYl0AZuYCh@N?$s1zOgm??9Y8-P2zLQlb+38+iEurrAI~jh`AGxw*{Vu+2f@ z@_dZ*lC%rnsD2!|%AJ+@v)*ct#MVVCF^k?*I2$}#{~{g4enf);i&kuwywz}moQhUt z7VjRhgWPF?J`RyH`6Y=a^1(G-N9*J;v$T(Ni;*$Q_Q9B7p#hka5{`w`K z^rW3T2NaXG&s02>&WZmXQO?>h9= zR=R+J415teUvdyFFhy<3M}Vw77t4+%atFv?#hw7S6?vivL~IxNj)yn&Gvpm zo%@w~oI~`g;4evMz6sADP**T(I^wu|@S(zqw=}0L*G-n6J4?H)*N+zKY8;YR zmW#e?oi^@?rXdvvL>{H4j-SwLH2#x@kfn}$E41p#Kpwu3GL+fhiACpSt8++adyinw zHKra{E5>^BhP9HV9(#^rpRpqsz4K*FhjE`lkX>oYqQ7yi`r*hkO{R*kq7us=ek{aO zVOf2o+jP|^yvIM=!zm&wo9zT0pv*n7?0os*Z57*!s54{_aGu34al2=a4IheMn-CS{ z=h9B2I~>A1vb&-Urx)e6>|E!{Ua+i+uyKM}AbCZ(zhxn#I(E8gMY)P{kOY<;$WLz& z#+;NoPI*OBqed5Ep6Y%|S+3ch^OGXc5cG#PY zKgX8h>{*M(dko?aIRx8_)AY||ox!vaW+KbRno=3xQr`4)M|Ja?kCXqZL(YJG@hpO>gb zw-XMvfW%Xat-RrO&bHpZE1I_6p$>%eUT#sESg`pK{JnWHK>YH8_K18>evNfrmkhXp zrQiC4@SqHFD8rRFSNeqm3VP|@x6H8RrolAtTRjmkVb4@!0PDCNTiZJ_R8)!t$USd}62ffMfG?4C? zo2{NGsDk8m(pO68)cc>K#UW&kEA%8MP65QD~DF&qtaW{oCW|l+Bc=})}I^m5+=qLA=%?a zah(KKR4#O-H%WR43xJ2#CIOnzBa|AUB|(Q~c}V>}`0E@JEJpMgRj5J(l@Nzkk9H40 z2oj=4;Cy#EN2zS2*z(@8H*xC?_rhJ5gDRW%H>S#e^+vO|}=kWa9X#laU zS6;IJm11>fivu~6%k3TSkred_&4r}x0-7xP8~QH%|CZqVI5v03r=HvmjK3ctR!aPC z_vE7TYB%9y#~)N~A=UOC7Qk7oB9)ZL*ex!R4Vl|7YfmFvxA~0K$1&)S$O)pZHEeU< zs_lD1a6vq|CHA-ye`T$n*{TH;MctOS`n*4w=YBE1?1UkvYNP7+M>w~w9<@Gx3ooh{ zCW1HX8@^yLrBu6N#ezJw7EGx!8V;m=(Ka?pR(b6Dt^)pgG+pA!71jy6hE6Q!G=yVI z7{n$d7T4pKk*{!lX{+V;_sg8~hpDZds60&DxqF*L+c_by8{#2e+gmoE;KThTsrZ?| zqc2FedPqE^N^*DT-n%~t$-uM!6*rM}1c%CW_n`>(l=9PKuW;T^Up^nf4XqG1c;?>W z|AuCMIqe*hx9KS(2mN=(thBu&;zB-31xMssE&SnJi3hy(*QyP5NGOpq`NBIVD@Ftl z)H@&%vzI3pvuB3Jx%s&sKs9;kyD3zG1X+q7CU|t9aDs%|zv3E=g@X2HTO-|v0;NW< z&dZbE$)D~n$H{w?|9lL2#*ak4H~fHgZtxvE4$;_ga_fx={8aY#+mrV;>bXqweNiyt zsXR`n0)W1)ex2L-wfHIRW9eJJ)Q=~`oH~o%tvk(L&6C2nzKg;;0LYJ8eYGBtI4iu9 za?Q58AGSZpwqJbPiAPx5NVH!(r_5J8JMTYUJkQJicy=~?yx3zqU2xa*1*y6Cc3^`q zY;~@dWHIq>s=#|ORqf2eg|j*ANBd%;-oCcjUzGDex83$dN(wk4sce7YjFa(SCi8XQ z+DpuT@sSw!^-`$$1L^`r>Oe`0TYfW4yJE<4bAt(++K z*MmQ2N|sE5oP@i53VVi`hPkdVyWQ97u58QWS^v}Ly1Y%n2q4!nb&DdL8`Qsn`-FN8 zPcTXh1cbhu32aL5R?7*^K2+Wyk(#%=;P0lB*{?SctOJ7*Rb=)r^L}&*#))9%-Sj_! zCl`%3za(mA%HKe)lFe14*S}29;C;l6uHr7V^rp)|jUd6>pJ$D~dc~1lFz)EKYL$X; z!Bwmr!J?6`0BjpZ1<}?{H*-|qM%*h|+kNpAV;fe1#x8j@-m`#PzG4u3VS{ zXB&9n%^mah6Y_!PyY4}0rzUG(5d3kMC;EitHs$@iPd#VYbHKl(Lv1MnX^D|=fU(Y())YJU*v=*||1;1ThjyX{ROzB~NUR31zs zhH}of)e;r}w~oH`hO+MBW&v=7!OMsB4R`*bFRxCWo?)`|rN58}*j(jeW!& zu1&}~0EBnjO5{>>H`tuHnp6|_3!K1J<_+v&w@ubl!1*w=AP<}wtG{L++Irl$mVuln zrxxo3&|A-JNvWE^>StPqQ;U>d8}Wh-1+GFj5z^@(^xIRB)>(2^PxNL3idM~M&l5t2 ze1BJ*SBWn@n9niBzq(ib*_uC%_6;Xt=5_xVQQBzLeor@4J=3#ixqVM4U6iC?Ed}1r zomh77`AWI^7f7gQ82C9?I>J}$__idYU$_cIOj%J*X`Fo0=Y0#^SrUja*-Js!W7;Q7 zGr`X!X+&*FG{EFhSy_V(e{BUak&x}x9)SyWKGHq9F!;0Lw-E@h!#iehoUtSFWQDne zmg4J)y_@-vcTJ9q*979dF)>#g7hnk(e*89_=#gDV$x;4z%(899UVgXGoU=OfvcCu- ztSPwrHi_mSwWdG&0vSWg&d>WSb2C>_q3TecR9oWx^bZO;4YZ%TE(9I&XEqdXRPI>;Ql>q$R!@Qi zA_x7sK#v(#QZCQhB6rz))@-2zs5Xz8%5Eh54}Mp16P25x-5>mBN3|u7gs+A=?C%*1+N43B9**3oXW6~IUkOROvO17`{Fza1IN?IsR8 z+UK=;aU_VX{+$=Evj#Y(Za&tOKIT@%j?iqfW-tHHn-eanhYl$87T>^1%8}R8~ zVk2lDQ(7ru(a9iXmBPfI+NWbeQ1b*?wQx@5OTuQjjk*8 zXc02qSefmWN5H+ZSbbCNH6=Q;YICXCINkX4(<|>*tMNpLfTI#Ti}laA8f&Z7kgD&3 zTWZTkM6%^503cF-+13oLvurmOc=Ie!dqrOvcmLqax8S(s?g@X1tlp~E``!lMmVAq` zKID%6AeT7W$3gyy=%mZ#LAJS69Xat(9AS)M4r%MhKO*#{zuz1RD=7a4^wp)f5{_%( zq<2SmzR$YEefe)?^|x|wP2iVg&}b`=eBy;iR3)B?@B+|0vt7d8Ef2F&bwSCSUH@^m z_46UcAyHLMfm_L@gnP`%#xkc?d$LK9hc%xY)9r5tR;i;Jc?pOAFj$pRgeoYT?~#^@ zBV|z6Cw=?MiLu5w*vNuszPkoLk45!S=_JDDGxT!kiRgCf?rWm>24CC$nkd{XWktT@ z)azVK21*?=I({!+-e@m%N*Yyq7pK@vfbV#liTozhdVM%_#O5MwCYGCpSk0qcbbHKv zil^cIU3K3i1B$P2+sS^^J-h1m)V8Y}!Z!=C08uX5J(5AGt3i>7OXmv|x{_cVT}dfi zC=u~{=YPL`E`ibkl(wN1@%>8jn_50f zIG6L;i(*Qo#4---F`fS+tv%dDdViw5@VcR1qHQ@?5V&!kN6%SR*f!zGOC;{uN-O6uqlu%{TzP=EOA0zuiAv6SlpoA)Q z^G6BQipCS)(<^wY&sat3k_%ccg5xM$f2gNTs41WCpe+ZeRk^1SN9goNs248^=oGX_ zKG2LMN`TVU_2&>U)9VH?7F57&9&26tDTEAa1`jHx^c0{84XP_20uMmb#rpn6`I>jd zvK3ZB1w3Fw{dE6;z_%uYwgyY6+Mo+U1r3a%glgih7+MSBW8`!CSKyZ;Vn9d|)LD|U zl$+48c_|aaYM%sj9^n{SQspT`oUfkh0spucW0wTVfCl;uUExvaJo_>7gkP-Y+kNWW z+HJs;Mjw0$l`piGSWtgACBVD4gk${<=ASj?cZ!aYIm8#1W8}AZ2)sG%YagAs#1&?) zxjQ`Xp~0kn)rQxSL$3LmQO!-Ib(NQy7pQrjHnYQJXSGPI=NH-`d)G0(92xNnUtkZ-5FDrXY9 z)Nb3eI~OVEJu^VdVrUS%3*_38S6E-R-3<)TjwsTlcjC`Jfp}ySwT=rdG1Ujk=3)rg zx(BPr>~_#)3qBCQdcYnv+!|De7XBj0{EYpzPeN|d(VOb_kgB5FhV@e6WVCOPo$HbT zdhurbGT)5z`-^=WC^7BZ$4A~8;@Y@=UzvNb-rbSN4VOCMW0=%u&i#(jQTv^6l9Vt>z6Y>;Fp=-18TpDKA`ri&A_pY|A2m1{#{@-?O4DX+HJN# zUja@6{yFVmTh!jQdW+h-dbg;Z>lAP@?M_?N-Zc`FgQ=_^f8cc5t$^R4-RwbK(_QtT z+QD`KzYRPDtYtj`XVGr;pxVVs9#VVQ44}>YA5y#6YT$LuAJ|Cy6>tID=^?e3eejUl z%dXw3cB0y?X8mZZt{ZLMs`6{^R$VVTvQ_2RxvjeHQL;_t*OG0@N6WV9I$IRDoAb48 z%2)fh>3r;6f8djp2itUBHs)dFw<_SXlt;i9*l!wO7CYu-bu!ZC88G@a<}k zp157@Ig_@l9lCbA+Mh$)b$uYbUDtz8Z`XOix$Qa+cyGJv{UaVxeLwJs>i5SUQT?92 z)70M^cBo$7v_s|WdSHV50!&dp?oheaw?o(PF93VUe=m=!yt)>+n*0gmdDiD1Rr~Kp zz7j{GB)e}{jhcItP5?+j5NYRbEjn6&;q?c2bABptg|ZY|lZa;s~% z%Bl6cRZi{Ot#au6Zk0bZy()LE?N#~G)T?r3eXq)uExjsNcJ-=U+1IObriU{~rLaq`Y`i`F-k>%Fj{Y zRlsiGH_4|@Dj)X)ze77TCgtCwT^JZ3fA3ZPT@P%ad;!j*{M@VjI{Yc+&n3Wxj0arI zc)(?h2fT^&Jgs)_iBGG2y9wyBJWuP1<@AHTnfwo2NxFcyQjR^XcJ2#L>t2yz&w!tp ze-7|2=KGA=y_3KVl!L&Hlpny&r0*HEhxb3D_V5pY53yeNp`Vh@eQF=?1wO`l1U}Au zfxUchpW4fZ{TTg{>j%J}u)M$nj1N4-_5=Qu>j%JBSiWb~e%=avm2&-AwWDu-R`<5- z1)kx!0DOz}1bm12`~>4L%Ln`gTmmXN9F1LYKQt@zuKXyo>Mzi;5oHJ zZFx@ZP=}sVJ5>L3>POjdKi>}R=r@~Vdd{*hgAr+rTkH z)q|M&z^ptKQ zxW@^2FHf<4348^d3fu%-0=y5n`X${HwE=iP@Eq^~=5s{Pxt;`kaG3fKe{Th@18xKE z1#Sl(0`lbRbHE)up&R%pu;FEl7c3WW7jOsg@nPz9yc_sFuoqbJ3dRrMMBtOm2lz5D z3_J?l|BCL>dKY+{d%A#qz+p$B_p+S8zv5}%z+aF);4gsz;IEj@QJp7s9o7E2{;1BA z_8--Ld*P_|_x_`1UHq8#fA@xC+TXj6>3hA$^u7LLMlX3)`}vGlbw0J~Rb7|b^{URN z`d-!bsSB@~^{L~!9#wT*_hU31*Zmev$5sDWbzIk-Rv*`Or!Bw~(>tzw@X>MY|1*BB z{lE3+y6+D9qUuOa$ld? zlh5_h{~GrewI7GhYCqn0 zR^>UpdfAUZe>%%^?X*n%_tq8M^*h8GHq6RDGKn+K-&|p3&mH-fE7ZY8qUFBWBe%Ja z`^aIN*BMWok7N(_5cU6QGfqsyt2A|aF?WIp&;9sPm2NwgN4Zb)$m_TGd6iZ9;ZzQ- z%d7MxgfHj6dvjs&P8QyNrK%w1DOIx7)4IAUkHGI0f5zdL9*R=t*5igMt-2v}d;ZY) zTrR1i--0Pg?n5}kn3P+XY^=&$@Y^~(vaP#H>q6c=bCDXjyQ+Yk&OaJZ`E>r+SjB`) z<^RB(l>C4n_*oOklY4eZ;Lu#4Ts(nLw$3xAy|PcgWcG6DK5TYCzjAV|nJq9kWuNjR zfA$k1f72=dud9ms46F7+mG;8HUVOhwooat)NGpmXXB~{yk$_GRUlMNt#9;up$!e8m zzlTFhh*knqXWfs&-s)Ta)*IZ#QdFK)ol3Bk25X8gFfYg=YTTD%f^{X&PJn5 z;|ZNZsI>9`&mnhMdcLQ`;qjlOcFH)@!5GL>0;sEACxJtAf!Vg8<{BH9S0p}_V&_ic zf0W9hiJ5Bc=5eMu3L@u@)Ew+x9?{7m`1x^p6?<&lfQset+&3(Y@>0uKe=3Qa>J3->GO)UU3gKVBCsQYhebQS)ir?Z6 zft8=|)?kdxce$(JPQMatM)j zXGf}ORx?A%slxhM;WtX|tRx9Pi)cf+x9XSGs;m9aY9k-+%$F@W=_-+b>lgL^e^jex z_q%Gtn|J0*mCw}-E>-C7A{QfTR3R*@$s34sdCBd#ngN3yb;m!iQ3=m|b>FGcnlIL8 zsN>C{w;7c_9>Pdvlbe1U2P!|*KbO`RMr$-wP#H~1{Ncs%fUBZkf$4Jf2={X+nTKkYQ>M$sEm?FPZieEvwjLMWy7gJzh1*Z zz{rQ+6xQ>dS!bxj^e@VKOl$t5cF|Lj-3pE5Q4q2mY3 zZjcl>Egd<&NRi;&U`%l!C!iC@|3Ov9xy9GVtB{vR-yL62b+gBRQVQ&~fAhy1$?5kl zPJP?PtNJ%&RK760nCKp4fZ#kQIzF%e7d7i3O(R=F$AA2QPIJ?pZpPU!R7m&k2RxXa1eer$8X_9f@F(n-GWnZL-WAu164g7;4Is5ct za)$G}fBytxIrsbAguFqVe|>cb1!eh!i?_%kv!h=M>9^^S`9|h&{&>{{qhnle0wt;3 ziA@~g0uz+>B7Wy|vw1?^H0_q``Bj{Oh9{VDsxhDZB9$*=J`iTzF+u%+?)GUc7^ZXO zDU@0d8?S^XC;Xm+JEw>*OfYjj{=725pGwk7b8_9z zXOZ-~`KJj*ItlswKk@^4=G2r}+?#UE^lN5Lop!bSe&g%koHnH{5st(=r_70XcBXAg zI`*|>G}9T0r>CUbQ<0>{XXeAdQ`!?LcQS6Qb|>w&xbbwvi>z?1w3nL3pR26)u9OvZ z<5pU~lpb@sao6c}e_3srjt)0vc?r*nT9I(Km2#tr_8_m?6Um-tH|9k6Epfi0-=A*K z7qjglyHlbCYK_MiJS6&~5f287q7YCM1hbwtGo07?p!pLyAsk6A7 z_S|rg>E;)`pa^_;NorK8GQF_5!HT(FS0ZeM9nYC2zgHRVuXCbNmcAo^K&!)cov`Q^ zb%|Iqf9j&Bd95s!RUoNmCBmi?w&6;YGzm)ACE^}xt5t;4CFvn8p6kRGCsNB*%xZN` z^Q+ZpExtzNxiN@Pyujy%9ZXCogPIudLIlm!iAbi|8Q1ch&RpB46DhxIq}*6yh1*I6 z%p{gSi265Ot*OW*P|0HGJCXK8G?7YAi9u7=e@oSggsk+fb@L1@>04)M-sxNC6_O`! zq3^A%lMB6#SdnHY9!|uXM5)ZyOjf_nB@@wCf>Nbj19CBMn#}NWB+hrj=mfJ;2`3EA z-m^qSbyqOPC9Rdb8X3GZT*};ZqLOkQ4-*j#{r`tyC%uH`OB}hvlYHVD_$fIBF$U#!=^Cmm@`McAS7)2}VI-X*NNcxO7}MWX3!SBU4D z=@Lx2lc-bEH0%S~$8y~vp8Z*Yahb$tQc=T0hJS@aSulBlkNH2ZAL-?6zvwelG#$jk z`uZi3k*uXWQnJ+_bG)u*_ZA8Ze~T(fz06KU#c59@qG9x)nX#;P6M7U_k7W!k7=`rpwU}A$IC!oA@MeoVN0gH9YaA!2GiNuP9&O1xmLC?Gr{Ne z=qYu==Rxf~+M|jd)kR%LYHz>;k^Q(?ga-JSXLVg}`*O{oI2tc!#>0}ue_+oto;z61 zvm+NN>m1k9jG9&JEPCAHdRnkR1geCW083vihGbheJJKyGL)xlqf|l#GChEEz&#DVb z=*(y|u@a437p&*FJ~wSA63cV&CbL#SAgR)H0yu#b%kz@mgD_laA(_iU5a)n-! zdliFAYoZ~+{wGbjP&>NzI4clIL(O*^(KGA2lTjq0wnd9IIJqv0XBL`;snl`Mnj6P+ zYi_zl%$d`sPQ3;S{mmE8+9%u9V3%04AYs2P&~QQe=U3=AQp*&Aj5L` zK`75Ga9?rQ>}bOAiUW-VFAA014WR=b4M^j9x5rjH!@vi|COhzfOdg7Y^{OD$cG8Gk z5HvRqwJhe>QQ@QXOwO|g)LY(lLAaJ~K=h_ex@$lUGH_rOGIWqSWN>j!F>H`BFnExv zZW*KzO_!I}rLNB)%)2%nF3T3Lh8T6+h!pS{&rjmeJ<4 zFHaBhi1vtXf1@!Dc-ri&Y)Yi1oR&~%>ZuW$I~t`9%?YT#CF4Xb?K#2vcsRW{f{xoN znsIPZ0!m1$s@d5K*T10pZ!Xa#z#;iJtqB=x&8Wg5Tx*tg8$Zymf9Zeh&&3Y{P^8!> zgFVyxuoVoV3W7O9iV5HXT;3%I%K5E}8b#Fx!RAR4e~PL9hT2Mk!DKXOls??}`l+wh z&CkR{jjfM6ZBf^hNkSHxnBhog#7jftZI8%(XRs|#;ox17t}-xa9!Iupu+(E`uuI7{ z!mBeFX>ihoYLN*OrNj?Os|IA!NY75tK-dH};GI#+afQAz+t; zTv&$)f8V0};z*Dmg?Ggf;+bf)=(aeDu}2mMGhFx16+ZV0ZgWM!O3sIDvb3+;vESq$w4BRn=b{;6e`O= z=~yt`l~@@>{X|woyqg9roZ?MCLeCaBxQXE7;1L^Udv zJ~Bk>15A84u9)E_8#HIoAd_Xx=~foae@i0nB+>F-F31nb*GmhsG>Hv-L3L_YNxe*{ zb8m5u!FzvLFmu;}(Kq*y`d{uz!MNI$ZMx#vc_VZFvv~L-nauGsQ4N6ubBk8Z$3;;c z<6=e4ALPj~E43avVjf#tdez+c9Ex?kHz%5CbE2&&C!TI~Qmo}gre}kzxT=Hfe;20R zl13PL5pkno4H2bZ zu1sS$wLy(D*Rwhn(`G!YheqiRtBq*FOpN-R{@KiNe6sw4F+IqKIJ+TP(M_dfD9|X- z2Ekn^R70YpBkg)7n4LG%=Chy&e^Dj|A4H|rgs$O03#Ap1Hrl*y>R(y37l^6AYBxQ^ z;+SkqDhiWHuXHf!?H^-w;W|V@pF;r2YGIyLI?16tlXkf*xWWx~$RZ~$7|wz>LO&2u zDf4!zF)`g{^|7o0O(LKg8#{9Gn_VX?(N%J^$S|PSGo#5a#|ntiQ(kD6e`Mq`?yi(_ zp|paAWHfq?;#pj)6h$N}&g;8*?Kfk6+-r6_S`+pDgcr&R@}BK1ca2FwI;Pi@N+d1Z zatKMvbyQ}_h^t1KnKb)aWTPfD1r>Cc7GR2pygI^mL zov4R+r_1KHc&D#$-s94Me{5zSrlEZG6%ox8!=#hz@m%hXw6mS#2@hkF+GR|#GsWs> zVIq@CMKG==;?W)%E_%Rwxx!+&1dBvE!G9Ra$f>dL%v5Kd08K8)Bru{|5bQA%oMmY8 z>fCVdzOloE&`+lGv+61SqW=xa65WvZ#S-1OcUg(}b%n}H#GR>@e=h;A zI5cZbiTDJ~y0=8!fEu=yh^vpivqb!Q?59e^rzdovM7(rDFPDe|j{Q!F_|Vw@qeR?h zY@SqJX<32)TOwXBe}SQ;;>QyD<5KZeu`eqX_msdDrQ(7T;ule>5I(t7Tt@5}rQ#)G z*O!Vvh|RCx)u24VQgPd8=qwf23_DRO-Wc|6rQ(2LZzvUKiU3bI{|XOWC>5^>`^;#XO&LiqnH6`z8@e}9yUqd@3S^n~-!<$A(- zU~-vk`43%PCcE}+eoBvrKk!hj_Aj0Dl+CWM8)ZPi3;@+WuXc?6S6pl*`6y z`wQi=TRJqVe_ZxFhpNhDn{(*Oa@nbDUtKQSkL^IYY%vZkDwkcwfpEEOBn~YvmmR_O z9p$nKIJB``w)+OQmdj4w0KX)+5V)sY_TL8hO~=J_Y%iDHwD!y8vUN6erd;;PhJH~l zJ74Wzm&;yO`?uw?P1XKgx$H>|@e6W6eh8pKHkk%4f2)ukrJ;%n*+gpBREXz`J*7fU zcDKJ%As(If^%dfYA6Qx;UI+oVLOeVJi3;)X46LaT56{qs3h~IdAFB{gPkT>=czW8; zRfvbOeY8S6KJ7Ou#N#vYPKE4+wa-_G$Flv872?5f|7(SKfZFWb8Q|wfi3g}%GDGDbPl~U zN=|4A{O?h6;;#MgqvWKPz#mnL2edt+Qcj`|l~&4$;r7*)aw4xCsFXvT?8Zv*kPd|^ z#Y5UoRf>mnU`?fXNC$XQ{zl;DN;%{xz!UTDe*^BWl#_Y`2P(ybI`p$jIhix?t4i^t z4*a@OJgEb}t&|fwLmyPi37w(J(Q-m(X#Qw9p)=%-7EkNYw$XAzXXt06<%G`AuSSdK zb?85VkMf}FF>+F8h+nAM$pgv8h(~s4=NR$G4!tr)JhDR<#>mN?A)cV$3;Ztd{{too G0uLPA?%bOI diff --git a/scripting/ngs_mathtype.sp b/scripting/ngs_mathtype.sp index e09db0d..22df82b 100644 --- a/scripting/ngs_mathtype.sp +++ b/scripting/ngs_mathtype.sp @@ -80,6 +80,7 @@ public Action OnClientSayMessage(int client, const char[] command, int argc) { char jsonEncode[MAX_BUFFER_LENGTH * 3 + 1]; obj.Encode(jsonEncode, sizeof(jsonEncode)); + obj.Cleanup(); delete obj; SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodPOST, MATHJSURL); From b6d93faa89ec883fcb0c9cf03700836f5a57e14e Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Wed, 6 Feb 2019 16:49:19 -0800 Subject: [PATCH 19/29] Log math type, get result --- plugins/ngs_mathtype.smx | Bin 35360 -> 35373 bytes scripting/ngs_mathtype.sp | 9 +++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/ngs_mathtype.smx b/plugins/ngs_mathtype.smx index 565765ca46ac19d390ed5a9a8822460785f4a9bb..97eb46cbe1399d974d5452640bc8be7d029ff891 100644 GIT binary patch delta 34036 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 Q#FO-Uf!_uGU$P4wp@Zc;Y5)KL diff --git a/scripting/ngs_mathtype.sp b/scripting/ngs_mathtype.sp index 22df82b..dfe6a90 100644 --- a/scripting/ngs_mathtype.sp +++ b/scripting/ngs_mathtype.sp @@ -56,7 +56,6 @@ public Action OnClientSayMessage(int client, const char[] command, int argc) { char buffer[MAX_BUFFER_LENGTH]; GetCmdArgString(buffer, sizeof(buffer)); StripQuotes(buffer); - TrimString(buffer); if (buffer[0] == '=') { int cooldownAmt = GetTime() - cooldownNum; @@ -83,6 +82,8 @@ public Action OnClientSayMessage(int client, const char[] command, int argc) { obj.Cleanup(); delete obj; + Timber.d("Sending %s to math.js", jsonEncode); + SWHTTPRequest mathRequest = new SWHTTPRequest(k_EHTTPMethodPOST, MATHJSURL); mathRequest.SetRawPostBody("application/json", jsonEncode, sizeof(jsonEncode)); mathRequest.SetContextValue(GetClientUserId(client)); @@ -119,9 +120,9 @@ public void OnMathJSReceived(SWHTTPRequest hRequest, bool bFailure, bool bReques obj.GetString("error", error, sizeof(error)); Timber.e("Math.js request failed for userid %d! Status code is %d, success was %s, error response was %s.", userid, eStatusCode, (bRequestSuccessful) ? "true" : "false", error); } else if (client != 0) { - char answer[MAX_BUFFER_LENGTH]; - obj.GetString("answer", answer, sizeof(answer)); - CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Answer is: %s", answer); + char result[MAX_BUFFER_LENGTH]; + obj.GetString("result", result, sizeof(result)); + CPrintToChat(client, "{GREEN}[SM]{DEFAULT} Answer is: %s", result); } obj.Cleanup(); delete obj; From 6cf71e25e39a5e3368473e562e82562a805339f9 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 9 Mar 2019 12:24:13 -0800 Subject: [PATCH 20/29] Newdecls on includes --- scripting/include/cURL.inc | 43 ++++++++-------- scripting/include/smac.inc | 22 ++++---- scripting/include/smac_stocks.inc | 85 ++++++++++++++++--------------- 3 files changed, 75 insertions(+), 75 deletions(-) diff --git a/scripting/include/cURL.inc b/scripting/include/cURL.inc index de7a509..7486455 100644 --- a/scripting/include/cURL.inc +++ b/scripting/include/cURL.inc @@ -6,7 +6,6 @@ #include - /* ======================================== The Following CURLOPT_* NOT support: @@ -152,7 +151,7 @@ enum Openssl_Hash { typeset CURL_OnComplete { function void(Handle hndl, CURLcode code); - function void(Handle hndl, CURLcode code , any data); + function void(Handle hndl, CURLcode code, any data); }; /** @@ -252,7 +251,7 @@ native bool curl_easy_setopt_int(Handle hndl, CURLoption opt, int value); * @ param cell_t array_size The array size. * @ return bool 1 on success. 0 = The option not accept integer or unsupport. */ -native bool curl_easy_setopt_int_array(Handle hndl, int array[][2], int array_size); +native bool curl_easy_setopt_int_array(Handle hndl, int[][] array, int array_size); /** * Set a curl option for CURLOPTTYPE_OFF_T type @@ -312,7 +311,7 @@ native CURLcode curl_easy_perform(Handle hndl); * @ param cell_t value Value to set. * @ noreturn */ -native void curl_easy_perform_thread(Handle hndl, CURL_OnComplete:perform_callback, any value=0); +native void curl_easy_perform_thread(Handle hndl, CURL_OnComplete perform_callback, any value=0); /** * Create a send & receive function for a connected curl handle @@ -327,7 +326,7 @@ native void curl_easy_perform_thread(Handle hndl, CURL_OnComplete:perform_callba * @ param cell_t value Value to set. * @ noreturn */ -native void curl_easy_send_recv(Handle hndl, CURL_OnSend:send_callback, CURL_OnReceive:receive_callback, CURL_OnComplete:complete_callback, SendRecv_Act:act, send_timeout, recv_timeout, recv_buffer_Size = 1024, any value=0); +native void curl_easy_send_recv(Handle hndl, CURL_OnSend send_callback, CURL_OnReceive receive_callback, CURL_OnComplete complete_callback, SendRecv_Act act, int send_timeout, int recv_timeout, int recv_buffer_Size = 1024, any value=0); /** * Send a signal to a send & receive curl handle @@ -335,7 +334,7 @@ native void curl_easy_send_recv(Handle hndl, CURL_OnSend:send_callback, CURL_OnR * @ param SendRecv_Act act The SendRecv_Act action after the singal * @ return bool 1 on success. 0 = not a curl_easy_send_recv() curl, or not running/waiting */ -native bool curl_send_recv_Signal(Handle hndl, SendRecv_Act:act); +native bool curl_send_recv_Signal(Handle hndl, SendRecv_Act act); /** * Check send & receive curl handle is Waiting or not @@ -375,7 +374,7 @@ native void curl_set_send_timeout(Handle hndl, int timeout); * @ param cell_t timeout How long will try to receive data before it timeout (milliseconds). * @ noreturn */ -native curl_set_recv_timeout(Handle hndl, timeout); +native void curl_set_recv_timeout(Handle hndl, int timeout); /** * Get CURLOPT_ERRORBUFFER error string in curl handle @@ -384,7 +383,7 @@ native curl_set_recv_timeout(Handle hndl, timeout); * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ noreturn */ -native curl_get_error_buffer(Handle hndl, char[] buffer, maxlen); +native void curl_get_error_buffer(Handle hndl, char[] buffer, int maxlen); /** * Extract information from a curl handle. (CURLINFO_STRING only) @@ -394,7 +393,7 @@ native curl_get_error_buffer(Handle hndl, char[] buffer, maxlen); * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ return The CURLcode code, see cURL_header.inc */ -native CURLcode curl_easy_getinfo_string(Handle hndl, CURLINFO:info, char[] buffer, maxlen); +native CURLcode curl_easy_getinfo_string(Handle hndl, CURLINFO info, char[] buffer, int maxlen); /** * Extract information from a curl handle. (CURLINFO_LONG, CURLINFO_DOUBLE only) @@ -403,7 +402,7 @@ native CURLcode curl_easy_getinfo_string(Handle hndl, CURLINFO:info, char[] buff * @ param value Variable to store the value. * @ return The CURLcode code, see cURL_header.inc */ -native CURLcode curl_easy_getinfo_int(Handle hndl, CURLINFO:info, &any value); +native CURLcode curl_easy_getinfo_int(Handle hndl, CURLINFO info, any &value); /** * URL encodes the given string @@ -413,7 +412,7 @@ native CURLcode curl_easy_getinfo_int(Handle hndl, CURLINFO:info, &any value); * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ return 1 on success. */ -native bool curl_easy_escape(Handle hndl, const String:url[], char[] buffer, maxlen); +native bool curl_easy_escape(Handle hndl, const char[] url, char[] buffer, int maxlen); /** * URL decodes the given string @@ -423,7 +422,7 @@ native bool curl_easy_escape(Handle hndl, const String:url[], char[] buffer, max * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ return The output length. */ -native curl_easy_unescape(Handle hndl, const String:url[], char[] buffer, maxlen); +native int curl_easy_unescape(Handle hndl, const char[] url, char[] buffer, int maxlen); /** * Return string describing error code @@ -432,7 +431,7 @@ native curl_easy_unescape(Handle hndl, const String:url[], char[] buffer, maxlen * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ noreturn */ -native curl_easy_strerror(CURLcode code, char[] buffer, maxlen); +native void curl_easy_strerror(CURLcode code, char[] buffer, int maxlen); /** * Returns the libcurl version string @@ -440,7 +439,7 @@ native curl_easy_strerror(CURLcode code, char[] buffer, maxlen); * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ noreturn */ -native curl_version(char[] buffer, maxlen); +native void curl_version(char[] buffer, int maxlen); /** * Returns the libcurl supported protocols string @@ -448,13 +447,13 @@ native curl_version(char[] buffer, maxlen); * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ noreturn */ -native curl_protocols(char[] buffer, maxlen); +native void curl_protocols(char[] buffer, int maxlen); /** * Returns the libcurl supported features * @ return The currently features bits. see CURL_VERSION_* */ -native curl_features(); +native int curl_features(); /** * This funcitopn same as Sourcemod OpenFile() @@ -472,7 +471,7 @@ native curl_features(); * @ param mode Open mode. * @ return A Handle to the file, INVALID_HANDLE on open error. */ -native Handle curl_OpenFile(const String:file[], const String:mode[]); +native Handle curl_OpenFile(const char[] file, const char[] mode); /** @@ -495,7 +494,7 @@ native Handle curl_httppost(); * @ param ... Variable number of format parameters. * @ return The CURLFORMcode code, see cURL_header.inc */ -native CURLFORMcode:curl_formadd(Handle handl, any ...); +native CURLFORMcode curl_formadd(Handle handl, any ...); /** * Create a curl_slist struct @@ -522,7 +521,7 @@ native Handle curl_slist(); * @ param String buffer The string to add * @ noreturn */ -native curl_slist_append(Handle hndl, const char[] buffer); +native void curl_slist_append(Handle hndl, const char[] buffer); /** * Hash a file @@ -532,7 +531,7 @@ native curl_slist_append(Handle hndl, const char[] buffer); * @ param cell_t value Value to set. * @ noreturn */ -native curl_hash_file(const String:file[], Openssl_Hash:algorithm, Openssl_Hash_Complete:complete_callback, any value=0); +native void curl_hash_file(const char[] file, Openssl_Hash algorithm, Openssl_Hash_Complete complete_callback, any value=0); /** * Hash a string @@ -543,13 +542,13 @@ native curl_hash_file(const String:file[], Openssl_Hash:algorithm, Openssl_Hash_ * @ param cell_t maxlen Destination buffer length (includes null terminator). * @ return 1 on success */ -native bool curl_hash_string(const String:input[], dataSize, Openssl_Hash:algorithm, char[] buffer, maxlength); +native bool curl_hash_string(const char[] input, int dataSize, Openssl_Hash algorithm, char[] buffer, int maxlength); /** * Do not edit below this line! */ -public Extension:__ext_curl = +public Extension __ext_curl = { name = "curl", file = "curl.ext", diff --git a/scripting/include/smac.inc b/scripting/include/smac.inc index 3778d1c..3c64ff1 100644 --- a/scripting/include/smac.inc +++ b/scripting/include/smac.inc @@ -89,19 +89,19 @@ enum DetectionType { }; /* Natives */ -native GameType:SMAC_GetGameType(); -native SMAC_Log(const String:format[], any:...); -native SMAC_LogAction(client, const String:format[], any:...); -native SMAC_Ban(client, const String:reason[], any:...); -native SMAC_PrintAdminNotice(const String:format[], any:...); -native Handle:SMAC_CreateConVar(const String:name[], const String:defaultValue[], const String:description[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0); -native Action:SMAC_CheatDetected(client, DetectionType:type = Detection_Unknown, Handle:info = INVALID_HANDLE); +native GameType SMAC_GetGameType(); +native void SMAC_Log(const char[] format, any ...); +native void SMAC_LogAction(int client, const char[] format, any ...); +native void SMAC_Ban(int client, const char[] reason, any ...); +native void SMAC_PrintAdminNotice(const char[] format, any ...); +native ConVar SMAC_CreateConVar(const char[] name, const char[] defaultValue, const char[] description="", int flags=0, bool hasMin=false, float min=0.0, bool hasMax=false, float max=0.0); +native Action SMAC_CheatDetected(int client, DetectionType type = Detection_Unknown, Handle info = INVALID_HANDLE); /* Forwards */ -forward Action:SMAC_OnCheatDetected(client, const String:module[], DetectionType:type, Handle:info); +forward Action SMAC_OnCheatDetected(int client, const char[] module, DetectionType type, Handle info); +forward Action SMAC_OnActionLogged() - -public SharedPlugin:__pl_smac = +public SharedPlugin __pl_smac = { name = "smac", file = "smac.smx", @@ -113,7 +113,7 @@ public SharedPlugin:__pl_smac = }; #if !defined REQUIRE_PLUGIN -public __pl_smac_SetNTVOptional() +public void __pl_smac_SetNTVOptional() { MarkNativeAsOptional("SMAC_GetGameType"); MarkNativeAsOptional("SMAC_Log"); diff --git a/scripting/include/smac_stocks.inc b/scripting/include/smac_stocks.inc index 6e55ce7..fb797af 100644 --- a/scripting/include/smac_stocks.inc +++ b/scripting/include/smac_stocks.inc @@ -72,11 +72,11 @@ enum { /** * General */ -stock GetPluginBasename(Handle:plugin, String:buffer[], maxlength) +stock void GetPluginBasename(Handle plugin, char[] buffer, int maxlength) { GetPluginFilename(plugin, buffer, maxlength); - new check = -1; + int check = -1; if ((check = FindCharInString(buffer, '/', true)) != -1 || (check = FindCharInString(buffer, '\\', true)) != -1) { @@ -84,20 +84,20 @@ stock GetPluginBasename(Handle:plugin, String:buffer[], maxlength) } } -stock bool:IsConVarDefault(Handle:convar) +stock bool IsConVarDefault(ConVar convar) { - decl String:sDefaultVal[16], String:sCurrentVal[16]; + char sDefaultVal[16], sCurrentVal[16]; GetConVarDefault(convar, sDefaultVal, sizeof(sDefaultVal)); GetConVarString(convar, sCurrentVal, sizeof(sCurrentVal)); return StrEqual(sDefaultVal, sCurrentVal); } -stock StringToLower(String:input[]) +stock void StringToLower(char[] input) { - new length = strlen(input); + int length = strlen(input); - for (new i = 0; i < length; i++) + for (int i = 0; i < length; i++) { input[i] = CharToLower(input[i]); } @@ -106,15 +106,15 @@ stock StringToLower(String:input[]) /** * Clients */ -stock bool:IsClientNew(client) +stock bool IsClientNew(int client) { // Client must be ingame. return IsFakeClient(client) || GetGameTime() > GetClientTime(client); } -stock bool:GetClientAbsVelocity(client, Float:velocity[3]) +stock bool GetClientAbsVelocity(int client, float velocity[3]) { - static offset = -1; + static int offset = -1; if (offset == -1 && (offset = FindDataMapOffs(client, "m_vecAbsVelocity")) == -1) { @@ -126,14 +126,14 @@ stock bool:GetClientAbsVelocity(client, Float:velocity[3]) return true; } -stock GetClientHudFlags(client) +stock int GetClientHudFlags(int client) { return GetEntProp(client, Prop_Send, "m_iHideHUD"); } -stock GetClientObserverMode(client) +stock int GetClientObserverMode(int client) { - static offset = -1; + static int offset = -1; if (offset == -1 && (offset = FindSendPropOffs("CBasePlayer", "m_iObserverMode")) == -1) { @@ -143,9 +143,9 @@ stock GetClientObserverMode(client) return GetEntData(client, offset); } -stock GetClientObserverTarget(client) +stock int GetClientObserverTarget(int client) { - static offset = -1; + static int offset = -1; if (offset == -1 && (offset = FindSendPropOffs("CBasePlayer", "m_hObserverTarget")) == -1) { @@ -158,20 +158,20 @@ stock GetClientObserverTarget(client) /** * Game Specific */ -stock bool:DODS_IsPlayerProne(client) +stock bool DODS_IsPlayerProne(int client) { - return bool:GetEntProp(client, Prop_Send, "m_bProne") || + return bool GetEntProp(client, Prop_Send, "m_bProne") || GetEntPropFloat(client, Prop_Send, "m_flGoProneTime") > 0.0 || GetEntPropFloat(client, Prop_Send, "m_flUnProneTime") > 0.0; } -stock bool:L4D_IsPlayerGhost(client) +stock bool L4D_IsPlayerGhost(int client) { - return bool:GetEntProp(client, Prop_Send, "m_isGhost", 1); + return view_as(GetEntProp(client, Prop_Send, "m_isGhost", 1)); } // "Busy" implies that the client is not in their typical first-person state. -stock bool:L4D_IsSurvivorBusy(client) +stock bool L4D_IsSurvivorBusy(int client) { return GetEntityFlags(client) & FL_FROZEN || GetClientHudFlags(client) & ~HIDEHUD_BONUS_PROGRESS || @@ -182,14 +182,14 @@ stock bool:L4D_IsSurvivorBusy(client) GetEntPropEnt(client, Prop_Send, "m_tongueOwner") > 0; } -stock bool:L4D_IsInfectedBusy(client) +stock bool L4D_IsInfectedBusy(int client) { return GetEntPropFloat(client, Prop_Send, "m_vomitFadeStart") > GetGameTime() || GetEntPropEnt(client, Prop_Send, "m_pounceVictim") > 0 || GetEntPropEnt(client, Prop_Send, "m_tongueVictim") > 0; } -stock bool:L4D2_IsSurvivorBusy(client) +stock bool L4D2_IsSurvivorBusy(int client) { return GetEntityFlags(client) & FL_FROZEN || GetClientHudFlags(client) & ~HIDEHUD_BONUS_PROGRESS || @@ -203,7 +203,7 @@ stock bool:L4D2_IsSurvivorBusy(client) GetEntPropEnt(client, Prop_Send, "m_tongueOwner") > 0; } -stock bool:L4D2_IsInfectedBusy(client) +stock bool L4D2_IsInfectedBusy(int client) { return GetEntProp(client, Prop_Send, "m_iGlowType") == 3 || GetEntPropFloat(client, Prop_Send, "m_vomitFadeStart") > GetGameTime() || @@ -214,7 +214,7 @@ stock bool:L4D2_IsInfectedBusy(client) GetEntPropEnt(client, Prop_Send, "m_tongueVictim") > 0; } -stock bool:ND_IsPlayerCommander(client) +stock bool ND_IsPlayerCommander(int client) { return GameRules_GetPropEnt("m_hCommanders", 0) == client || GameRules_GetPropEnt("m_hCommanders", 1) == client; } @@ -222,51 +222,51 @@ stock bool:ND_IsPlayerCommander(client) /** * Math */ -stock ZeroVector(Float:vec[3]) +stock void ZeroVector(float vec[3]) { vec[0] = vec[1] = vec[2] = 0.0; } -stock bool:IsVectorZero(const Float:vec[3]) +stock bool IsVectorZero(const float vec[3]) { return vec[0] == 0.0 && vec[1] == 0.0 && vec[2] == 0.0; } -stock bool:IsVectorAlmostZero(const Float:vec[3], const Float:tolerance=0.1) +stock bool IsVectorAlmostZero(const float vec[3], const float tolerance=0.1) { return FloatAbs(vec[0]) <= tolerance && FloatAbs(vec[1]) <= tolerance && FloatAbs(vec[2]) <= tolerance; } -stock bool:AreVectorsEqual(const Float:vec1[3], const Float:vec2[3]) +stock bool AreVectorsEqual(const float vec1[3], const float vec2[3]) { return vec1[0] == vec2[0] && vec1[1] == vec2[1] && vec1[2] == vec2[2]; } -stock bool:AreVectorsAlmostEqual(const Float:vec1[3], const Float:vec2[3], const Float:tolerance=0.1) +stock bool AreVectorsAlmostEqual(const float vec1[3], const float vec2[3], const float tolerance=0.1) { return FloatAbs(vec1[0] - vec2[0]) <= tolerance && FloatAbs(vec1[1] - vec2[1]) <= tolerance && FloatAbs(vec1[2] - vec2[2]) <= tolerance; } -stock AbsValue(value) +stock int AbsValue(int value) { return (value >= 0) ? value : -value; } -stock any:MinValue(any:value, any:min) +stock any MinValue(any value, any min) { return (value < min) ? min : value; } -stock any:MaxValue(any:value, any:max) +stock any MaxValue(any value, any max) { return (value > max) ? max : value; } -stock any:ClampValue(any:value, any:min, any:max) +stock any ClampValue(any value, any min, any max) { value = MinValue(value, min); value = MaxValue(value, max); @@ -274,9 +274,9 @@ stock any:ClampValue(any:value, any:min, any:max) return value; } -stock IPToLong(const String:ip[]) +stock int IPToLong(const char[] ip) { - decl String:pieces[4][4]; + char pieces[4][4]; if (ExplodeString(ip, ".", pieces, sizeof(pieces), sizeof(pieces[])) != 4) return 0; @@ -287,32 +287,33 @@ stock IPToLong(const String:ip[]) StringToInt(pieces[3]); } -stock LongToIP(ip, String:buffer[], size) +stock void LongToIP(int ip, char[] buffer, int size) { FormatEx(buffer, size, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF); } -stock MT_GetRandomInt(min, max) +stock int MT_GetRandomInt(int min, int max) { return RoundToNearest(GetURandomFloat() * float(max - min) + float(min)); } -stock Float:MT_GetRandomFloat(Float:min, Float:max) +stock float MT_GetRandomFloat(float min, float max) { return GetURandomFloat() * (max - min) + min; } -stock BfWriteSBitLong(Handle:bf, data, numBits) +stock void BfWriteSBitLong(Handle bf, int data, int numBits) { - for (new i = 0; i < numBits; i++) + for (int i = 0; i < numBits; i++) { BfWriteBool(bf, !!(data & (1 << i))); } } -stock BfReadSBitLong(Handle:bf, numBits) +stock int BfReadSBitLong(Handle bf, int numBits) { - decl bits[numBits], ret, i; + int[] bits = new int[numBits]; + int ret, i; for (i = 0; i < numBits; i++) { From 8f6285904d1198143e7886ab11b8ce1dd62b9fb4 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 9 Mar 2019 12:25:29 -0800 Subject: [PATCH 21/29] Autorestart revert to server restart --- scripting/ngs_autorestart.sp | 65 ++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/scripting/ngs_autorestart.sp b/scripting/ngs_autorestart.sp index 62895f4..1c01dc8 100644 --- a/scripting/ngs_autorestart.sp +++ b/scripting/ngs_autorestart.sp @@ -16,8 +16,11 @@ #define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" #define RELOAD_ON_UPDATE 1 -#include +#undef REQUIRE_PLUGIN #include +#define REQUIRE_PLUGIN + +#include #include #include #include @@ -27,7 +30,7 @@ public Plugin myinfo = { name = "[NGS] Timed Restart", author = "TheXeon", - description = "Restart the server's map automagically :D", + description = "Restart the server automagically :D", version = "1.0.7", url = "https://www.neogenesisnetwork.net/" } @@ -73,7 +76,7 @@ public Action CommandStartRestartTimer(int client, int args) status = StringToInt(arg1); } autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, status); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} A %srestart timer has been started, server map %s be restarting in 30 seconds!", + CPrintToChatAll("{GREEN}[SM]{DEFAULT} A %srestart timer has been started, server %s be restarting in 30 seconds!", (status == 1) ? "forced " : "", (status == 1) ? "will" : "may"); } else @@ -90,16 +93,19 @@ public Action CommandCheckRestartTimer(int client, int args) return Plugin_Handled; } -public void OnClientPostAdminCheck(int client) +stock void ProcessClientsAwake(int client, bool sendMsg) { if (autoRestartTimer != null && !IsFakeClient(client) && !IsValidForcedTime()) { delete autoRestartTimer; - CPrintToChatAll("{GREEN}[SM]{DEFAULT} Map restart aborted (someone joined)!"); + if (sendMsg) + { + CPrintToChatAll("{GREEN}[SM]{DEFAULT} Server restart aborted (we're awake)!"); + } } } -public void OnClientDisconnect_Post(int client) +stock void ProcessClientsAsleep(int client) { if (cvarEnabled.BoolValue && autoRestartTimer == null) { @@ -107,16 +113,43 @@ public void OnClientDisconnect_Post(int client) if (IsValidForcedTime()) { autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, 1); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server has been up for %d hours, forcing a map restart in 30 seconds!", RoundToNearest(time / 3600.0)); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server has been up for %d hours, forcing a restart in 30 seconds!", RoundToNearest(time / 3600.0)); } - else if ((GetClientCount(false) == 0 || - !NonAFKPlayersExist()) && (time / 60.0) > cvarUptimeRequirement.FloatValue) + else if ((time / 60.0) > cvarUptimeRequirement.FloatValue) { - autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, 0); - CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server will attempt a map restart in 30 seconds!"); + if (GetClientCount(false) == 0) + { + autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, 0); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} The server will attempt a restart in 30 seconds!"); + } + else if (!NonAFKPlayersExist()) + { + // Don't spam message + autoRestartTimer = new SMTimer(30.0, AutoRestartTimer, 0); + } } } } + +public void OnClientPostAdminCheck(int client) +{ + ProcessClientsAwake(client, true); +} + +// public void AFKM_OnClientAFK(int client) +// { +// ProcessClientsAsleep(client); +// } + +// public void AFKM_OnClientBack(int client) +// { +// ProcessClientsAwake(client, false); +// } + +public void OnClientDisconnect_Post(int client) +{ + ProcessClientsAsleep(client); +} public Action AutoRestartTimer(Handle timer, any status) { @@ -126,17 +159,15 @@ public Action AutoRestartTimer(Handle timer, any status) if (status == 1 || GetClientCount(false) == 0 || !NonAFKPlayersExist()) { #if defined DEBUG - PrintToServer("Fake doing a restart!"); + Timber.d("Fake doing a restart!"); #else - Timber.i("Server is restarting map at Unix Timestamp %d!", GetTime()); - char mapName[MAX_BUFFER_LENGTH]; - GetCurrentMap(mapName, sizeof(mapName)); - ForceChangeLevel(mapName, "Having a quick map refresh, sit tight!"); + Timber.i("Server is restarting at Unix Timestamp %d!", GetTime()); + ServerCommand("_restart"); #endif } else { - CPrintToChatAll("{GREEN}[SM]{DEFAULT} Map restart aborted!"); + CPrintToChatAll("{GREEN}[SM]{DEFAULT} Server restart aborted!"); } } From 46c8b6439f446db5a69fa2861dbe2609d45b5585 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 9 Mar 2019 12:33:46 -0800 Subject: [PATCH 22/29] Base testshell for shell commands --- scripting/ngs_testshell.sp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 scripting/ngs_testshell.sp diff --git a/scripting/ngs_testshell.sp b/scripting/ngs_testshell.sp new file mode 100644 index 0000000..de9ac37 --- /dev/null +++ b/scripting/ngs_testshell.sp @@ -0,0 +1,29 @@ +#include + +public void OnPluginStart() +{ + RegServerCmd("sm_shell", CommandShellCallback, "A direct shell to run commands on."); +} + +public Action CommandShellCallback(int args) +{ + char arg[256]; + GetCmdArg(1, arg, sizeof(arg)); + StripQuotes(arg); + System2_ExecuteThreaded(ShellCommandCallback, arg); +} + +public void ShellCommandCallback(bool success, const char[] command, System2ExecuteOutput output, any data) +{ + if (!success || output.ExitStatus != 0) + { + LogError("Couldn't execute shell command %s successfully, exit status is %d!", command, output.ExitStatus); + } + else + { + int len = output.Length; + char[] outputStr = new char[len]; + output.GetOutput(outputStr, len); + PrintToServer("Output is:\n%s", outputStr); + } +} From 4d54114475d43698ebbcaba996dfe68f2ba9ec6f Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 9 Mar 2019 12:53:15 -0800 Subject: [PATCH 23/29] Reserved slot + Kartify clean --- scripting/ngs_kartify.sp | 45 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/scripting/ngs_kartify.sp b/scripting/ngs_kartify.sp index 26bacc3..44a95b9 100644 --- a/scripting/ngs_kartify.sp +++ b/scripting/ngs_kartify.sp @@ -30,7 +30,6 @@ public Plugin myinfo = { ConVar g_cvarSpawnKart; ConVar g_cvarStartPercentage; -ConVar g_cvarForcedPercentage; ConVar g_cvarAllowSuicide; bool g_KartSpawn[MAXPLAYERS + 1]; @@ -38,7 +37,6 @@ bool g_KartSpawn[MAXPLAYERS + 1]; public void OnPluginStart() { g_cvarSpawnKart = CreateConVar("kartify_spawn", "0", "0 = do nothing, 1 = put all players into karts when they spawn, 2 = put players into karts when they spawn only if sm_kartify was used on them", _, true, 0.0, true, 2.0); g_cvarStartPercentage = CreateConVar("kartify_start_percentage", "0", "Starting percentage, as an integer, of damage for kartified players", _, true, 0.0); - g_cvarForcedPercentage = CreateConVar("kartify_forced_percentage", "-1", "If 0 or greater, karts will not take damage and will instead have this percent of damage all the time (as an integer)", _, true, -1.0); g_cvarAllowSuicide = CreateConVar("kartify_allow_suicide", "1", "Allow players to suicide while in a kart", _, true, 0.0, true, 1.0); RegAdminCmd("sm_kartify", Command_Kartify, ADMFLAG_SLAY, "Put players into karts!"); @@ -59,13 +57,16 @@ public void OnPluginStart() { AddCommandListener(Command_Kill, "explode"); } -public Action Command_Kill(int client, const char[] command, int argc) { - if(g_cvarAllowSuicide.BoolValue) { +public Action Command_Kill(int client, const char[] command, int argc) +{ + if(g_cvarAllowSuicide.BoolValue) + { Unkartify(client); // Won't do anything if they're not in a kart } } -public void OnMapStart() { +public void OnMapStart() +{ PrecacheModel("models/player/items/taunts/bumpercar/parts/bumpercar.mdl"); PrecacheModel("models/player/items/taunts/bumpercar/parts/bumpercar_nolights.mdl"); @@ -117,7 +118,7 @@ public Action Command_Kartify(int client, int args) { return Plugin_Handled; } - if(result == 1 && TF2_IsPlayerInCondition(targets[0], view_as(82))) { + if(result == 1 && TF2_IsPlayerInCondition(targets[0], TFCond_HalloweenKart)) { // Only one player chosen and they're in a kart CShowActivity2(client, "{GREEN}[SM]{DEFAULT} ", "Unkartified {LIGHTGREEN}%s{DEFAULT}!", target_name); LogAction(client, targets[0], "\"%L\" unkartified \"%L\"", client, targets[0]); @@ -167,7 +168,7 @@ public Action Command_Unkartify(int client, int args) { } public Action Command_KartifyMe(int client, int args) { - if(TF2_IsPlayerInCondition(client, view_as(82))) { + if(TF2_IsPlayerInCondition(client, TFCond_HalloweenKart)) { Command_UnkartifyMe(client, 0); return Plugin_Handled; } @@ -204,7 +205,7 @@ public void Event_PlayerSpawn(Handle event, const char[] name, bool dontBroadcas public void Event_PlayerTeam(Handle event, const char[] name, bool dontBroadcast) { int client = GetClientOfUserId(GetEventInt(event, "userid")); - if(TF2_IsPlayerInCondition(client, view_as(82))) { + if(TF2_IsPlayerInCondition(client, TFCond_HalloweenKart)) { // Kill them otherwise they'll just spawn as the other team where they're standing Unkartify(client); ForcePlayerSuicide(client); @@ -219,16 +220,16 @@ bool Kartify(int client, bool triggerAdmin=false) { } TF2Friendly_SetFriendly(client, 1, -1); TF2_RespawnPlayer(client); - TF2_AddCondition(client, view_as(82), TFCondDuration_Infinite); + TF2_AddCondition(client, TFCond_HalloweenKart, TFCondDuration_Infinite); SetEntProp(client, Prop_Send, "m_iKartHealth", GetConVarInt(g_cvarStartPercentage)); return true; } bool Unkartify(int client) { - if (TF2_IsPlayerInCondition(client, view_as(82))) + if (TF2_IsPlayerInCondition(client, TFCond_HalloweenKart)) { - TF2_RemoveCondition(client, view_as(82)); + TF2_RemoveCondition(client, TFCond_HalloweenKart); if (!TF2Friendly_IsLocked(client)) { TF2Friendly_SetFriendly(client, 0, -1); @@ -238,14 +239,14 @@ bool Unkartify(int client) } return false; } - -public void OnGameFrame() { - int forcedPct = g_cvarForcedPercentage.IntValue; - if(forcedPct >= 0) { - for(int i = 1; i <= MaxClients; i++) { - if(IsClientInGame(i)) { - SetEntProp(i, Prop_Send, "m_iKartHealth", forcedPct); - } - } - } -} +// +//public void OnGameFrame() { +// int forcedPct = g_cvarForcedPercentage.IntValue; +// if(forcedPct >= 0) { +// for(int i = 1; i <= MaxClients; i++) { +// if(IsClientInGame(i)) { +// SetEntProp(i, Prop_Send, "m_iKartHealth", forcedPct); +// } +// } +// } +//} From bb596d7c462bb3ac9c4fd037ca915c0c37bb993c Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 9 Mar 2019 12:54:30 -0800 Subject: [PATCH 24/29] MGE Configs --- configs/mgemod_spawns.cfg | 4635 +++++++++++++++++++++++++++++++++ configs/mgemod_spawns_2v2.cfg | 4154 +++++++++++++++++++++++++++++ configs/mgemod_stats.cfg | 284 ++ 3 files changed, 9073 insertions(+) create mode 100644 configs/mgemod_spawns.cfg create mode 100644 configs/mgemod_spawns_2v2.cfg create mode 100644 configs/mgemod_stats.cfg diff --git a/configs/mgemod_spawns.cfg b/configs/mgemod_spawns.cfg new file mode 100644 index 0000000..a849439 --- /dev/null +++ b/configs/mgemod_spawns.cfg @@ -0,0 +1,4635 @@ +// "map_name" +// { +// "arena_name" +// { +// "1" "X Y Z yaw" // Spawn points. +// "2" "X Y Z yaw" // Spawn points. +// //optional +// "fraglimit" "3" // Fraglimit, for BBall, this is the capture limit. +// "maxrating" "2000" // Max ELO Rating of players allowed to join this arena. +// "minrating" "1500" // Min ELO Rating of players allowed to join this arena. +// "cdtime" "3" // Time before round starts (when players can't shoot) +// "classes" "scout soldier pyro demoman heavy engineer medic sniper spy" // Allowed classes for this arena. if player's class not allowed then player will be switched to first allowed class +// "hpratio" "1.5" // How much of a buff players should get in this arena. 1.0=normal hp, 1.5 = full buff, any floating point value is accepted. +// "earlyleave" "0" // When a player leaves an arena early, if they have less points than their opponent AND their opponent has more points than this value, the leaver loses rating. +// "vishoop" "0" // Set to 1 to make the BBall hoop entities visible. Useful when adding spawns to a new arena. Only applies to BBall arenas. +// "infammo" "1" // enable(1)/disable(0) infinite ammo for this arena +// "mindist" "100" // Minimum distance a player's foe must be away from a spawn point for a player to spawn there. Measured in Hammer units. +// "respawntime" "0.1" // for gamemodes with respawning, this controls the respawn length +// "4player" "0" // enable(1)/disable(0) 4 player arenas +// "ultiduo" "0" // enable(1)/disable(0) makes arena only have 1 of each class (soldier/medic) +// "turris" "0" // enable(1)/disable(0) Regens the arena every 5 seconds like actual turris +// "koth" "0" // enable(1)/disable(0) Koth mode for this arena +// "Timer" "180" // Sets the default start timer in koth mode, defauly is 180 or 3 minutes +// //Only enable ONE of the following +// "ammomod" "1" // enable(1)/disable(0) original Ammomod gameplay for this arena +// "midair" "0" // enable(1)/disable(0) midairmod for this arena +// "mge" "0" // enable(1)/disable(0) MGE Training mode for this arena +// "bball" "0" // enable(1)/disable(0) BBall for this arena +// "endif" "0" // enable(1)/disable(0) Endif for this arena +// } +// } +// MAX 15 ARENAS PER MAP! +// MAX 15 SPAWNS PER ARENA! + + +SpawnConfigs +{ + "duels_midair_v2" + { + "[Midair] Turris 1" + { + "1" "412 -4677 -1260 -45" + "2" "1446 -5700 -1260 135" + "midair" "1" + "cdtime" "0" + } + "[Midair] Turris 2" + { + "1" "-458 -5905 -1395 135" + "2" "-1467 -4885 -1395 -45" + "midair" "1" + "cdtime" "0" + } + "[Midair] Regular 1" + { + "1" "-2930.36 -5053.19 -1268 -89.20" + "2" "-2906.53 -5913.81 -1268 91.95" + "midair" "1" + } + "[Midair] Regular 2" + { + "1" "-4725.75 -4973.90 -1222 -88.67" + "2" "-4698.87 -5840 -1222 91.91" + "midair" "1" + } + "[Midair] Granary Mid 1" + { + "1" "3352.93 -5092.18 -976 -148.51" + "2" "2400.47 -5849.33 -976 37.13" + "midair" "1" + } + "[Midair] Granary Mid 2" + { + "1" "7337.31 -5091.22 -976 -143.26" + "2" "6414.14 -5852.94 -976 38.12" + "midair" "1" + } + } + "am_variety_test3" + { + "Regular 1" + { + "1" "-1412.276733 -1676.996460 -1223.027344 -90" + "2" "-1431.968018 -2557.931641 -1223.027344 90" + "fraglimit" "2" + "hpratio" "6" + "ammomod" "1" + } + "Regular 2 (1725+ only)" + { + "1" "-2786.840088 -1626.397095 -1223.027344 -91.151024" + "2" "-2805.131348 -2531.600342 -1223.027344 89.745850" + "fraglimit" "4" + "minrating" "1725" + "hpratio" "4" + "hpratio" "6" + "ammomod" "1" + } + "Oldschool" + { + "1" "8277.875977 -1509.120117 -2191.968750 -86.681198" + "2" "8529.970703 -2510.064453 -2191.968750 91.784729" + "fraglimit" "5" + "hpratio" "1.5" + "ammomod" "1" + } + "No Splash" + { + "1" "5009.058594 -379.998749 -1267.027344 -29.655741" + "2" "5761.857910 -814.545288 -1267.027344 149.702255" + "fraglimit" "1" + "classes" "soldier demoman" + "hpratio" "6" + "ammomod" "1" + } + "Endif 1" + { + "1" "5681.151855 -4871.657715 -950 90" + "2" "5449.007813 -4585.144531 -950 0" + "3" "5754.729492 -4406.645996 -950 -90" + "4" "5998.674316 -4629.772949 -950 180" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Endif 2" + { + "1" "8818.646484 -4598.492676 -950 0" + "2" "9162.908203 -4290.289063 -950 -90" + "3" "9349.802734 -4611.180664 -950 -180" + "4" "9045.556641 -4915.236816 -950 90" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Badlands mid" + { + "1" "-5040.179688 -2122.799561 -593.512329 -0.159478" + "2" "-4543.730469 -2122.498535 -593.512329 -179.966309" + "hpratio" "6" + "ammomod" "1" + } + "Gravelpit C" + { + "1" "379.828766 -2636.744385 -896.750732 89.007950" + "2" "377.990967 -1395.398071 -896.750732 -89.520828" + "hpratio" "6" + "ammomod" "1" + } + "Badlands spire" + { + "1" "1771.468994 -7269.258301 -675.576965 103.115448" + "2" "1420.005005 -5716.803223 -678.373718 -81.142761" + "hpratio" "6" + "ammomod" "1" + } + "Granary mid" + { + "1" "3188.463867 -1938.652710 -1244.027344 1.062489" + "2" "3656.447266 -1925.876343 -1244.027344 -179.130829" + "hpratio" "6" + "ammomod" "1" + } + } + "am_variety_test10" + { + "Regular 1" + { + "1" "-5069.770020 2534.885742 -1544.027344 -90" + "2" "-5061.914063 1567.021484 -1544.027344 90" + "fraglimit" "2" + "hpratio" "6" + "ammomod" "1" + } + "Regular 2" + { + "1" "-180.343384 2747.968750 -1544.027344 -91.151024" + "2" "-172.520660 1736.391113 -1544.027344 89.745850" + "fraglimit" "3" + "hpratio" "6" + "ammomod" "1" + } + "Oldschool" + { + "1" "8277.875977 -1509.120117 -2191.968750 -86.681198" + "2" "8529.970703 -2510.064453 -2191.968750 91.784729" + "fraglimit" "5" + "hpratio" "1.5" + } + "Directs" + { + "1" "3470.873535 -1429.757568 -1559.287354 180" + "2" "2533.883545 -1420.801758 -1559.287354 180" + "fraglimit" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "ammomod" "1" + } + "Endif 1" + { + "1" "5681.151855 -4871.657715 -950 90" + "2" "5449.007813 -4585.144531 -950 0" + "3" "5754.729492 -4406.645996 -950 -90" + "4" "5998.674316 -4629.772949 -950 180" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Endif 2" + { + "1" "8818.646484 -4598.492676 -950 0" + "2" "9162.908203 -4290.289063 -950 -90" + "3" "9349.802734 -4611.180664 -950 -180" + "4" "9045.556641 -4915.236816 -950 90" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Badlands mid" + { + "1" "-2367.562256 -2117.650635 -530.027405 0.343550" + "2" "-1752.006714 -2124.842041 -530.027405 179.224030" + "hpratio" "6" + "ammomod" "1" + } + "Gravelpit C" + { + "1" "379.828766 -2636.744385 -896.750732 89.007950" + "2" "377.990967 -1395.398071 -896.750732 -89.520828" + "hpratio" "6" + "ammomod" "1" + } + "Badlands spire" + { + "1" "1771.468994 -7269.258301 -675.576965 103.115448" + "2" "1420.005005 -5716.803223 -678.373718 -81.142761" + "hpratio" "6" + "ammomod" "1" + } + "Granary mid" + { + "1" "4975.793457 1018.314026 -1333.367432 -0.935107" + "2" "5313.360840 1013.421875 -1333.366943 179.130829" + "hpratio" "6" + "ammomod" "1" + } + } + "mge_training_pro" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "1" + "infammo" "1" + "showhp" "0" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Coldfront Middle" + { + "1" "6383.006836 4912.959961 -47.567116 -0.128536 -20.806692 0.000000" + "2" "6571.136719 4238.881836 -102.968887 -1.758723 42.342129 0.000000" + "3" "7151.087891 4204.558105 -86.855179 -2.359316 98.069260 0.000000" + "4" "7703.587402 4492.280273 -48.149124 -2.488018 155.555603 0.000000" + "5" "7589.781738 5170.391113 -92.138184 -0.600406 -128.339890 0.000000" + "6" "6952.505371 4839.285156 -38.483078 3.389303 -41.724876 0.000000" + "7" "7210.519043 4569.479492 -33.211716 2.145200 135.821335 0.000000" + "8" "7095.079102 5243.062988 -84.583145 -0.471705 -91.660759 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Yukon Second" + { + "1" "8823.489258 -1957.666992 -1447.837402 -2.231640 -126.732574 0.000000" + "2" "8952.040039 -2644.574463 -1250.551025 0.556859 179.513977 0.000000" + "3" "9024.213867 -3205.805664 -1144.053467 -0.815941 138.501602 0.000000" + "4" "8590.097656 -3109.852051 -1426.759277 -0.429834 125.073608 0.000000" + "5" "8153.355469 -3319.900391 -1427.627197 0.942963 118.638748 0.000000" + "6" "7799.316406 -2620.197266 -1250.560303 0.042063 0.277563 0.000000" + "7" "7923.224121 -1888.819214 -1458.079102 -1.159136 -42.579590 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + } + "mge_training_proA" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "1" + "infammo" "1" + "showhp" "0" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Coldfront Middle" + { + "1" "6383.006836 4912.959961 -47.567116 -0.128536 -20.806692 0.000000" + "2" "6571.136719 4238.881836 -102.968887 -1.758723 42.342129 0.000000" + "3" "7151.087891 4204.558105 -86.855179 -2.359316 98.069260 0.000000" + "4" "7703.587402 4492.280273 -48.149124 -2.488018 155.555603 0.000000" + "5" "7589.781738 5170.391113 -92.138184 -0.600406 -128.339890 0.000000" + "6" "6952.505371 4839.285156 -38.483078 3.389303 -41.724876 0.000000" + "7" "7210.519043 4569.479492 -33.211716 2.145200 135.821335 0.000000" + "8" "7095.079102 5243.062988 -84.583145 -0.471705 -91.660759 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Yukon Second" + { + "1" "8823.489258 -1957.666992 -1447.837402 -2.231640 -126.732574 0.000000" + "2" "8952.040039 -2644.574463 -1250.551025 0.556859 179.513977 0.000000" + "3" "9024.213867 -3205.805664 -1144.053467 -0.815941 138.501602 0.000000" + "4" "8590.097656 -3109.852051 -1426.759277 -0.429834 125.073608 0.000000" + "5" "8153.355469 -3319.900391 -1427.627197 0.942963 118.638748 0.000000" + "6" "7799.316406 -2620.197266 -1250.560303 0.042063 0.277563 0.000000" + "7" "7923.224121 -1888.819214 -1458.079102 -1.159136 -42.579590 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + } + "mge_training_v2" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Coldfront Middle" + { + "1" "6383.006836 4912.959961 -47.567116 -0.128536 -20.806692 0.000000" + "2" "6571.136719 4238.881836 -102.968887 -1.758723 42.342129 0.000000" + "3" "7151.087891 4204.558105 -86.855179 -2.359316 98.069260 0.000000" + "4" "7703.587402 4492.280273 -48.149124 -2.488018 155.555603 0.000000" + "5" "7589.781738 5170.391113 -92.138184 -0.600406 -128.339890 0.000000" + "6" "6952.505371 4839.285156 -38.483078 3.389303 -41.724876 0.000000" + "7" "7210.519043 4569.479492 -33.211716 2.145200 135.821335 0.000000" + "8" "7095.079102 5243.062988 -84.583145 -0.471705 -91.660759 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "BBall 1" + { + "1" "9663.772461 -2552.907959 -864.665344 -0.943803 -89.858566 0.000000" // Player 1 spawns + "2" "9927.164063 -2552.254883 -864.665344 -0.943803 -89.858566 0.000000" // '' + "3" "10140.030273 -2551.727539 -864.665344 -0.986703 -89.858566 0.000000" // '' + "4" "10404.137695 -2568.479736 -864.665344 -0.858001 -90.287567 0.000000" // '' + "5" "10410.448242 -4457.441406 -864.665344 -0.986704 90.647774 0.000000" // Player 2 spawns + "6" "10148.243164 -4460.408691 -864.665344 -1.458604 90.647774 0.000000" // '' + "7" "9929.341797 -4460.158691 -864.665344 -1.630204 90.090073 0.000000" // '' + "8" "9664.025391 -4460.571289 -864.665344 -1.630204 90.090073 0.000000" // '' + "9" "10034.460938 -3514.353760 -880 0 0 0" // Center intel spawn, for the start of a round. + "10" "10036.291016 -4030.868408 -880 0 0 0" // Where the intel appears after player 1 dunks. + "11" "10035.222656 -2986.938965 -880 0 0 0" // Where the intel appears after player 2 dunks. + "12" "10036.189453 -2714 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "10035.548828 -4303 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + "BBall 2" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -880 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -880 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -880 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4270 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2676 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v3" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "mindist" "200" + "ammomod" "1" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v4" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v4_fixed" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v5" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Snakewater Middle" + { + "1" "-9471 -1415 -756 180" + "2" "-11434 -1361 -756 -0" + "3" "-9740 -1886 -751 121" + "4" "-11185 -885 -752 -62" + "5" "-10448 -1838 -668 90" + "6" "-10453 -931 -668 -90" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v7" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Snakewater Middle" + { + "1" "-9471 -1415 -756 180" + "2" "-11434 -1361 -756 -0" + "3" "-9740 -1886 -751 121" + "4" "-11185 -885 -752 -62" + "5" "-10448 -1838 -668 90" + "6" "-10453 -931 -668 -90" + "7" "-9576 -879 -572 180" + "8" "-11333 -1895 -572 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "0" + } + "No Splash" + { + "1" "6862.301270 -3937.054199 -1515.530273 0 60 0" + "2" "7165.354980 -3413.613525 -1515.530273 0 -120 0" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + "4player" "0" + } + "BBall 1v1" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -850 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -850 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + } + + "koth_ultiduo_nologic" + { + "ultiduo" + { + "1" "-2512 1040 0 0 -90 0" //red team spawns + "2" "-2560 1040 0 0 -90 0" + "3" "-2608 1040 0 0 -90 0" + "4" "-2609 -1040 0 0 90 0" //Blu team spawns + "5" "-2513 -1040 0 0 90 0" + "6" "-2513 -1040 0 0 90 0" + "7" "-2567.787598 -7.029320 -228.567810 0 0 0" //spawn point pos + "fraglimit" "2" + "cdtime" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "ammomod" "0" + "bball" "0" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "10.0" + "koth" "1" + "ultiduo" "1" + "4player" "0" + "turris" "0" + } + } + + + "mge_training_v8_beta4a" + { + "Viaduct Middle" + { + "1" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "2" "6418.329102 12404.434570 -202.985687 11.583488 -16.006359 0.000000" + "3" "6849.119141 12678.232422 -322.409607 5.346490 -68.278381 0.000000" + "4" "7534.082031 11372.428711 -269.931183 1.089500 133.915527 0.000000" + "5" "6957.675781 11432.859375 -318.533752 -0.923496 85.504501 0.000000" + "6" "6417.302734 11675.087891 -202.985687 3.069469 26.797421 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" //left of blu train + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" //back of blu train + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" //right of blu train + "4" "-11289 -13813 -852 17" //blu house exit + "5" "-10701 -14274 -846 90" //blu balcony + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" //left of red train + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" //back of red train + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" //right of red train + "9" "-10248 -12949 -854 -162" //red house exit + "10" "-10833 -12474 -846 -90" //red balcony + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" //pride rock + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" //gray bridge + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" //front door + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" //battlements + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" //bottom of spire + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" //bottom of pride + "7" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" //midlevel spire + "8" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" //pill + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "4player" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "4player" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Snakewater Middle" + { + "1" "-11434 -1361 -756 -0" + "2" "-11185 -885 -752 -62" + "3" "-11333 -1895 -572 0" + "4" "-11094.696289 -505.179871 -523.997437 7.128137 -80.694138 0.000000" + "5" "-9471 -1415 -756 180" + "6" "-9740 -1886 -751 121" + "7" "-9576 -879 -572 180" + "8" "-9818.991211 -2285.646484 -521.429626 8.052133 96.218925 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Gravelpit C" + { + "1" "5578 7625 58 -90" + "2" "5578 6474 58 90" + "3" "5118 7060 -108 0" + "4" "6506 6330 84 129" + "5" "6582 7637 84 -143" + "6" "6816 6949 180 176" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "300" + "4player" "0" + } + "Process Middle" + { + "1" "-3231 1221 -230 90" //BLU Sewer + "2" "-3240 3156 -230 -90" //RED Sewer + "3" "-2838 2784 -255 -124" //RED Rock + "4" "-3585 1640 -257 56" //BLU Rock + "5" "-2591 2218 -166 180" //RED Computer + "6" "-3870 2228 -166 0" //BLU Computer + "7" "-4066 2709 -198 0" //BLU Forward + "8" "-2400 1720 -180 160" //RED Forward + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Trainyard" + { + "1" "2063 1750 1208 0" + "2" "3883 2511 1208 179" + "3" "2154 3063 1208 -48" + "4" "3786 1192 1208 132" + "5" "3075 1635 1210 101" + "6" "2878 2605 1210 -75" + "7" "2498 2204 1210 -9" + "8" "3461 2024 1210 169" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Turris 1" + { + "1" "11863 6812 -520 135" + "2" "11665 6765 -520 136" + "3" "11926 6988 -520 132" + "4" "11329 7346 -520 -45" + "5" "11542 7379 -520 -44" + "6" "11285 7130 -520 -44" + "7" "11611.962891 7066.257324 -165.198700 0" // CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "Turris 2" + { + "1" "11863 5512 -520 135" + "2" "11665 5465 -520 136" + "3" "11926 5688 -520 132" + "4" "11329 6046 -520 -45" + "5" "11542 6079 -520 -44" + "6" "11285 5830 -520 -44" + "7" "11608.865234 5792.714844 -165.198700 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "0" + } + "No Splash" + { + "1" "6862.301270 -3937.054199 -1515.530273 0 60 0" + "2" "7165.354980 -3413.613525 -1515.530273 0 -120 0" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + "4player" "0" + } + "BBall 2v2" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -850 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -850 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge2_test" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //BLU + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 45" //RED + "5" "840 -1950 -782 45" + "6" "640 -2150 -782 45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "0" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //BLU + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 45" //RED + "5" "840 -700 -782 45" + "6" "640 -900 -782 45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "BBall 1 (2v2)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_training_v8_beta4b" + { + "Viaduct Middle" + { + "1" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "2" "6418.329102 12404.434570 -202.985687 11.583488 -16.006359 0.000000" + "3" "6849.119141 12678.232422 -322.409607 5.346490 -68.278381 0.000000" + "4" "7534.082031 11372.428711 -269.931183 1.089500 133.915527 0.000000" + "5" "6957.675781 11432.859375 -318.533752 -0.923496 85.504501 0.000000" + "6" "6417.302734 11675.087891 -202.985687 3.069469 26.797421 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" //left of blu train + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" //back of blu train + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" //right of blu train + "4" "-11289 -13813 -852 17" //blu house exit + "5" "-10701 -14274 -846 90" //blu balcony + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" //left of red train + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" //back of red train + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" //right of red train + "9" "-10248 -12949 -854 -162" //red house exit + "10" "-10833 -12474 -846 -90" //red balcony + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" //pride rock + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" //gray bridge + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" //front door + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" //battlements + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" //bottom of spire + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" //bottom of pride + "7" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" //midlevel spire + "8" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" //pill + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "4player" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "4player" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Snakewater Middle" + { + "1" "-11434 -1361 -756 -0" + "2" "-11185 -885 -752 -62" + "3" "-11333 -1895 -572 0" + "4" "-11094.696289 -505.179871 -523.997437 7.128137 -80.694138 0.000000" + "5" "-9471 -1415 -756 180" + "6" "-9740 -1886 -751 121" + "7" "-9576 -879 -572 180" + "8" "-9818.991211 -2285.646484 -521.429626 8.052133 96.218925 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Gravelpit C" + { + "1" "5578 7625 58 -90" + "2" "5578 6474 58 90" + "3" "5118 7060 -108 0" + "4" "6506 6330 84 129" + "5" "6582 7637 84 -143" + "6" "6816 6949 180 176" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "300" + "4player" "0" + } + "Process Middle" + { + "1" "-3231 1221 -230 90" //BLU Sewer + "2" "-3240 3156 -230 -90" //RED Sewer + "3" "-2838 2784 -255 -124" //RED Rock + "4" "-3585 1640 -257 56" //BLU Rock + "5" "-2591 2218 -166 180" //RED Computer + "6" "-3870 2228 -166 0" //BLU Computer + "7" "-4066 2709 -198 0" //BLU Forward + "8" "-2400 1720 -180 160" //RED Forward + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Trainyard" + { + "1" "2063 1750 1208 0" + "2" "3883 2511 1208 179" + "3" "2154 3063 1208 -48" + "4" "3786 1192 1208 132" + "5" "3075 1635 1210 101" + "6" "2878 2605 1210 -75" + "7" "2498 2204 1210 -9" + "8" "3461 2024 1210 169" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Turris 1" + { + "1" "11863 6812 -520 135" + "2" "11665 6765 -520 136" + "3" "11926 6988 -520 132" + "4" "11329 7346 -520 -45" + "5" "11542 7379 -520 -44" + "6" "11285 7130 -520 -44" + "7" "11611.962891 7066.257324 -165.198700 0" // CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "Turris 2" + { + "1" "11863 5512 -520 135" + "2" "11665 5465 -520 136" + "3" "11926 5688 -520 132" + "4" "11329 6046 -520 -45" + "5" "11542 6079 -520 -44" + "6" "11285 5830 -520 -44" + "7" "11608.865234 5792.714844 -165.198700 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "0" + } + "No Splash" + { + "1" "6862.301270 -3937.054199 -1515.530273 0 60 0" + "2" "7165.354980 -3413.613525 -1515.530273 0 -120 0" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + "4player" "0" + } + "BBall 2v2" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -850 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -850 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + "mge2_test" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //BLU + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 45" //RED + "5" "840 -1950 -782 45" + "6" "640 -2150 -782 45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "0" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //BLU + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 45" //RED + "5" "840 -700 -782 45" + "6" "640 -900 -782 45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "BBall 1 (2v2)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_dueling_v1" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //RED + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 -45" //BLU + "5" "840 -1950 -782 -45" + "6" "640 -2150 -782 -45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "0" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //RED + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 -45" //BLU + "5" "840 -700 -782 -45" + "6" "640 -900 -782 -45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "BBall 1 (1v1)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_dueling_v1_fix1" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "0" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //RED + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 -45" //BLU + "5" "840 -1950 -782 -45" + "6" "640 -2150 -782 -45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "0" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //RED + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 -45" //BLU + "5" "840 -700 -782 -45" + "6" "640 -900 -782 -45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "BBall 1 (1v1)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_bball_v2" + { + "BBall 1 (1v1)" + { + "1" "-128 -960 32 0 90 0" //team 1 spawns + "2" "-256 -960 32 0 90 0" //team 1 spawns + "3" "128 -960 32 0 90 0" //team 1 spawns + "4" "256 -960 32 0 90 0" //team 1 spawns + "5" "-128 960 32 0 270 0" //team2 spawn + "6" "-256 960 32 0 270 0" //team2 spawn + "7" "128 960 32 0 270 0" //team2 spawn + "8" "256 960 32 0 270 0" //team2 spawn + "9" "0 0 142 0" // Center intel spawn, for the start of a round. + "10" "0 512 96 0" // Where the intel appears after player 1 dunks. + "11" "0 -512 96 0" // Where the intel appears after player 1 dunks. + "12" "0 -796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "0 796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + "BBall 2 (1v1)" + { + "1" "8744 -960 32 0 90 0" //team 1 spawns + "2" "8872 -960 32 0 90 0" //team 1 spawns + "3" "9128 -960 32 0 90 0" //team 1 spawns + "4" "9256 -960 32 0 90 0" //team 1 spawns + "5" "8744 960 32 0 270 0" //team2 spawn + "6" "8872 960 32 0 270 0" //team2 spawn + "7" "9128 960 32 0 270 0" //team2 spawn + "8" "9256 960 32 0 270 0" //team2 spawn + "9" "9000 0 142 0" // Center intel spawn, for the start of a round. + "10" "9000 512 96 0" // Where the intel appears after player 1 dunks. + "11" "9000 -512 96 0" // Where the intel appears after player 1 dunks. + "12" "9000 -796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "9000 796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + "BBall 3 (1v1)" + { + "1" "-8744 -960 32 0 90 0" //team 1 spawns + "2" "-8872 -960 32 0 90 0" //team 1 spawns + "3" "-9128 -960 32 0 90 0" //team 1 spawns + "4" "-9256 -960 32 0 90 0" //team 1 spawns + "5" "-8744 960 32 0 270 0" //team2 spawn + "6" "-8872 960 32 0 270 0" //team2 spawn + "7" "-9128 960 32 0 270 0" //team2 spawn + "8" "-9256 960 32 0 270 0" //team2 spawn + "9" "-9000 0 142 0" // Center intel spawn, for the start of a round. + "10" "-9000 512 96 0" // Where the intel appears after player 1 dunks. + "11" "-9000 -512 96 0" // Where the intel appears after player 1 dunks. + "12" "-9000 -796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-9000 796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "0" + } + "BBall 4 (2v2)" + { + "1" "-128 8040 32 0 90 0" //team 1 spawns + "2" "-256 8040 32 0 90 0" //team 1 spawns + "3" "128 8040 32 0 90 0" //team 1 spawns + "4" "256 8040 32 0 90 0" //team 1 spawns + "5" "-128 9960 32 0 270 0" //team2 spawn + "6" "-256 9960 32 0 270 0" //team2 spawn + "7" "128 9960 32 0 270 0" //team2 spawn + "8" "256 9960 32 0 270 0" //team2 spawn + "9" "0 9000 142 0" // Center intel spawn, for the start of a round. + "10" "0 9512 96 0" // Where the intel appears after player 1 dunks. + "11" "0 8488 96 0" // Where the intel appears after player 1 dunks. + "12" "0 8203.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "0 9796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 5 (2v2)" + { + "1" "8744 8040 32 0 90 0" //team 1 spawns + "2" "8872 8040 32 0 90 0" //team 1 spawns + "3" "9128 8040 32 0 90 0" //team 1 spawns + "4" "9256 8040 32 0 90 0" //team 1 spawns + "5" "8744 9960 32 0 270 0" //team2 spawn + "6" "8872 9960 32 0 270 0" //team2 spawn + "7" "9128 9960 32 0 270 0" //team2 spawn + "8" "9256 9960 32 0 270 0" //team2 spawn + "9" "9000 9000 142 0" // Center intel spawn, for the start of a round. + "10" "9000 9512 96 0" // Where the intel appears after player 1 dunks. + "11" "9000 8488 96 0" // Where the intel appears after player 1 dunks. + "12" "9000 8203.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "9000 9796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 6 (2v2)" + { + "1" "-8744 8040 32 0 90 0" //team 1 spawns + "2" "-8872 8040 32 0 90 0" //team 1 spawns + "3" "-9128 8040 32 0 90 0" //team 1 spawns + "4" "-9256 8040 32 0 90 0" //team 1 spawns + "5" "-8744 9960 32 0 270 0" //team2 spawn + "6" "-8872 9960 32 0 270 0" //team2 spawn + "7" "-9128 9960 32 0 270 0" //team2 spawn + "8" "-9256 9960 32 0 270 0" //team2 spawn + "9" "-9000 9000 142 0" // Center intel spawn, for the start of a round. + "10" "-9000 9512 96 0" // Where the intel appears after player 1 dunks. + "11" "-9000 8488 96 0" // Where the intel appears after player 1 dunks. + "12" "-9000 8203.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-9000 9796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 7 (2v2)" + { + "1" "-128 -9960 32 0 90 0" //team 1 spawns + "2" "-256 -9960 32 0 90 0" //team 1 spawns + "3" "128 -9960 32 0 90 0" //team 1 spawns + "4" "256 -9960 32 0 90 0" //team 1 spawns + "5" "-128 -8040 32 0 270 0" //team2 spawn + "6" "-256 -8040 32 0 270 0" //team2 spawn + "7" "128 -8040 32 0 270 0" //team2 spawn + "8" "256 -8040 32 0 270 0" //team2 spawn + "9" "0 -9000 142 0" // Center intel spawn, for the start of a round. + "10" "0 -8488 96 0" // Where the intel appears after player 1 dunks. + "11" "0 -9512 96 0" // Where the intel appears after player 1 dunks. + "12" "0 -9796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "0 -8203.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 8 (2v2)" + { + "1" "8744 -9960 32 0 90 0" //team 1 spawns + "2" "8872 -9960 32 0 90 0" //team 1 spawns + "3" "9128 -9960 32 0 90 0" //team 1 spawns + "4" "9256 -9960 32 0 90 0" //team 1 spawns + "5" "8744 -8040 32 0 270 0" //team2 spawn + "6" "8872 -8040 32 0 270 0" //team2 spawn + "7" "9128 -8040 32 0 270 0" //team2 spawn + "8" "9256 -8040 32 0 270 0" //team2 spawn + "9" "9000 -9000 142 0" // Center intel spawn, for the start of a round. + "10" "9000 -8488 96 0" // Where the intel appears after player 1 dunks. + "11" "9000 -9512 96 0" // Where the intel appears after player 1 dunks. + "12" "9000 -9796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "9000 -8203.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 9 (2v2)" + { + "1" "-8744 -9960 32 0 90 0" //team 1 spawns + "2" "-8872 -9960 32 0 90 0" //team 1 spawns + "3" "-9128 -9960 32 0 90 0" //team 1 spawns + "4" "-9256 -9960 32 0 90 0" //team 1 spawns + "5" "-8744 -8040 32 0 270 0" //team2 spawn + "6" "-8872 -8040 32 0 270 0" //team2 spawn + "7" "-9128 -8040 32 0 270 0" //team2 spawn + "8" "-9256 -8040 32 0 270 0" //team2 spawn + "9" "-9000 -9000 142 0" // Center intel spawn, for the start of a round. + "10" "-9000 -8488 96 0" // Where the intel appears after player 1 dunks. + "11" "-9000 -9512 96 0" // Where the intel appears after player 1 dunks. + "12" "-9000 -9796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-9000 -8203.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + "mge_oihguv_sucks_a12" + { + "Height Advantage" + { + "1" "-873.309937 -9505.487305 -1227 0 -135 0" + "2" "-1735.685059 -10374.450195 -1227 0 45 0" + "fraglimit" "5" + "cdtime" "3" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "showhp" "1" + "ammomod" "1" + "infammo" "1" + "4player" "0" + } + "8) 2ez" + { + "1" "800.796814 -10975.446289 -1728.968750 -0.891035 90.441719 0.000000" + "2" "-30.374973 -10143.489258 -1728.968750 -0.924022 -0.209289 0.000000" + "3" "804.776306 -9280.537109 -1728.968750 0.560966 -90.761658 0.000000" + "4" "1663.570313 -10144.500977 -1728.968750 -1.254011 -179.993591 0.000000" + "5" "786.352600 -10144.899414 -1627.968628 2.905230 0.848901 0.000000" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "koth" "1" + "4player" "0" + "Timer" "120" + } + "8)" + { + "1" "-1390.326904 -6298.315430 -1725 0 -45 0" + "2" "383.515747 -6267.929199 -1725 0 -135 0" + "3" "405.986176 -8080.430176 -1725 0 135 0" + "4" "-1412.171753 -8047.813477 -1725 0 45 0" + "fraglimit" "20" + "cdtime" "3" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "showhp" "1" + "mge" "1" + "mindist" "550" + "infammo" "0" + "4player" "0" + } + "Blands Mid" + { + "1" "2900.626953 -5742.559082 778 0 0 0" //left of blu train + "2" "2533.993408 -5903.314941 778 0 0 0" //back of blu train + "3" "2885.988770 -6059.058594 778 0 0 0" //right of blu train + "4" "2896.451416 -6284.223633 760 0 37.633713 0" //blu house exit + "5" "3482.823730 -6786.180664 770 0 90 0" //blu balcony + "6" "4054.755615 -6057.953613 778 0 180 0" //left of red train + "7" "4336.721680 -5901.596680 778 0 180 0" //back of red train + "8" "4064.069336 -5757.403320 778 0 180 0" //right of red train + "9" "3980.436035 -5522.731934 761 0 -143.672012 0" //red house exit + "10" "3365.520996 -4992.046875 770 0 -90 0" //red balcony + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Spire" + { + "1" "2769.343506 -2459.627197 613 0 90 0" //pride rock + "2" "1979.489502 -1788.810181 354 -30 19 0" //gray bridge + "3" "2044.491333 -1180.353394 354 -29 -42 0" //front door + "4" "2559.648193 -915.454102 610 0 -90 0" //battlements + "5" "2450.895752 -1808.680298 550 0 90 0" //pill + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "4player" "0" + } + "Spire Again" + { + "1" "5756.836914 -2496.402832 612.528015 0 90 0.000000" //pride rock + "2" "5027.334473 -1866.687988 356.003693 -17.215183 23.920334 0.000000" //gray bridge + "3" "5022.126465 -1277.570190 356.031311 -16.830212 -37.514668 0.000000" //front door + "4" "5528.168945 -978.129822 612.031311 0 -90 0.000000" //battlements + "5" "5404.636230 -1806.472656 551.363342 0 90 0" //pill + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "4player" "0" + } + "Viaduct Mid" + { + "1" "6481.683594 -6230.021484 561.031311 2.730096 29.322062 0.000000" + "2" "6927.344727 -6434.062500 454.821594 -1.870117 83.925957 0.000000" + "3" "7425.377930 -6451.493652 513.832031 2.505701 101.990303 0.000000" + "4" "7470.322266 -5224.172363 505.230042 1.982109 -120.826607 0.000000" + "5" "6890.553711 -5341.143555 472.806030 -0.486294 -83.202339 0.000000" + "6" "6477.710449 -5484.271484 561.031311 4.899300 -28.822889 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Gran Mid" + { + "1" "5504.005371 -9082.657227 209.031311 0 -135 0" + "2" "4960.655762 -8976.870117 209.031311 0 -90 0" + "3" "4370.888184 -9127.026367 209.031311 0 -45 0" + "4" "3817.526123 -9517.050781 209.031311 0 0 0" + "5" "3779.989502 -10219.092773 209.031311 0 45 0" + "6" "4330.944824 -10243.580078 209.031311 0 90 0" + "7" "4916.598145 -10155.872070 209.031311 0 135 0" + "8" "5409.224121 -9736.402344 209.031311 0 180 0" + "fraglimit" "20" + "cdtime" "3" + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Gully Mid" + { + "1" "8550.310547 1390.721191 213.818436 -3.465037 -7.661868 0.000000" + "2" "8591.301758 835.796265 207.622833 -3.234060 0.852090 0.000000" + "3" "9002.867188 288.417664 445.031311 5.510953 90.747078 0.000000" + "4" "9518.852539 890.297424 192.110519 -8.612938 179.550247 0.000000" + "5" "9554.975586 1475.360840 205.252594 -8.018939 -179.624741 0.000000" + "6" "9143.195313 1968.748657 445.031311 3.366059 -89.072929 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Snake Mid" + { + "1" "8333.794922 -851.806458 474.451691 5.972856 -77.090782 0.000000" + "2" "8304.668945 -1334.017944 309.156494 -0.528143 -46.499901 0.000000" + "3" "8225.913086 -1790.774048 332.358002 1.517858 -1.454873 0.000000" + "4" "8141.102539 -2331.468506 418.988007 0.989858 27.519142 0.000000" + "5" "9564.053711 -2810.747314 471.873718 6.764846 104.574005 0.000000" + "6" "9533.014648 -2326.674805 308.051758 0.725847 132.524902 0.000000" + "7" "9667.199219 -1844.093506 328.233398 0.494848 177.075134 0.000000" + "8" "9716.423828 -1337.320190 418.988007 2.309848 -152.267883 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "0" + } + "Amphi" + { + "1" "-6880.188965 -1776.092896 404.031311 0 44.843876 0.000000" + "2" "-6828.701172 -351.019073 404.031311 0 -44.784237 0.000000" + "3" "-5434.201660 -322.879181 404.031311 0 -134.940338 0.000000" + "4" "-5436.924805 -1726.196045 404.031311 0 134.969666 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "0" + } + "(8" + { + "1" "-928.789246 -13491.996094 -1646.968750 3.398727 43.690529 0.000000" + "2" "-982.225220 -12014.620117 -1646.968750 4.553785 -40.888451 0.000000" + "3" "523.759460 -12225.052734 -1598.968750 8.217022 -131.506912 0.000000" + "4" "269.176544 -13398.360352 -1646.968750 9.075096 133.882141 0.000000" + "5" "-158.731918 -13459.017578 -1726.968750 6.732187 91.015221 0.000000" + "6" "-754.902222 -12958.593750 -1646.968750 6.864232 12.343256 0.000000" + "7" "-481.724823 -12254.785156 -1646.968750 3.069260 -62.467827 0.000000" + "8" "659.328369 -12660.296875 -1646.968750 9.108348 -169.981674 0.000000" + "fraglimit" "20" + "cdtime" "3" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.25" + "showhp" "1" + "mge" "1" + "mindist" "550" + "infammo" "0" + "4player" "0" + } + "Endif" + { + "1" "-1639.748291 430.628021 457.559875 1.253807 -88.828598 0.000000" + "2" "-1182.447876 97.574333 439.422577 0.279786 -178.631668 0.000000" + "3" "-1567.934326 -374.877106 439.828400 0.207629 90.807503 0.000000" + "4" "-1968.742920 40.668037 470.228607 1.939476 0.102337 0.000000" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Counterjump" + { + "1" "-8226.124023 -5597.952637 -1726.968750 0 135 0" + "2" "-9251.655273 -5600.906738 -1726.968750 0 45 0" + "3" "-9258.193359 -4568.868164 -1726.968750 0 -45 0" + "4" "-8237.867188 -4580.630859 -1726.968750 0 -135 0" + "fraglimit" "10" + "cdtime" "0" + "classes" "soldier" + "hpratio" "2.5" + "showhp" "1" + "mge" "1" + "mindist" "100" + "infammo" "1" + "4player" "0" + } + "Counterjump Gran" + { + "1" "5239.196777 -12982.215820 -1686.958252 -0.860130 153.514709 0.000000" + "2" "4637.408203 -13442.159180 -1723.968628 0.411423 89.610344 0.000000" + "3" "4169.733887 -13091.726563 -1683.958130 4.263623 50.889320 0.000000" + "4" "4009.031494 -12455.100586 -1683.958130 2.805026 -38.459381 0.000000" + "5" "4648.108398 -12006.251953 -1723.968628 1.346431 -91.978500 0.000000" + "6" "5123.058594 -12326.029297 -1683.958130 0.299234 -133.903809 0.000000" + "fraglimit" "10" + "cdtime" "0" + "classes" "soldier" + "hpratio" "2.5" + "showhp" "1" + "mge" "1" + "mindist" "100" + "infammo" "1" + "4player" "0" + } + "Counterjump Ringout" + { + "1" "-4606.921387 -5623.304199 -1726.968750 0 135 0" + "2" "-5611.715332 -5615.364258 -1726.968750 0 45 0" + "3" "-5639.965820 -4603.966797 -1726.968750 0 -45 0" + "4" "-4603.087891 -4602.770996 -1726.968750 0 -135 0" + "fraglimit" "10" + "cdtime" "0" + "classes" "soldier" + "hpratio" "100" + "showhp" "1" + "mge" "1" + "mindist" "100" + "infammo" "1" + "4player" "0" + } + "Jump Castle" + { + "1" "663.074707 -4907.820801 -650 0 90 0" + "2" "8.201495 -4309.766113 -650 0 0 0" + "3" "645.230408 -3694.851074 -650 0 -90 0" + "4" "1307.208862 -4281.333496 -650 0 180 0" + "fraglimit" "5" + "cdtime" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "endif" "1" + "infammo" "1" + "4player" "0" + } + "Spiremod" + { + "1" "-42.024635 -463.800964 758.994385 0.164877 -69.860649 0.000000" + "2" "18.418732 -659.530518 758.994385 2.672882 110.319267 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Ammomod" + { + "1" "-1620.981201 -2861.676270 129.031311 0 90 0.000000" + "2" "-1611.113403 -2098.115234 129.031311 0 -90 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "OG Ammomod" + { + "1" "-2822.900635 -2811.483887 161.031311 -1.335494 89.539223 0.000000" + "2" "-2815.024658 -2085.616943 161.031311 -0.758235 -89.850525 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Ammomod [MGE]" + { + "1" "-1612.457275 -1533.337646 129.031311 0 90 0.000000" + "2" "-1990.188354 -1180.642822 129.031311 0 0 0.000000" + "3" "-1614.766846 -777.056030 129.031311 0 -90 0.000000" + "4" "-1206.005737 -1177.616089 129.031311 0 -180 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "0" + } + "OG Ammomod [MGE]" + { + "1" "-2817.488770 -1567.891846 161.031311 -0.117550 90.110321 0.000000" + "2" "-3180.838135 -1273.708130 161.031311 0.279339 -0.342204 0.000000" + "3" "-2820.722900 -916.671143 161.031311 0.567982 -88.810287 0.000000" + "4" "-2462.133545 -1279.667358 161.031311 -0.009295 179.907516 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "0" + } + "No Splash" + { + "1" "494.636169 -2824.535889 132.031311 0.436058 88.996269 0.000000" + "2" "512.597168 -2263.206787 132.031311 1.707661 -90.286880 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "powowwV" + { + "1" "-1594.710083 1852.771118 -50 1.319916 -90.577667 0.000000" + "2" "-1598.351074 860.989136 -50 0.923914 89.668480 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "0" + } + "Amphi 2v2" + { + "1" "-9427.330078 -309.098053 404.031311 0 -44.255997 0.000000" + "2" "-7910.303711 -237.436615 404.031311 0 -134.873459 0.000000" + "3" "-7991.344238 -1747.776733 404.031311 0 132.726334 0.000000" + "4" "-9475.584961 -1795.090454 404.031311 0 44.844284 0.000000" + "fraglimit" "20" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "1" + } + "Counterjump 2v2" + { + "1" "-8232.066406 -9179.555664 -1726.968750 0 135 0" + "2" "-9260.887695 -9189.034180 -1726.968750 0 45 0" + "3" "-9240.204102 -8168.028320 -1726.968750 0 -45 0" + "4" "-8224.851563 -8159.415527 -1726.968750 0 -135 0" + "fraglimit" "10" + "cdtime" "0" + "classes" "soldier" + "hpratio" "2.5" + "showhp" "1" + "mge" "1" + "mindist" "100" + "infammo" "1" + "4player" "1" + } + "Counterjump Ringout 2v2" + { + "1" "-4623.987793 -9165.198242 -1726.968750 0 135 0" + "2" "-5645.717285 -9195.712891 -1726.968750 0 45 0" + "3" "-5631.333008 -8162.409180 -1726.968750 0 -45 0" + "4" "-4611.345215 -8158.451660 -1726.968750 0 -135 0" + "fraglimit" "10" + "cdtime" "0" + "classes" "soldier" + "hpratio" "100" + "showhp" "1" + "mge" "1" + "mindist" "100" + "infammo" "1" + "4player" "1" + } + "Jump Castle 2v2" + { + "1" "-1193.818359 -4932.302734 -650 0 90 0" + "2" "-1876.097290 -4293.671387 -650 0 0 0" + "3" "-1237.496338 -3649.917725 -650 0 -90 0" + "4" "-503.711761 -4291.670410 -650 0 -180 0" + "fraglimit" "5" + "cdtime" "0" + "classes" "soldier demoman scout spy medic engineer sniper pyro heavy" + "hpratio" "1" + "endif" "1" + "infammo" "1" + "4player" "1" + } + } +} diff --git a/configs/mgemod_spawns_2v2.cfg b/configs/mgemod_spawns_2v2.cfg new file mode 100644 index 0000000..db3dd3f --- /dev/null +++ b/configs/mgemod_spawns_2v2.cfg @@ -0,0 +1,4154 @@ +// "map_name" +// { +// "arena_name" +// { +// "1" "X Y Z yaw" // Spawn points. +// "2" "X Y Z yaw" // Spawn points. +// //optional +// "fraglimit" "3" // Fraglimit, for BBall, this is the capture limit. +// "maxrating" "2000" // Max ELO Rating of players allowed to join this arena. +// "minrating" "1500" // Min ELO Rating of players allowed to join this arena. +// "cdtime" "3" // Time before round starts (when players can't shoot) +// "classes" "scout soldier pyro demoman heavy engineer medic sniper spy" // Allowed classes for this arena. if player's class not allowed then player will be switched to first allowed class +// "hpratio" "1.5" // How much of a buff players should get in this arena. 1.0=normal hp, 1.5 = full buff, any floating point value is accepted. +// "earlyleave" "0" // When a player leaves an arena early, if they have less points than their opponent AND their opponent has more points than this value, the leaver loses rating. +// "vishoop" "0" // Set to 1 to make the BBall hoop entities visible. Useful when adding spawns to a new arena. Only applies to BBall arenas. +// "infammo" "1" // enable(1)/disable(0) infinite ammo for this arena +// "mindist" "100" // Minimum distance a player's foe must be away from a spawn point for a player to spawn there. Measured in Hammer units. +// "respawntime" "0.1" // for gamemodes with respawning, this controls the respawn length +// "4player" "0" // enable(1)/disable(0) 4 player arenas +// "ultiduo" "0" // enable(1)/disable(0) makes arena only have 1 of each class (soldier/medic) +// "turris" "0" // enable(1)/disable(0) Regens the arena every 5 seconds like actual turris +// "koth" "0" // enable(1)/disable(0) Koth mode for this arena +// "Timer" "180" // Sets the default start timer in koth mode, defauly is 180 or 3 minutes +// //Only enable ONE of the following +// "ammomod" "1" // enable(1)/disable(0) original Ammomod gameplay for this arena +// "midair" "0" // enable(1)/disable(0) midairmod for this arena +// "mge" "0" // enable(1)/disable(0) MGE Training mode for this arena +// "bball" "0" // enable(1)/disable(0) BBall for this arena +// "endif" "0" // enable(1)/disable(0) Endif for this arena +// } +// } +// MAX 15 ARENAS PER MAP! +// MAX 15 SPAWNS PER ARENA! + + +SpawnConfigs +{ + "duels_midair_v2" + { + "[Midair] Turris 1" + { + "1" "412 -4677 -1260 -45" + "2" "1446 -5700 -1260 135" + "midair" "1" + "cdtime" "0" + } + "[Midair] Turris 2" + { + "1" "-458 -5905 -1395 135" + "2" "-1467 -4885 -1395 -45" + "midair" "1" + "cdtime" "0" + } + "[Midair] Regular 1" + { + "1" "-2930.36 -5053.19 -1268 -89.20" + "2" "-2906.53 -5913.81 -1268 91.95" + "midair" "1" + } + "[Midair] Regular 2" + { + "1" "-4725.75 -4973.90 -1222 -88.67" + "2" "-4698.87 -5840 -1222 91.91" + "midair" "1" + } + "[Midair] Granary Mid 1" + { + "1" "3352.93 -5092.18 -976 -148.51" + "2" "2400.47 -5849.33 -976 37.13" + "midair" "1" + } + "[Midair] Granary Mid 2" + { + "1" "7337.31 -5091.22 -976 -143.26" + "2" "6414.14 -5852.94 -976 38.12" + "midair" "1" + } + } + "am_variety_test3" + { + "Regular 1" + { + "1" "-1412.276733 -1676.996460 -1223.027344 -90" + "2" "-1431.968018 -2557.931641 -1223.027344 90" + "fraglimit" "2" + "hpratio" "6" + "ammomod" "1" + } + "Regular 2 (1725+ only)" + { + "1" "-2786.840088 -1626.397095 -1223.027344 -91.151024" + "2" "-2805.131348 -2531.600342 -1223.027344 89.745850" + "fraglimit" "4" + "minrating" "1725" + "hpratio" "4" + "hpratio" "6" + "ammomod" "1" + } + "Oldschool" + { + "1" "8277.875977 -1509.120117 -2191.968750 -86.681198" + "2" "8529.970703 -2510.064453 -2191.968750 91.784729" + "fraglimit" "5" + "hpratio" "1.5" + "ammomod" "1" + } + "No Splash" + { + "1" "5009.058594 -379.998749 -1267.027344 -29.655741" + "2" "5761.857910 -814.545288 -1267.027344 149.702255" + "fraglimit" "1" + "classes" "soldier demoman" + "hpratio" "6" + "ammomod" "1" + } + "Endif 1" + { + "1" "5681.151855 -4871.657715 -950 90" + "2" "5449.007813 -4585.144531 -950 0" + "3" "5754.729492 -4406.645996 -950 -90" + "4" "5998.674316 -4629.772949 -950 180" + "classes" "soldier demoman" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Endif 2" + { + "1" "8818.646484 -4598.492676 -950 0" + "2" "9162.908203 -4290.289063 -950 -90" + "3" "9349.802734 -4611.180664 -950 -180" + "4" "9045.556641 -4915.236816 -950 90" + "classes" "soldier demoman" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Badlands mid" + { + "1" "-5040.179688 -2122.799561 -593.512329 -0.159478" + "2" "-4543.730469 -2122.498535 -593.512329 -179.966309" + "hpratio" "6" + "ammomod" "1" + } + "Gravelpit C" + { + "1" "379.828766 -2636.744385 -896.750732 89.007950" + "2" "377.990967 -1395.398071 -896.750732 -89.520828" + "hpratio" "6" + "ammomod" "1" + } + "Badlands spire" + { + "1" "1771.468994 -7269.258301 -675.576965 103.115448" + "2" "1420.005005 -5716.803223 -678.373718 -81.142761" + "hpratio" "6" + "ammomod" "1" + } + "Granary mid" + { + "1" "3188.463867 -1938.652710 -1244.027344 1.062489" + "2" "3656.447266 -1925.876343 -1244.027344 -179.130829" + "hpratio" "6" + "ammomod" "1" + } + } + "am_variety_test10" + { + "Regular 1" + { + "1" "-5069.770020 2534.885742 -1544.027344 -90" + "2" "-5061.914063 1567.021484 -1544.027344 90" + "fraglimit" "2" + "hpratio" "6" + "ammomod" "1" + } + "Regular 2" + { + "1" "-180.343384 2747.968750 -1544.027344 -91.151024" + "2" "-172.520660 1736.391113 -1544.027344 89.745850" + "fraglimit" "3" + "hpratio" "6" + "ammomod" "1" + } + "Oldschool" + { + "1" "8277.875977 -1509.120117 -2191.968750 -86.681198" + "2" "8529.970703 -2510.064453 -2191.968750 91.784729" + "fraglimit" "5" + "hpratio" "1.5" + } + "Directs" + { + "1" "3470.873535 -1429.757568 -1559.287354 180" + "2" "2533.883545 -1420.801758 -1559.287354 180" + "fraglimit" "1" + "classes" "soldier demoman" + "hpratio" "6" + "ammomod" "1" + } + "Endif 1" + { + "1" "5681.151855 -4871.657715 -950 90" + "2" "5449.007813 -4585.144531 -950 0" + "3" "5754.729492 -4406.645996 -950 -90" + "4" "5998.674316 -4629.772949 -950 180" + "classes" "soldier demoman" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Endif 2" + { + "1" "8818.646484 -4598.492676 -950 0" + "2" "9162.908203 -4290.289063 -950 -90" + "3" "9349.802734 -4611.180664 -950 -180" + "4" "9045.556641 -4915.236816 -950 90" + "classes" "soldier demoman" + "cdtime" "0" + "endif" "1" + "fraglimit" "5" + "hpratio" "1" + } + "Badlands mid" + { + "1" "-2367.562256 -2117.650635 -530.027405 0.343550" + "2" "-1752.006714 -2124.842041 -530.027405 179.224030" + "hpratio" "6" + "ammomod" "1" + } + "Gravelpit C" + { + "1" "379.828766 -2636.744385 -896.750732 89.007950" + "2" "377.990967 -1395.398071 -896.750732 -89.520828" + "hpratio" "6" + "ammomod" "1" + } + "Badlands spire" + { + "1" "1771.468994 -7269.258301 -675.576965 103.115448" + "2" "1420.005005 -5716.803223 -678.373718 -81.142761" + "hpratio" "6" + "ammomod" "1" + } + "Granary mid" + { + "1" "4975.793457 1018.314026 -1333.367432 -0.935107" + "2" "5313.360840 1013.421875 -1333.366943 179.130829" + "hpratio" "6" + "ammomod" "1" + } + } + "mge_training_pro" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "1" + "infammo" "1" + "showhp" "0" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Coldfront Middle" + { + "1" "6383.006836 4912.959961 -47.567116 -0.128536 -20.806692 0.000000" + "2" "6571.136719 4238.881836 -102.968887 -1.758723 42.342129 0.000000" + "3" "7151.087891 4204.558105 -86.855179 -2.359316 98.069260 0.000000" + "4" "7703.587402 4492.280273 -48.149124 -2.488018 155.555603 0.000000" + "5" "7589.781738 5170.391113 -92.138184 -0.600406 -128.339890 0.000000" + "6" "6952.505371 4839.285156 -38.483078 3.389303 -41.724876 0.000000" + "7" "7210.519043 4569.479492 -33.211716 2.145200 135.821335 0.000000" + "8" "7095.079102 5243.062988 -84.583145 -0.471705 -91.660759 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Yukon Second" + { + "1" "8823.489258 -1957.666992 -1447.837402 -2.231640 -126.732574 0.000000" + "2" "8952.040039 -2644.574463 -1250.551025 0.556859 179.513977 0.000000" + "3" "9024.213867 -3205.805664 -1144.053467 -0.815941 138.501602 0.000000" + "4" "8590.097656 -3109.852051 -1426.759277 -0.429834 125.073608 0.000000" + "5" "8153.355469 -3319.900391 -1427.627197 0.942963 118.638748 0.000000" + "6" "7799.316406 -2620.197266 -1250.560303 0.042063 0.277563 0.000000" + "7" "7923.224121 -1888.819214 -1458.079102 -1.159136 -42.579590 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + } + "mge_training_proA" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "1" + "infammo" "1" + "showhp" "0" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Coldfront Middle" + { + "1" "6383.006836 4912.959961 -47.567116 -0.128536 -20.806692 0.000000" + "2" "6571.136719 4238.881836 -102.968887 -1.758723 42.342129 0.000000" + "3" "7151.087891 4204.558105 -86.855179 -2.359316 98.069260 0.000000" + "4" "7703.587402 4492.280273 -48.149124 -2.488018 155.555603 0.000000" + "5" "7589.781738 5170.391113 -92.138184 -0.600406 -128.339890 0.000000" + "6" "6952.505371 4839.285156 -38.483078 3.389303 -41.724876 0.000000" + "7" "7210.519043 4569.479492 -33.211716 2.145200 135.821335 0.000000" + "8" "7095.079102 5243.062988 -84.583145 -0.471705 -91.660759 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Yukon Second" + { + "1" "8823.489258 -1957.666992 -1447.837402 -2.231640 -126.732574 0.000000" + "2" "8952.040039 -2644.574463 -1250.551025 0.556859 179.513977 0.000000" + "3" "9024.213867 -3205.805664 -1144.053467 -0.815941 138.501602 0.000000" + "4" "8590.097656 -3109.852051 -1426.759277 -0.429834 125.073608 0.000000" + "5" "8153.355469 -3319.900391 -1427.627197 0.942963 118.638748 0.000000" + "6" "7799.316406 -2620.197266 -1250.560303 0.042063 0.277563 0.000000" + "7" "7923.224121 -1888.819214 -1458.079102 -1.159136 -42.579590 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + } + "mge_training_v2" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "Coldfront Middle" + { + "1" "6383.006836 4912.959961 -47.567116 -0.128536 -20.806692 0.000000" + "2" "6571.136719 4238.881836 -102.968887 -1.758723 42.342129 0.000000" + "3" "7151.087891 4204.558105 -86.855179 -2.359316 98.069260 0.000000" + "4" "7703.587402 4492.280273 -48.149124 -2.488018 155.555603 0.000000" + "5" "7589.781738 5170.391113 -92.138184 -0.600406 -128.339890 0.000000" + "6" "6952.505371 4839.285156 -38.483078 3.389303 -41.724876 0.000000" + "7" "7210.519043 4569.479492 -33.211716 2.145200 135.821335 0.000000" + "8" "7095.079102 5243.062988 -84.583145 -0.471705 -91.660759 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + } + "BBall 1" + { + "1" "9663.772461 -2552.907959 -864.665344 -0.943803 -89.858566 0.000000" // Player 1 spawns + "2" "9927.164063 -2552.254883 -864.665344 -0.943803 -89.858566 0.000000" // '' + "3" "10140.030273 -2551.727539 -864.665344 -0.986703 -89.858566 0.000000" // '' + "4" "10404.137695 -2568.479736 -864.665344 -0.858001 -90.287567 0.000000" // '' + "5" "10410.448242 -4457.441406 -864.665344 -0.986704 90.647774 0.000000" // Player 2 spawns + "6" "10148.243164 -4460.408691 -864.665344 -1.458604 90.647774 0.000000" // '' + "7" "9929.341797 -4460.158691 -864.665344 -1.630204 90.090073 0.000000" // '' + "8" "9664.025391 -4460.571289 -864.665344 -1.630204 90.090073 0.000000" // '' + "9" "10034.460938 -3514.353760 -880 0 0 0" // Center intel spawn, for the start of a round. + "10" "10036.291016 -4030.868408 -880 0 0 0" // Where the intel appears after player 1 dunks. + "11" "10035.222656 -2986.938965 -880 0 0 0" // Where the intel appears after player 2 dunks. + "12" "10036.189453 -2714 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "10035.548828 -4303 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + "BBall 2" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -880 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -880 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -880 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4270 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2676 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v3" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "mindist" "200" + "ammomod" "1" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v4" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v4_fixed" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ashville Middle" + { + "1" "-9409.163086 -4519.055176 70.888306 2.016346 87.507294 0.000000" + "2" "-9943.433594 -4323.051270 -87.744507 -1.072440 56.259048 0.000000" + "3" "-9574.945313 -4261.616211 -77.192474 -0.600541 89.763962 0.000000" + "4" "-9073.233398 -4361.253418 -89.281036 -1.201142 144.118057 0.000000" + "5" "-10442.394531 -4274.557129 -19.111732 1.844760 21.123554 0.000000" + "6" "-9800.135742 -3300.248047 70.888306 2.402466 -88.914932 0.000000" + "7" "-10095.650391 -3523.648193 -82.351517 -0.214415 -41.338997 0.000000" + "8" "-9600.838867 -3495.187988 -81.923584 -0.128616 -89.129623 0.000000" + "9" "-9220.366211 -3579.548340 -85.895798 -0.042806 -126.109406 0.000000" + "10" "-8751.975586 -3581.698730 -19.111732 2.574093 -160.472382 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v5" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "10" "3304.342773 -9000.506836 -622.149353 -1.115262 -159.314911 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Snakewater Middle" + { + "1" "-9471 -1415 -756 180" + "2" "-11434 -1361 -756 -0" + "3" "-9740 -1886 -751 121" + "4" "-11185 -885 -752 -62" + "5" "-10448 -1838 -668 90" + "6" "-10453 -931 -668 -90" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + } + "BBall" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -875 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -875 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "5" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "1.25" + } + } + "mge_training_v7" + { + "Viaduct Middle" + { + "1" "7601.548340 11904.446289 -219.047333 -0.428825 179.819794 0.000000" + "2" "7579.247559 12204.311523 -219.047333 -1.415522 -179.579834 0.000000" + "3" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "4" "7132.458496 12747.166992 -317.409119 -2.702507 -89.404037 0.000000" + "5" "6609.057129 12418.530273 -203.047333 -0.171390 -25.955128 0.000000" + "6" "6659.044434 12156.637695 -203.047333 0.901120 0.814477 0.000000" + "7" "6655.788086 11924.690430 -203.047333 0.729523 -0.000734 0.000000" + "8" "6489.857422 11650.149414 -203.047333 0.944030 31.042061 0.000000" + "9" "7152.413574 11349.573242 -313.870483 -5.190666 90.415688 0.000000" + "10" "7476.770020 11511.439453 -238.875366 0.729535 121.904442 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" + "4" "-11357.441406 -13937.748047 -781.972351 0.125557 62.356293 0.000000" + "5" "-11011.691406 -14308.496094 -781.972351 1.283856 31.725655 0.000000" + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" + "9" "-10154.511719 -12793.357422 -781.972351 0.425842 -121.084824 0.000000" + "10" "-10488.816406 -12447.143555 -781.972351 0.168442 -151.329407 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" + "7" "2495.524902 -11252.045898 -821.359863 -1.029508 95.177322 0.000000" + "8" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" + "9" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Snakewater Middle" + { + "1" "-9471 -1415 -756 180" + "2" "-11434 -1361 -756 -0" + "3" "-9740 -1886 -751 121" + "4" "-11185 -885 -752 -62" + "5" "-10448 -1838 -668 90" + "6" "-10453 -931 -668 -90" + "7" "-9576 -879 -572 180" + "8" "-11333 -1895 -572 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "1" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "1" + } + "No Splash" + { + "1" "6862.301270 -3937.054199 -1515.530273 0 60 0" + "2" "7165.354980 -3413.613525 -1515.530273 0 -120 0" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "1" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + "4player" "1" + } + "BBall 1v1" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -850 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -850 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "koth_ultiduo_nologic" + { + "ultiduo" + { + "1" "-2512 1040 0 0 -90 0" //red team spawns + "2" "-2560 1040 0 0 -90 0" + "3" "-2608 1040 0 0 -90 0" + "4" "-2609 -1040 0 0 90 0" //Blu team spawns + "5" "-2513 -1040 0 0 90 0" + "6" "-2513 -1040 0 0 90 0" + "7" "-2567.787598 -7.029320 -228.567810 0 0 0" //spawn point pos + "fraglimit" "2" + "cdtime" "1" + "classes" "soldier medic" + "hpratio" "1" + "ammomod" "0" + "bball" "0" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "10.0" + "koth" "1" + "ultiduo" "1" + "4player" "1" + "turris" "0" + } + } + + + "mge_training_v8_beta4a" + { + "Viaduct Middle" + { + "1" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "2" "6418.329102 12404.434570 -202.985687 11.583488 -16.006359 0.000000" + "3" "6849.119141 12678.232422 -322.409607 5.346490 -68.278381 0.000000" + "4" "7534.082031 11372.428711 -269.931183 1.089500 133.915527 0.000000" + "5" "6957.675781 11432.859375 -318.533752 -0.923496 85.504501 0.000000" + "6" "6417.302734 11675.087891 -202.985687 3.069469 26.797421 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" //left of blu train + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" //back of blu train + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" //right of blu train + "4" "-11289 -13813 -852 17" //blu house exit + "5" "-10701 -14274 -846 90" //blu balcony + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" //left of red train + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" //back of red train + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" //right of red train + "9" "-10248 -12949 -854 -162" //red house exit + "10" "-10833 -12474 -846 -90" //red balcony + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" //pride rock + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" //gray bridge + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" //front door + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" //battlements + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" //bottom of spire + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" //bottom of pride + "7" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" //midlevel spire + "8" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" //pill + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "4player" "1" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "4player" "1" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Snakewater Middle" + { + "1" "-11434 -1361 -756 -0" + "2" "-11185 -885 -752 -62" + "3" "-11333 -1895 -572 0" + "4" "-11094.696289 -505.179871 -523.997437 7.128137 -80.694138 0.000000" + "5" "-9471 -1415 -756 180" + "6" "-9740 -1886 -751 121" + "7" "-9576 -879 -572 180" + "8" " -9818.991211 -2285.646484 -521.429626 8.052133 96.218925 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Gravelpit C" + { + "1" "5578 7625 58 -90" + "2" "5578 6474 58 90" + "3" "5118 7060 -108 0" + "4" "6506 6330 84 129" + "5" "6582 7637 84 -143" + "6" "6816 6949 180 176" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "300" + "4player" "1" + } + "Process Middle" + { + "1" "-3231 1221 -230 90" //BLU Sewer + "2" "-3240 3156 -230 -90" //RED Sewer + "3" "-2838 2784 -255 -124" //RED Rock + "4" "-3585 1640 -257 56" //BLU Rock + "5" "-2591 2218 -166 180" //RED Computer + "6" "-3870 2228 -166 0" //BLU Computer + "7" "-4066 2709 -198 0" //BLU Forward + "8" "-2400 1720 -180 160" //RED Forward + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Trainyard" + { + "1" "2063 1750 1208 0" + "2" "3883 2511 1208 179" + "3" "2154 3063 1208 -48" + "4" "3786 1192 1208 132" + "5" "3075 1635 1210 101" + "6" "2878 2605 1210 -75" + "7" "2498 2204 1210 -9" + "8" "3461 2024 1210 169" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Turris 1" + { + "1" "11863 6812 -520 135" + "2" "11665 6765 -520 136" + "3" "11926 6988 -520 132" + "4" "11329 7346 -520 -45" + "5" "11542 7379 -520 -44" + "6" "11285 7130 -520 -44" + "7" "11611.962891 7066.257324 -165.198700 0" // CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "11863 5512 -520 135" + "2" "11665 5465 -520 136" + "3" "11926 5688 -520 132" + "4" "11329 6046 -520 -45" + "5" "11542 6079 -520 -44" + "6" "11285 5830 -520 -44" + "7" "11608.865234 5792.714844 -165.198700 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "1" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "1" + } + "No Splash" + { + "1" "6862.301270 -3937.054199 -1515.530273 0 60 0" + "2" "7165.354980 -3413.613525 -1515.530273 0 -120 0" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "1" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + "4player" "1" + } + "BBall 2v2" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -850 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -850 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge2_test" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //BLU + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 45" //RED + "5" "840 -1950 -782 45" + "6" "640 -2150 -782 45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "1" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //BLU + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 45" //RED + "5" "840 -700 -782 45" + "6" "640 -900 -782 45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "BBall 1 (2v2)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_training_v8_beta4b" + { + "Viaduct Middle" + { + "1" "7462.735352 12617.682617 -244.979523 -1.286812 -125.869080 0.000000" + "2" "6418.329102 12404.434570 -202.985687 11.583488 -16.006359 0.000000" + "3" "6849.119141 12678.232422 -322.409607 5.346490 -68.278381 0.000000" + "4" "7534.082031 11372.428711 -269.931183 1.089500 133.915527 0.000000" + "5" "6957.675781 11432.859375 -318.533752 -0.923496 85.504501 0.000000" + "6" "6417.302734 11675.087891 -202.985687 3.069469 26.797421 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Granary Middle" + { + "1" "-10500.877930 9174.597656 -1596.560303 -0.085802 2.213739 0.000000" + "2" "-9790.553711 9171.893555 -1596.560303 0.729289 -179.339035 0.000000" + "3" "-10600.943359 8428.930664 -1628.560303 -1.544397 65.174164 0.000000" + "4" "-10142.636719 8675.520508 -1628.560303 -1.244103 90.382286 0.000000" + "5" "-10981.164063 8713.298828 -1628.560303 6.778175 18.841347 0.000000" + "6" "-9304.777344 8944.693359 -1628.560303 -1.072500 166.057846 0.000000" + "7" "-9371.643555 9702.720703 -1628.560303 -0.300283 -141.132233 0.000000" + "8" "-9735.581055 9844.334961 -1628.560303 -1.415702 -112.646744 0.000000" + "9" "-10241.205078 9725.969727 -1628.560303 -0.300301 -88.107880 0.000000" + "10" "-10985.475586 9397.042969 -1628.560303 -1.072495 -15.950445 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Granary Last" + { + "1" "-755.098633 13635.547852 -734.179199 3.089007 179.777359 0.000000" + "2" "-728.491516 12963.237305 -688.375977 2.488399 149.704483 0.000000" + "3" "-931.402039 13948.276367 -851.879456 -0.557448 -90.990547 0.000000" + "4" "-1564.665894 13701.014648 -876.626831 -0.085541 -41.569546 0.000000" + "5" "-1725.263550 13098.915039 -913.247803 -0.557447 11.883853 0.000000" + "6" "-876.588989 12787.411133 -886.884216 -1.501236 91.892326 0.000000" + "7" "-240.221924 12895.516602 -876.642761 0.944057 130.545212 0.000000" + "8" "-207.278275 13394.867188 -878.083130 0.214758 -179.047470 0.000000" + "9" "-285.157318 13857.316406 -880.729187 1.201464 -151.891724 0.000000" + "10" "-861.436096 13314.040039 -933.751038 -0.214227 -178.017761 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Badlands Middle" + { + "1" "-11686.038086 -13377.470703 -773.972351 -1.847847 0.065498 0.000000" //left of blu train + "2" "-11248.954102 -13521.552734 -773.972351 -0.174749 0.107838 0.000000" //back of blu train + "3" "-11192.996094 -13216.810547 -773.972351 0.382947 -0.663850 0.000000" //right of blu train + "4" "-11289 -13813 -852 17" //blu house exit + "5" "-10701 -14274 -846 90" //blu balcony + "6" "-10279.387695 -13526.661133 -773.972351 -0.346368 179.327744 0.000000" //left of red train + "7" "-9849.915039 -13380.535156 -773.572449 -1.547566 178.769791 0.000000" //back of red train + "8" "-10289.443359 -13229.824219 -773.972351 -0.174761 179.799072 0.000000" //right of red train + "9" "-10248 -12949 -854 -162" //red house exit + "10" "-10833 -12474 -846 -90" //red balcony + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Badlands Spire" + { + "1" "2433.757568 -9322.249023 -554.137817 0.815180 -81.381874 0.000000" //pride rock + "2" "3135.268555 -10005.759766 -814.149353 -4.461515 -158.730377 0.000000" //gray bridge + "3" "3175.294189 -10564.104492 -814.149353 -2.187812 137.048004 0.000000" //front door + "4" "2737.638184 -10791.839844 -558.149353 1.158377 87.626755 0.000000" //battlements + "5" "2011.138062 -10389.405273 -807.615112 -14.714617 34.902794 0.000000" //bottom of spire + "6" "2087.291504 -9721.594727 -812.644409 -14.929108 -37.340809 0.000000" //bottom of pride + "7" "2438.531982 -10378.755859 -674.019409 -45.516830 61.157566 0.000000" //midlevel spire + "8" "2823.546631 -10013.893555 -618.176208 -32.689671 -115.444809 0.000000" //pill + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "4player" "1" + } + "Gullywash Middle" + { + "1" "181.960205 -3669.378174 -495.685364 0.472025 161.319550 0.000000" + "2" "-299.259186 -4027.780518 -451.685364 0.986824 90.792053 0.000000" + "3" "-764.675476 -3947.147705 -451.685364 1.415822 55.442425 0.000000" + "4" "-1429.694092 -3306.507813 -580.685364 -0.557584 3.361782 0.000000" + "5" "-761.098999 -2923.945313 -685.009216 -8.365400 10.097102 0.000000" + "6" "-721.122925 -3437.863037 -691.561401 -16.344799 -2.086474 0.000000" + "7" "222.930923 -3291.988770 -687.844299 -12.698290 -171.395935 0.000000" + "8" "301.796661 -2857.531006 -675.072693 -11.625794 166.896912 0.000000" + "9" "862.233521 -2926.431885 -580.685364 0.429110 178.222382 0.000000" + "10" "183.221542 -2213.947998 -451.685364 1.716107 -121.588669 0.000000" + "11" "-210.607101 -2203.826416 -451.685364 0.858109 -91.644539 0.000000" + "12" "-792.099792 -2588.748779 -495.685364 -0.643392 -23.235617 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "4player" "1" + "mindist" "550" + } + "Waste Middle" + { + "1" "10780.262695 -11310.363281 -1306.570313 -0.643454 -41.887989 0.000000" + "2" "12203.897461 -13298.905273 -1306.570313 0.815232 138.232574 0.000000" + "3" "10768.610352 -13280.571289 -1482.570313 0.257548 45.782566 0.000000" + "4" "12164.866211 -11304.351563 -1482.570313 -1.630058 -130.777496 0.000000" + "5" "11444.488281 -13159.397461 -1678.431396 -0.128536 88.381653 0.000000" + "6" "11528.577148 -11344.557617 -1678.796387 1.072660 -90.108353 0.000000" + "7" "12207.083984 -12087.253906 -1292.570313 -1.243937 -136.079941 0.000000" + "8" "10758.924805 -12472.022461 -1290.570313 -1.630032 51.247665 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Snakewater Middle" + { + "1" "-11434 -1361 -756 -0" + "2" "-11185 -885 -752 -62" + "3" "-11333 -1895 -572 0" + "4" "-11094.696289 -505.179871 -523.997437 7.128137 -80.694138 0.000000" + "5" "-9471 -1415 -756 180" + "6" "-9740 -1886 -751 121" + "7" "-9576 -879 -572 180" + "8" " -9818.991211 -2285.646484 -521.429626 8.052133 96.218925 0.000000" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Gravelpit C" + { + "1" "5578 7625 58 -90" + "2" "5578 6474 58 90" + "3" "5118 7060 -108 0" + "4" "6506 6330 84 129" + "5" "6582 7637 84 -143" + "6" "6816 6949 180 176" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "300" + "4player" "1" + } + "Process Middle" + { + "1" "-3231 1221 -230 90" //BLU Sewer + "2" "-3240 3156 -230 -90" //RED Sewer + "3" "-2838 2784 -255 -124" //RED Rock + "4" "-3585 1640 -257 56" //BLU Rock + "5" "-2591 2218 -166 180" //RED Computer + "6" "-3870 2228 -166 0" //BLU Computer + "7" "-4066 2709 -198 0" //BLU Forward + "8" "-2400 1720 -180 160" //RED Forward + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Trainyard" + { + "1" "2063 1750 1208 0" + "2" "3883 2511 1208 179" + "3" "2154 3063 1208 -48" + "4" "3786 1192 1208 132" + "5" "3075 1635 1210 101" + "6" "2878 2605 1210 -75" + "7" "2498 2204 1210 -9" + "8" "3461 2024 1210 169" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "1" + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + } + "Turris 1" + { + "1" "11863 6812 -520 135" + "2" "11665 6765 -520 136" + "3" "11926 6988 -520 132" + "4" "11329 7346 -520 -45" + "5" "11542 7379 -520 -44" + "6" "11285 7130 -520 -44" + "7" "11611.962891 7066.257324 -165.198700 0" // CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "11863 5512 -520 135" + "2" "11665 5465 -520 136" + "3" "11926 5688 -520 132" + "4" "11329 6046 -520 -45" + "5" "11542 6079 -520 -44" + "6" "11285 5830 -520 -44" + "7" "11608.865234 5792.714844 -165.198700 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "Ammomod" + { + "1" "2374.901367 -5966.045898 -1395.980225 0.746808 -91.430145 0.000000" + "2" "1963.888062 -6362.004395 -1395.980225 0.403608 -0.010179 0.000000" + "3" "2359.500977 -6784.875977 -1395.980225 0.618107 89.221878 0.000000" + "4" "2783.858887 -6372.402344 -1395.980225 0.746808 178.710815 0.000000" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman scout" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "1" + } + "Ammomod [MGE]" + { + "1" "4038 -6775 -1460 90" + "2" "4470 -6353 -1460 180" + "3" "4038 -5946 -1460 -90" + "4" "3602 -6353 -1460 0" + "fraglimit" "20" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.5" + "earlyleave" "3" + "mge" "1" + "infammo" "0" + "showhp" "0" + "mindist" "200" + "4player" "1" + } + "No Splash" + { + "1" "6862.301270 -3937.054199 -1515.530273 0 60 0" + "2" "7165.354980 -3413.613525 -1515.530273 0 -120 0" + "fraglimit" "3" + "cdtime" "3" //time before round starts (when players cant shoot) + "mge" "0" + "classes" "soldier demoman" + "hpratio" "6" + "earlyleave" "0" + "infammo" "1" + "showhp" "1" + "ammomod" "1" + "mindist" "200" + "4player" "1" + } + "Endif" + { + "1" "-893.789490 -6358.934082 -450 0 180 0" + "2" "-1165.897583 -6062.639160 -450 0 -90 0" + "3" "-1167.762085 -6659.994629 -450 0 90 0" + "4" "-1504.839722 -6364.257813 -450 0 0 0" + "fraglimit" "5" + "cdtime" "0" //time before round starts (when players cant shoot) + "classes" "soldier demoman" + "hpratio" "1.0" + "endif" "1" + "earlyleave" "0" + "infammo" "1" + "showhp" "0" + "4player" "1" + } + "BBall 2v2" + { + "1" "13017.106445 -4427.000000 -861.662415 -1.304493 89.636497 0.000000" // Player 1 spawns + "2" "13279.293945 -4428.445313 -861.662415 -1.089993 90.580299 0.000000" // '' + "3" "13501.717773 -4426.184082 -861.662415 -1.089993 90.580299 0.000000" // '' + "4" "13757.980469 -4423.578613 -861.662415 -1.089993 90.580299 0.000000" // '' + "5" "13017.221680 -2496.139893 -861.662415 -1.261615 -89.754524 0.000000" // Player 2 spawns + "6" "13282.120117 -2495.007568 -861.662415 -1.261615 -89.754524 0.000000" // '' + "7" "13497.504883 -2494.087891 -861.662415 -1.261615 -89.754524 0.000000" // '' + "8" "13762.208984 -2492.956299 -861.662415 -1.261615 -89.754524 0.000000" // '' + "9" "13393.764648 -3474.881592 -800 0 0 0" // Center intel spawn, for the start of a round. + "10" "13391.996094 -2958.594238 -850 0 0 0" // Where the intel appears after player 1 dunks. + "11" "13388.965820 -3990.781250 -850 0 0 0" // Where the intel appears after player 2 dunks. + "12" "13390.275391 -4267 -793 0 0 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "13389.509766 -2679 -793 0 0 0" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + "mge2_test" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1.25" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //BLU + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 45" //RED + "5" "840 -1950 -782 45" + "6" "640 -2150 -782 45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "1" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //BLU + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 45" //RED + "5" "840 -700 -782 45" + "6" "640 -900 -782 45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "BBall 1 (2v2)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_dueling_v1" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //RED + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 -45" //BLU + "5" "840 -1950 -782 -45" + "6" "640 -2150 -782 -45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "1" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //RED + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 -45" //BLU + "5" "840 -700 -782 -45" + "6" "640 -900 -782 -45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "BBall 1 (1v1)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_dueling_v1_fix1" + { + "Ultiduo 1" + { + "1" "1393 5239 -288 -90" //RED + "2" "1441 5239 -288 -90" + "3" "1489 5239 -288 -90" + "4" "1393 5287 -288 -90" + "5" "1441 5287 -288 -90" + "6" "1489 5287 -288 -90" + "7" "1488 3159 -288 90" //BLU + "8" "1440 3159 -288 90" + "9" "1392 3159 -288 90" + "10" "1488 3111 -288 90" + "11" "1440 3111 -288 90" + "12" "1392 3111 -288 90" + "13" "1441 4201 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Ultiduo 2" + { + "1" "1383 2467 -288 -90"//RED + "2" "1431 2467 -288 -90" + "3" "1479 2467 -288 -90" + "4" "1383 2515 -288 -90" + "5" "1431 2515 -288 -90" + "6" "1479 2515 -288 -90" + "7" "1478 387 -288 90" //BLU + "8" "1430 387 -288 90" + "9" "1382 387 -288 90" + "10" "1478 339 -288 90" + "11" "1430 339 -288 90" + "12" "1382 339 -288 90" + "13" "1431 1429 -538 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier medic" + "hpratio" "1" + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "4player" "1" + "respawntime" "7.0" + "koth" "1" + "ultiduo" "1" + } + "Spireking 1" + { + "1" "-1226 5587 -428 -90" //A side + "2" "-1354 5587 -428 -90" + "3" "-1482 5587 -428 -90" + "4" "-1610 5587 -428 -90" + "5" "-1738 5587 -428 -90" + "6" "-1866 5587 -428 -90" + "7" "-1994 5587 -428 -90" + "8" "-1226 4179 -428 90" //B side + "9" "-1354 4179 -428 90" + "10" "-1482 4179 -428 90" + "11" "-1610 4179 -428 90" + "12" "-1738 4179 -428 90" + "13" "-1866 4179 -428 90" + "14" "-1994 4179 -428 90" + "15" "-1636 4819 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Spireking 2" + { + "1" "-1226 2346 -428 -90" //A side + "2" "-1354 2346 -428 -90" + "3" "-1482 2346 -428 -90" + "4" "-1610 2346 -428 -90" + "5" "-1738 2346 -428 -90" + "6" "-1866 2346 -428 -90" + "7" "-1994 2346 -428 -90" + "8" "-1226 938 -428 90" //B side + "9" "-1354 938 -428 90" + "10" "-1482 938 -428 90" + "11" "-1610 938 -428 90" + "12" "-1738 938 -428 90" + "13" "-1866 938 -428 90" + "14" "-1994 938 -428 90" + "15" "-1636 1578 26 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "4player" "1" + "koth" "1" + "turris" "1" + "Timer" "120" + } + "Turris 1" + { + "1" "1280 -2590 -782 135" //RED + "2" "1080 -2590 -782 135" + "3" "1280 -2390 -782 135" + "4" "640 -1950 -782 -45" //BLU + "5" "840 -1950 -782 -45" + "6" "640 -2150 -782 -45" + "7" "956 -2276 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "100" + "respawntime" "5.0" + "turris" "1" + "4player" "1" + "koth" "1" + "Timer" "120" + } + "Turris 2" + { + "1" "1280 -1310 -782 135" //RED + "2" "1080 -1310 -782 135" + "3" "1280 -1110 -782 135" + "4" "640 -700 -782 -45" //BLU + "5" "840 -700 -782 -45" + "6" "640 -900 -782 -45" + "7" "956 -1008 -507 0" //CAP + "fraglimit" "2" + "cdtime" "3" //time before round starts (when players cant shoot) + "classes" "soldier demoman scout sniper" + "hpratio" "1" + "earlyleave" "3" + "infammo" "0" + "showhp" "0" + "mindist" "550" + "respawntime" "5.0" + "turris" "1" + "koth" "1" + "4player" "1" + "Timer" "120" + } + "BBall 1 (1v1)" + { + "1" "-937.940063 -5687.088867 -228.693726 -0.099971 88.271400 0.000000" //team 1 spawns + "2" "-1382.175171 -5669.834473 -228.693726 -0.337577 90.013817 0.000000" //team 1 spawns + "3" "-1210.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "4" "-849.358276 -5689.939453 -228.693726 0.375201 90.532082 0.000000" //team 1 spawns + "5" "-1376.044189 -3785.735596 -228.693726 0.018803 -89.133324 0.000000" //team2 spawn + "6" "-1204.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "7" "-1004.210327 -3780.032471 -228.693726 0.216794 -91.232086 0.000000" //team2 spawn + "8" "-871.717834 -3794.541016 -228.693726 0.612794 -88.578850 0.000000" //team2 spawn + "9" "-1099 -4734 -150 0" // Center intel spawn, for the start of a round. + "10" "-1100.554688 -4216.206543 -228.693726 0" // Where the intel appears after player 1 dunks. + "11" "-1110.061279 -5248.967773 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "12" "-1098.989380 -5528.571289 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1098.777100 -3938.822510 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 2 (2v2)" + { + "1" "-1419.982300 -2505.699951 -228.693726 -0.277215 90.601242 0.000000" //team 1 spawns + "2" "-1211.553223 -2503.510010 -228.693726 -0.158375 90.878357 0.000000" //team 1 spawns + "3" "-1053.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "4" "-853.747009 -2498.325439 -228.693726 -0.039575 90.403183 0.000000" //team 1 spawns + "5" "-835.152405 -633.120850 -228.693726 0.533611 -89.615173 0.000000" //team2 spawn + "6" "-1063.000061 -633.979187 -228.693726 -0.139602 -89.417282 0.000000" //team2 spawn + "7" "-1226.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "8" "-1426.153564 -645.356750 -228.693726 0.058390 -90.090599 0.000000" //team2 spawn + "9" "-1099 -1581 -140 0" // Center intel spawn, for the start of a round. + "10" "-1100.073853 -1061.878296 -228.693726 0.000000" // Where the intel appears after player 1 dunks. + "11" "-1100.414795 -2085.041016 -228.693726 0.000000" // Where the intel appears after player 2 dunks. + "12" "-1099.184570 -2375.568848 -160.058678 0.000000" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-1099.980103 -785.572632 -160.058678 0.000000" // Hoop on player 2's side of the map that player 1 dunks into. + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } + + "mge_bball_v2" + { + "BBall 1 (1v1)" + { + "1" "-128 -960 32 0 90 0" //team 1 spawns + "2" "-256 -960 32 0 90 0" //team 1 spawns + "3" "128 -960 32 0 90 0" //team 1 spawns + "4" "256 -960 32 0 90 0" //team 1 spawns + "5" "-128 960 32 0 270 0" //team2 spawn + "6" "-256 960 32 0 270 0" //team2 spawn + "7" "128 960 32 0 270 0" //team2 spawn + "8" "256 960 32 0 270 0" //team2 spawn + "9" "0 0 142 0" // Center intel spawn, for the start of a round. + "10" "0 512 96 0" // Where the intel appears after player 1 dunks. + "11" "0 -512 96 0" // Where the intel appears after player 1 dunks. + "12" "0 -796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "0 796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 2 (1v1)" + { + "1" "8744 -960 32 0 90 0" //team 1 spawns + "2" "8872 -960 32 0 90 0" //team 1 spawns + "3" "9128 -960 32 0 90 0" //team 1 spawns + "4" "9256 -960 32 0 90 0" //team 1 spawns + "5" "8744 960 32 0 270 0" //team2 spawn + "6" "8872 960 32 0 270 0" //team2 spawn + "7" "9128 960 32 0 270 0" //team2 spawn + "8" "9256 960 32 0 270 0" //team2 spawn + "9" "9000 0 142 0" // Center intel spawn, for the start of a round. + "10" "9000 512 96 0" // Where the intel appears after player 1 dunks. + "11" "9000 -512 96 0" // Where the intel appears after player 1 dunks. + "12" "9000 -796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "9000 796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 3 (1v1)" + { + "1" "-8744 -960 32 0 90 0" //team 1 spawns + "2" "-8872 -960 32 0 90 0" //team 1 spawns + "3" "-9128 -960 32 0 90 0" //team 1 spawns + "4" "-9256 -960 32 0 90 0" //team 1 spawns + "5" "-8744 960 32 0 270 0" //team2 spawn + "6" "-8872 960 32 0 270 0" //team2 spawn + "7" "-9128 960 32 0 270 0" //team2 spawn + "8" "-9256 960 32 0 270 0" //team2 spawn + "9" "-9000 0 142 0" // Center intel spawn, for the start of a round. + "10" "-9000 512 96 0" // Where the intel appears after player 1 dunks. + "11" "-9000 -512 96 0" // Where the intel appears after player 1 dunks. + "12" "-9000 -796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-9000 796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 4 (2v2)" + { + "1" "-128 8040 32 0 90 0" //team 1 spawns + "2" "-256 8040 32 0 90 0" //team 1 spawns + "3" "128 8040 32 0 90 0" //team 1 spawns + "4" "256 8040 32 0 90 0" //team 1 spawns + "5" "-128 9960 32 0 270 0" //team2 spawn + "6" "-256 9960 32 0 270 0" //team2 spawn + "7" "128 9960 32 0 270 0" //team2 spawn + "8" "256 9960 32 0 270 0" //team2 spawn + "9" "0 9000 142 0" // Center intel spawn, for the start of a round. + "10" "0 9512 96 0" // Where the intel appears after player 1 dunks. + "11" "0 8488 96 0" // Where the intel appears after player 1 dunks. + "12" "0 8203.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "0 9796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 5 (2v2)" + { + "1" "8744 8040 32 0 90 0" //team 1 spawns + "2" "8872 8040 32 0 90 0" //team 1 spawns + "3" "9128 8040 32 0 90 0" //team 1 spawns + "4" "9256 8040 32 0 90 0" //team 1 spawns + "5" "8744 9960 32 0 270 0" //team2 spawn + "6" "8872 9960 32 0 270 0" //team2 spawn + "7" "9128 9960 32 0 270 0" //team2 spawn + "8" "9256 9960 32 0 270 0" //team2 spawn + "9" "9000 9000 142 0" // Center intel spawn, for the start of a round. + "10" "9000 9512 96 0" // Where the intel appears after player 1 dunks. + "11" "9000 8488 96 0" // Where the intel appears after player 1 dunks. + "12" "9000 8203.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "9000 9796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 6 (2v2)" + { + "1" "-8744 8040 32 0 90 0" //team 1 spawns + "2" "-8872 8040 32 0 90 0" //team 1 spawns + "3" "-9128 8040 32 0 90 0" //team 1 spawns + "4" "-9256 8040 32 0 90 0" //team 1 spawns + "5" "-8744 9960 32 0 270 0" //team2 spawn + "6" "-8872 9960 32 0 270 0" //team2 spawn + "7" "-9128 9960 32 0 270 0" //team2 spawn + "8" "-9256 9960 32 0 270 0" //team2 spawn + "9" "-9000 9000 142 0" // Center intel spawn, for the start of a round. + "10" "-9000 9512 96 0" // Where the intel appears after player 1 dunks. + "11" "-9000 8488 96 0" // Where the intel appears after player 1 dunks. + "12" "-9000 8203.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-9000 9796.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 7 (2v2)" + { + "1" "-128 -9960 32 0 90 0" //team 1 spawns + "2" "-256 -9960 32 0 90 0" //team 1 spawns + "3" "128 -9960 32 0 90 0" //team 1 spawns + "4" "256 -9960 32 0 90 0" //team 1 spawns + "5" "-128 -8040 32 0 270 0" //team2 spawn + "6" "-256 -8040 32 0 270 0" //team2 spawn + "7" "128 -8040 32 0 270 0" //team2 spawn + "8" "256 -8040 32 0 270 0" //team2 spawn + "9" "0 -9000 142 0" // Center intel spawn, for the start of a round. + "10" "0 -8488 96 0" // Where the intel appears after player 1 dunks. + "11" "0 -9512 96 0" // Where the intel appears after player 1 dunks. + "12" "0 -9796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "0 -8203.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 8 (2v2)" + { + "1" "8744 -9960 32 0 90 0" //team 1 spawns + "2" "8872 -9960 32 0 90 0" //team 1 spawns + "3" "9128 -9960 32 0 90 0" //team 1 spawns + "4" "9256 -9960 32 0 90 0" //team 1 spawns + "5" "8744 -8040 32 0 270 0" //team2 spawn + "6" "8872 -8040 32 0 270 0" //team2 spawn + "7" "9128 -8040 32 0 270 0" //team2 spawn + "8" "9256 -8040 32 0 270 0" //team2 spawn + "9" "9000 -9000 142 0" // Center intel spawn, for the start of a round. + "10" "9000 -8488 96 0" // Where the intel appears after player 1 dunks. + "11" "9000 -9512 96 0" // Where the intel appears after player 1 dunks. + "12" "9000 -9796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "9000 -8203.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + "BBall 9 (2v2)" + { + "1" "-8744 -9960 32 0 90 0" //team 1 spawns + "2" "-8872 -9960 32 0 90 0" //team 1 spawns + "3" "-9128 -9960 32 0 90 0" //team 1 spawns + "4" "-9256 -9960 32 0 90 0" //team 1 spawns + "5" "-8744 -8040 32 0 270 0" //team2 spawn + "6" "-8872 -8040 32 0 270 0" //team2 spawn + "7" "-9128 -8040 32 0 270 0" //team2 spawn + "8" "-9256 -8040 32 0 270 0" //team2 spawn + "9" "-9000 -9000 142 0" // Center intel spawn, for the start of a round. + "10" "-9000 -8488 96 0" // Where the intel appears after player 1 dunks. + "11" "-9000 -9512 96 0" // Where the intel appears after player 1 dunks. + "12" "-9000 -9796.5 135 0" // Hoop on player 1's side of the map that player 2 dunks into. + "13" "-9000 -8203.5 135 0" // Hoop on player 2's side of the map that player 1 dunks into. + + "fraglimit" "10" + "cdtime" "1" //time before round starts (when players cant shoot) + "bball" "1" + "classes" "soldier" + "hpratio" "1" + "vishoop" "0" // Set to 1 to make the hoop entities visible. Useful when adding spawns to a new arena. + "earlyleave" "1" + "infammo" "0" + "showhp" "0" + "respawntime" "2.0" + "4player" "1" + } + } +} \ No newline at end of file diff --git a/configs/mgemod_stats.cfg b/configs/mgemod_stats.cfg new file mode 100644 index 0000000..2239b22 --- /dev/null +++ b/configs/mgemod_stats.cfg @@ -0,0 +1,284 @@ +StatsConfig +{ +// Weapons with no reserve ammo (Sniper Rifle, Huntsman, Sydney Sleeper, Minigun, Natascha, etc) cannot be tracked. +// "NAME" +// { +// "idx" "" +// "maxdmg" "" +// "projectile" "" +// } + + "Shotgun (Engineer)" + { + "idx" "9" + "maxdmg" "90" + } + + "Shotgun (Soldier)" + { + "idx" "10" + "maxdmg" "90" + } + + "Shotgun (Heavy)" + { + "idx" "11" + "maxdmg" "90" + } + + "Shotgun (Pyro)" + { + "idx" "12" + "maxdmg" "90" + } + + "Scattergun" + { + "idx" "13" + "maxdmg" "105" + } + + "Submachine Gun" + { + "idx" "16" + } + + "Syringe Gun" + { + "idx" "17" + "projectile" "1" + } + + "Rocket Launcher" + { + "idx" "18" + "projectile" "1" + } + + "Pipe Launcher" + { + "idx" "19" + "projectile" "1" + } + + "Sticky Launcher" + { + "idx" "20" + "projectile" "1" + } + + "Pistol (Engineer)" + { + "idx" "22" + } + + "Pistol (Scout)" + { + "idx" "23" + } + + "Revolver" + { + "idx" "24" + } + + "The Blutsauger" + { + "idx" "36" + "projectile" "1" + } + + "Flaregun" + { + "idx" "39" + "projectile" "1" + } + + "Force-A-Nature" + { + "idx" "45" + "maxdmg" "113" + } + + "Ambassador" + { + "idx" "61" + } + + "The Direct Hit" + { + "idx" "127" + "projectile" "1" + } + + "The Frontier Justice" + { + "idx" "141" + "maxdmg" "90" + } + + + "Lugermorph" + { + "idx" "160" + } + + "Big Kill" + { + "idx" "161" + } + + "Shotgun" + { + "idx" "199" + "maxdmg" "90" + } + + "Scattergun" + { + "idx" "200" + "maxdmg" "105" + } + + "Submachine Gun" + { + "idx" "203" + } + + "Syringe Gun" + { + "idx" "204" + "projectile" "1" + } + + "Rocket Launcher" + { + "idx" "205" + "projectile" "1" + } + + "Pipe Launcher" + { + "idx" "206" + "projectile" "1" + } + + "Sticky Launcher" + { + "idx" "207" + "projectile" "1" + } + + "Pistol" + { + "idx" "209" + } + + "Revolver" + { + "idx" "210" + } + + "The Shortstop" + { + "idx" "220" + "maxdmg" "72" + } + + "L'Etranger" + { + "idx" "224" + } + + "The Black Box" + { + "idx" "228" + "projectile" "1" + } + + "Lugermorph" + { + "idx" "294" + } + + "Crusader's Crossbow" + { + "idx" "305" + "projectile" "1" + } + + "Loch-n-Load" + { + "idx" "308" + "projectile" "1" + } + + "The Detonator" + { + "idx" "351" + "projectile" "1" + } + + "The Overdose" + { + "idx" "412" + "projectile" "1" + } + + "The Reserve Shooter" + { + "idx" "415" + "maxdmg" "90" + } + + "The Family Business" + { + "idx" "425" + "maxdmg" "76" + } + + "The Cow Mangler 5000" + { + "idx" "441" + "projectile" "1" + } + + "The Winger" + { + "idx" "449" + } + + "The Enforcer" + { + "idx" "460" + } + + "The Original" + { + "idx" "513" + "projectile" "1" + } + + "The Diamondback" + { + "idx" "525" + } + + "Rocket Launcher" + { + "idx" "658" + "projectile" "1" + } + + "Sticky Launcher" + { + "idx" "661" + "projectile" "1" + } + + "Scattergun" + { + "idx" "669" + "maxdmg" "105" + } +} \ No newline at end of file From 8fae56ab8e4a8d93508830ea7f119686c4f78a15 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Sat, 9 Mar 2019 12:55:00 -0800 Subject: [PATCH 25/29] Spycrab cleanup --- scripting/ngs_spycrab.sp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripting/ngs_spycrab.sp b/scripting/ngs_spycrab.sp index 455214b..f455ee8 100644 --- a/scripting/ngs_spycrab.sp +++ b/scripting/ngs_spycrab.sp @@ -94,7 +94,7 @@ public void OnPluginStart() RegAdminCmd("sm_cancelcrab", CommandCancelCrab, ADMFLAG_GENERIC, "Cancels the spycrab."); RegAdminCmd("sm_reloadcrab", CommandReloadCrabConfig, ADMFLAG_GENERIC, "Reloads the map config file."); - mapNameContains = CreateConVar("sm_spycrab_config_contains", "1", "Whether map names in config will be checked partially or fully."); + mapNameContains = CreateConVar("spycrab_config_contains", "1", "Whether map names in config will be checked partially or fully."); HookEvent("player_death", OnPlayerDeath); HookEvent("player_disconnect", OnPlayerDisconnect, EventHookMode_Pre); From 19e6ddf3d3b72e5264f2cf2cb8d99a0f34d986a2 Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Mon, 27 May 2019 23:59:18 -0700 Subject: [PATCH 26/29] Type-errors in includes --- scripting/include/tf2idb.inc | 4 ++-- scripting/include/timber.inc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripting/include/tf2idb.inc b/scripting/include/tf2idb.inc index 5918339..3fa2012 100644 --- a/scripting/include/tf2idb.inc +++ b/scripting/include/tf2idb.inc @@ -69,10 +69,10 @@ native Handle TF2IDB_GetItemEquipRegions(int id); native bool TF2IDB_DoRegionsConflict(const char[] region1, const char[] region2); //TF2IDB_ListParticles returns an Array Handle containing a list of the particle IDs -native Handle TF2IDB_ListParticles(); +native ArrayList TF2IDB_ListParticles(); //TF2IDB_FindItemCustom returns an Array Handle containing a list of integers for the first column of the query result -native Handle TF2IDB_FindItemCustom(const char[] query); +native ArrayList TF2IDB_FindItemCustom(const char[] query); native bool TF2IDB_ItemHasAttribute(int id, int aid); diff --git a/scripting/include/timber.inc b/scripting/include/timber.inc index c1a3f18..d3c59d5 100644 --- a/scripting/include/timber.inc +++ b/scripting/include/timber.inc @@ -56,7 +56,7 @@ methodmap Timber { char logLine[8192]; VFormat(logLine, sizeof(logLine), log, 2); - this.log(Log_Verbose, logLine); + Timber.log(Log_Verbose, logLine); } } From d0ab13a0921761abc1cad5a3df581d385324e09e Mon Sep 17 00:00:00 2001 From: ZeronTheXeon Date: Tue, 28 May 2019 00:01:16 -0700 Subject: [PATCH 27/29] Rename to ngs_discord_admin --- scripting/discord_calladmin.sp | 239 ------------------- scripting/ngs_discord_admin.sp | 403 +++++++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+), 239 deletions(-) delete mode 100644 scripting/discord_calladmin.sp create mode 100644 scripting/ngs_discord_admin.sp diff --git a/scripting/discord_calladmin.sp b/scripting/discord_calladmin.sp deleted file mode 100644 index 497ef88..0000000 --- a/scripting/discord_calladmin.sp +++ /dev/null @@ -1,239 +0,0 @@ -#pragma newdecls required -#pragma semicolon 1 - -#include -#include -#include - -#define PLUGIN_VERSION "1.1" - -#define REPORT_MSG "{\"username\":\"{BOTNAME}\",\"content\":\"{MENTION} A new report has come in, handle it with `/calladmin_handle {REPORT_ID}`.\",\"attachments\":[{\"color\":\"{COLOR}\",\"title\":\"{HOSTNAME} (steam://connect/{SERVER_IP}:{SERVER_PORT}){REFER_ID}\",\"fields\":[{\"title\":\"Reason\",\"value\":\"{REASON}\",\"short\":true},{\"title\":\"Reporter\",\"value\":\"{REPORTER_NAME} ({REPORTER_ID})\",\"short\":true},{\"title\":\"Target\",\"value\":\"{TARGET_NAME} ({TARGET_ID})\",\"short\":true},{\"title\":\"Report ID\",\"value\":\"{REPORT_ID}\",\"short\":true}]}]}" -#define CLAIM_MSG "{\"username\":\"{BOTNAME}\", \"content\":\"{MSG}\",\"attachments\": [{\"color\": \"{COLOR}\",\"title\": \"{HOSTNAME} (steam://connect/{SERVER_IP}:{SERVER_PORT})\",\"fields\": [{\"title\": \"Admin\",\"value\": \"{ADMIN}\",\"short\": false}]}]}" -#define HANDLED_MSG "{\"username\":\"{BOTNAME}\",\"content\":\"{MSG}\",\"attachments\":[{\"color\":\"{COLOR}\",\"title\":\"{HOSTNAME} (steam://connect/{SERVER_IP}:{SERVER_PORT})\",\"fields\":[{\"title\":\"Admin\",\"value\": \"{ADMIN}\",\"short\":true},{\"title\":\"Report ID\",\"value\":\"{REPORT_ID}\",\"short\":true}]}]}" - -char sSymbols[25][1] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; - -char g_sHostPort[6]; -char g_sServerName[256]; -char g_sHostIP[16]; - -ConVar g_cBotName = null; -ConVar g_cClaimMsg = null; -ConVar g_cColor = null; -ConVar g_cColor2 = null; -ConVar g_cColor3 = null; -ConVar g_cMention = null; -ConVar g_cRemove = null; -ConVar g_cRemove2 = null; -ConVar g_cWebhook = null; - -public Plugin myinfo = -{ - name = "Discord: CallAdmin", - author = ".#Zipcore / TheXeon", - description = "", - version = PLUGIN_VERSION, - url = "www.zipcore.net" -} - -public void OnPluginStart() -{ - CreateConVar("discord_calladmin_version", PLUGIN_VERSION, "Discord CallAdmin version", FCVAR_DONTRECORD|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); - - g_cBotName = CreateConVar("discord_calladmin_botname", "", "Report botname, leave this blank to use the webhook default name."); - g_cClaimMsg = CreateConVar("discord_calladmin_claimmsg", "An admin is claiming reports on this server.", "Message to send when admin uses the claim command."); - g_cColor = CreateConVar("discord_calladmin_color", "#ff2222", "Discord/Slack attachment color used for reports."); - g_cColor2 = CreateConVar("discord_calladmin_color2", "#22ff22", "Discord/Slack attachment color used for admin claims."); - g_cColor3 = CreateConVar("discord_calladmin_color3", "#ff9911", "Discord/Slack attachment color used for admin reports."); - g_cMention = CreateConVar("discord_calladmin_mention", "@here", "This allows you to mention reports, leave blank to disable."); - g_cRemove = CreateConVar("discord_calladmin_remove", " | By PulseServers.com", "Remove this part from servername before sending the report."); - g_cRemove2 = CreateConVar("discord_calladmin_remove2", "3kliksphilip.com | ", "Remove this part from servername before sending the report."); - g_cWebhook = CreateConVar("discord_calladmin_webhook", "calladmin", "Config key from configs/discord.cfg."); - - AutoExecConfig(true, "discord_calladmin"); -} - -public void OnAllPluginsLoaded() -{ - if (!LibraryExists("calladmin")) - { - SetFailState("CallAdmin not found"); - return; - } - - UpdateIPPort(); - CallAdmin_GetHostName(g_sServerName, sizeof(g_sServerName)); -} - -void UpdateIPPort() -{ - FindConVar("hostport").GetString(g_sHostPort, sizeof(g_sHostPort)); - - if(FindConVar("net_public_adr") != null) - FindConVar("net_public_adr").GetString(g_sHostIP, sizeof(g_sHostIP)); - - int hostiplen = strlen(g_sHostIP); - - if(hostiplen == 0) - { - if (FindConVar("ip") != null) - { - FindConVar("ip").GetString(g_sHostIP, sizeof(g_sHostIP)); - } - else if (FindConVar("hostip") != null) - { - int ip = FindConVar("hostip").IntValue; - FormatEx(g_sHostIP, sizeof(g_sHostIP), "%d.%d.%d.%d", (ip >> 24) & 0x000000FF, (ip >> 16) & 0x000000FF, (ip >> 8) & 0x000000FF, ip & 0x000000FF); - } - } -} - -public void CallAdmin_OnServerDataChanged(ConVar convar, ServerData type, const char[] oldVal, const char[] newVal) -{ - if (type == ServerData_HostName) - CallAdmin_GetHostName(g_sServerName, sizeof(g_sServerName)); -} - -public void CallAdmin_OnReportHandled(int client, int id) -{ - char sName[(MAX_NAME_LENGTH + 1) * 2], sID[16]; - - if (client == 0) - { - strcopy(sName, sizeof(sName), "CONSOLE"); - } - else - { - GetClientName(client, sName, sizeof(sName)); - Discord_EscapeString(sName, sizeof(sName)); - } - - char sRemove[32]; - g_cRemove.GetString(sRemove, sizeof(sRemove)); - if (!StrEqual(sRemove, "")) - ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); - - g_cRemove2.GetString(sRemove, sizeof(sRemove)); - if (!StrEqual(sRemove, "")) - ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); - - Discord_EscapeString(g_sServerName, sizeof(g_sServerName)); - - char sClaimMsg[512]; - g_cClaimMsg.GetString(sClaimMsg, sizeof(sClaimMsg)); - - Discord_EscapeString(sClaimMsg, sizeof(sClaimMsg)); - - char sBot[512]; - g_cBotName.GetString(sBot, sizeof(sBot)); - - char sColor[8]; - g_cColor2.GetString(sColor, sizeof(sColor)); - - IntToString(id, sID, sizeof(sID)); - - char sMSG[512] = HANDLED_MSG; - - ReplaceString(sMSG, sizeof(sMSG), "{BOTNAME}", sBot); - ReplaceString(sMSG, sizeof(sMSG), "{COLOR}", sColor); - ReplaceString(sMSG, sizeof(sMSG), "{ADMIN}", sName); - ReplaceString(sMSG, sizeof(sMSG), "{REPORT_ID}", sID); - ReplaceString(sMSG, sizeof(sMSG), "{MSG}", sClaimMsg); - - ReplaceString(sMSG, sizeof(sMSG), "{HOSTNAME}", g_sServerName); - ReplaceString(sMSG, sizeof(sMSG), "{SERVER_IP}", g_sHostIP); - ReplaceString(sMSG, sizeof(sMSG), "{SERVER_PORT}", g_sHostPort); - - SendMessage(sMSG); - - ReplyToCommand(client, "Discord Module: Message sent."); -} - -public void CallAdmin_OnReportPost(int client, int target, const char[] reason) -{ - char sColor[8]; - if(!CheckCommandAccess(client, "sm_admin", ADMFLAG_GENERIC, true)) - g_cColor.GetString(sColor, sizeof(sColor)); - else - g_cColor3.GetString(sColor, sizeof(sColor)); - - char sReason[(REASON_MAX_LENGTH + 1) * 2]; - strcopy(sReason, sizeof(sReason), reason); - Discord_EscapeString(sReason, sizeof(sReason)); - - char clientAuth[21]; - char clientName[(MAX_NAME_LENGTH + 1) * 2]; - - if (client == REPORTER_CONSOLE) - { - strcopy(clientName, sizeof(clientName), "Server"); - strcopy(clientAuth, sizeof(clientAuth), "CONSOLE"); - } - else - { - GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth)); - GetClientName(client, clientName, sizeof(clientName)); - Discord_EscapeString(clientName, sizeof(clientName)); - } - - char targetAuth[21]; - char targetName[(MAX_NAME_LENGTH + 1) * 2]; - - GetClientAuthId(target, AuthId_Steam2, targetAuth, sizeof(targetAuth)); - GetClientName(target, targetName, sizeof(targetName)); - Discord_EscapeString(targetName, sizeof(targetName)); - - char sRemove[32]; - g_cRemove.GetString(sRemove, sizeof(sRemove)); - if (!StrEqual(sRemove, "")) - ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); - - g_cRemove2.GetString(sRemove, sizeof(sRemove)); - if (!StrEqual(sRemove, "")) - ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); - - - Discord_EscapeString(g_sServerName, sizeof(g_sServerName)); - - char sMention[512]; - g_cMention.GetString(sMention, sizeof(sMention)); - - char sBot[512]; - g_cBotName.GetString(sBot, sizeof(sBot)); - - char sID[16]; - IntToString(CallAdmin_GetReportID(), sID, sizeof(sID)); - - char sMSG[4096] = REPORT_MSG; - - ReplaceString(sMSG, sizeof(sMSG), "{BOTNAME}", sBot); - ReplaceString(sMSG, sizeof(sMSG), "{MENTION}", sMention); - - ReplaceString(sMSG, sizeof(sMSG), "{COLOR}", sColor); - - ReplaceString(sMSG, sizeof(sMSG), "{HOSTNAME}", g_sServerName); - ReplaceString(sMSG, sizeof(sMSG), "{SERVER_IP}", g_sHostIP); - ReplaceString(sMSG, sizeof(sMSG), "{SERVER_PORT}", g_sHostPort); - ReplaceString(sMSG, sizeof(sMSG), "{REPORT_ID}", sID); - - ReplaceString(sMSG, sizeof(sMSG), "{REASON}", sReason); - - ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_NAME}", clientName); - ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_ID}", clientAuth); - - ReplaceString(sMSG, sizeof(sMSG), "{TARGET_NAME}", targetName); - ReplaceString(sMSG, sizeof(sMSG), "{TARGET_ID}", targetAuth); - - char sRefer[16]; - Format(sRefer, sizeof(sRefer), " # %s%s-%d%d", sSymbols[GetRandomInt(0, 25-1)], sSymbols[GetRandomInt(0, 25-1)], GetRandomInt(0, 9), GetRandomInt(0, 9)); - ReplaceString(sMSG, sizeof(sMSG), "{REFER_ID}", sRefer); - - SendMessage(sMSG); -} - -void SendMessage(char[] sMessage) -{ - char sWebhook[32]; - g_cWebhook.GetString(sWebhook, sizeof(sWebhook)); - Discord_SendMessage(sWebhook, sMessage); -} diff --git a/scripting/ngs_discord_admin.sp b/scripting/ngs_discord_admin.sp new file mode 100644 index 0000000..7183be9 --- /dev/null +++ b/scripting/ngs_discord_admin.sp @@ -0,0 +1,403 @@ +#pragma newdecls required +#pragma semicolon 1 + +#define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" +#define RELOAD_ON_UPDATE 1 +#define ALL_PLUGINS_LOADED_FUNC AllPluginsLoaded; + +#include +#include +#undef REQUIRE_PLUGIN +#include +#define REQUIRE_PLUGIN +#include +#include +#include + +#define REPORT_MSG "{\"username\":\"{BOTNAME}\",\"content\":\"{MENTION} A new report has come in, handle it with `/calladmin_handle {REPORT_ID}`.\",\"attachments\":[{\"color\":\"{COLOR}\",\"title\":\"{HOSTNAME} (steam://connect/{SERVER_IP}:{SERVER_PORT}){REFER_ID}\",\"fields\":[{\"title\":\"Reason\",\"value\":\"{REASON}\",\"short\":true},{\"title\":\"Reporter\",\"value\":\"{REPORTER_NAME}\",\"short\":true},{\"title\":\"Reporter User ID\",\"value\":\"#{REPORTER_USERID}\",\"short\":true},{\"title\":\"Reporter Steam ID\",\"value\":\"{REPORTER_ID}\",\"short\":true},{\"title\":\"Target\",\"value\":\"{TARGET_NAME}\",\"short\":true},{\"title\":\"Target User ID\",\"value\":\"#{TARGET_USERID}\",\"short\":true},{\"title\":\"Target Steam ID\",\"value\":\"{TARGET_ID}\",\"short\":true},{\"title\":\"Report ID\",\"value\":\"{REPORT_ID}\",\"short\":true},{\"title\":\"Sourcebans Bans\",\"value\":\"{SB_BANS}\"},{\"title\":\"Sourcebans Comms\",\"value\":\"{SB_COMMS}\"},{\"title\":\"Administration Online\",\"value\":\"{ADMINS_ONLINE}\"}]}]}" +#define CLAIM_MSG "{\"username\":\"{BOTNAME}\", \"content\":\"{MSG}\",\"attachments\": [{\"color\": \"{COLOR}\",\"title\": \"{HOSTNAME} (steam://connect/{SERVER_IP}:{SERVER_PORT})\",\"fields\": [{\"title\": \"Admin\",\"value\": \"{ADMIN}\",\"short\": false}]}]}" +#define HANDLED_MSG "{\"username\":\"{BOTNAME}\",\"content\":\"{MSG}\",\"attachments\":[{\"color\":\"{COLOR}\",\"title\":\"{HOSTNAME} (steam://connect/{SERVER_IP}:{SERVER_PORT})\",\"fields\":[{\"title\":\"Admin\",\"value\": \"{ADMIN}\",\"short\":true},{\"title\":\"Report ID\",\"value\":\"{REPORT_ID}\",\"short\":true}]}]}" +#define SMAC_MSG "{\"username\":\"{BOTNAME}\",\"content\":\"{MSG}\",\"attachments\":[{\"color\":\"{COLOR}\",\"title\":\"{HOSTNAME} (steam://connect/{SERVER_IP}:{SERVER_PORT})\",\"fields\":[{\"title\":\"Admin\",\"value\": \"{ADMIN}\",\"short\":true},{\"title\":\"Report ID\",\"value\":\"{REPORT_ID}\",\"short\":true}]}]}" + +char sSymbols[25][1] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; + +char g_sHostPort[6]; +char g_sServerName[256]; +char g_sHostIP[16]; + +ConVar g_cBotName = null; +ConVar g_cClaimMsg = null; +ConVar g_cColor = null; +ConVar g_cColor2 = null; +ConVar g_cColor3 = null; +ConVar g_cMention = null; +ConVar g_cRemove = null; +ConVar g_cRemove2 = null; +ConVar g_cWebhook = null; +ConVar g_cSourceBansUrl = null; + +public Plugin myinfo = +{ + name = "[NGS] Discord: Admin Connection Module", + author = ".#Zipcore / TheXeon", + description = "", + version = "1.2", + url = "www.zipcore.net" +} + +public void OnPluginStart() +{ + AutoExecConfig_SetCreateDirectory(true); + AutoExecConfig_SetFile("autorestart"); + AutoExecConfig_SetCreateFile(true); + bool appended; + Timber.plantToFile(appended); + + g_cBotName = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_botname", "", "Report botname, leave this blank to use the webhook default name."); + g_cClaimMsg = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_claimmsg", "An admin is claiming reports on this server.", "Message to send when admin uses the claim command."); + g_cColor = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_color", "#ff2222", "Discord/Slack attachment color used for reports."); + g_cColor2 = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_color2", "#22ff22", "Discord/Slack attachment color used for admin claims."); + g_cColor3 = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_color3", "#ff9911", "Discord/Slack attachment color used for admin reports."); + g_cMention = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_mention", "@here", "This allows you to mention reports, leave blank to disable."); + g_cRemove = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_remove", " | By PulseServers.com", "Remove this part from servername before sending the report."); + g_cRemove2 = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_remove2", "3kliksphilip.com | ", "Remove this part from servername before sending the report."); + g_cWebhook = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_webhook", "calladmin", "Config key from configs/discord.cfg."); + g_cSourceBansUrl = AutoExecConfig_CreateConVarCheckAppend(appended, "discord_calladmin_sbpp_url", "https://www.neogenesisnetwork.net/sourcebans/index.php", "Index.php page of sourcebans-pp"); + AutoExecConfig_ExecAndClean(appended); +} + +public Action SMAC_OnCheatDetected(int client, const char[] module, DetectionType type, Handle info) { + char sColor[8]; + if(!CheckCommandAccess(client, "sm_admin", ADMFLAG_GENERIC, true)) + g_cColor.GetString(sColor, sizeof(sColor)); + else + g_cColor3.GetString(sColor, sizeof(sColor)); + + char sReason[(REASON_MAX_LENGTH + 1) * 2]; + strcopy(sReason, sizeof(sReason), reason); + Discord_EscapeString(sReason, sizeof(sReason)); + + char clientAuth[21], clientUserID[21]; + char clientName[(MAX_NAME_LENGTH + 1) * 2]; + + strcopy(clientName, sizeof(clientName), "Server"); + strcopy(clientUserID, sizeof(clientUserID), "CONSOLE"); + strcopy(clientAuth, sizeof(clientAuth), "CONSOLE"); + + char targetAuth[21], targetUserID[21]; + char targetName[(MAX_NAME_LENGTH + 1) * 2]; + + GetClientAuthId(client, AuthId_Steam2, targetAuth, sizeof(targetAuth)); + IntToString(GetClientUserId(client), targetUserID, sizeof(targetUserID)); + GetClientName(client, targetName, sizeof(targetName)); + Discord_EscapeString(targetName, sizeof(targetName)); + + char explodedAdminNames[MAXPLAYERS + 1][MAX_NAME_LENGTH]; + char implodedNames[MAXPLAYERS * MAX_NAME_LENGTH + 1]; + + int j = 0; + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i, _, _, _, _, true) && CheckCommandAccess(i, "sm_ngsstaff_administra_override", ADMFLAG_GENERIC) && !CheckCommandAccess(i, "sm_ngsstaff_dev_override", ADMFLAG_ROOT)) + { + GetClientName(i, explodedAdminNames[j], sizeof(explodedAdminNames[])); + Discord_EscapeString(explodedAdminNames[j], sizeof(explodedAdminNames[])); + j++; + } + } + + if (j == 0) + { + explodedAdminNames[0] = "No admins online"; + j++; + } + + ImplodeStrings(explodedAdminNames, j, ", ", implodedNames, sizeof(implodedNames)); + StrCat(implodedNames, sizeof(implodedNames), "."); + + char sRemove[32]; + g_cRemove.GetString(sRemove, sizeof(sRemove)); + if (!StrEqual(sRemove, "")) + ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); + + g_cRemove2.GetString(sRemove, sizeof(sRemove)); + if (!StrEqual(sRemove, "")) + ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); + + + Discord_EscapeString(g_sServerName, sizeof(g_sServerName)); + + char sMention[512]; + g_cMention.GetString(sMention, sizeof(sMention)); + + char sBot[512]; + g_cBotName.GetString(sBot, sizeof(sBot)); + + char sourceBansUrl[512]; + g_cSourceBansUrl.GetString(sourceBansUrl, sizeof(sourceBansUrl)); + + char sBansUrl[1024], sCommsUrl[1024]; + Format(sBansUrl, sizeof(sBansUrl), "%s?p=banlist&advSearch=%s&advType=steamid", sourceBansUrl, targetAuth); + Format(sCommsUrl, sizeof(sCommsUrl), "%s?p=commslist&advSearch=%s&advType=steamid", sourceBansUrl, targetAuth); + + char sID[16]; + IntToString(CallAdmin_GetReportID(), sID, sizeof(sID)); + + char sMSG[4096] = REPORT_MSG; + + ReplaceString(sMSG, sizeof(sMSG), "{BOTNAME}", sBot); + ReplaceString(sMSG, sizeof(sMSG), "{MENTION}", sMention); + + ReplaceString(sMSG, sizeof(sMSG), "{COLOR}", sColor); + + ReplaceString(sMSG, sizeof(sMSG), "{HOSTNAME}", g_sServerName); + ReplaceString(sMSG, sizeof(sMSG), "{SERVER_IP}", g_sHostIP); + ReplaceString(sMSG, sizeof(sMSG), "{SERVER_PORT}", g_sHostPort); + ReplaceString(sMSG, sizeof(sMSG), "{REPORT_ID}", sID); + + ReplaceString(sMSG, sizeof(sMSG), "{REASON}", sReason); + + ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_NAME}", clientName); + ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_USERID}", clientUserID); + ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_ID}", clientAuth); + + ReplaceString(sMSG, sizeof(sMSG), "{TARGET_NAME}", targetName); + ReplaceString(sMSG, sizeof(sMSG), "{TARGET_USERID}", targetUserID); + ReplaceString(sMSG, sizeof(sMSG), "{TARGET_ID}", targetAuth); + + ReplaceString(sMSG, sizeof(sMSG), "{SB_BANS}", sBansUrl); + ReplaceString(sMSG, sizeof(sMSG), "{SB_COMMS}", sCommsUrl); + + ReplaceString(sMSG, sizeof(sMSG), "{ADMINS_ONLINE}", implodedNames); + + char sRefer[16]; + Format(sRefer, sizeof(sRefer), " # %s%s-%d%d", sSymbols[GetRandomInt(0, 25-1)], sSymbols[GetRandomInt(0, 25-1)], GetRandomInt(0, 9), GetRandomInt(0, 9)); + ReplaceString(sMSG, sizeof(sMSG), "{REFER_ID}", sRefer); + + SendMessage(sMSG); +} + +public void AllPluginsLoaded() +{ + if (!LibraryExists("calladmin")) + { + SetFailState("CallAdmin not found"); + return; + } + + UpdateIPPort(); + CallAdmin_GetHostName(g_sServerName, sizeof(g_sServerName)); +} + +void UpdateIPPort() +{ + FindConVar("hostport").GetString(g_sHostPort, sizeof(g_sHostPort)); + + if(FindConVar("net_public_adr") != null) + FindConVar("net_public_adr").GetString(g_sHostIP, sizeof(g_sHostIP)); + + int hostiplen = strlen(g_sHostIP); + + if(hostiplen == 0) + { + if (FindConVar("ip") != null) + { + FindConVar("ip").GetString(g_sHostIP, sizeof(g_sHostIP)); + } + else if (FindConVar("hostip") != null) + { + int ip = FindConVar("hostip").IntValue; + FormatEx(g_sHostIP, sizeof(g_sHostIP), "%d.%d.%d.%d", (ip >> 24) & 0x000000FF, (ip >> 16) & 0x000000FF, (ip >> 8) & 0x000000FF, ip & 0x000000FF); + } + } +} + +public void CallAdmin_OnServerDataChanged(ConVar convar, ServerData type, const char[] oldVal, const char[] newVal) +{ + if (type == ServerData_HostName) + CallAdmin_GetHostName(g_sServerName, sizeof(g_sServerName)); +} + +public void CallAdmin_OnReportHandled(int client, int id) +{ + char sName[(MAX_NAME_LENGTH + 1) * 2], sID[16]; + + if (client == 0) + { + strcopy(sName, sizeof(sName), "CONSOLE"); + } + else + { + GetClientName(client, sName, sizeof(sName)); + Discord_EscapeString(sName, sizeof(sName)); + } + + char sRemove[32]; + g_cRemove.GetString(sRemove, sizeof(sRemove)); + if (!StrEqual(sRemove, "")) + ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); + + g_cRemove2.GetString(sRemove, sizeof(sRemove)); + if (!StrEqual(sRemove, "")) + ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); + + Discord_EscapeString(g_sServerName, sizeof(g_sServerName)); + + char sClaimMsg[512]; + g_cClaimMsg.GetString(sClaimMsg, sizeof(sClaimMsg)); + + Discord_EscapeString(sClaimMsg, sizeof(sClaimMsg)); + + char sBot[512]; + g_cBotName.GetString(sBot, sizeof(sBot)); + + char sColor[8]; + g_cColor2.GetString(sColor, sizeof(sColor)); + + IntToString(id, sID, sizeof(sID)); + + char sMSG[512] = HANDLED_MSG; + + ReplaceString(sMSG, sizeof(sMSG), "{BOTNAME}", sBot); + ReplaceString(sMSG, sizeof(sMSG), "{COLOR}", sColor); + ReplaceString(sMSG, sizeof(sMSG), "{ADMIN}", sName); + ReplaceString(sMSG, sizeof(sMSG), "{REPORT_ID}", sID); + ReplaceString(sMSG, sizeof(sMSG), "{MSG}", sClaimMsg); + + ReplaceString(sMSG, sizeof(sMSG), "{HOSTNAME}", g_sServerName); + ReplaceString(sMSG, sizeof(sMSG), "{SERVER_IP}", g_sHostIP); + ReplaceString(sMSG, sizeof(sMSG), "{SERVER_PORT}", g_sHostPort); + + SendMessage(sMSG); + + ReplyToCommand(client, "Discord Module: Message sent."); +} + +public void CallAdmin_OnReportPost(int client, int target, const char[] reason) +{ + char sColor[8]; + if(!CheckCommandAccess(client, "sm_admin", ADMFLAG_GENERIC, true)) + g_cColor.GetString(sColor, sizeof(sColor)); + else + g_cColor3.GetString(sColor, sizeof(sColor)); + + char sReason[(REASON_MAX_LENGTH + 1) * 2]; + strcopy(sReason, sizeof(sReason), reason); + Discord_EscapeString(sReason, sizeof(sReason)); + + char clientAuth[21], clientUserID[21]; + char clientName[(MAX_NAME_LENGTH + 1) * 2]; + + if (client == REPORTER_CONSOLE) + { + strcopy(clientName, sizeof(clientName), "Server"); + strcopy(clientUserID, sizeof(clientUserID), "CONSOLE"); + strcopy(clientAuth, sizeof(clientAuth), "CONSOLE"); + } + else + { + GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth)); + GetClientName(client, clientName, sizeof(clientName)); + IntToString(GetClientUserId(client), clientUserID, sizeof(clientUserID)); + Discord_EscapeString(clientName, sizeof(clientName)); + } + + char targetAuth[21], targetUserID[21]; + char targetName[(MAX_NAME_LENGTH + 1) * 2]; + + GetClientAuthId(target, AuthId_Steam2, targetAuth, sizeof(targetAuth)); + IntToString(GetClientUserId(target), targetUserID, sizeof(targetUserID)); + GetClientName(target, targetName, sizeof(targetName)); + Discord_EscapeString(targetName, sizeof(targetName)); + + char explodedAdminNames[MAXPLAYERS + 1][MAX_NAME_LENGTH]; + char implodedNames[MAXPLAYERS * MAX_NAME_LENGTH + 1]; + + int j = 0; + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i, _, _, _, _, true) && CheckCommandAccess(i, "sm_ngsstaff_administra_override", ADMFLAG_GENERIC) && !CheckCommandAccess(i, "sm_ngsstaff_dev_override", ADMFLAG_ROOT)) + { + GetClientName(i, explodedAdminNames[j], sizeof(explodedAdminNames[])); + Discord_EscapeString(explodedAdminNames[j], sizeof(explodedAdminNames[])); + j++; + } + } + + if (j == 0) + { + explodedAdminNames[0] = "No admins online"; + j++; + } + + ImplodeStrings(explodedAdminNames, j, ", ", implodedNames, sizeof(implodedNames)); + StrCat(implodedNames, sizeof(implodedNames), "."); + + char sRemove[32]; + g_cRemove.GetString(sRemove, sizeof(sRemove)); + if (!StrEqual(sRemove, "")) + ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); + + g_cRemove2.GetString(sRemove, sizeof(sRemove)); + if (!StrEqual(sRemove, "")) + ReplaceString(g_sServerName, sizeof(g_sServerName), sRemove, ""); + + + Discord_EscapeString(g_sServerName, sizeof(g_sServerName)); + + char sMention[512]; + g_cMention.GetString(sMention, sizeof(sMention)); + + char sBot[512]; + g_cBotName.GetString(sBot, sizeof(sBot)); + + char sourceBansUrl[512]; + g_cSourceBansUrl.GetString(sourceBansUrl, sizeof(sourceBansUrl)); + + char sBansUrl[1024], sCommsUrl[1024]; + Format(sBansUrl, sizeof(sBansUrl), "%s?p=banlist&advSearch=%s&advType=steamid", sourceBansUrl, targetAuth); + Format(sCommsUrl, sizeof(sCommsUrl), "%s?p=commslist&advSearch=%s&advType=steamid", sourceBansUrl, targetAuth); + + char sID[16]; + IntToString(CallAdmin_GetReportID(), sID, sizeof(sID)); + + char sMSG[4096] = REPORT_MSG; + + ReplaceString(sMSG, sizeof(sMSG), "{BOTNAME}", sBot); + ReplaceString(sMSG, sizeof(sMSG), "{MENTION}", sMention); + + ReplaceString(sMSG, sizeof(sMSG), "{COLOR}", sColor); + + ReplaceString(sMSG, sizeof(sMSG), "{HOSTNAME}", g_sServerName); + ReplaceString(sMSG, sizeof(sMSG), "{SERVER_IP}", g_sHostIP); + ReplaceString(sMSG, sizeof(sMSG), "{SERVER_PORT}", g_sHostPort); + ReplaceString(sMSG, sizeof(sMSG), "{REPORT_ID}", sID); + + ReplaceString(sMSG, sizeof(sMSG), "{REASON}", sReason); + + ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_NAME}", clientName); + ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_USERID}", clientUserID); + ReplaceString(sMSG, sizeof(sMSG), "{REPORTER_ID}", clientAuth); + + ReplaceString(sMSG, sizeof(sMSG), "{TARGET_NAME}", targetName); + ReplaceString(sMSG, sizeof(sMSG), "{TARGET_USERID}", targetUserID); + ReplaceString(sMSG, sizeof(sMSG), "{TARGET_ID}", targetAuth); + + ReplaceString(sMSG, sizeof(sMSG), "{SB_BANS}", sBansUrl); + ReplaceString(sMSG, sizeof(sMSG), "{SB_COMMS}", sCommsUrl); + + ReplaceString(sMSG, sizeof(sMSG), "{ADMINS_ONLINE}", implodedNames); + + char sRefer[16]; + Format(sRefer, sizeof(sRefer), " # %s%s-%d%d", sSymbols[GetRandomInt(0, 25-1)], sSymbols[GetRandomInt(0, 25-1)], GetRandomInt(0, 9), GetRandomInt(0, 9)); + ReplaceString(sMSG, sizeof(sMSG), "{REFER_ID}", sRefer); + + SendMessage(sMSG); +} + +void SendMessage(char[] sMessage) +{ + char sWebhook[32]; + g_cWebhook.GetString(sWebhook, sizeof(sWebhook)); + Discord_SendMessage(sWebhook, sMessage); +} From 8c2b0578016aac175a7ca3125e1f83c8e4b8770e Mon Sep 17 00:00:00 2001 From: Sanjeet Jain Date: Fri, 11 Sep 2020 02:23:26 -0700 Subject: [PATCH 28/29] Fix syntax in discord and smac.inc --- scripting/include/smac.inc | 2 +- scripting/ngs_discord_admin.sp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripting/include/smac.inc b/scripting/include/smac.inc index 3c64ff1..3a6f9f5 100644 --- a/scripting/include/smac.inc +++ b/scripting/include/smac.inc @@ -99,7 +99,7 @@ native Action SMAC_CheatDetected(int client, DetectionType type = Detection_Unkn /* Forwards */ forward Action SMAC_OnCheatDetected(int client, const char[] module, DetectionType type, Handle info); -forward Action SMAC_OnActionLogged() +forward Action SMAC_OnActionLogged(); public SharedPlugin __pl_smac = { diff --git a/scripting/ngs_discord_admin.sp b/scripting/ngs_discord_admin.sp index 7183be9..dbdcebf 100644 --- a/scripting/ngs_discord_admin.sp +++ b/scripting/ngs_discord_admin.sp @@ -3,7 +3,7 @@ #define CONTENT_URL "https://github.com/NGSNetwork/sm-plugins/raw/master/" #define RELOAD_ON_UPDATE 1 -#define ALL_PLUGINS_LOADED_FUNC AllPluginsLoaded; +#define ALL_PLUGINS_LOADED_FUNC AllPluginsLoaded #include #include From 9942260acccf5bc434b9c76dddab99b4c989bcec Mon Sep 17 00:00:00 2001 From: Blueberryy <36592509+Blueberryy@users.noreply.github.com> Date: Wed, 15 Sep 2021 00:11:44 +0500 Subject: [PATCH 29/29] translation (#10) --- translations/free_duels.phrases.txt | 26 ++- translations/ru/backpack-tf.phrases.txt | 66 ++++++ translations/ru/serverhop.phrases.txt | 21 ++ translations/ru/store.killawards.txt | 21 ++ translations/ru/store.txt | 259 ++++++++++++++++++++++++ translations/ru/weddings.phrases.txt | 187 +++++++++++++++++ translations/tradechat.phrases.txt | 6 + 7 files changed, 585 insertions(+), 1 deletion(-) create mode 100644 translations/ru/backpack-tf.phrases.txt create mode 100644 translations/ru/serverhop.phrases.txt create mode 100644 translations/ru/store.killawards.txt create mode 100644 translations/ru/store.txt create mode 100644 translations/ru/weddings.phrases.txt diff --git a/translations/free_duels.phrases.txt b/translations/free_duels.phrases.txt index 3034b99..ed1ffc7 100644 --- a/translations/free_duels.phrases.txt +++ b/translations/free_duels.phrases.txt @@ -1,52 +1,60 @@ -"Phrases" +"Phrases" { "ChangeClass" { "en" "{cyan}[Duel]{default} You can't change class during a restricted duel!" "fr" "{cyan}[Duel]{default} Vous ne pouvez pas changer de classe pendant un duel avec restriction de classe!" "it" "{cyan}[Duel]{default} Non puoi cambiare classe durante un duello con restrizioni!" + "ru" "{cyan}[Дуэль]{default} Вы не можете изменить класс во время дуэли!" } "Abort" { "en" "{cyan}[Duel]{Red} !abort {olive} to abort a duel." "fr" "{cyan}[Duel]{Red} !abort {olive} pour annuler un duel." "it" "{cyan}[Duel]{Red} !abort {olive} per annullare un duello." + "ru" "{cyan}[Дуэль]{Red} !abort {olive} для отмены дуэли." } "NoFound" { "en" "{cyan}[Duel]{Orange} No player found." "fr" "{cyan}[Duel]{Orange} Aucun joueur trouve." "it" "{cyan}[Duel]{Orange} Nessun giocatore trovato." + "ru" "{cyan}[Дуэль]{Orange} Игрок не найден." } "NoFlag" { "en" "{cyan}[Duel]{default} You don't have access to this command!" "fr" "{cyan}[Duel]{default} Vous n'avez pas acces à cette commande !" "it" "{cyan}[Duel]{default} Non hai accesso a questo comando !" + "ru" "{cyan}[Дуэль]{default} У вас нет доступа к этой команде!" } "Spectator" { "en" "{cyan}[Duel]{default} You can't duel in spectator!" "fr" "{cyan}[Duel]{default} Vous ne pouvez pas faire de duel en spectateur !" "it" "{cyan}[Duel]{default} Non puoi iniziare un duello come spettatore !" + "ru" "{cyan}[Дуэль]{default} Дуэль за наблюдателя не устроишь!" } "InDuel" { "en" "{cyan}[Duel]{Red} You're already in a duel!" "fr" "{cyan}[Duel]{Red} Vous etes deja en duel !" "it" "{cyan}[Duel]{Red} Hai già iniziato un duello !" + "ru" "{cyan}[Дуэль]{Red} Вы уже на дуэли!" } "NotInGame" { "en" "{cyan}[Duel]{Red} Player isn't in game!" "fr" "{cyan}[Duel]{Red} Joueur non en jeu !" "it" "{cyan}[Duel]{Red} Giocatori non in partita !" + "ru" "{cyan}[Дуэль]{Red} Игрок не в игре!" } "NotInDuel" { "en" "{cyan}[Duel]{olive} You aren't in a duel!" "fr" "{cyan}[Duel]{olive} Vous n'etes pas dans un duel !" "it" "{cyan}[Duel]{olive} Non hai iniziato alcun duello !" + "ru" "{cyan}[Дуэль]{olive} Вы не на дуэли!" } "Score" { @@ -54,6 +62,7 @@ "en" "{cyan}[Duel]{default} {1} : {2} - {3} : {4}" "fr" "{cyan}[Duel]{default} {1} : {2} - {3} : {4}" "it" "{cyan}[Duel]{default} {1} : {2} - {3} : {4}" + "ru" "{cyan}[Дуэль]{default} {1} : {2} - {3} : {4}" } "Victory" { @@ -61,6 +70,7 @@ "en" "{cyan}[Duel]{green} {1} {olive}wins their duel against{green} {2} {default}{3}" "fr" "{cyan}[Duel]{green} {1} {olive}gagne le duel contre{green} {2} {default}{3}" "it" "{cyan}[Duel]{green} {1} {olive}vince il duello contro{green} {2} {default}{3}" + "ru" "{cyan}[Дуэль]{green} {1} {olive}выигрывает дуэль против{green} {2} {default}{3}" } "Challenged" { @@ -68,6 +78,7 @@ "en" "{cyan}[Duel]{Green} {1} {Orange}has challenged {green}{2} !" "fr" "{cyan}[Duel]{Green} {1} {Orange}a defie{green}{2} !" "it" "{cyan}[Duel]{Green} {1} {Orange}ha sfidato {green}{2} !" + "ru" "{cyan}[Дуэль]{Green} {1} {Orange}бросает вызов {green}{2} !" } "You!" { @@ -75,6 +86,7 @@ "en" "{cyan}[Duel]{green} {1} {olive}has challenged you!" "fr" "{cyan}[Duel]{green} {1} {olive}vous defie!" "it" "{cyan}[Duel]{green} {1} {olive}ti ha sfidato!" + "ru" "{cyan}[Дуэль]{green} {1} {olive}бросает вам вызов!" } "Refused" { @@ -82,6 +94,7 @@ "en" "{cyan}[Duel]{Red} But {Green} {1} {Red}refused {Green}{2}{Red}'s duel!" "fr" "{cyan}[Duel]{Red} Mais {Green} {1} {Red}a refuse le duel de {Green}{2}{Red} !" "it" "{cyan}[Duel]{Red} Ma {Green} {1} {Red}ha rifiutato la sfida di {Green}{2}{Red}!" + "ru" "{cyan}[Дуэль]{Red} Но {Green} {1} {Red}отказался от дуэли {Green}{2}{Red} !" } "Accepts" { @@ -89,6 +102,7 @@ "en" "{cyan}[Duel]{green} {1} {olive}accepts {Green}{2}{olive}'s challenge!" "fr" "{cyan}[Duel]{green} {1} {olive}a accepte le defi de {Green}{2}{olive}!" "it" "{cyan}[Duel]{green} {1} {olive}ha accettato la sfida di {Green}{2}{olive}!" + "ru" "{cyan}[Дуэль]{green} {1} {olive}принимает вызов {Green}{2}{olive} !" } "TooAfraid" { @@ -96,6 +110,7 @@ "en" "{cyan}[Duel]{Green} {1} {Red} is too afraid to accept {Green}{2}{Red}'s challenge!" "fr" "{cyan}[Duel]{Green} {1} {Red} a trop peur de repondre à {Green}{2} !" "it" "{cyan}[Duel]{Green} {1} {Red} è troppo spaventato per rispondere a {Green}{2} !" + "ru" "{cyan}[Дуэль]{Green} {1} {Red} слишком боится отвечать на вызов {Green}{2} !" } "IsInDuel" { @@ -103,24 +118,28 @@ "en" "{cyan}[Duel]{Green} {1} {Red} is already in a duel!" "fr" "{cyan}[Duel]{Green} {1} {Red} est deja dans un duel !" "it" "{cyan}[Duel]{Green} {1} {Red} è già in duello con un giocatore !" + "ru" "{cyan}[Дуэль]{Green} {1} {Red} уже в дуэли !" } "TeamError" { "en" "{cyan}[Duel]{Red} Team error!" "fr" "{cyan}[Duel]{Red} Erreur d'equipe !" "it" "{cyan}[Duel]{Red} Squadra errata !" + "ru" "{cyan}[Дуэль]{Red} Ошибка команды !" } "!myduels" { "en" "{cyan}[Duel]{default} Write {Green}!myduels {default}to see your duels ratio." "fr" "{cyan}[Duel]{default} Tapes {Green}!myduels {default}pour voir le rapport de tes duels." "it" "{cyan}[Duel]{default} Scrivi {Green}!myduels {default}per consultare le statistiche dei tuoi duelli." + "ru" "{cyan}[Дуэль]{default} Напишите {Green}!myduels{default}, чтобы увидеть соотношение ваших дуэлей." } "!topduel" { "en" "{cyan}[Duel]{default} Write {Green}!topduel {default}to see the top duelists." "fr" "{cyan}[Duel]{default} Tapes {Green}!topduel {default}pour voir les meilleurs dueleurs." "it" "{cyan}[Duel]{default} Scrivi {Green}!topduel {default}per l'elenco dei migliori duellanti." + "ru" "{cyan}[Дуэль]{default} Напишите {Green}!topduel{default}, чтобы увидеть лучших дуэлянтов." } "Equality" { @@ -128,6 +147,7 @@ "en" "{cyan}[Duel]{red} Duel finished :{green} {1} {olive}and {green}{2} {olive}have tied with the same level!" "fr" "{cyan}[Duel]{red} Duel termine :{green} {1} {olive}et {green}{2} {olive}on le meme niveau !" "it" "{cyan}[Duel]{red} Duello terminato :{green} {1} {olive} e {green}{2} {olive}sono in parità !" + "ru" "{cyan}[Дуэль]{red} Дуэль окончена :{green} {1} {olive}и {green}{2} {olive}равнялись на одном уровне!" } "VictoryNbr" { @@ -135,6 +155,7 @@ "en" "{cyan}[Duel]{green} {1} {olive}has{green} {2} {orange}victory!" "fr" "{cyan}[Duel]{green} {1} {olive}a{green} {2} {orange}victore!" "it" "{cyan}[Duel]{green} {1} {olive}ha{green} {2} {orange}vittoria!" + "ru" "{cyan}[Дуэль]{green} {1} {olive}имеет{green} {2} {orange}победу!" } "Victories" { @@ -142,17 +163,20 @@ "en" "{cyan}[Duel]{green} {1} {olive}has{green} {2} {orange}victories!" "fr" "{cyan}[Duel]{green} {1} {olive}a{green} {2} {orange}victoires!" "it" "{cyan}[Duel]{green} {1} {olive}ha{green} {2} {orange}vittorie!" + "ru" "{cyan}[Дуэль]{green} {1} {olive}имеет{green} {2} {orange}побед!" } "WaitAnwser" { "en" "{cyan}[Duel]{orange} You must wait for an answer to your last challenge before create a new one." "fr" "{cyan}[Duel]{orange} Tu dois attendre la reponse de ton dernier duel avant d'en creer un nouveau." "it" "{cyan}[Duel]{orange} Devi aspettare una risposta alla tua ultima richiesta di duello prima di farne una nuova." + "ru" "{cyan}[Дуэль]{orange} Вы должны дождаться своего последнего дуэльного ответа, прежде чем создавать новый." } "Don'tBuilt" { "en" "{cyan}[Duel]{default} In Challenger Protection, you are not allow to build objects!" "fr" "{cyan}[Duel]{default} En GodMod, tu n'es pas autorise à construire des objets!" "it" "{cyan}[Duel]{default} In GodMod, non sei abilitato a costruire oggetti!" + "ru" "{cyan}[Дуэль]{default} В защите вызова вы не можете строить объекты!" } } diff --git a/translations/ru/backpack-tf.phrases.txt b/translations/ru/backpack-tf.phrases.txt new file mode 100644 index 0000000..c41b25b --- /dev/null +++ b/translations/ru/backpack-tf.phrases.txt @@ -0,0 +1,66 @@ +// Exported from SourceMod Translator +// Date: 2020-12-26 10:23:14 UTC +// Language: Russian (ru) +// +// To view other translations for this plugin, please visit: +// http://translator.mitchdempsey.com/sourcemod_plugins/122 +// +"Phrases" +{ + + "Price list updated" + { + "ru" "Список цен обновлен." + } + + "Type !pc for a price check" + { + "ru" "Введите !pc для просмотра цен." + } + + "Up" + { + "ru" "Вверх" + } + + "Down" + { + "ru" "Вниз" + } + + "From" + { + "ru" "из" + } + + "To" + { + "ru" "для" + } + + "Price check" + { + "ru" "Предмет: {1}" + } + + "Prices are estimates only" + { + "ru" "Цены являются ориентировочными" + } + + "Prices courtesy of backpack.tf" + { + "ru" "Цены предоставлены сайтом backpack.tf" + } + + "Please allow backpack.tf time to load" + { + "ru" "Пожалуйста, дождитесь загрузки backpack.tf" + } + + "The price list has not loaded yet" + { + "ru" "Список цен не загружен" + } + +} diff --git a/translations/ru/serverhop.phrases.txt b/translations/ru/serverhop.phrases.txt new file mode 100644 index 0000000..76dc3d8 --- /dev/null +++ b/translations/ru/serverhop.phrases.txt @@ -0,0 +1,21 @@ +"Phrases" +{ + "SelectServer" + { + "ru" "Выберите сервер для присоединения ..." + } + "AboutToJoinServer" + { + "ru" "Собирается подключиться к серверу ..." + } + "HopNotification" + { + "#format" "{1:s},{2:s}" + "ru" "{1} подключается к {2} !" + } + "Advert" + { + "#format" "{1:s},{2:s}" + "ru" "{1} [напишите {2} чтобы присоединиться]" + } +} \ No newline at end of file diff --git a/translations/ru/store.killawards.txt b/translations/ru/store.killawards.txt new file mode 100644 index 0000000..9f7eb0d --- /dev/null +++ b/translations/ru/store.killawards.txt @@ -0,0 +1,21 @@ +"Phrases" +{ + + "Received Credits Suicide" + { + "#format" "{1:d},{2:s}" + "ru" "Вы получили {1} {2} за самоубийство!" + } + + "Received Credits Kill" + { + "#format" "{1:d},{2:s},{3:N}" + "ru" "Вы получили {1} {2} за убийство {3}" + } + + "Received Credits TeamKill" + { + "#format" "{1:d},{2:s},{3:N}" + "ru" "Вы получили {1} {2} помощь в убийстве {3}" + } +} \ No newline at end of file diff --git a/translations/ru/store.txt b/translations/ru/store.txt new file mode 100644 index 0000000..3d5aea6 --- /dev/null +++ b/translations/ru/store.txt @@ -0,0 +1,259 @@ +"Phrases" +{ + "Store Menu Title" + { + "#format" "{1:s}" + "ru" "Магазин NGS [{1}]" + } + + "Store Menu Credits" + { + "#format" "{1:d},{2:s}" + "ru" "У вас есть {1} {2}." + } + + "Inventory" + { + "ru" "Инвентарь" + } + + "Shop" + { + "ru" "Магазин" + } + + "Loadout" + { + "ru" "Снаряжение" + } + + "No items in this category" + { + "ru" "В этой категории нет предметов." + } + + "Item type not registered" + { + "ru" "Тип предмета '{1}' не был зарегистрирован ни одним плагином." + } + + "Not enough credits to buy" + { + "ru" "Вам не хватает {1}, чтобы купить этот предмет." + } + + "No item attributes" + { + "ru" "Атрибуты не найдены." + } + + "Equipped item" + { + "ru" "Вы надели {1}." + } + + "Unequipped item" + { + "ru" "Вы убрали {1}." + } + + "Must be alive to equip" + { + "ru" "Вы должны быть живы, чтобы надеть этот предмет." + } + + "Must be alive to use" + { + "ru" "Вы должны быть живы, чтобы надеть этот предмет." + } + + "Must be human to equip" + { + "ru" "Вы должны быть человеком, чтобы надеть этот предмет." + } + + "Must be human to use" + { + "ru" "Вы должны быть человеком, чтобы надеть этот предмет." + } + + "Limit item uses in a round" + { + "ru" "Вы можете использовать этот предмет только {1} раз за раунд." + } + + "Player model unsupported" + { + "ru" "Ваша модель игрока не поддерживает снаряжение." + } + + "Received Credits" + { + "ru" "Вы только что получили {1} {2}!" + } + + "Item Purchase Confirmation" + { + "ru" "Вы уверены, что хотите купить {1}?" + } + + "Item Purchase Successful" + { + "ru" "Вы купили '{olive}{1}{default}'!" + } + + "Refund" + { + "ru" "Возврат" + } + + "Gift" + { + "ru" "Подарить" + } + + "Refund Message" + { + "ru" "Вы сдали обратно {1} за {2} {3}." + } + + "Item Refund Confirmation" + { + "ru" "Вы уверены, что хотите вернуть предмет обратно {1} за {2} {3}?" + } + + "Equipped item apply next spawn" + { + "ru" "Вы надели предмет. Он вступит в силу в вашем следующем возрождении." + } + + "Shop Description" + { + "ru" "Вы можете купить классные вещи здесь!" + } + + "Inventory Description" + { + "ru" "Экипируйте или используйте ваши предметы." + } + + "Refund Description" + { + "ru" "Не довольны? Возврат здесь." + } + + "Gift Description" + { + "ru" "Пожертвуйте деньги или предметы для нуждающихся!" + } + + "Loadout Description" + { + "ru" "Настрой своё снаряжение." + } + + "Gift Type Menu Title" + { + "ru" "Что вы хотите подарить?" + } + + "Gift Delivery Method" + { + "ru" "Как вы хотите доставить подарок?" + } + + "Gift Method Send" + { + "ru" "Отправить игроку" + } + + "Gift Method Drop" + { + "ru" "Выбросить на землю" + } + + "Item" + { + "ru" "Предмет" + } + + "Gift Credit Confirmation" + { + "ru" "Вы уверены, что хотите дать {1} {2} {3}?" + } + + "Gift Item Confirmation" + { + "ru" "Вы уверены, что хотите дать {1} предмет {2}?" + } + + "Drop Credit Confirmation" + { + "ru" "Вы уверены, что хотите выбросить {1} {2}?" + } + + "Drop Item Confirmation" + { + "ru" "Вы уверены, что хотите выбросить {1}?" + } + + "Gift Item Dropped" + { + "ru" "Вы выбросили {olive}{1}{default}!" + } + + "Gift Credits Dropped" + { + "ru" "Вы выбросили {olive}{1}{default} {2}!" + } + + "Gift Credits Found" + { + "ru" "Вы нашли {olive}{1}{default} {2}!" + } + + "Gift Item Found" + { + "ru" "Вы нашли {olive}{1}{default}!" + } + + "No items" + { + "ru" "У вас нет предметов." + } + + "Gift Request Accept" + { + "ru" "{teamcolor}{1} {default}хочет дать вам {olive}{2}{default}. Напишите {teamcolor}!accept{default}, чтобы принять подарок." + } + + "Gift Waiting to accept" + { + "ru" "В ожидании пока {teamcolor}{1} {default}примет подарок." + } + + "Not enough credits" + { + "ru" "Вам не хватает {1}." + } + + "Gift accepted - sender" + { + "ru" "{teamcolor}{1} {default}принял ваш подарок." + } + + "Gift accepted - receiver" + { + "ru" "Вы приняли подарок игрока {teamcolor}{1}{default}" + } + + "Already purchased item" + { + "ru" "Вы уже купили этот предмет: {1}" + } + + "You can't wear this item" + { + "ru" "Вы не можете носить этот предмет." + } +} \ No newline at end of file diff --git a/translations/ru/weddings.phrases.txt b/translations/ru/weddings.phrases.txt new file mode 100644 index 0000000..8bd83b7 --- /dev/null +++ b/translations/ru/weddings.phrases.txt @@ -0,0 +1,187 @@ +"Phrases" +{ + "status being checked" + { + "ru" "Ваше супружеское положение проверяется, попробуйте позже." + } + + "no singles on server" + { + "ru" "В данный момент на сервере нет одиночек." + } + + "already proposed" + { + "#format" "{1:s}" + "ru" "Вы уже предложили игроку {green}{1}{default}!" + } + + "already married" + { + "#format" "{1:s}" + "ru" "Вы уже женаты на {green}{1}{default}!" + } + + "revoke info" + { + "ru" "Напишите !revoke чтобы отменить ваше предложение." + } + + "divorce info" + { + "ru" "Напишите !divorce для развода." + } + + "proposal revoked" + { + "#format" "{1:s}" + "ru" "Вы отменили свое предложение для {green}{1}{default}!" + } + + "not proposed" + { + "ru" "Вы никому не предлагали." + } + + "not married" + { + "ru" "Вы не женаты." + } + + "marriage info" + { + "ru" "Напишите !marry чтобы просмотреть всех одиночек." + } + + "marriage revoked days" + { + "#format" "{1:s},{2:s},{3:i}" + "ru" "{green}{1}{default} развелся с {green}{2}{default} после {green}{3} дня{default} брака!" + } + + "marriage revoked months" + { + "#format" "{1:s},{2:s},{3:i}" + "ru" "{green}{1}{default} развелся с {green}{2}{default} после {green}{3} месяцев{default} брака!" + } + + "marriage revoked years" + { + "#format" "{1:s},{2:s},{3:i}" + "ru" "{green}{1}{default} развелся с {green}{2}{default} после {green}{3} лет{default} брака!" + } + + "divorce notification" + { + "ru" "Они оба снова свободны!" + } + + "no proposals" + { + "ru" "В настоящее время никто не предложил вам." + } + + "proposal notification" + { + "#format" "{1:s}" + "ru" "Вы получили предложение о браке от {green}{1}{default}!" + } + + "proposal info" + { + "ru" "Напишите !proposals просмотреть всех игроков, которые предложили вам." + } + + "submission info" + { + "ru" "Ваше предложение было отправлено. Удачи!" + } + + "bidirectional proposal" + { + "#format" "{1:s}" + "ru" "{green}{1}{default} уже предложил вам!" + } + + "target not on server" + { + "ru" "Ваша вторая половинка уже покинула сервер." + } + + "got married" + { + "#format" "{1:s}" + "ru" "Вы женились {green}{1}{default}!" + } + + "proposal accepted" + { + "#format" "{1:s}" + "ru" "{green}{1}{default} принял ваше предложение о браке!" + } + + "marriage notification" + { + "#format" "{1:s},{2:s}" + "ru" "{green}{1}{default} и {green}{2}{default} теперь женаты! Поздравляем!" + } + + "proposer not on server" + { + "ru" "Ваша любовь сейчас не на сервере, вы должны подождать." + } + + "love already married" + { + "ru" "Ваша любовь уже вышла замуж за кого-то другого." + } + + "!marry menu title" + { + "ru" "Одиночек онлайн:" + } + + "!proposals menu title" + { + "ru" "Принять предложение от:" + } + + "!couples menu title" + { + "#format" "{1:i}" + "ru" "Топ {1} пар:" + } + + "!couples menu entry" + { + "#format" "{1:s},{2:s},{3:s},{4:i}" + "ru" "{1} & {2} - {3} - {4} очков" + } + + "no couples" + { + "ru" "На сервере нет зарегистрированных супружеских пар." + } + + "reset proposals" + { + "ru" "Таблица weddings_proposals была успешно очищена." + } + + "reset marriages" + { + "ru" "Таблица weddings_marriages была успешно очищена." + } + + "spam" + { + "ru" "Уважайте брак, не злоупотребляй командами!" + } + + "delay info" + { + "#format" "{1:.2f}" + "ru" "Перезарядка команды команды {green}{1} мин.{default}." + } + +} \ No newline at end of file diff --git a/translations/tradechat.phrases.txt b/translations/tradechat.phrases.txt index 16fd94e..d0ec24f 100644 --- a/translations/tradechat.phrases.txt +++ b/translations/tradechat.phrases.txt @@ -27,12 +27,14 @@ "en" "{green}[%s] {default}To send your last offer again, type {lightgreen}/LT{default}." "hu" "{green}[%s] {default}Az utolsó ajánlatok megtekintéséhez írd be: {lightgreen}/LT{default}." "pl" "{green}[%s] {default}By wysłać ponownie poprzednią ofertę, wpisz {lightgreen}/LT{default}." + "ru" "{green}[%s] {default}Чтобы отправить последнее предложение ещё раз, введите {lightgreen}/LT{default}." "ko" "{green}[%s] {default}마지막으로 보낸 거래 메세지를 다시 보내려면, 채팅에 {lightgreen}/LT{default}을(를) 입력하세요." } "Advert4" { "en" "{green}[%s] {default}To check what your last offer was, type {lightgreen}/MLT{default}." "pl" "{green}[%s] {default}By sprawdzić jaka była Twoja poprzednia oferta, wpisz {lightgreen}/MLT{default}." + "ru" "{green}[%s] {default}Чтобы узнать, какое было ваше последнее предложение, введите {lightgreen}/MLT{default}." "ko" "{green}[%s] {default}자신이 마지막으로 보낸 거래 메세지를 확인하려면, 채팅에 {lightgreen}/MLT{default}을(를) 입력하세요." } "HideChatOn" @@ -61,6 +63,7 @@ { "en" "{green}[%s] {lightgreen}This option is currently unavailable." "pl" "{green}[%s] {lightgreen}Ta opcja jest chwilo niedostępna." + "ru" "{green}[%s] {lightgreen}Эта опция в настоящее время недоступна." "ko" "{green}[%s] {lightgreen}이 기능은 사용할 수 없습니다." } "TradeDisabledForYou" @@ -144,6 +147,7 @@ { "en" "{green}[%s] {lightgreen}You must wait %d seconds before sending your next offer." "pl" "{green}[%s] {lightgreen}Musisz poczekać %d sekund przed wysłaniem kolejnej oferty." + "ru" "{green}[%s] {lightgreen}Вы должны подождать %d сек. перед отправкой следующего предложения." "ko" "{green}[%s] {lightgreen}%d초 이내에 거래 채팅을 다시 보낼 수 없습니다." } "LastMessageIsEmpty" @@ -151,12 +155,14 @@ "en" "{green}[%s] {lightgreen}You have not sent any offers yet." "hu" "{green}[%s] {lightgreen}Nem küldtél semmilyen ajánlatot." "pl" "{green}[%s] {lightgreen}Nie wysłałeś jeszcze żadnej oferty." + "ru" "{green}[%s] {lightgreen}Вы ещё не отправляли ни одного предложения." "ko" "{green}[%s] {lightgreen}아직 거래 채팅을 사용하지 않았습니다." } "YourLastMessage" { "en" "{green}[%s] {lightgreen}Your last offer: {default}%s" "pl" "{green}[%s] {lightgreen}Twoja poprzednia oferta: {default}%s" + "ru" "{green}[%s] {lightgreen}Ваше последнее предложение: {default}%s" "ko" "{green}[%s] {lightgreen}마지막으로 보낸 거래 채팅: {default}%s" } "Offer"