Initial commit

This commit is contained in:
2025-04-15 22:27:20 -04:00
parent 5b7b68f81f
commit 771d8fe8e8
597 changed files with 149544 additions and 0 deletions

2
scripting/temp/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.smx
discord_api.zip

2482
scripting/temp/BossSpawns.sp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,379 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod SQL Admins Plugin (Prefetch)
* Prefetches admins from an SQL database without threading.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
/* We like semicolons */
#pragma semicolon 1
#include <sourcemod>
#pragma newdecls required
public Plugin myinfo =
{
name = "SQL Admins (Prefetch)",
author = "AlliedModders LLC",
description = "Reads all admins from SQL",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
public void OnRebuildAdminCache(AdminCachePart part)
{
/* First try to get a database connection */
char error[255];
Database db;
if (SQL_CheckConfig("admins"))
{
db = SQL_Connect("admins", true, error, sizeof(error));
} else {
db = SQL_Connect("default", true, error, sizeof(error));
}
if (db == null)
{
LogError("Could not connect to database \"default\": %s", error);
return;
}
if (part == AdminCache_Overrides)
{
FetchOverrides(db);
} else if (part == AdminCache_Groups) {
FetchGroups(db);
} else if (part == AdminCache_Admins) {
FetchUsers(db);
}
delete db;
}
void FetchUsers(Database db)
{
char query[255], error[255];
DBResultSet rs;
Format(query, sizeof(query), "SELECT id, authtype, identity, password, flags, name, immunity FROM sm_admins");
if ((rs = SQL_Query(db, query)) == null)
{
SQL_GetError(db, error, sizeof(error));
LogError("FetchUsers() query failed: %s", query);
LogError("Query error: %s", error);
return;
}
char authtype[16];
char identity[80];
char password[80];
char flags[32];
char name[80];
int immunity;
AdminId adm;
GroupId grp;
int id;
/* Keep track of a mapping from admin DB IDs to internal AdminIds to
* enable group lookups en masse */
StringMap htAdmins = new StringMap();
char key[16];
while (rs.FetchRow())
{
id = rs.FetchInt(0);
IntToString(id, key, sizeof(key));
rs.FetchString(1, authtype, sizeof(authtype));
rs.FetchString(2, identity, sizeof(identity));
rs.FetchString(3, password, sizeof(password));
rs.FetchString(4, flags, sizeof(flags));
rs.FetchString(5, name, sizeof(name));
immunity = rs.FetchInt(6);
/* Use a pre-existing admin if we can */
if ((adm = FindAdminByIdentity(authtype, identity)) == INVALID_ADMIN_ID)
{
adm = CreateAdmin(name);
if (!adm.BindIdentity(authtype, identity))
{
LogError("Could not bind prefetched SQL admin (authtype \"%s\") (identity \"%s\")", authtype, identity);
continue;
}
}
htAdmins.SetValue(key, adm);
#if defined _DEBUG
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s,%d):%d", id, authtype, identity, password, flags, name, immunity, adm);
#endif
/* See if this admin wants a password */
if (password[0] != '\0')
{
adm.SetPassword(password);
}
/* Apply each flag */
int len = strlen(flags);
AdminFlag flag;
for (int i=0; i<len; i++)
{
if (!FindFlagByChar(flags[i], flag))
{
continue;
}
adm.SetFlag(flag, true);
}
adm.ImmunityLevel = immunity;
}
delete rs;
Format(query, sizeof(query), "SELECT ag.admin_id AS id, g.name FROM sm_admins_groups ag JOIN sm_groups g ON ag.group_id = g.id ORDER BY id, inherit_order ASC");
if ((rs = SQL_Query(db, query)) == null)
{
SQL_GetError(db, error, sizeof(error));
LogError("FetchUsers() query failed: %s", query);
LogError("Query error: %s", error);
return;
}
char group[80];
while (rs.FetchRow())
{
IntToString(rs.FetchInt(0), key, sizeof(key));
rs.FetchString(1, group, sizeof(group));
if (htAdmins.GetValue(key, adm))
{
if ((grp = FindAdmGroup(group)) == INVALID_GROUP_ID)
{
/* Group wasn't found, don't bother with it. */
continue;
}
adm.InheritGroup(grp);
}
}
delete rs;
delete htAdmins;
}
void FetchGroups(Database db)
{
char query[255];
DBResultSet rs;
Format(query, sizeof(query), "SELECT flags, name, immunity_level FROM sm_groups");
if ((rs = SQL_Query(db, query)) == null)
{
char error[255];
SQL_GetError(db, error, sizeof(error));
LogError("FetchGroups() query failed: %s", query);
LogError("Query error: %s", error);
return;
}
/* Now start fetching groups */
char flags[32];
char name[128];
int immunity;
while (rs.FetchRow())
{
rs.FetchString(0, flags, sizeof(flags));
rs.FetchString(1, name, sizeof(name));
immunity = rs.FetchInt(2);
#if defined _DEBUG
PrintToServer("Adding group (%d, %s, %s)", immunity, flags, name);
#endif
/* Find or create the group */
GroupId grp;
if ((grp = FindAdmGroup(name)) == INVALID_GROUP_ID)
{
grp = CreateAdmGroup(name);
}
/* Add flags from the database to the group */
int num_flag_chars = strlen(flags);
for (int i=0; i<num_flag_chars; i++)
{
AdminFlag flag;
if (!FindFlagByChar(flags[i], flag))
{
continue;
}
grp.SetFlag(flag, true);
}
/* Set the immunity level this group has */
grp.ImmunityLevel = immunity;
}
delete rs;
/**
* Get immunity in a big lump. This is a nasty query but it gets the job done.
*/
int len = 0;
len += Format(query[len], sizeof(query)-len, "SELECT g1.name, g2.name FROM sm_group_immunity gi");
len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g1 ON g1.id = gi.group_id ");
len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g2 ON g2.id = gi.other_id");
if ((rs = SQL_Query(db, query)) == null)
{
char error[255];
SQL_GetError(db, error, sizeof(error));
LogError("FetchGroups() query failed: %s", query);
LogError("Query error: %s", error);
return;
}
while (rs.FetchRow())
{
char group1[80];
char group2[80];
GroupId grp, other;
rs.FetchString(0, group1, sizeof(group1));
rs.FetchString(1, group2, sizeof(group2));
if (((grp = FindAdmGroup(group1)) == INVALID_GROUP_ID)
|| (other = FindAdmGroup(group2)) == INVALID_GROUP_ID)
{
continue;
}
grp.AddGroupImmunity(other);
#if defined _DEBUG
PrintToServer("SetAdmGroupImmuneFrom(%d, %d)", grp, other);
#endif
}
delete rs;
/**
* Fetch overrides in a lump query.
*/
Format(query, sizeof(query), "SELECT g.name, go.type, go.name, go.access FROM sm_group_overrides go LEFT JOIN sm_groups g ON go.group_id = g.id");
if ((rs = SQL_Query(db, query)) == null)
{
char error[255];
SQL_GetError(db, error, sizeof(error));
LogError("FetchGroups() query failed: %s", query);
LogError("Query error: %s", error);
return;
}
char type[16];
char cmd[64];
char access[16];
while (rs.FetchRow())
{
rs.FetchString(0, name, sizeof(name));
rs.FetchString(1, type, sizeof(type));
rs.FetchString(2, cmd, sizeof(cmd));
rs.FetchString(3, access, sizeof(access));
GroupId grp;
if ((grp = FindAdmGroup(name)) == INVALID_GROUP_ID)
{
continue;
}
OverrideType o_type = Override_Command;
if (StrEqual(type, "group"))
{
o_type = Override_CommandGroup;
}
OverrideRule o_rule = Command_Deny;
if (StrEqual(access, "allow"))
{
o_rule = Command_Allow;
}
#if defined _DEBUG
PrintToServer("AddAdmGroupCmdOverride(%d, %s, %d, %d)", grp, cmd, o_type, o_rule);
#endif
grp.AddCommandOverride(cmd, o_type, o_rule);
}
delete rs;
}
void FetchOverrides(Database db)
{
char query[255];
DBResultSet rs;
Format(query, sizeof(query), "SELECT type, name, flags FROM sm_overrides");
if ((rs = SQL_Query(db, query)) == null)
{
char error[255];
SQL_GetError(db, error, sizeof(error));
LogError("FetchOverrides() query failed: %s", query);
LogError("Query error: %s", error);
return;
}
char type[64];
char name[64];
char flags[32];
int flag_bits;
while (rs.FetchRow())
{
rs.FetchString(0, type, sizeof(type));
rs.FetchString(1, name, sizeof(name));
rs.FetchString(2, flags, sizeof(flags));
#if defined _DEBUG
PrintToServer("Adding override (%s, %s, %s)", type, name, flags);
#endif
flag_bits = ReadFlagString(flags);
if (StrEqual(type, "command"))
{
AddCommandOverride(name, Override_Command, flag_bits);
} else if (StrEqual(type, "group")) {
AddCommandOverride(name, Override_CommandGroup, flag_bits);
}
}
delete rs;
}

View File

@@ -0,0 +1,847 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod SQL Admins Plugin (Threaded)
* Fetches admins from an SQL database dynamically.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
/* We like semicolons */
#pragma semicolon 1
#include <sourcemod>
#pragma newdecls required
public Plugin myinfo =
{
name = "SQL Admins (Threaded)",
author = "AlliedModders LLC",
description = "Reads admins from SQL dynamically",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
/**
* Notes:
*
* 1) All queries in here are high priority. This is because the admin stuff
* is very important. Do not take this to mean that in your script,
* everything should be high priority.
*
* 2) All callbacks are locked with "sequence numbers." This is to make sure
* that multiple calls to sm_reloadadmins and the like do not make us
* store the results from two or more callbacks accidentally. Instead, we
* check the sequence number in each callback with the current "allowed"
* sequence number, and if it doesn't match, the callback is cancelled.
*
* 3) Sequence numbers for groups and overrides are not cleared unless there
* was a 100% success in the fetch. This is so we can potentially implement
* connection retries in the future.
*
* 4) Sequence numbers for the user cache are ignored except for being
* non-zero, which means players in-game should be re-checked for admin
* powers.
*/
Database hDatabase = null; /** Database connection */
int g_sequence = 0; /** Global unique sequence number */
int ConnectLock = 0; /** Connect sequence number */
int RebuildCachePart[3] = {0}; /** Cache part sequence numbers */
int PlayerSeq[MAXPLAYERS+1]; /** Player-specific sequence numbers */
bool PlayerAuth[MAXPLAYERS+1]; /** Whether a player has been "pre-authed" */
//#define _DEBUG
public void OnMapEnd()
{
/**
* Clean up on map end just so we can start a fresh connection when we need it later.
*/
delete hDatabase;
}
public bool OnClientConnect(int client, char[] rejectmsg, int maxlen)
{
PlayerSeq[client] = 0;
PlayerAuth[client] = false;
return true;
}
public void OnClientDisconnect(int client)
{
PlayerSeq[client] = 0;
PlayerAuth[client] = false;
}
public void OnDatabaseConnect(Database db, const char[] error, any data)
{
#if defined _DEBUG
PrintToServer("OnDatabaseConnect(%x, %d) ConnectLock=%d", db, data, ConnectLock);
#endif
/**
* If this happens to be an old connection request, ignore it.
*/
if (data != ConnectLock || hDatabase != null)
{
delete db;
return;
}
ConnectLock = 0;
hDatabase = db;
/**
* See if the connection is valid. If not, don't un-mark the caches
* as needing rebuilding, in case the next connection request works.
*/
if (hDatabase == null)
{
LogError("Failed to connect to database: %s", error);
return;
}
/**
* See if we need to get any of the cache stuff now.
*/
int sequence;
if ((sequence = RebuildCachePart[AdminCache_Overrides]) != 0)
{
FetchOverrides(hDatabase, sequence);
}
if ((sequence = RebuildCachePart[AdminCache_Groups]) != 0)
{
FetchGroups(hDatabase, sequence);
}
if ((sequence = RebuildCachePart[AdminCache_Admins]) != 0)
{
FetchUsersWeCan(hDatabase);
}
}
void RequestDatabaseConnection()
{
ConnectLock = ++g_sequence;
if (SQL_CheckConfig("admins"))
{
Database.Connect(OnDatabaseConnect, "admins", ConnectLock);
} else {
Database.Connect(OnDatabaseConnect, "default", ConnectLock);
}
}
public void OnRebuildAdminCache(AdminCachePart part)
{
/**
* Mark this part of the cache as being rebuilt. This is used by the
* callback system to determine whether the results should still be
* used.
*/
int sequence = ++g_sequence;
RebuildCachePart[part] = sequence;
/**
* If we don't have a database connection, we can't do any lookups just yet.
*/
if (!hDatabase)
{
/**
* Ask for a new connection if we need it.
*/
if (!ConnectLock)
{
RequestDatabaseConnection();
}
return;
}
if (part == AdminCache_Overrides)
{
FetchOverrides(hDatabase, sequence);
} else if (part == AdminCache_Groups) {
FetchGroups(hDatabase, sequence);
} else if (part == AdminCache_Admins) {
FetchUsersWeCan(hDatabase);
}
}
public Action OnClientPreAdminCheck(int client)
{
PlayerAuth[client] = true;
/**
* Play nice with other plugins. If there's no database, don't delay the
* connection process. Unfortunately, we can't attempt anything else and
* we just have to hope either the database is waiting or someone will type
* sm_reloadadmins.
*/
if (hDatabase == null)
{
return Plugin_Continue;
}
/**
* Similarly, if the cache is in the process of being rebuilt, don't delay
* the user's normal connection flow. The database will soon auth the user
* normally.
*/
if (RebuildCachePart[AdminCache_Admins] != 0)
{
return Plugin_Continue;
}
/**
* If someone has already assigned an admin ID (bad bad bad), don't
* bother waiting.
*/
if (GetUserAdmin(client) != INVALID_ADMIN_ID)
{
return Plugin_Continue;
}
FetchUser(hDatabase, client);
return Plugin_Handled;
}
public void OnReceiveUserGroups(Database db, DBResultSet rs, const char[] error, any data)
{
DataPack pk = view_as<DataPack>(data);
pk.Reset();
int client = pk.ReadCell();
int sequence = pk.ReadCell();
/**
* Make sure it's the same client.
*/
if (PlayerSeq[client] != sequence)
{
delete pk;
return;
}
AdminId adm = view_as<AdminId>(pk.ReadCell());
/**
* Someone could have sneakily changed the admin id while we waited.
*/
if (GetUserAdmin(client) != adm)
{
NotifyPostAdminCheck(client);
delete pk;
return;
}
/**
* See if we got results.
*/
if (rs == null)
{
char query[255];
pk.ReadString(query, sizeof(query));
LogError("SQL error receiving user: %s", error);
LogError("Query dump: %s", query);
NotifyPostAdminCheck(client);
delete pk;
return;
}
char name[80];
GroupId grp;
while (rs.FetchRow())
{
rs.FetchString(0, name, sizeof(name));
if ((grp = FindAdmGroup(name)) == INVALID_GROUP_ID)
{
continue;
}
#if defined _DEBUG
PrintToServer("Binding user group (%d, %d, %d, %s, %d)", client, sequence, adm, name, grp);
#endif
adm.InheritGroup(grp);
}
/**
* We're DONE! Omg.
*/
NotifyPostAdminCheck(client);
delete pk;
}
public void OnReceiveUser(Database db, DBResultSet rs, const char[] error, any data)
{
DataPack pk = view_as<DataPack>(data);
pk.Reset();
int client = pk.ReadCell();
/**
* Check if this is the latest result request.
*/
int sequence = pk.ReadCell();
if (PlayerSeq[client] != sequence)
{
/* Discard everything, since we're out of sequence. */
delete pk;
return;
}
/**
* If we need to use the results, make sure they succeeded.
*/
if (rs == null)
{
char query[255];
pk.ReadString(query, sizeof(query));
LogError("SQL error receiving user: %s", error);
LogError("Query dump: %s", query);
RunAdminCacheChecks(client);
NotifyPostAdminCheck(client);
delete pk;
return;
}
int num_accounts = rs.RowCount;
if (num_accounts == 0)
{
RunAdminCacheChecks(client);
NotifyPostAdminCheck(client);
delete pk;
return;
}
char authtype[16];
char identity[80];
char password[80];
char flags[32];
char name[80];
int immunity, id;
AdminId adm;
/**
* Cache user info -- [0] = db id, [1] = cache id, [2] = groups
*/
int[][] user_lookup = new int[num_accounts][3];
int total_users = 0;
while (rs.FetchRow())
{
id = rs.FetchInt(0);
rs.FetchString(1, authtype, sizeof(authtype));
rs.FetchString(2, identity, sizeof(identity));
rs.FetchString(3, password, sizeof(password));
rs.FetchString(4, flags, sizeof(flags));
rs.FetchString(5, name, sizeof(name));
immunity = rs.FetchInt(7);
/* For dynamic admins we clear anything already in the cache. */
if ((adm = FindAdminByIdentity(authtype, identity)) != INVALID_ADMIN_ID)
{
RemoveAdmin(adm);
}
adm = CreateAdmin(name);
if (!adm.BindIdentity(authtype, identity))
{
LogError("Could not bind prefetched SQL admin (authtype \"%s\") (identity \"%s\")", authtype, identity);
continue;
}
user_lookup[total_users][0] = id;
user_lookup[total_users][1] = view_as<int>(adm);
user_lookup[total_users][2] = rs.FetchInt(6);
total_users++;
#if defined _DEBUG
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s,%d):%d:%d", id, authtype, identity, password, flags, name, immunity, adm, user_lookup[total_users-1][2]);
#endif
/* See if this admin wants a password */
if (password[0] != '\0')
{
adm.SetPassword(password);
}
adm.ImmunityLevel = immunity;
/* Apply each flag */
int len = strlen(flags);
AdminFlag flag;
for (int i=0; i<len; i++)
{
if (!FindFlagByChar(flags[i], flag))
{
continue;
}
adm.SetFlag(flag, true);
}
}
/**
* Try binding the user.
*/
int group_count = 0;
RunAdminCacheChecks(client);
adm = GetUserAdmin(client);
id = 0;
for (int i=0; i<total_users; i++)
{
if (user_lookup[i][1] == view_as<int>(adm))
{
id = user_lookup[i][0];
group_count = user_lookup[i][2];
break;
}
}
#if defined _DEBUG
PrintToServer("Binding client (%d, %d) resulted in: (%d, %d, %d)", client, sequence, id, adm, group_count);
#endif
/**
* If we can't verify that we assigned a database admin, or the user has no
* groups, don't bother doing anything.
*/
if (!id || !group_count)
{
NotifyPostAdminCheck(client);
delete pk;
return;
}
/**
* The user has groups -- we need to fetch them!
*/
char query[255];
Format(query, sizeof(query), "SELECT g.name FROM sm_admins_groups ag JOIN sm_groups g ON ag.group_id = g.id WHERE ag.admin_id = %d", id);
pk.Reset();
pk.WriteCell(client);
pk.WriteCell(sequence);
pk.WriteCell(adm);
pk.WriteString(query);
db.Query(OnReceiveUserGroups, query, pk, DBPrio_High);
}
void FetchUser(Database db, int client)
{
char name[MAX_NAME_LENGTH];
char safe_name[(MAX_NAME_LENGTH * 2) - 1];
char steamid[32];
char steamidalt[32];
char ipaddr[24];
/**
* Get authentication information from the client.
*/
GetClientName(client, name, sizeof(name));
GetClientIP(client, ipaddr, sizeof(ipaddr));
steamid[0] = '\0';
if (GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)))
{
if (StrEqual(steamid, "STEAM_ID_LAN"))
{
steamid[0] = '\0';
}
}
db.Escape(name, safe_name, sizeof(safe_name));
/**
* Construct the query using the information the user gave us.
*/
char query[512];
int len = 0;
len += Format(query[len], sizeof(query)-len, "SELECT a.id, a.authtype, a.identity, a.password, a.flags, a.name, COUNT(ag.group_id), immunity");
len += Format(query[len], sizeof(query)-len, " FROM sm_admins a LEFT JOIN sm_admins_groups ag ON a.id = ag.admin_id WHERE ");
len += Format(query[len], sizeof(query)-len, " (a.authtype = 'ip' AND a.identity = '%s')", ipaddr);
len += Format(query[len], sizeof(query)-len, " OR (a.authtype = 'name' AND a.identity = '%s')", safe_name);
if (steamid[0] != '\0')
{
strcopy(steamidalt, sizeof(steamidalt), steamid);
steamidalt[6] = (steamid[6] == '0') ? '1' : '0';
len += Format(query[len], sizeof(query)-len, " OR (a.authtype = 'steam' AND (a.identity = '%s' OR a.identity = '%s'))", steamid, steamidalt);
}
len += Format(query[len], sizeof(query)-len, " GROUP BY a.id");
/**
* Send the actual query.
*/
PlayerSeq[client] = ++g_sequence;
DataPack pk = new DataPack();
pk.WriteCell(client);
pk.WriteCell(PlayerSeq[client]);
pk.WriteString(query);
#if defined _DEBUG
PrintToServer("Sending user query: %s", query);
#endif
db.Query(OnReceiveUser, query, pk, DBPrio_High);
}
void FetchUsersWeCan(Database db)
{
for (int i=1; i<=MaxClients; i++)
{
if (PlayerAuth[i] && GetUserAdmin(i) == INVALID_ADMIN_ID)
{
FetchUser(db, i);
}
}
/**
* This round of updates is done. Go in peace.
*/
RebuildCachePart[AdminCache_Admins] = 0;
}
public void OnReceiveGroupImmunity(Database db, DBResultSet rs, const char[] error, any data)
{
DataPack pk = view_as<DataPack>(data);
pk.Reset();
/**
* Check if this is the latest result request.
*/
int sequence = pk.ReadCell();
if (RebuildCachePart[AdminCache_Groups] != sequence)
{
/* Discard everything, since we're out of sequence. */
delete pk;
return;
}
/**
* If we need to use the results, make sure they succeeded.
*/
if (rs == null)
{
char query[255];
pk.ReadString(query, sizeof(query));
LogError("SQL error receiving group immunity: %s", error);
LogError("Query dump: %s", query);
delete pk;
return;
}
/* We're done with the pack forever. */
delete pk;
while (rs.FetchRow())
{
char group1[80];
char group2[80];
GroupId grp, other;
rs.FetchString(0, group1, sizeof(group1));
rs.FetchString(1, group2, sizeof(group2));
if (((grp = FindAdmGroup(group1)) == INVALID_GROUP_ID)
|| (other = FindAdmGroup(group2)) == INVALID_GROUP_ID)
{
continue;
}
grp.AddGroupImmunity(other);
#if defined _DEBUG
PrintToServer("SetAdmGroupImmuneFrom(%d, %d)", grp, other);
#endif
}
/* Clear the sequence so another connect doesn't refetch */
RebuildCachePart[AdminCache_Groups] = 0;
}
public void OnReceiveGroupOverrides(Database db, DBResultSet rs, const char[] error, any data)
{
DataPack pk = view_as<DataPack>(data);
pk.Reset();
/**
* Check if this is the latest result request.
*/
int sequence = pk.ReadCell();
if (RebuildCachePart[AdminCache_Groups] != sequence)
{
/* Discard everything, since we're out of sequence. */
delete pk;
return;
}
/**
* If we need to use the results, make sure they succeeded.
*/
if (rs == null)
{
char query[255];
pk.ReadString(query, sizeof(query));
LogError("SQL error receiving group overrides: %s", error);
LogError("Query dump: %s", query);
delete pk;
return;
}
/**
* Fetch the overrides.
*/
char name[80];
char type[16];
char command[64];
char access[16];
GroupId grp;
while (rs.FetchRow())
{
rs.FetchString(0, name, sizeof(name));
rs.FetchString(1, type, sizeof(type));
rs.FetchString(2, command, sizeof(command));
rs.FetchString(3, access, sizeof(access));
/* Find the group. This is actually faster than doing the ID lookup. */
if ((grp = FindAdmGroup(name)) == INVALID_GROUP_ID)
{
/* Oh well, just ignore it. */
continue;
}
OverrideType o_type = Override_Command;
if (StrEqual(type, "group"))
{
o_type = Override_CommandGroup;
}
OverrideRule o_rule = Command_Deny;
if (StrEqual(access, "allow"))
{
o_rule = Command_Allow;
}
#if defined _DEBUG
PrintToServer("AddAdmGroupCmdOverride(%d, %s, %d, %d)", grp, command, o_type, o_rule);
#endif
grp.AddCommandOverride(command, o_type, o_rule);
}
/**
* It's time to get the group immunity list.
*/
int len = 0;
char query[256];
len += Format(query[len], sizeof(query)-len, "SELECT g1.name, g2.name FROM sm_group_immunity gi");
len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g1 ON g1.id = gi.group_id ");
len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g2 ON g2.id = gi.other_id");
pk.Reset();
pk.WriteCell(sequence);
pk.WriteString(query);
db.Query(OnReceiveGroupImmunity, query, pk, DBPrio_High);
}
public void OnReceiveGroups(Database db, DBResultSet rs, const char[] error, any data)
{
DataPack pk = view_as<DataPack>(data);
pk.Reset();
/**
* Check if this is the latest result request.
*/
int sequence = pk.ReadCell();
if (RebuildCachePart[AdminCache_Groups] != sequence)
{
/* Discard everything, since we're out of sequence. */
delete pk;
return;
}
/**
* If we need to use the results, make sure they succeeded.
*/
if (rs == null)
{
char query[255];
pk.ReadString(query, sizeof(query));
LogError("SQL error receiving groups: %s", error);
LogError("Query dump: %s", query);
delete pk;
return;
}
/**
* Now start fetching groups.
*/
char flags[32];
char name[128];
int immunity;
while (rs.FetchRow())
{
rs.FetchString(0, flags, sizeof(flags));
rs.FetchString(1, name, sizeof(name));
immunity = rs.FetchInt(2);
#if defined _DEBUG
PrintToServer("Adding group (%d, %s, %s)", immunity, flags, name);
#endif
/* Find or create the group */
GroupId grp;
if ((grp = FindAdmGroup(name)) == INVALID_GROUP_ID)
{
grp = CreateAdmGroup(name);
}
/* Add flags from the database to the group */
int num_flag_chars = strlen(flags);
for (int i=0; i<num_flag_chars; i++)
{
AdminFlag flag;
if (!FindFlagByChar(flags[i], flag))
{
continue;
}
grp.SetFlag(flag, true);
}
grp.ImmunityLevel = immunity;
}
/**
* It's time to get the group override list.
*/
char query[255];
Format(query,
sizeof(query),
"SELECT g.name, og.type, og.name, og.access FROM sm_group_overrides og JOIN sm_groups g ON og.group_id = g.id ORDER BY g.id DESC");
pk.Reset();
pk.WriteCell(sequence);
pk.WriteString(query);
db.Query(OnReceiveGroupOverrides, query, pk, DBPrio_High);
}
void FetchGroups(Database db, int sequence)
{
char query[255];
Format(query, sizeof(query), "SELECT flags, name, immunity_level FROM sm_groups");
DataPack pk = new DataPack();
pk.WriteCell(sequence);
pk.WriteString(query);
db.Query(OnReceiveGroups, query, pk, DBPrio_High);
}
public void OnReceiveOverrides(Database db, DBResultSet rs, const char[] error, any data)
{
DataPack pk = view_as<DataPack>(data);
pk.Reset();
/**
* Check if this is the latest result request.
*/
int sequence = pk.ReadCell();
if (RebuildCachePart[AdminCache_Overrides] != sequence)
{
/* Discard everything, since we're out of sequence. */
delete pk;
return;
}
/**
* If we need to use the results, make sure they succeeded.
*/
if (rs == null)
{
char query[255];
pk.ReadString(query, sizeof(query));
LogError("SQL error receiving overrides: %s", error);
LogError("Query dump: %s", query);
delete pk;
return;
}
/**
* We're done with you, now.
*/
delete pk;
char type[64];
char name[64];
char flags[32];
int flag_bits;
while (rs.FetchRow())
{
rs.FetchString(0, type, sizeof(type));
rs.FetchString(1, name, sizeof(name));
rs.FetchString(2, flags, sizeof(flags));
#if defined _DEBUG
PrintToServer("Adding override (%s, %s, %s)", type, name, flags);
#endif
flag_bits = ReadFlagString(flags);
if (StrEqual(type, "command"))
{
AddCommandOverride(name, Override_Command, flag_bits);
} else if (StrEqual(type, "group")) {
AddCommandOverride(name, Override_CommandGroup, flag_bits);
}
}
/* Clear the sequence so another connect doesn't refetch */
RebuildCachePart[AdminCache_Overrides] = 0;
}
void FetchOverrides(Database db, int sequence)
{
char query[255];
Format(query, sizeof(query), "SELECT type, name, flags FROM sm_overrides");
DataPack pk = new DataPack();
pk.WriteCell(sequence);
pk.WriteString(query);
db.Query(OnReceiveOverrides, query, pk, DBPrio_High);
}

157
scripting/temp/adminhelp.sp Normal file
View File

@@ -0,0 +1,157 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Admin Help Plugin
* Displays and searches SourceMod commands and descriptions.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#pragma newdecls required
#define COMMANDS_PER_PAGE 10
public Plugin myinfo =
{
name = "Admin Help",
author = "AlliedModders LLC",
description = "Display command information",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("adminhelp.phrases");
RegConsoleCmd("sm_help", HelpCmd, "Displays SourceMod commands and descriptions");
RegConsoleCmd("sm_searchcmd", HelpCmd, "Searches SourceMod commands");
}
public Action HelpCmd(int client, int args)
{
char arg[64], CmdName[20];
int PageNum = 1;
bool DoSearch;
GetCmdArg(0, CmdName, sizeof(CmdName));
if (GetCmdArgs() >= 1)
{
GetCmdArg(1, arg, sizeof(arg));
StringToIntEx(arg, PageNum);
PageNum = (PageNum <= 0) ? 1 : PageNum;
}
DoSearch = (strcmp("sm_help", CmdName) == 0) ? false : true;
if (GetCmdReplySource() == SM_REPLY_TO_CHAT)
{
ReplyToCommand(client, "[SM] %t", "See console for output");
}
char Name[64];
char Desc[255];
char NoDesc[128];
int Flags;
Handle CmdIter = GetCommandIterator();
FormatEx(NoDesc, sizeof(NoDesc), "%T", "No description available", client);
if (DoSearch)
{
int i = 1;
while (ReadCommandIterator(CmdIter, Name, sizeof(Name), Flags, Desc, sizeof(Desc)))
{
if ((StrContains(Name, arg, false) != -1) && CheckCommandAccess(client, Name, Flags))
{
PrintToConsole(client, "[%03d] %s - %s", i++, Name, (Desc[0] == '\0') ? NoDesc : Desc);
}
}
if (i == 1)
{
PrintToConsole(client, "%t", "No matching results found");
}
} else {
PrintToConsole(client, "%t", "SM help commands");
/* Skip the first N commands if we need to */
if (PageNum > 1)
{
int i;
int EndCmd = (PageNum-1) * COMMANDS_PER_PAGE - 1;
for (i=0; ReadCommandIterator(CmdIter, Name, sizeof(Name), Flags, Desc, sizeof(Desc)) && i<EndCmd; )
{
if (CheckCommandAccess(client, Name, Flags))
{
i++;
}
}
if (i == 0)
{
PrintToConsole(client, "%t", "No commands available");
delete CmdIter;
return Plugin_Handled;
}
}
/* Start printing the commands to the client */
int i;
int StartCmd = (PageNum-1) * COMMANDS_PER_PAGE;
for (i=0; ReadCommandIterator(CmdIter, Name, sizeof(Name), Flags, Desc, sizeof(Desc)) && i<COMMANDS_PER_PAGE; )
{
if (CheckCommandAccess(client, Name, Flags))
{
i++;
PrintToConsole(client, "[%03d] %s - %s", i+StartCmd, Name, (Desc[0] == '\0') ? NoDesc : Desc);
}
}
if (i == 0)
{
PrintToConsole(client, "%t", "No commands available");
} else {
PrintToConsole(client, "%t", "Entries n - m in page k", StartCmd+1, i+StartCmd, PageNum);
}
/* Test if there are more commands available */
if (ReadCommandIterator(CmdIter, Name, sizeof(Name), Flags, Desc, sizeof(Desc)) && CheckCommandAccess(client, Name, Flags))
{
PrintToConsole(client, "%t", "Type sm_help to see more", PageNum+1);
}
}
delete CmdIter;
return Plugin_Handled;
}

269
scripting/temp/adminmenu.sp Normal file
View File

@@ -0,0 +1,269 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Admin Menu Plugin
* Creates the base admin menu, for plugins to add items to.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#include <topmenus>
#pragma newdecls required
public Plugin myinfo =
{
name = "Admin Menu",
author = "AlliedModders LLC",
description = "Administration Menu",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
/* Forwards */
Handle hOnAdminMenuReady = null;
Handle hOnAdminMenuCreated = null;
/* Menus */
TopMenu hAdminMenu;
/* Top menu objects */
TopMenuObject obj_playercmds = INVALID_TOPMENUOBJECT;
TopMenuObject obj_servercmds = INVALID_TOPMENUOBJECT;
TopMenuObject obj_votingcmds = INVALID_TOPMENUOBJECT;
#include "adminmenu/dynamicmenu.sp"
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("GetAdminTopMenu", __GetAdminTopMenu);
CreateNative("AddTargetsToMenu", __AddTargetsToMenu);
CreateNative("AddTargetsToMenu2", __AddTargetsToMenu2);
RegPluginLibrary("adminmenu");
return APLRes_Success;
}
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("adminmenu.phrases");
hOnAdminMenuCreated = CreateGlobalForward("OnAdminMenuCreated", ET_Ignore, Param_Cell);
hOnAdminMenuReady = CreateGlobalForward("OnAdminMenuReady", ET_Ignore, Param_Cell);
RegAdminCmd("sm_admin", Command_DisplayMenu, ADMFLAG_GENERIC, "Displays the admin menu");
}
public void OnConfigsExecuted()
{
char path[PLATFORM_MAX_PATH];
char error[256];
BuildPath(Path_SM, path, sizeof(path), "configs/adminmenu_sorting.txt");
if (!hAdminMenu.LoadConfig(path, error, sizeof(error)))
{
LogError("Could not load admin menu config (file \"%s\": %s)", path, error);
return;
}
}
public void OnMapStart()
{
ParseConfigs();
}
public void OnAllPluginsLoaded()
{
hAdminMenu = new TopMenu(DefaultCategoryHandler);
obj_playercmds = hAdminMenu.AddCategory("PlayerCommands", DefaultCategoryHandler);
obj_servercmds = hAdminMenu.AddCategory("ServerCommands", DefaultCategoryHandler);
obj_votingcmds = hAdminMenu.AddCategory("VotingCommands", DefaultCategoryHandler);
BuildDynamicMenu();
Call_StartForward(hOnAdminMenuCreated);
Call_PushCell(hAdminMenu);
Call_Finish();
Call_StartForward(hOnAdminMenuReady);
Call_PushCell(hAdminMenu);
Call_Finish();
}
public void DefaultCategoryHandler(TopMenu topmenu,
TopMenuAction action,
TopMenuObject object_id,
int param,
char[] buffer,
int maxlength)
{
if (action == TopMenuAction_DisplayTitle)
{
if (object_id == INVALID_TOPMENUOBJECT)
{
Format(buffer, maxlength, "%T:", "Admin Menu", param);
}
else if (object_id == obj_playercmds)
{
Format(buffer, maxlength, "%T:", "Player Commands", param);
}
else if (object_id == obj_servercmds)
{
Format(buffer, maxlength, "%T:", "Server Commands", param);
}
else if (object_id == obj_votingcmds)
{
Format(buffer, maxlength, "%T:", "Voting Commands", param);
}
}
else if (action == TopMenuAction_DisplayOption)
{
if (object_id == obj_playercmds)
{
Format(buffer, maxlength, "%T", "Player Commands", param);
}
else if (object_id == obj_servercmds)
{
Format(buffer, maxlength, "%T", "Server Commands", param);
}
else if (object_id == obj_votingcmds)
{
Format(buffer, maxlength, "%T", "Voting Commands", param);
}
}
}
public int __GetAdminTopMenu(Handle plugin, int numParams)
{
return view_as<int>(hAdminMenu);
}
public int __AddTargetsToMenu(Handle plugin, int numParams)
{
bool alive_only = false;
if (numParams >= 4)
{
alive_only = GetNativeCell(4);
}
return UTIL_AddTargetsToMenu(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3), alive_only);
}
public int __AddTargetsToMenu2(Handle plugin, int numParams)
{
return UTIL_AddTargetsToMenu2(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3));
}
public Action Command_DisplayMenu(int client, int args)
{
if (client == 0)
{
ReplyToCommand(client, "[SM] %t", "Command is in-game only");
return Plugin_Handled;
}
hAdminMenu.Display(client, TopMenuPosition_Start);
return Plugin_Handled;
}
stock int UTIL_AddTargetsToMenu2(Menu menu, int source_client, int flags)
{
char user_id[12];
char name[MAX_NAME_LENGTH];
char display[MAX_NAME_LENGTH+12];
int num_clients;
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientConnected(i) || IsClientInKickQueue(i))
{
continue;
}
if (((flags & COMMAND_FILTER_NO_BOTS) == COMMAND_FILTER_NO_BOTS)
&& IsFakeClient(i))
{
continue;
}
if (((flags & COMMAND_FILTER_CONNECTED) != COMMAND_FILTER_CONNECTED)
&& !IsClientInGame(i))
{
continue;
}
if (((flags & COMMAND_FILTER_ALIVE) == COMMAND_FILTER_ALIVE)
&& !IsPlayerAlive(i))
{
continue;
}
if (((flags & COMMAND_FILTER_DEAD) == COMMAND_FILTER_DEAD)
&& IsPlayerAlive(i))
{
continue;
}
if ((source_client && ((flags & COMMAND_FILTER_NO_IMMUNITY) != COMMAND_FILTER_NO_IMMUNITY))
&& !CanUserTarget(source_client, i))
{
continue;
}
IntToString(GetClientUserId(i), user_id, sizeof(user_id));
GetClientName(i, name, sizeof(name));
Format(display, sizeof(display), "%s (%s)", name, user_id);
menu.AddItem(user_id, display);
num_clients++;
}
return num_clients;
}
stock int UTIL_AddTargetsToMenu(Menu menu, int source_client, bool in_game_only, bool alive_only)
{
int flags = 0;
if (!in_game_only)
{
flags |= COMMAND_FILTER_CONNECTED;
}
if (alive_only)
{
flags |= COMMAND_FILTER_ALIVE;
}
return UTIL_AddTargetsToMenu2(menu, source_client, flags);
}

View File

@@ -0,0 +1,317 @@
#include <sourcemod>
#include <colorvariables>
#undef REQUIRE_PLUGIN
#include <updater>
#include "advertisements/topcolors.sp"
#pragma newdecls required
#pragma semicolon 1
#define PL_VERSION "2.0.2"
#define UPDATE_URL "http://ErikMinekus.github.io/sm-advertisements/update.txt"
public Plugin myinfo =
{
name = "Advertisements",
author = "Tsunami",
description = "Display advertisements",
version = PL_VERSION,
url = "http://www.tsunami-productions.nl"
};
/**
* Globals
*/
KeyValues g_hAdvertisements;
ConVar g_hEnabled;
ConVar g_hFile;
ConVar g_hInterval;
Handle g_hTimer;
/**
* Plugin Forwards
*/
public void OnPluginStart()
{
CreateConVar("sm_advertisements_version", PL_VERSION, "Display advertisements", FCVAR_NOTIFY);
g_hEnabled = CreateConVar("sm_advertisements_enabled", "1", "Enable/disable displaying advertisements.");
g_hFile = CreateConVar("sm_advertisements_file", "advertisements.txt", "File to read the advertisements from.");
g_hInterval = CreateConVar("sm_advertisements_interval", "30", "Amount of seconds between advertisements.");
g_hFile.AddChangeHook(ConVarChange_File);
g_hInterval.AddChangeHook(ConVarChange_Interval);
RegServerCmd("sm_advertisements_reload", Command_ReloadAds, "Reload the advertisements");
AddTopColors();
if (LibraryExists("updater")) {
Updater_AddPlugin(UPDATE_URL);
}
}
public void OnMapStart()
{
ParseAds();
g_hTimer = CreateTimer(g_hInterval.IntValue * 1.0, Timer_DisplayAd, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}
public void OnLibraryAdded(const char[] name)
{
if (StrEqual(name, "updater")) {
Updater_AddPlugin(UPDATE_URL);
}
}
public void ConVarChange_File(ConVar convar, const char[] oldValue, const char[] newValue)
{
ParseAds();
}
public void ConVarChange_Interval(ConVar convar, const char[] oldValue, const char[] newValue)
{
if (g_hTimer) {
KillTimer(g_hTimer);
}
g_hTimer = CreateTimer(g_hInterval.IntValue * 1.0, Timer_DisplayAd, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}
/**
* Commands
*/
public Action Command_ReloadAds(int args)
{
ParseAds();
return Plugin_Handled;
}
/**
* Menu Handlers
*/
public int Handler_DoNothing(Menu menu, MenuAction action, int param1, int param2) {}
/**
* Timers
*/
public Action Timer_DisplayAd(Handle timer)
{
if (!g_hEnabled.BoolValue) {
return;
}
char sCenter[1024], sChat[1024], sHint[1024], sMenu[1024], sTop[1024], sFlags[16];
g_hAdvertisements.GetString("center", sCenter, sizeof(sCenter));
g_hAdvertisements.GetString("chat", sChat, sizeof(sChat));
g_hAdvertisements.GetString("hint", sHint, sizeof(sHint));
g_hAdvertisements.GetString("menu", sMenu, sizeof(sMenu));
g_hAdvertisements.GetString("top", sTop, sizeof(sTop));
g_hAdvertisements.GetString("flags", sFlags, sizeof(sFlags), "none");
int iFlags = ReadFlagString(sFlags);
bool bAdmins = StrEqual(sFlags, ""),
bFlags = !StrEqual(sFlags, "none");
if (sCenter[0]) {
ProcessVariables(sCenter);
CRemoveColors(sCenter, sizeof(sCenter));
for (int i = 1; i <= MaxClients; i++) {
if (IsClientInGame(i) && !IsFakeClient(i) &&
((!bAdmins && !(bFlags && (GetUserFlagBits(i) & (iFlags|ADMFLAG_ROOT)))) ||
(bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))) {
PrintCenterText(i, sCenter);
DataPack hCenterAd;
CreateDataTimer(1.0, Timer_CenterAd, hCenterAd, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
hCenterAd.WriteCell(i);
hCenterAd.WriteString(sCenter);
}
}
}
if (sHint[0]) {
ProcessVariables(sHint);
CRemoveColors(sHint, sizeof(sHint));
for (int i = 1; i <= MaxClients; i++) {
if (IsClientInGame(i) && !IsFakeClient(i) &&
((!bAdmins && !(bFlags && (GetUserFlagBits(i) & (iFlags|ADMFLAG_ROOT)))) ||
(bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))) {
PrintHintText(i, sHint);
}
}
}
if (sMenu[0]) {
ProcessVariables(sMenu);
CRemoveColors(sMenu, sizeof(sMenu));
Panel hPl = new Panel();
hPl.DrawText(sMenu);
hPl.CurrentKey = 10;
for (int i = 1; i <= MaxClients; i++) {
if (IsClientInGame(i) && !IsFakeClient(i) &&
((!bAdmins && !(bFlags && (GetUserFlagBits(i) & (iFlags|ADMFLAG_ROOT)))) ||
(bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))) {
hPl.Send(i, Handler_DoNothing, 10);
}
}
delete hPl;
}
if (sChat[0]) {
bool bTeamColor = StrContains(sChat, "{teamcolor}", false) != -1;
ProcessVariables(sChat);
CProcessVariables(sChat, sizeof(sChat));
CAddWhiteSpace(sChat, sizeof(sChat));
for (int i = 1; i <= MaxClients; i++) {
if (IsClientInGame(i) && !IsFakeClient(i) &&
((!bAdmins && !(bFlags && (GetUserFlagBits(i) & (iFlags|ADMFLAG_ROOT)))) ||
(bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))) {
if (bTeamColor) {
CSayText2(i, sChat, i);
} else {
PrintToChat(i, sChat);
}
}
}
}
if (sTop[0]) {
int iStart = 0,
aColor[4] = {255, 255, 255, 255};
ParseTopColor(sTop, iStart, aColor);
ProcessVariables(sTop[iStart]);
KeyValues hKv = new KeyValues("Stuff", "title", sTop[iStart]);
hKv.SetColor4("color", aColor);
hKv.SetNum("level", 1);
hKv.SetNum("time", 10);
for (int i = 1; i <= MaxClients; i++) {
if (IsClientInGame(i) && !IsFakeClient(i) &&
((!bAdmins && !(bFlags && (GetUserFlagBits(i) & (iFlags|ADMFLAG_ROOT)))) ||
(bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))) {
CreateDialog(i, hKv, DialogType_Msg);
}
}
delete hKv;
}
if (!g_hAdvertisements.GotoNextKey()) {
g_hAdvertisements.Rewind();
g_hAdvertisements.GotoFirstSubKey();
}
}
public Action Timer_CenterAd(Handle timer, DataPack pack)
{
char sCenter[1024];
static int iCount = 0;
pack.Reset();
int iClient = pack.ReadCell();
pack.ReadString(sCenter, sizeof(sCenter));
if (!IsClientInGame(iClient) || ++iCount >= 5) {
iCount = 0;
return Plugin_Stop;
}
PrintCenterText(iClient, sCenter);
return Plugin_Continue;
}
/**
* Stocks
*/
void ParseAds()
{
delete g_hAdvertisements;
g_hAdvertisements = CreateKeyValues("Advertisements");
char sFile[64], sPath[PLATFORM_MAX_PATH];
g_hFile.GetString(sFile, sizeof(sFile));
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/%s", sFile);
if (!FileExists(sPath)) {
SetFailState("File Not Found: %s", sPath);
}
g_hAdvertisements.ImportFromFile(sPath);
g_hAdvertisements.GotoFirstSubKey();
}
void ProcessVariables(char sText[1024])
{
char sBuffer[64];
if (StrContains(sText, "\\n") != -1) {
Format(sBuffer, sizeof(sBuffer), "%c", 13);
ReplaceString(sText, sizeof(sText), "\\n", sBuffer);
}
if (StrContains(sText, "{currentmap}", false) != -1) {
GetCurrentMap(sBuffer, sizeof(sBuffer));
ReplaceString(sText, sizeof(sText), "{currentmap}", sBuffer, false);
}
if (StrContains(sText, "{date}", false) != -1) {
FormatTime(sBuffer, sizeof(sBuffer), "%m/%d/%Y");
ReplaceString(sText, sizeof(sText), "{date}", sBuffer, false);
}
if (StrContains(sText, "{time}", false) != -1) {
FormatTime(sBuffer, sizeof(sBuffer), "%I:%M:%S%p");
ReplaceString(sText, sizeof(sText), "{time}", sBuffer, false);
}
if (StrContains(sText, "{time24}", false) != -1) {
FormatTime(sBuffer, sizeof(sBuffer), "%H:%M:%S");
ReplaceString(sText, sizeof(sText), "{time24}", sBuffer, false);
}
if (StrContains(sText, "{timeleft}", false) != -1) {
int iMins, iSecs, iTimeLeft;
if (GetMapTimeLeft(iTimeLeft) && iTimeLeft > 0) {
iMins = iTimeLeft / 60;
iSecs = iTimeLeft % 60;
}
Format(sBuffer, sizeof(sBuffer), "%d:%02d", iMins, iSecs);
ReplaceString(sText, sizeof(sText), "{timeleft}", sBuffer, false);
}
ConVar hConVar;
char sConVar[64], sSearch[64], sReplace[64];
int iEnd = -1, iStart = StrContains(sText, "{"), iStart2;
while (iStart != -1) {
iEnd = StrContains(sText[iStart + 1], "}");
if (iEnd == -1) {
break;
}
strcopy(sConVar, iEnd + 1, sText[iStart + 1]);
Format(sSearch, sizeof(sSearch), "{%s}", sConVar);
if ((hConVar = FindConVar(sConVar))) {
hConVar.GetString(sReplace, sizeof(sReplace));
ReplaceString(sText, sizeof(sText), sSearch, sReplace, false);
}
iStart2 = StrContains(sText[iStart + 1], "{");
if (iStart2 == -1) {
break;
}
iStart += iStart2 + 1;
}
}

120
scripting/temp/antiflood.sp Normal file
View File

@@ -0,0 +1,120 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Anti-Flood Plugin
* Protects against chat flooding.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#pragma newdecls required
public Plugin myinfo =
{
name = "Anti-Flood",
author = "AlliedModders LLC",
description = "Protects against chat flooding",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
float g_LastTime[MAXPLAYERS + 1] = {0.0, ...}; /* Last time player used say or say_team */
int g_FloodTokens[MAXPLAYERS + 1] = {0, ...}; /* Number of flood tokens player has */
ConVar sm_flood_time; /* Handle to sm_flood_time convar */
public void OnPluginStart()
{
sm_flood_time = CreateConVar("sm_flood_time", "0.75", "Amount of time allowed between chat messages");
}
public void OnClientPutInServer(int client)
{
g_LastTime[client] = 0.0;
g_FloodTokens[client] = 0;
}
float max_chat;
public bool OnClientFloodCheck(int client)
{
max_chat = sm_flood_time.FloatValue;
if (max_chat <= 0.0
|| CheckCommandAccess(client, "sm_flood_access", ADMFLAG_ROOT, true))
{
return false;
}
if (g_LastTime[client] >= GetGameTime())
{
/* If player has 3 or more flood tokens, block their message */
if (g_FloodTokens[client] >= 3)
{
return true;
}
}
return false;
}
public void OnClientFloodResult(int client, bool blocked)
{
if (max_chat <= 0.0
|| CheckCommandAccess(client, "sm_flood_access", ADMFLAG_ROOT, true))
{
return;
}
float curTime = GetGameTime();
float newTime = curTime + max_chat;
if (g_LastTime[client] >= curTime)
{
/* If the last message was blocked, update their time limit */
if (blocked)
{
newTime += 3.0;
}
/* Add one flood token when player goes over chat time limit */
else if (g_FloodTokens[client] < 3)
{
g_FloodTokens[client]++;
}
}
else if (g_FloodTokens[client] > 0)
{
/* Remove one flood token when player chats within time limit (slow decay) */
g_FloodTokens[client]--;
}
g_LastTime[client] = newTime;
}

View File

@@ -0,0 +1,933 @@
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <steamtools>
#include <advanced_motd>
#define PLUGIN_VERSION "2.11.1"
#define BACKPACK_TF_URL "http://backpack.tf/api/IGetPrices/v3/"
#define ITEM_EARBUDS 143
#define ITEM_REFINED 5002
#define ITEM_KEY 5021
#define ITEM_CRATE 5022
#define ITEM_SALVAGED_CRATE 5068
#define ITEM_HAUNTED_SCRAP 267
#define ITEM_HEADTAKER 266
#define QUALITY_UNIQUE "6"
#define QUALITY_UNUSUAL "5"
#define NOTIFICATION_SOUND "replay/downloadcomplete.wav"
public Plugin:myinfo = {
name = "[TF2] backpack.tf Price Check",
author = "Dr. McKay",
description = "Provides a price check command for use with backpack.tf",
version = PLUGIN_VERSION,
url = "http://www.doctormckay.com"
};
new lastCacheTime;
new cacheTime;
new Handle:backpackTFPricelist;
new Handle:qualityNameTrie;
new Handle:unusualNameTrie;
new Handle:cvarBPCommand;
new Handle:cvarDisplayUpdateNotification;
new Handle:cvarDisplayChangedPrices;
new Handle:cvarHudXPos;
new Handle:cvarHudYPos;
new Handle:cvarHudRed;
new Handle:cvarHudGreen;
new Handle:cvarHudBlue;
new Handle:cvarHudHoldTime;
new Handle:cvarMenuHoldTime;
new Handle:cvarAPIKey;
new Handle:cvarTag;
new Handle:hudText;
new Handle:sv_tags;
new Float:budsToKeys;
new Float:keysToRef;
new Float:refToUsd;
#define UPDATE_FILE "backpack-tf.txt"
#define CONVAR_PREFIX "backpack_tf"
#include "mckayupdater.sp"
public OnPluginStart() {
cvarBPCommand = CreateConVar("backpack_tf_bp_command", "1", "Enables the !bp command for use with backpack.tf");
cvarDisplayUpdateNotification = CreateConVar("backpack_tf_display_update_notification", "1", "Display a notification to clients when the cached price list has been updated?");
cvarDisplayChangedPrices = CreateConVar("backpack_tf_display_changed_prices", "1", "If backpack_tf_display_update_notification is set to 1, display all prices that changed since the last update?");
cvarHudXPos = CreateConVar("backpack_tf_update_notification_x_pos", "-1.0", "X position for HUD text from 0.0 to 1.0, -1.0 = center", _, true, -1.0, true, 1.0);
cvarHudYPos = CreateConVar("backpack_tf_update_notification_y_pos", "0.1", "Y position for HUD text from 0.0 to 1.0, -1.0 = center", _, true, -1.0, true, 1.0);
cvarHudRed = CreateConVar("backpack_tf_update_notification_red", "0", "Red value of HUD text", _, true, 0.0, true, 255.0);
cvarHudGreen = CreateConVar("backpack_tf_update_notification_green", "255", "Green value of HUD text", _, true, 0.0, true, 255.0);
cvarHudBlue = CreateConVar("backpack_tf_update_notification_blue", "0", "Blue value of HUD text", _, true, 0.0, true, 255.0);
cvarHudHoldTime = CreateConVar("backpack_tf_update_notification_message_time", "5", "Seconds to keep each message in the update ticker on the screen", _, true, 0.0);
cvarMenuHoldTime = CreateConVar("backpack_tf_menu_open_time", "0", "Time to keep the price panel open for, 0 = forever");
cvarAPIKey = CreateConVar("backpack_tf_api_key", "", "API key obtained at http://backpack.tf/api/register/", FCVAR_PROTECTED);
cvarTag = CreateConVar("backpack_tf_add_tag", "1", "If 1, adds the backpack.tf tag to your server's sv_tags, which is required to be listed on http://backpack.tf/servers", _, true, 0.0, true, 1.0);
AutoExecConfig();
LoadTranslations("backpack-tf.phrases");
sv_tags = FindConVar("sv_tags");
RegConsoleCmd("sm_bp", Command_Backpack, "Usage: sm_bp <player>");
RegConsoleCmd("sm_backpack", Command_Backpack, "Usage: sm_backpack <player>");
RegConsoleCmd("sm_pc", Command_PriceCheck, "Usage: sm_pc <item>");
RegConsoleCmd("sm_pricecheck", Command_PriceCheck, "Usage: sm_pricecheck <item>");
RegAdminCmd("sm_updateprices", Command_UpdatePrices, ADMFLAG_ROOT, "Updates backpack.tf prices");
qualityNameTrie = CreateTrie();
SetTrieString(qualityNameTrie, "0", "Normal");
SetTrieString(qualityNameTrie, "1", "Genuine");
SetTrieString(qualityNameTrie, "2", "rarity2");
SetTrieString(qualityNameTrie, "3", "Vintage");
SetTrieString(qualityNameTrie, "4", "rarity3");
SetTrieString(qualityNameTrie, "5", "Unusual");
SetTrieString(qualityNameTrie, "6", "Unique");
SetTrieString(qualityNameTrie, "7", "Community");
SetTrieString(qualityNameTrie, "8", "Valve");
SetTrieString(qualityNameTrie, "9", "Self-Made");
SetTrieString(qualityNameTrie, "10", "Customized");
SetTrieString(qualityNameTrie, "11", "Strange");
SetTrieString(qualityNameTrie, "12", "Completed");
SetTrieString(qualityNameTrie, "13", "Haunted");
SetTrieString(qualityNameTrie, "14", "Collector's");
SetTrieString(qualityNameTrie, "300", "Uncraftable Vintage"); // custom for backpack.tf
SetTrieString(qualityNameTrie, "600", "Uncraftable"); // custom for backpack.tf
SetTrieString(qualityNameTrie, "1100", "Uncraftable Strange"); // custom for backpack.tf
SetTrieString(qualityNameTrie, "1300", "Uncraftable Haunted"); // custom for backpack.tf
unusualNameTrie = CreateTrie();
// Original effects
SetTrieString(unusualNameTrie, "6", "Green Confetti");
SetTrieString(unusualNameTrie, "7", "Purple Confetti");
SetTrieString(unusualNameTrie, "8", "Haunted Ghosts");
SetTrieString(unusualNameTrie, "9", "Green Energy");
SetTrieString(unusualNameTrie, "10", "Purple Energy");
SetTrieString(unusualNameTrie, "11", "Circling TF Logo");
SetTrieString(unusualNameTrie, "12", "Massed Flies");
SetTrieString(unusualNameTrie, "13", "Burning Flames");
SetTrieString(unusualNameTrie, "14", "Scorching Flames");
SetTrieString(unusualNameTrie, "15", "Searing Plasma");
SetTrieString(unusualNameTrie, "16", "Vivid Plasma");
SetTrieString(unusualNameTrie, "17", "Sunbeams");
SetTrieString(unusualNameTrie, "18", "Circling Peace Sign");
SetTrieString(unusualNameTrie, "19", "Circling Heart");
// Batch 2
SetTrieString(unusualNameTrie, "29", "Stormy Storm");
SetTrieString(unusualNameTrie, "30", "Blizzardy Storm");
SetTrieString(unusualNameTrie, "31", "Nuts n' Bolts");
SetTrieString(unusualNameTrie, "32", "Orbiting Planets");
SetTrieString(unusualNameTrie, "33", "Orbiting Fire");
SetTrieString(unusualNameTrie, "34", "Bubbling");
SetTrieString(unusualNameTrie, "35", "Smoking");
SetTrieString(unusualNameTrie, "36", "Steaming");
// Halloween
SetTrieString(unusualNameTrie, "37", "Flaming Lantern");
SetTrieString(unusualNameTrie, "38", "Cloudy Moon");
SetTrieString(unusualNameTrie, "39", "Cauldron Bubbles");
SetTrieString(unusualNameTrie, "40", "Eerie Orbiting Fire");
SetTrieString(unusualNameTrie, "43", "Knifestorm");
SetTrieString(unusualNameTrie, "44", "Misty Skull");
SetTrieString(unusualNameTrie, "45", "Harvest Moon");
SetTrieString(unusualNameTrie, "46", "It's A Secret To Everybody");
SetTrieString(unusualNameTrie, "47", "Stormy 13th Hour");
// Batch 3
SetTrieString(unusualNameTrie, "56", "Kill-a-Watt");
SetTrieString(unusualNameTrie, "57", "Terror-Watt");
SetTrieString(unusualNameTrie, "58", "Cloud 9");
SetTrieString(unusualNameTrie, "59", "Aces High");
SetTrieString(unusualNameTrie, "60", "Dead Presidents");
SetTrieString(unusualNameTrie, "61", "Miami Nights");
SetTrieString(unusualNameTrie, "62", "Disco Beat Down");
// Robo-effects
SetTrieString(unusualNameTrie, "63", "Phosphorous");
SetTrieString(unusualNameTrie, "64", "Sulphurous");
SetTrieString(unusualNameTrie, "65", "Memory Leak");
SetTrieString(unusualNameTrie, "66", "Overclocked");
SetTrieString(unusualNameTrie, "67", "Electrostatic");
SetTrieString(unusualNameTrie, "68", "Power Surge");
SetTrieString(unusualNameTrie, "69", "Anti-Freeze");
SetTrieString(unusualNameTrie, "70", "Time Warp");
SetTrieString(unusualNameTrie, "71", "Green Black Hole");
SetTrieString(unusualNameTrie, "72", "Roboactive");
// Halloween 2013
SetTrieString(unusualNameTrie, "73", "Arcana");
SetTrieString(unusualNameTrie, "74", "Spellbound");
SetTrieString(unusualNameTrie, "75", "Chiroptera Venenata");
SetTrieString(unusualNameTrie, "76", "Poisoned Shadows");
SetTrieString(unusualNameTrie, "77", "Something Burning This Way Comes");
SetTrieString(unusualNameTrie, "78", "Hellfire");
SetTrieString(unusualNameTrie, "79", "Darkblaze");
SetTrieString(unusualNameTrie, "80", "Demonflame");
// Halloween 2014
SetTrieString(unusualNameTrie, "81", "Bonzo The All-Gnawing");
SetTrieString(unusualNameTrie, "82", "Amaranthine");
SetTrieString(unusualNameTrie, "83", "Stare From Beyond");
SetTrieString(unusualNameTrie, "84", "The Ooze");
SetTrieString(unusualNameTrie, "85", "Ghastly Ghosts Jr");
SetTrieString(unusualNameTrie, "86", "Haunted Phantasm Jr");
// EOTL
SetTrieString(unusualNameTrie, "87", "Frostbite");
SetTrieString(unusualNameTrie, "88", "Molten Mallard");
SetTrieString(unusualNameTrie, "89", "Morning Glory");
SetTrieString(unusualNameTrie, "90", "Death at Dusk");
// Taunt effects
SetTrieString(unusualNameTrie, "3001", "Showstopper");
SetTrieString(unusualNameTrie, "3002", "Showstopper");
SetTrieString(unusualNameTrie, "3003", "Holy Grail");
SetTrieString(unusualNameTrie, "3004", "'72");
SetTrieString(unusualNameTrie, "3005", "Fountain of Delight");
SetTrieString(unusualNameTrie, "3006", "Screaming Tiger");
SetTrieString(unusualNameTrie, "3007", "Skill Gotten Gains");
SetTrieString(unusualNameTrie, "3008", "Midnight Whirlwind");
SetTrieString(unusualNameTrie, "3009", "Silver Cyclone");
SetTrieString(unusualNameTrie, "3010", "Mega Strike");
// Halloween 2014 taunt effects
SetTrieString(unusualNameTrie, "3011", "Haunted Phantasm");
SetTrieString(unusualNameTrie, "3012", "Ghastly Ghosts");
hudText = CreateHudSynchronizer();
}
public OnConfigsExecuted() {
CreateTimer(2.0, Timer_AddTag); // Let everything load first
}
public Action:Timer_AddTag(Handle:timer) {
if(!GetConVarBool(cvarTag)) {
return;
}
decl String:value[512];
GetConVarString(sv_tags, value, sizeof(value));
TrimString(value);
if(strlen(value) == 0) {
SetConVarString(sv_tags, "backpack.tf");
return;
}
decl String:tags[64][64];
new total = ExplodeString(value, ",", tags, sizeof(tags), sizeof(tags[]));
for(new i = 0; i < total; i++) {
if(StrEqual(tags[i], "backpack.tf")) {
return; // Tag found, nothing to do here
}
}
StrCat(value, sizeof(value), ",backpack.tf");
SetConVarString(sv_tags, value);
}
public OnMapStart() {
PrecacheSound(NOTIFICATION_SOUND);
}
public Steam_FullyLoaded() {
CreateTimer(1.0, Timer_Update); // In case of late-loads
}
GetCachedPricesAge() {
decl String:path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/backpack-tf.txt");
if(!FileExists(path)) {
return -1;
}
new Handle:kv = CreateKeyValues("Response");
if(!FileToKeyValues(kv, path)) {
CloseHandle(kv);
return -1;
}
new offset = KvGetNum(kv, "time_offset", 1337); // The actual offset can be positive, negative, or zero, so we'll just use 1337 as a default since that's unlikely
new time = KvGetNum(kv, "current_time");
CloseHandle(kv);
if(offset == 1337 || time == 0) {
return -1;
}
return GetTime() - time;
}
public Action:Timer_Update(Handle:timer) {
new age = GetCachedPricesAge();
if(age != -1 && age < 900) { // 15 minutes
LogMessage("Locally saved pricing data is %d minutes old, bypassing backpack.tf query", age / 60);
if(backpackTFPricelist != INVALID_HANDLE) {
CloseHandle(backpackTFPricelist);
}
decl String:path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/backpack-tf.txt");
backpackTFPricelist = CreateKeyValues("Response");
FileToKeyValues(backpackTFPricelist, path);
budsToKeys = GetConversion(ITEM_EARBUDS);
keysToRef = GetConversion(ITEM_KEY);
KvRewind(backpackTFPricelist);
refToUsd = KvGetFloat(backpackTFPricelist, "refined_usd_value");
CreateTimer(float(3600 - age), Timer_Update);
return;
}
decl String:key[32];
GetConVarString(cvarAPIKey, key, sizeof(key));
if(strlen(key) == 0) {
LogError("No API key set. Fill in your API key and reload the plugin.");
return;
}
new HTTPRequestHandle:request = Steam_CreateHTTPRequest(HTTPMethod_GET, BACKPACK_TF_URL);
Steam_SetHTTPRequestGetOrPostParameter(request, "key", key);
Steam_SetHTTPRequestGetOrPostParameter(request, "format", "vdf");
Steam_SetHTTPRequestGetOrPostParameter(request, "names", "1");
Steam_SendHTTPRequest(request, OnBackpackTFComplete);
}
public OnBackpackTFComplete(HTTPRequestHandle:request, bool:successful, HTTPStatusCode:status) {
if(status != HTTPStatusCode_OK || !successful) {
if(status == HTTPStatusCode_BadRequest) {
LogError("backpack.tf API failed: You have not set an API key");
Steam_ReleaseHTTPRequest(request);
CreateTimer(600.0, Timer_Update); // Set this for 10 minutes instead of 1 minute
return;
} else if(status == HTTPStatusCode_Forbidden) {
LogError("backpack.tf API failed: Your API key is invalid");
Steam_ReleaseHTTPRequest(request);
CreateTimer(600.0, Timer_Update); // Set this for 10 minutes instead of 1 minute
return;
} else if(status == HTTPStatusCode_PreconditionFailed) {
decl String:retry[16];
Steam_GetHTTPResponseHeaderValue(request, "Retry-After", retry, sizeof(retry));
LogError("backpack.tf API failed: We are being rate-limited by backpack.tf, next request allowed in %s seconds", retry);
} else if(status >= HTTPStatusCode_InternalServerError) {
LogError("backpack.tf API failed: An internal server error occurred");
} else if(status == HTTPStatusCode_OK && !successful) {
LogError("backpack.tf API failed: backpack.tf returned an OK response but no data");
} else if(status != HTTPStatusCode_Invalid) {
LogError("backpack.tf API failed: Unknown error (status code %d)", _:status);
} else {
LogError("backpack.tf API failed: Unable to connect to server or server returned no data");
}
Steam_ReleaseHTTPRequest(request);
CreateTimer(60.0, Timer_Update); // try again!
return;
}
decl String:path[256];
BuildPath(Path_SM, path, sizeof(path), "data/backpack-tf.txt");
Steam_WriteHTTPResponseBody(request, path);
Steam_ReleaseHTTPRequest(request);
LogMessage("backpack.tf price list successfully downloaded!");
CreateTimer(3600.0, Timer_Update);
if(backpackTFPricelist != INVALID_HANDLE) {
CloseHandle(backpackTFPricelist);
}
backpackTFPricelist = CreateKeyValues("Response");
FileToKeyValues(backpackTFPricelist, path);
lastCacheTime = cacheTime;
cacheTime = KvGetNum(backpackTFPricelist, "current_time");
new offset = GetTime() - cacheTime;
KvSetNum(backpackTFPricelist, "time_offset", offset);
KeyValuesToFile(backpackTFPricelist, path);
budsToKeys = GetConversion(ITEM_EARBUDS);
keysToRef = GetConversion(ITEM_KEY);
KvRewind(backpackTFPricelist);
refToUsd = KvGetFloat(backpackTFPricelist, "refined_usd_value");
if(!GetConVarBool(cvarDisplayUpdateNotification)) {
return;
}
if(lastCacheTime == 0) { // first download
new Handle:array = CreateArray(128);
PushArrayString(array, "#Type_command");
SetHudTextParams(GetConVarFloat(cvarHudXPos), GetConVarFloat(cvarHudYPos), GetConVarFloat(cvarHudHoldTime), GetConVarInt(cvarHudRed), GetConVarInt(cvarHudGreen), GetConVarInt(cvarHudBlue), 255);
for(new i = 1; i <= MaxClients; i++) {
if(!IsClientInGame(i)) {
continue;
}
ShowSyncHudText(i, hudText, "%t", "Price list updated");
EmitSoundToClient(i, NOTIFICATION_SOUND);
}
CreateTimer(GetConVarFloat(cvarHudHoldTime), Timer_DisplayHudText, array, TIMER_REPEAT);
return;
}
PrepPriceKv();
KvGotoFirstSubKey(backpackTFPricelist);
new bool:isNegative = false;
new lastUpdate, Float:valueOld, Float:valueOldHigh, Float:value, Float:valueHigh, Float:difference;
decl String:defindex[16], String:qualityIndex[32], String:quality[32], String:name[64], String:message[128], String:currency[32], String:currencyOld[32], String:oldPrice[64], String:newPrice[64];
new Handle:array = CreateArray(128);
PushArrayString(array, "#Type_command");
if(GetConVarBool(cvarDisplayChangedPrices)) {
do {
// loop through items
KvGetSectionName(backpackTFPricelist, defindex, sizeof(defindex));
if(StringToInt(defindex) == ITEM_REFINED) {
continue; // Skip over refined price changes
}
KvGotoFirstSubKey(backpackTFPricelist);
do {
// loop through qualities
KvGetSectionName(backpackTFPricelist, qualityIndex, sizeof(qualityIndex));
if(StrEqual(qualityIndex, "item_info")) {
KvGetString(backpackTFPricelist, "item_name", name, sizeof(name));
continue;
}
KvGotoFirstSubKey(backpackTFPricelist);
do {
// loop through instances (series #s, effects)
lastUpdate = KvGetNum(backpackTFPricelist, "last_change");
if(lastUpdate == 0 || lastUpdate < lastCacheTime) {
continue; // hasn't updated
}
valueOld = KvGetFloat(backpackTFPricelist, "value_old");
valueOldHigh = KvGetFloat(backpackTFPricelist, "value_high_old");
value = KvGetFloat(backpackTFPricelist, "value");
valueHigh = KvGetFloat(backpackTFPricelist, "value_high");
KvGetString(backpackTFPricelist, "currency", currency, sizeof(currency));
KvGetString(backpackTFPricelist, "currency_old", currencyOld, sizeof(currencyOld));
if(strlen(currency) == 0 || strlen(currencyOld) == 0) {
continue;
}
FormatPriceRange(valueOld, valueOldHigh, currency, oldPrice, sizeof(oldPrice), StrEqual(qualityIndex, QUALITY_UNUSUAL));
FormatPriceRange(value, valueHigh, currency, newPrice, sizeof(newPrice), StrEqual(qualityIndex, QUALITY_UNUSUAL));
// Get an average so we can determine if it went up or down
if(valueOldHigh != 0.0) {
valueOld = FloatDiv(FloatAdd(valueOld, valueOldHigh), 2.0);
}
if(valueHigh != 0.0) {
value = FloatDiv(FloatAdd(value, valueHigh), 2.0);
}
// Get prices in terms of refined now so we can determine if it went up or down
if(StrEqual(currencyOld, "earbuds")) {
valueOld = FloatMul(FloatMul(valueOld, budsToKeys), keysToRef);
} else if(StrEqual(currencyOld, "keys")) {
valueOld = FloatMul(valueOld, keysToRef);
}
if(StrEqual(currency, "earbuds")) {
value = FloatMul(FloatMul(value, budsToKeys), keysToRef);
} else if(StrEqual(currency, "keys")) {
value = FloatMul(value, keysToRef);
}
difference = FloatSub(value, valueOld);
if(difference < 0.0) {
isNegative = true;
difference = FloatMul(difference, -1.0);
} else {
isNegative = false;
}
// Format a quality name
if(StrEqual(qualityIndex, QUALITY_UNIQUE)) {
Format(quality, sizeof(quality), ""); // if quality is unique, don't display a quality
} else if(StrEqual(qualityIndex, QUALITY_UNUSUAL) && (StringToInt(defindex) != ITEM_HAUNTED_SCRAP && StringToInt(defindex) != ITEM_HEADTAKER)) {
decl String:effect[16];
KvGetSectionName(backpackTFPricelist, effect, sizeof(effect));
if(!GetTrieString(unusualNameTrie, effect, quality, sizeof(quality))) {
LogError("Unknown unusual effect: %s in OnBackpackTFComplete. Please report this!", effect);
decl String:kvPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, kvPath, sizeof(kvPath), "data/backpack-tf.%d.txt", GetTime());
if(!FileExists(kvPath)) {
KeyValuesToFile(backpackTFPricelist, kvPath);
}
continue;
}
} else {
if(!GetTrieString(qualityNameTrie, qualityIndex, quality, sizeof(quality))) {
LogError("Unknown quality index: %s. Please report this!", qualityIndex);
continue;
}
}
Format(message, sizeof(message), "%s%s%s: %s #From %s #To %s", quality, StrEqual(quality, "") ? "" : " ", name, isNegative ? "#Down" : "#Up", oldPrice, newPrice);
PushArrayString(array, message);
} while(KvGotoNextKey(backpackTFPricelist)); // end: instances
KvGoBack(backpackTFPricelist);
} while(KvGotoNextKey(backpackTFPricelist)); // end: qualities
KvGoBack(backpackTFPricelist);
} while(KvGotoNextKey(backpackTFPricelist)); // end: items
}
SetHudTextParams(GetConVarFloat(cvarHudXPos), GetConVarFloat(cvarHudYPos), GetConVarFloat(cvarHudHoldTime), GetConVarInt(cvarHudRed), GetConVarInt(cvarHudGreen), GetConVarInt(cvarHudBlue), 255);
for(new i = 1; i <= MaxClients; i++) {
if(!IsClientInGame(i)) {
continue;
}
ShowSyncHudText(i, hudText, "%t", "Price list updated");
EmitSoundToClient(i, NOTIFICATION_SOUND);
}
CreateTimer(GetConVarFloat(cvarHudHoldTime), Timer_DisplayHudText, array, TIMER_REPEAT);
}
Float:GetConversion(defindex) {
decl String:buffer[32];
PrepPriceKv();
IntToString(defindex, buffer, sizeof(buffer));
KvJumpToKey(backpackTFPricelist, buffer);
KvJumpToKey(backpackTFPricelist, "6");
KvJumpToKey(backpackTFPricelist, "0");
new Float:value = KvGetFloat(backpackTFPricelist, "value");
new Float:valueHigh = KvGetFloat(backpackTFPricelist, "value_high");
if(valueHigh == 0.0) {
return value;
}
return FloatDiv(FloatAdd(value, valueHigh), 2.0);
}
FormatPrice(Float:price, const String:currency[], String:output[], maxlen, bool:includeCurrency = true, bool:forceBuds = false) {
new String:outputCurrency[32];
if(StrEqual(currency, "metal")) {
Format(outputCurrency, sizeof(outputCurrency), "refined");
} else if(StrEqual(currency, "keys")) {
Format(outputCurrency, sizeof(outputCurrency), "key");
} else if(StrEqual(currency, "earbuds")) {
Format(outputCurrency, sizeof(outputCurrency), "bud");
} else if(StrEqual(currency, "usd")) {
if(forceBuds) {
Format(outputCurrency, sizeof(outputCurrency), "earbuds"); // This allows us to force unusual price ranges to display buds only
}
ConvertUSD(price, outputCurrency, sizeof(outputCurrency));
} else {
ThrowError("Unknown currency: %s", currency);
}
if(FloatIsInt(price)) {
Format(output, maxlen, "%d", RoundToFloor(price));
} else {
Format(output, maxlen, "%.2f", price);
}
if(!includeCurrency) {
return;
}
if(StrEqual(output, "1") || StrEqual(currency, "metal")) {
Format(output, maxlen, "%s %s", output, outputCurrency);
} else {
Format(output, maxlen, "%s %ss", output, outputCurrency);
}
}
FormatPriceRange(Float:low, Float:high, const String:currency[], String:output[], maxlen, bool:forceBuds = false) {
if(high == 0.0) {
FormatPrice(low, currency, output, maxlen, true, forceBuds);
return;
}
decl String:buffer[32];
FormatPrice(low, currency, output, maxlen, false, forceBuds);
FormatPrice(high, currency, buffer, sizeof(buffer), true, forceBuds);
Format(output, maxlen, "%s-%s", output, buffer);
}
ConvertUSD(&Float:price, String:outputCurrency[], maxlen) {
new Float:budPrice = FloatMul(FloatMul(refToUsd, keysToRef), budsToKeys);
if(price < budPrice && !StrEqual(outputCurrency, "earbuds")) {
new Float:keyPrice = FloatMul(refToUsd, keysToRef);
price = FloatDiv(price, keyPrice);
Format(outputCurrency, maxlen, "key");
} else {
price = FloatDiv(price, budPrice);
Format(outputCurrency, maxlen, "bud");
}
}
bool:FloatIsInt(Float:input) {
return float(RoundToFloor(input)) == input;
}
public Action:Timer_DisplayHudText(Handle:timer, any:array) {
if(GetArraySize(array) == 0) {
CloseHandle(array);
return Plugin_Stop;
}
decl String:text[128], String:display[128];
GetArrayString(array, 0, text, sizeof(text));
SetHudTextParams(GetConVarFloat(cvarHudXPos), GetConVarFloat(cvarHudYPos), GetConVarFloat(cvarHudHoldTime), GetConVarInt(cvarHudRed), GetConVarInt(cvarHudGreen), GetConVarInt(cvarHudBlue), 255);
for(new i = 1; i <= MaxClients; i++) {
if(!IsClientInGame(i)) {
continue;
}
PerformTranslationTokenReplacement(i, text, display, sizeof(display));
ShowSyncHudText(i, hudText, display);
}
RemoveFromArray(array, 0);
return Plugin_Continue;
}
PerformTranslationTokenReplacement(client, const String:message[], String:output[], maxlen) {
SetGlobalTransTarget(client);
strcopy(output, maxlen, message);
decl String:buffer[64];
Format(buffer, maxlen, "%t", "Type !pc for a price check");
ReplaceString(output, maxlen, "#Type_command", buffer);
Format(buffer, maxlen, "%t", "Up");
ReplaceString(output, maxlen, "#Up", buffer);
Format(buffer, maxlen, "%t", "Down");
ReplaceString(output, maxlen, "#Down", buffer);
Format(buffer, maxlen, "%t", "From");
ReplaceString(output, maxlen, "#From", buffer);
Format(buffer, maxlen, "%t", "To");
ReplaceString(output, maxlen, "#To", buffer);
}
PrepPriceKv() {
KvRewind(backpackTFPricelist);
KvJumpToKey(backpackTFPricelist, "prices");
}
public Action:Command_PriceCheck(client, args) {
if(backpackTFPricelist == INVALID_HANDLE) {
decl String:key[32];
GetConVarString(cvarAPIKey, key, sizeof(key));
if(strlen(key) == 0) {
ReplyToCommand(client, "\x04[SM] \x01The server administrator has not filled in their API key yet. Please contact the server administrator.");
} else {
ReplyToCommand(client, "\x04[SM] \x01%t.", "The price list has not loaded yet");
}
return Plugin_Handled;
}
if(args == 0) {
new Handle:menu = CreateMenu(Handler_ItemSelection);
SetMenuTitle(menu, "Price Check");
PrepPriceKv();
KvGotoFirstSubKey(backpackTFPricelist);
decl String:name[128];
do {
if(!KvJumpToKey(backpackTFPricelist, "item_info")) {
continue;
}
KvGetString(backpackTFPricelist, "item_name", name, sizeof(name));
if(KvGetNum(backpackTFPricelist, "proper_name") == 1) {
Format(name, sizeof(name), "The %s", name);
}
AddMenuItem(menu, name, name);
KvGoBack(backpackTFPricelist);
} while(KvGotoNextKey(backpackTFPricelist));
DisplayMenu(menu, client, GetConVarInt(cvarMenuHoldTime));
return Plugin_Handled;
}
new resultDefindex = -1;
decl String:defindex[8], String:name[128], String:itemName[128];
GetCmdArgString(name, sizeof(name));
new bool:exact = StripQuotes(name);
PrepPriceKv();
KvGotoFirstSubKey(backpackTFPricelist);
new Handle:matches;
if(!exact) {
matches = CreateArray(128);
}
do {
KvGetSectionName(backpackTFPricelist, defindex, sizeof(defindex));
if(!KvJumpToKey(backpackTFPricelist, "item_info")) {
continue;
}
KvGetString(backpackTFPricelist, "item_name", itemName, sizeof(itemName));
if(KvGetNum(backpackTFPricelist, "proper_name") == 1) {
Format(itemName, sizeof(itemName), "The %s", itemName);
}
KvGoBack(backpackTFPricelist);
if(exact) {
if(StrEqual(itemName, name, false)) {
resultDefindex = StringToInt(defindex);
break;
}
} else {
if(StrContains(itemName, name, false) != -1) {
resultDefindex = StringToInt(defindex); // In case this is the only match, we store the resulting defindex here so that we don't need to search to find it again
PushArrayString(matches, itemName);
}
}
} while(KvGotoNextKey(backpackTFPricelist));
if(!exact && GetArraySize(matches) > 1) {
new Handle:menu = CreateMenu(Handler_ItemSelection);
SetMenuTitle(menu, "Search Results");
new size = GetArraySize(matches);
for(new i = 0; i < size; i++) {
GetArrayString(matches, i, itemName, sizeof(itemName));
AddMenuItem(menu, itemName, itemName);
}
DisplayMenu(menu, client, GetConVarInt(cvarMenuHoldTime));
CloseHandle(matches);
return Plugin_Handled;
}
if(!exact) {
CloseHandle(matches);
}
if(resultDefindex == -1) {
ReplyToCommand(client, "\x04[SM] \x01No matching item was found.");
return Plugin_Handled;
}
// At this point, we know that we've found our item. Its defindex is stored in resultDefindex as a cell
// defindex was used to store the defindex of every item as we searched it, so it's not reliable
if(resultDefindex == ITEM_REFINED) {
SetGlobalTransTarget(client);
new Handle:menu = CreateMenu(Handler_PriceListMenu);
SetMenuTitle(menu, "%t\n%t\n%t\n ", "Price check", itemName, "Prices are estimates only", "Prices courtesy of backpack.tf");
decl String:buffer[32];
Format(buffer, sizeof(buffer), "Unique: $%.2f USD", refToUsd);
AddMenuItem(menu, "", buffer);
DisplayMenu(menu, client, GetConVarInt(cvarMenuHoldTime));
return Plugin_Handled;
}
new bool:isCrate = (resultDefindex == ITEM_CRATE || resultDefindex == ITEM_SALVAGED_CRATE);
new bool:onlyOneUnusual = (resultDefindex == ITEM_HEADTAKER || resultDefindex == ITEM_HAUNTED_SCRAP);
PrepPriceKv();
IntToString(resultDefindex, defindex, sizeof(defindex));
KvJumpToKey(backpackTFPricelist, defindex);
KvJumpToKey(backpackTFPricelist, "item_info");
KvGetString(backpackTFPricelist, "item_name", itemName, sizeof(itemName));
if(KvGetNum(backpackTFPricelist, "proper_name") == 1) {
Format(itemName, sizeof(itemName), "The %s", itemName);
}
KvGotoNextKey(backpackTFPricelist);
SetGlobalTransTarget(client);
new Handle:menu = CreateMenu(Handler_PriceListMenu);
SetMenuTitle(menu, "%t\n%t\n%t\n ", "Price check", itemName, "Prices are estimates only", "Prices courtesy of backpack.tf");
new bool:unusualDisplayed = false;
new Float:value, Float:valueHigh;
decl String:currency[32], String:qualityIndex[16], String:quality[16], String:series[8], String:price[32], String:buffer[64];
do {
KvGetSectionName(backpackTFPricelist, qualityIndex, sizeof(qualityIndex));
if(StrEqual(qualityIndex, "item_info") || StrEqual(qualityIndex, "alt_defindex")) {
continue;
}
KvGotoFirstSubKey(backpackTFPricelist);
do {
if(StrEqual(qualityIndex, QUALITY_UNUSUAL) && !onlyOneUnusual) {
if(!unusualDisplayed) {
AddMenuItem(menu, defindex, "Unusual: View Effects");
unusualDisplayed = true;
}
} else {
value = KvGetFloat(backpackTFPricelist, "value");
valueHigh = KvGetFloat(backpackTFPricelist, "value_high");
KvGetString(backpackTFPricelist, "currency", currency, sizeof(currency));
FormatPriceRange(value, valueHigh, currency, price, sizeof(price));
if(!GetTrieString(qualityNameTrie, qualityIndex, quality, sizeof(quality))) {
LogError("Unknown quality index: %s. Please report this!", qualityIndex);
continue;
}
if(isCrate) {
KvGetSectionName(backpackTFPricelist, series, sizeof(series));
if(StrEqual(series, "0")) {
continue;
}
if(StrEqual(qualityIndex, QUALITY_UNIQUE)) {
Format(buffer, sizeof(buffer), "Series %s: %s", series, price);
} else {
Format(buffer, sizeof(buffer), "%s: Series %s: %s", quality, series, price);
}
} else {
Format(buffer, sizeof(buffer), "%s: %s", quality, price);
}
AddMenuItem(menu, "", buffer, ITEMDRAW_DISABLED);
}
} while(KvGotoNextKey(backpackTFPricelist));
KvGoBack(backpackTFPricelist);
} while(KvGotoNextKey(backpackTFPricelist));
DisplayMenu(menu, client, GetConVarInt(cvarMenuHoldTime));
return Plugin_Handled;
}
public Handler_ItemSelection(Handle:menu, MenuAction:action, client, param) {
if(action == MenuAction_End) {
CloseHandle(menu);
}
if(action != MenuAction_Select) {
return;
}
decl String:selection[128];
GetMenuItem(menu, param, selection, sizeof(selection));
FakeClientCommand(client, "sm_pricecheck \"%s\"", selection);
}
public Handler_PriceListMenu(Handle:menu, MenuAction:action, client, param) {
if(action == MenuAction_End) {
CloseHandle(menu);
}
if(action != MenuAction_Select) {
return;
}
decl String:defindex[32];
GetMenuItem(menu, param, defindex, sizeof(defindex));
decl String:name[64];
PrepPriceKv();
KvJumpToKey(backpackTFPricelist, defindex);
KvJumpToKey(backpackTFPricelist, "item_info");
KvGetString(backpackTFPricelist, "item_name", name, sizeof(name));
if(KvGetNum(backpackTFPricelist, "proper_name") == 1) {
Format(name, sizeof(name), "The Unusual %s", name);
} else {
Format(name, sizeof(name), "Unusual %s", name);
}
KvGoBack(backpackTFPricelist);
if(!KvJumpToKey(backpackTFPricelist, QUALITY_UNUSUAL)) {
return;
}
KvGotoFirstSubKey(backpackTFPricelist);
SetGlobalTransTarget(client);
new Handle:menu2 = CreateMenu(Handler_PriceListMenu);
SetMenuTitle(menu2, "%t\n%t\n%t\n ", "Price check", name, "Prices are estimates only", "Prices courtesy of backpack.tf");
decl String:effect[8], String:effectName[64], String:message[128], String:price[64], String:currency[32];
new Float:value, Float:valueHigh;
do {
KvGetSectionName(backpackTFPricelist, effect, sizeof(effect));
if(!GetTrieString(unusualNameTrie, effect, effectName, sizeof(effectName))) {
LogError("Unknown unusual effect: %s in Handler_PriceListMenu. Please report this!", effect);
decl String:path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/backpack-tf.%d.txt", GetTime());
if(!FileExists(path)) {
KeyValuesToFile(backpackTFPricelist, path);
}
continue;
}
value = KvGetFloat(backpackTFPricelist, "value");
valueHigh = KvGetFloat(backpackTFPricelist, "value_high");
KvGetString(backpackTFPricelist, "currency", currency, sizeof(currency));
if(StrEqual(currency, "")) {
continue;
}
FormatPriceRange(value, valueHigh, currency, price, sizeof(price), true);
Format(message, sizeof(message), "%s: %s", effectName, price);
AddMenuItem(menu2, "", message, ITEMDRAW_DISABLED);
} while(KvGotoNextKey(backpackTFPricelist));
DisplayMenu(menu2, client, GetConVarInt(cvarMenuHoldTime));
}
public Action:Command_Backpack(client, args) {
if(!GetConVarBool(cvarBPCommand)) {
return Plugin_Continue;
}
new target;
if(args == 0) {
target = GetClientAimTarget(client);
if(target <= 0) {
DisplayClientMenu(client);
return Plugin_Handled;
}
} else {
decl String:arg1[MAX_NAME_LENGTH];
GetCmdArg(1, arg1, sizeof(arg1));
target = FindTargetEx(client, arg1, true, false, false);
if(target == -1) {
DisplayClientMenu(client);
return Plugin_Handled;
}
}
decl String:steamID[64];
Steam_GetCSteamIDForClient(target, steamID, sizeof(steamID)); // we could use the regular Steam ID, but we already have SteamTools, so we can just bypass backpack.tf's redirect directly
decl String:url[256];
Format(url, sizeof(url), "http://backpack.tf/profiles/%s", steamID);
AdvMOTD_ShowMOTDPanel(client, "backpack.tf", url, MOTDPANEL_TYPE_URL, true, true, true, OnMOTDFailure);
return Plugin_Handled;
}
public OnMOTDFailure(client, MOTDFailureReason:reason) {
switch(reason) {
case MOTDFailure_Disabled: PrintToChat(client, "\x04[SM] \x01You cannot view backpacks with HTML MOTDs disabled.");
case MOTDFailure_Matchmaking: PrintToChat(client, "\x04[SM] \x01You cannot view backpacks after joining via Quickplay.");
case MOTDFailure_QueryFailed: PrintToChat(client, "\x04[SM] \x01Unable to open backpack.");
}
}
DisplayClientMenu(client) {
new Handle:menu = CreateMenu(Handler_ClientMenu);
SetMenuTitle(menu, "Select Player");
decl String:name[MAX_NAME_LENGTH], String:index[8];
for(new i = 1; i <= MaxClients; i++) {
if(!IsClientInGame(i) || IsFakeClient(i)) {
continue;
}
GetClientName(i, name, sizeof(name));
IntToString(GetClientUserId(i), index, sizeof(index));
AddMenuItem(menu, index, name);
}
DisplayMenu(menu, client, GetConVarInt(cvarMenuHoldTime));
}
public Handler_ClientMenu(Handle:menu, MenuAction:action, client, param) {
if(action == MenuAction_End) {
CloseHandle(menu);
}
if(action != MenuAction_Select) {
return;
}
decl String:selection[32];
GetMenuItem(menu, param, selection, sizeof(selection));
FakeClientCommand(client, "sm_backpack #%s", selection);
}
public Action:Command_UpdatePrices(client, args) {
new age = GetCachedPricesAge();
if(age != -1 && age < 900) { // 15 minutes
ReplyToCommand(client, "\x04[SM] \x01The price list cannot be updated more frequently than every 15 minutes. It is currently %d minutes old.", age / 60);
return Plugin_Handled;
}
ReplyToCommand(client, "\x04[SM] \x01Updating backpack.tf prices...");
Timer_Update(INVALID_HANDLE);
return Plugin_Handled;
}
FindTargetEx(client, const String:target[], bool:nobots = false, bool:immunity = true, bool:replyToError = true) {
decl String:target_name[MAX_TARGET_LENGTH];
decl target_list[1], target_count, bool:tn_is_ml;
new 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;
}
}

View File

@@ -0,0 +1,87 @@
#include <sourcemod>
#include <sdktools>
#define PLUGIN_NAME "Baseball Hell Randomizer"
#define PLUGIN_AUTHOR "SirDovahBearYT"
#define PLUGIN_DESCRIPTION "Picks a random gamemode every 60 seconds"
#define PLUGIN_VERSION "1.2.0"
#define GONG "misc/halloween/strongman_bell_01.wav"
bool Running;
public Plugin myinfo =
{
name = PLUGIN_NAME,
author = PLUGIN_AUTHOR,
description = PLUGIN_DESCRIPTION,
version = PLUGIN_VERSION,
url = "http://www.sourcemod.net"
};
public OnPluginStart()
{
PrecacheSound(GONG, true);
Running = false;
while(Running == false)
{
CreateTimer(60.0, Command_RandomExec);
Running = true;
}
}
public Action Command_RandomExec(Handle timer)
{
new RandomNumbersArray[7] = {1,2,3,4,5,6,7};
new randomnum = GetRandomInt(1, 7);
if (randomnum == 1)
{
ServerCommand("baseballhell_mode SCOUT_PLAY_ALL_WEAPONS");
ServerCommand("sm_csay SCOUT PLAYS WITH ALL WEAPONS!");
EmitSoundToAll(GONG);
Running = false;
}
if (randomnum == 2)
{
ServerCommand("baseballhell_mode SCOUT_PLAY_BAT_ONLY");
ServerCommand("sm_csay SCOUT PLAYS WITH BAT ONLY!");
EmitSoundToAll(GONG);
Running = false;
}
if (randomnum == 3)
{
ServerCommand("baseballhell_mode ALL_PLAY_ALL_WEAPONS");
ServerCommand("sm_csay ALL CLASSES PLAY ALL WEAPONS!");
EmitSoundToAll(GONG);
Running = false;
}
if (randomnum == 4)
{
ServerCommand("baseballhell_mode ALL_PLAY_BAT_ONLY");
ServerCommand("sm_csay EVERYONE PLAYS BAT ONLY");
EmitSoundToAll(GONG);
Running = false;
}
if (randomnum == 5)
{
ServerCommand("baseballhell_mode FLAK_CANNON");
ServerCommand("sm_csay FLAK CANNONS FOR ALL!");
EmitSoundToAll(GONG);
Running = false;
}
if (randomnum == 6)
{
ServerCommand("baseballhell_mode HUNTSMAN");
ServerCommand("sm_csay RAPID FIRE HUNTSMANS INCOMING!");
EmitSoundToAll(GONG);
Running = false;
}
if (randomnum == 7)
{
ServerCommand("baseballhell_mode ROCKETMAN");
ServerCommand("sm_csay VALVE ROCKET LAUNCHERS FOR ALL!");
EmitSoundToAll(GONG);
Running = false;
}
else
{
Running = false;
}
}

384
scripting/temp/basebans.sp Normal file
View File

@@ -0,0 +1,384 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Basic Commands Plugin
* Implements basic admin commands.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma newdecls required
public Plugin myinfo =
{
name = "Basic Ban Commands",
author = "AlliedModders LLC",
description = "Basic Banning Commands",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
TopMenu hTopMenu;
int g_BanTarget[MAXPLAYERS+1];
int g_BanTargetUserId[MAXPLAYERS+1];
int g_BanTime[MAXPLAYERS+1];
bool g_IsWaitingForChatReason[MAXPLAYERS+1];
KeyValues g_hKvBanReasons;
char g_BanReasonsPath[PLATFORM_MAX_PATH];
#include "basebans/ban.sp"
public void OnPluginStart()
{
BuildPath(Path_SM, g_BanReasonsPath, sizeof(g_BanReasonsPath), "configs/banreasons.txt");
LoadBanReasons();
LoadTranslations("common.phrases");
LoadTranslations("basebans.phrases");
LoadTranslations("core.phrases");
RegAdminCmd("sm_ban", Command_Ban, ADMFLAG_BAN, "sm_ban <#userid|name> <minutes|0> [reason]");
RegAdminCmd("sm_unban", Command_Unban, ADMFLAG_UNBAN, "sm_unban <steamid|ip>");
RegAdminCmd("sm_addban", Command_AddBan, ADMFLAG_RCON, "sm_addban <time> <steamid> [reason]");
RegAdminCmd("sm_banip", Command_BanIp, ADMFLAG_BAN, "sm_banip <ip|#userid|name> <time> [reason]");
//This to manage custom ban reason messages
RegConsoleCmd("sm_abortban", Command_AbortBan, "sm_abortban");
/* Account for late loading */
TopMenu topmenu;
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != null))
{
OnAdminMenuReady(topmenu);
}
}
public void OnMapStart()
{
//(Re-)Load BanReasons
LoadBanReasons();
}
public void OnClientDisconnect(int client)
{
g_IsWaitingForChatReason[client] = false;
}
void LoadBanReasons()
{
delete g_hKvBanReasons;
g_hKvBanReasons = new KeyValues("banreasons");
if (g_hKvBanReasons.ImportFromFile(g_BanReasonsPath))
{
char sectionName[255];
if (!g_hKvBanReasons.GetSectionName(sectionName, sizeof(sectionName)))
{
SetFailState("Error in %s: File corrupt or in the wrong format", g_BanReasonsPath);
return;
}
if (strcmp(sectionName, "banreasons") != 0)
{
SetFailState("Error in %s: Couldn't find 'banreasons'", g_BanReasonsPath);
return;
}
//Reset kvHandle
g_hKvBanReasons.Rewind();
} else {
SetFailState("Error in %s: File not found, corrupt or in the wrong format", g_BanReasonsPath);
return;
}
}
public void OnAdminMenuReady(Handle aTopMenu)
{
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
/* Block us from being called twice */
if (topmenu == hTopMenu)
{
return;
}
/* Save the Handle */
hTopMenu = topmenu;
/* Find the "Player Commands" category */
TopMenuObject player_commands = hTopMenu.FindCategory(ADMINMENU_PLAYERCOMMANDS);
if (player_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_ban", AdminMenu_Ban, player_commands, "sm_ban", ADMFLAG_BAN);
}
}
public Action Command_BanIp(int client, int args)
{
if (args < 2)
{
ReplyToCommand(client, "[SM] Usage: sm_banip <ip|#userid|name> <time> [reason]");
return Plugin_Handled;
}
int len, next_len;
char Arguments[256];
char arg[50], time[20];
GetCmdArgString(Arguments, sizeof(Arguments));
len = BreakString(Arguments, arg, sizeof(arg));
if ((next_len = BreakString(Arguments[len], time, sizeof(time))) != -1)
{
len += next_len;
}
else
{
len = 0;
Arguments[0] = '\0';
}
if (StrEqual(arg, "0"))
{
ReplyToCommand(client, "[SM] %t", "Cannot ban that IP");
return Plugin_Handled;
}
char target_name[MAX_TARGET_LENGTH];
int target_list[1];
bool tn_is_ml;
int found_client = -1;
if (ProcessTargetString(
arg,
client,
target_list,
1,
COMMAND_FILTER_CONNECTED|COMMAND_FILTER_NO_MULTI,
target_name,
sizeof(target_name),
tn_is_ml) > 0)
{
found_client = target_list[0];
}
bool has_rcon;
if (client == 0 || (client == 1 && !IsDedicatedServer()))
{
has_rcon = true;
}
else
{
AdminId id = GetUserAdmin(client);
has_rcon = (id == INVALID_ADMIN_ID) ? false : GetAdminFlag(id, Admin_RCON);
}
int hit_client = -1;
if (found_client != -1
&& !IsFakeClient(found_client)
&& (has_rcon || CanUserTarget(client, found_client)))
{
GetClientIP(found_client, arg, sizeof(arg));
hit_client = found_client;
}
if (hit_client == -1 && !has_rcon)
{
ReplyToCommand(client, "[SM] %t", "No Access");
return Plugin_Handled;
}
int minutes = StringToInt(time);
LogAction(client,
hit_client,
"\"%L\" added ban (minutes \"%d\") (ip \"%s\") (reason \"%s\")",
client,
minutes,
arg,
Arguments[len]);
ReplyToCommand(client, "[SM] %t", "Ban added");
BanIdentity(arg,
minutes,
BANFLAG_IP,
Arguments[len],
"sm_banip",
client);
if (hit_client != -1)
{
KickClient(hit_client, "Banned: %s", Arguments[len]);
}
return Plugin_Handled;
}
public Action Command_AddBan(int client, int args)
{
if (args < 2)
{
ReplyToCommand(client, "[SM] Usage: sm_addban <time> <steamid> [reason]");
return Plugin_Handled;
}
char arg_string[256];
char time[50];
char authid[50];
GetCmdArgString(arg_string, sizeof(arg_string));
int len, total_len;
/* Get time */
if ((len = BreakString(arg_string, time, sizeof(time))) == -1)
{
ReplyToCommand(client, "[SM] Usage: sm_addban <time> <steamid> [reason]");
return Plugin_Handled;
}
total_len += len;
/* Get steamid */
if ((len = BreakString(arg_string[total_len], authid, sizeof(authid))) != -1)
{
total_len += len;
}
else
{
total_len = 0;
arg_string[0] = '\0';
}
/* Verify steamid */
bool idValid = false;
if (!strncmp(authid, "STEAM_", 6) && authid[7] == ':')
idValid = true;
else if (!strncmp(authid, "[U:", 3))
idValid = true;
if (!idValid)
{
ReplyToCommand(client, "[SM] %t", "Invalid SteamID specified");
return Plugin_Handled;
}
int minutes = StringToInt(time);
LogAction(client,
-1,
"\"%L\" added ban (minutes \"%d\") (id \"%s\") (reason \"%s\")",
client,
minutes,
authid,
arg_string[total_len]);
BanIdentity(authid,
minutes,
BANFLAG_AUTHID,
arg_string[total_len],
"sm_addban",
client);
ReplyToCommand(client, "[SM] %t", "Ban added");
return Plugin_Handled;
}
public Action Command_Unban(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_unban <steamid|ip>");
return Plugin_Handled;
}
char arg[50];
GetCmdArgString(arg, sizeof(arg));
ReplaceString(arg, sizeof(arg), "\"", "");
int ban_flags;
if (IsCharNumeric(arg[0]))
{
ban_flags |= BANFLAG_IP;
}
else
{
ban_flags |= BANFLAG_AUTHID;
}
LogAction(client, -1, "\"%L\" removed ban (filter \"%s\")", client, arg);
RemoveBan(arg, ban_flags, "sm_unban", client);
ReplyToCommand(client, "[SM] %t", "Removed bans matching", arg);
return Plugin_Handled;
}
public Action Command_AbortBan(int client, int args)
{
if(!CheckCommandAccess(client, "sm_ban", ADMFLAG_BAN))
{
ReplyToCommand(client, "[SM] %t", "No Access");
return Plugin_Handled;
}
if(g_IsWaitingForChatReason[client])
{
g_IsWaitingForChatReason[client] = false;
ReplyToCommand(client, "[SM] %t", "AbortBan applied successfully");
}
else
{
ReplyToCommand(client, "[SM] %t", "AbortBan not waiting for custom reason");
}
return Plugin_Handled;
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs)
{
if(g_IsWaitingForChatReason[client])
{
g_IsWaitingForChatReason[client] = false;
PrepareBan(client, g_BanTarget[client], g_BanTime[client], sArgs);
return Plugin_Stop;
}
return Plugin_Continue;
}

428
scripting/temp/basechat.sp Normal file
View File

@@ -0,0 +1,428 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Basic Chat Plugin
* Implements basic communication commands.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#pragma newdecls required
public Plugin myinfo =
{
name = "Basic Chat",
author = "AlliedModders LLC",
description = "Basic Communication Commands",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
#define CHAT_SYMBOL '@'
char g_ColorNames[13][10] = {"White", "Red", "Green", "Blue", "Yellow", "Purple", "Cyan", "Orange", "Pink", "Olive", "Lime", "Violet", "Lightblue"};
int g_Colors[13][3] = {{255,255,255},{255,0,0},{0,255,0},{0,0,255},{255,255,0},{255,0,255},{0,255,255},{255,128,0},{255,0,128},{128,255,0},{0,255,128},{128,0,255},{0,128,255}};
ConVar g_Cvar_Chatmode;
EngineVersion g_GameEngine = Engine_Unknown;
public void OnPluginStart()
{
LoadTranslations("common.phrases");
g_GameEngine = GetEngineVersion();
g_Cvar_Chatmode = CreateConVar("sm_chat_mode", "1", "Allows player's to send messages to admin chat.", 0, true, 0.0, true, 1.0);
RegAdminCmd("sm_say", Command_SmSay, ADMFLAG_CHAT, "sm_say <message> - sends message to all players");
RegAdminCmd("sm_csay", Command_SmCsay, ADMFLAG_CHAT, "sm_csay <message> - sends centered message to all players");
/* HintText does not work on Dark Messiah */
if (g_GameEngine != Engine_DarkMessiah)
{
RegAdminCmd("sm_hsay", Command_SmHsay, ADMFLAG_CHAT, "sm_hsay <message> - sends hint message to all players");
}
RegAdminCmd("sm_tsay", Command_SmTsay, ADMFLAG_CHAT, "sm_tsay [color] <message> - sends top-left message to all players");
RegAdminCmd("sm_chat", Command_SmChat, ADMFLAG_CHAT, "sm_chat <message> - sends message to admins");
RegAdminCmd("sm_psay", Command_SmPsay, ADMFLAG_CHAT, "sm_psay <name or #userid> <message> - sends private message");
RegAdminCmd("sm_msay", Command_SmMsay, ADMFLAG_CHAT, "sm_msay <message> - sends message as a menu panel");
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs)
{
int startidx;
if (sArgs[startidx] != CHAT_SYMBOL)
return Plugin_Continue;
startidx++;
if (strcmp(command, "say", false) == 0)
{
if (sArgs[startidx] != CHAT_SYMBOL) // sm_say alias
{
if (!CheckCommandAccess(client, "sm_say", ADMFLAG_CHAT))
{
return Plugin_Continue;
}
SendChatToAll(client, sArgs[startidx]);
LogAction(client, -1, "\"%L\" triggered sm_say (text %s)", client, sArgs[startidx]);
return Plugin_Stop;
}
startidx++;
if (sArgs[startidx] != CHAT_SYMBOL) // sm_psay alias
{
if (!CheckCommandAccess(client, "sm_psay", ADMFLAG_CHAT))
{
return Plugin_Continue;
}
char arg[64];
int len = BreakString(sArgs[startidx], arg, sizeof(arg));
int target = FindTarget(client, arg, true, false);
if (target == -1 || len == -1)
return Plugin_Stop;
SendPrivateChat(client, target, sArgs[startidx+len]);
return Plugin_Stop;
}
startidx++;
// sm_csay alias
if (!CheckCommandAccess(client, "sm_csay", ADMFLAG_CHAT))
{
return Plugin_Continue;
}
DisplayCenterTextToAll(client, sArgs[startidx]);
LogAction(client, -1, "\"%L\" triggered sm_csay (text %s)", client, sArgs[startidx]);
return Plugin_Stop;
}
else if (strcmp(command, "say_team", false) == 0 || strcmp(command, "say_squad", false) == 0)
{
if (!CheckCommandAccess(client, "sm_chat", ADMFLAG_CHAT) && !g_Cvar_Chatmode.BoolValue)
{
return Plugin_Continue;
}
SendChatToAdmins(client, sArgs[startidx]);
LogAction(client, -1, "\"%L\" triggered sm_chat (text %s)", client, sArgs[startidx]);
return Plugin_Stop;
}
return Plugin_Continue;
}
public Action Command_SmSay(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_say <message>");
return Plugin_Handled;
}
char text[192];
GetCmdArgString(text, sizeof(text));
SendChatToAll(client, text);
LogAction(client, -1, "\"%L\" triggered sm_say (text %s)", client, text);
return Plugin_Handled;
}
public Action Command_SmCsay(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_csay <message>");
return Plugin_Handled;
}
char text[192];
GetCmdArgString(text, sizeof(text));
DisplayCenterTextToAll(client, text);
LogAction(client, -1, "\"%L\" triggered sm_csay (text %s)", client, text);
return Plugin_Handled;
}
public Action Command_SmHsay(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_hsay <message>");
return Plugin_Handled;
}
char text[192];
GetCmdArgString(text, sizeof(text));
char nameBuf[MAX_NAME_LENGTH];
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || IsFakeClient(i))
{
continue;
}
FormatActivitySource(client, i, nameBuf, sizeof(nameBuf));
PrintHintText(i, "%s: %s", nameBuf, text);
}
LogAction(client, -1, "\"%L\" triggered sm_hsay (text %s)", client, text);
return Plugin_Handled;
}
public Action Command_SmTsay(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_tsay <message>");
return Plugin_Handled;
}
char text[192], colorStr[16];
GetCmdArgString(text, sizeof(text));
int len = BreakString(text, colorStr, 16);
int color = FindColor(colorStr);
char nameBuf[MAX_NAME_LENGTH];
if (color == -1)
{
color = 0;
len = 0;
}
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || IsFakeClient(i))
{
continue;
}
FormatActivitySource(client, i, nameBuf, sizeof(nameBuf));
SendDialogToOne(i, color, "%s: %s", nameBuf, text[len]);
}
LogAction(client, -1, "\"%L\" triggered sm_tsay (text %s)", client, text);
return Plugin_Handled;
}
public Action Command_SmChat(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_chat <message>");
return Plugin_Handled;
}
char text[192];
GetCmdArgString(text, sizeof(text));
SendChatToAdmins(client, text);
LogAction(client, -1, "\"%L\" triggered sm_chat (text %s)", client, text);
return Plugin_Handled;
}
public Action Command_SmPsay(int client, int args)
{
if (args < 2)
{
ReplyToCommand(client, "[SM] Usage: sm_psay <name or #userid> <message>");
return Plugin_Handled;
}
char text[192], arg[64], message[192];
GetCmdArgString(text, sizeof(text));
int len = BreakString(text, arg, sizeof(arg));
BreakString(text[len], message, sizeof(message));
int target = FindTarget(client, arg, true, false);
if (target == -1)
return Plugin_Handled;
SendPrivateChat(client, target, message);
return Plugin_Handled;
}
public Action Command_SmMsay(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_msay <message>");
return Plugin_Handled;
}
char text[192];
GetCmdArgString(text, sizeof(text));
SendPanelToAll(client, text);
LogAction(client, -1, "\"%L\" triggered sm_msay (text %s)", client, text);
return Plugin_Handled;
}
int FindColor(const char[] color)
{
for (int i = 0; i < sizeof(g_ColorNames); i++)
{
if (strcmp(color, g_ColorNames[i], false) == 0)
return i;
}
return -1;
}
void SendChatToAll(int client, const char[] message)
{
char nameBuf[MAX_NAME_LENGTH];
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || IsFakeClient(i))
{
continue;
}
FormatActivitySource(client, i, nameBuf, sizeof(nameBuf));
PrintToChat(i, "\x04(ALL) %s: \x01%s", nameBuf, message);
}
}
void DisplayCenterTextToAll(int client, const char[] message)
{
char nameBuf[MAX_NAME_LENGTH];
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || IsFakeClient(i))
{
continue;
}
FormatActivitySource(client, i, nameBuf, sizeof(nameBuf));
PrintCenterText(i, "%s: %s", nameBuf, message);
}
}
void SendChatToAdmins(int from, const char[] message)
{
int fromAdmin = CheckCommandAccess(from, "sm_chat", ADMFLAG_CHAT);
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i) && (from == i || CheckCommandAccess(i, "sm_chat", ADMFLAG_CHAT)))
{
PrintToChat(i, "\x04(%sADMINS) %N: \x01%s", fromAdmin ? "" : "TO ", from, message);
}
}
}
void SendDialogToOne(int client, int color, const char[] text, any ...)
{
char message[100];
VFormat(message, sizeof(message), text, 4);
KeyValues kv = new KeyValues("Stuff", "title", message);
kv.SetColor("color", g_Colors[color][0], g_Colors[color][1], g_Colors[color][2], 255);
kv.SetNum("level", 1);
kv.SetNum("time", 10);
CreateDialog(client, kv, DialogType_Msg);
delete kv;
}
void SendPrivateChat(int client, int target, const char[] message)
{
if (!client)
{
PrintToServer("(Private to %N) %N: %s", target, client, message);
}
else if (target != client)
{
PrintToChat(client, "\x04(Private to %N) %N: \x01%s", target, client, message);
}
PrintToChat(target, "\x04(Private to %N) %N: \x01%s", target, client, message);
LogAction(client, -1, "\"%L\" triggered sm_psay to \"%L\" (text %s)", client, target, message);
}
void SendPanelToAll(int from, char[] message)
{
char title[100];
Format(title, 64, "%N:", from);
ReplaceString(message, 192, "\\n", "\n");
Panel mSayPanel = new Panel();
mSayPanel.SetTitle(title);
mSayPanel.DrawItem("", ITEMDRAW_SPACER);
mSayPanel.DrawText(message);
mSayPanel.DrawItem("", ITEMDRAW_SPACER);
mSayPanel.CurrentKey = GetMaxPageItems(mSayPanel.Style);
mSayPanel.DrawItem("Exit", ITEMDRAW_CONTROL);
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && !IsFakeClient(i))
{
mSayPanel.Send(i, Handler_DoNothing, 10);
}
}
delete mSayPanel;
}
public int Handler_DoNothing(Menu menu, MenuAction action, int param1, int param2)
{
/* Do nothing */
}

242
scripting/temp/basecomm.sp Normal file
View File

@@ -0,0 +1,242 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Communication Plugin
* Provides fucntionality for controlling communication on the server
*
* 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.
* 1
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <sourcemod>
#include <sdktools>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma semicolon 1
#pragma newdecls required
public Plugin myinfo =
{
name = "Basic Comm Control",
author = "AlliedModders LLC",
description = "Provides methods of controlling communication.",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
bool g_Muted[MAXPLAYERS+1]; // Is the player muted?
bool g_Gagged[MAXPLAYERS+1]; // Is the player gagged?
ConVar g_Cvar_Deadtalk; // Holds the handle for sm_deadtalk
ConVar g_Cvar_Alltalk; // Holds the handle for sv_alltalk
bool g_Hooked = false; // Tracks if we've hooked events for deadtalk
TopMenu hTopMenu;
int g_GagTarget[MAXPLAYERS+1];
#include "basecomm/gag.sp"
#include "basecomm/natives.sp"
#include "basecomm/forwards.sp"
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("BaseComm_IsClientGagged", Native_IsClientGagged);
CreateNative("BaseComm_IsClientMuted", Native_IsClientMuted);
CreateNative("BaseComm_SetClientGag", Native_SetClientGag);
CreateNative("BaseComm_SetClientMute", Native_SetClientMute);
RegPluginLibrary("basecomm");
return APLRes_Success;
}
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("basecomm.phrases");
g_Cvar_Deadtalk = CreateConVar("sm_deadtalk", "0", "Controls how dead communicate. 0 - Off. 1 - Dead players ignore teams. 2 - Dead players talk to living teammates.", 0, true, 0.0, true, 2.0);
g_Cvar_Alltalk = FindConVar("sv_alltalk");
RegAdminCmd("sm_mute", Command_Mute, ADMFLAG_CHAT, "sm_mute <player> - Removes a player's ability to use voice.");
RegAdminCmd("sm_gag", Command_Gag, ADMFLAG_CHAT, "sm_gag <player> - Removes a player's ability to use chat.");
RegAdminCmd("sm_silence", Command_Silence, ADMFLAG_CHAT, "sm_silence <player> - Removes a player's ability to use voice or chat.");
RegAdminCmd("sm_unmute", Command_Unmute, ADMFLAG_CHAT, "sm_unmute <player> - Restores a player's ability to use voice.");
RegAdminCmd("sm_ungag", Command_Ungag, ADMFLAG_CHAT, "sm_ungag <player> - Restores a player's ability to use chat.");
RegAdminCmd("sm_unsilence", Command_Unsilence, ADMFLAG_CHAT, "sm_unsilence <player> - Restores a player's ability to use voice and chat.");
g_Cvar_Deadtalk.AddChangeHook(ConVarChange_Deadtalk);
g_Cvar_Alltalk.AddChangeHook(ConVarChange_Alltalk);
/* Account for late loading */
TopMenu topmenu;
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != null))
{
OnAdminMenuReady(topmenu);
}
}
public void OnAdminMenuReady(Handle aTopMenu)
{
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
/* Block us from being called twice */
if (topmenu == hTopMenu)
{
return;
}
/* Save the Handle */
hTopMenu = topmenu;
/* Build the "Player Commands" category */
TopMenuObject player_commands = hTopMenu.FindCategory(ADMINMENU_PLAYERCOMMANDS);
if (player_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_gag", AdminMenu_Gag, player_commands, "sm_gag", ADMFLAG_CHAT);
}
}
public void ConVarChange_Deadtalk(ConVar convar, const char[] oldValue, const char[] newValue)
{
if (g_Cvar_Deadtalk.IntValue)
{
HookEvent("player_spawn", Event_PlayerSpawn, EventHookMode_Post);
HookEvent("player_death", Event_PlayerDeath, EventHookMode_Post);
g_Hooked = true;
}
else if (g_Hooked)
{
UnhookEvent("player_spawn", Event_PlayerSpawn);
UnhookEvent("player_death", Event_PlayerDeath);
g_Hooked = false;
}
}
public bool OnClientConnect(int client, char[] rejectmsg, int maxlen)
{
g_Gagged[client] = false;
g_Muted[client] = false;
return true;
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs)
{
if (client && g_Gagged[client])
{
return Plugin_Stop;
}
return Plugin_Continue;
}
public void ConVarChange_Alltalk(ConVar convar, const char[] oldValue, const char[] newValue)
{
int mode = g_Cvar_Deadtalk.IntValue;
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i))
{
continue;
}
if (g_Muted[i])
{
SetClientListeningFlags(i, VOICE_MUTED);
}
else if (g_Cvar_Alltalk.BoolValue)
{
SetClientListeningFlags(i, VOICE_NORMAL);
}
else if (!IsPlayerAlive(i))
{
if (mode == 1)
{
SetClientListeningFlags(i, VOICE_LISTENALL);
}
else if (mode == 2)
{
SetClientListeningFlags(i, VOICE_TEAM);
}
}
}
}
public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if (!client)
{
return;
}
if (g_Muted[client])
{
SetClientListeningFlags(client, VOICE_MUTED);
}
else
{
SetClientListeningFlags(client, VOICE_NORMAL);
}
}
public void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if (!client)
{
return;
}
if (g_Muted[client])
{
SetClientListeningFlags(client, VOICE_MUTED);
return;
}
if (g_Cvar_Alltalk.BoolValue)
{
SetClientListeningFlags(client, VOICE_NORMAL);
return;
}
int mode = g_Cvar_Deadtalk.IntValue;
if (mode == 1)
{
SetClientListeningFlags(client, VOICE_LISTENALL);
}
else if (mode == 2)
{
SetClientListeningFlags(client, VOICE_TEAM);
}
}

View File

@@ -0,0 +1,433 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Basic Commands Plugin
* Implements basic admin commands.
*
* 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 <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative 1works) 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma newdecls required
public Plugin myinfo =
{
name = "Basic Commands",
author = "AlliedModders LLC",
description = "Basic Admin Commands",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
TopMenu hTopMenu;
Menu g_MapList;
StringMap g_ProtectedVars;
#include "basecommands/kick.sp"
#include "basecommands/reloadadmins.sp"
#include "basecommands/cancelvote.sp"
#include "basecommands/who.sp"
#include "basecommands/map.sp"
#include "basecommands/execcfg.sp"
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("plugin.basecommands");
RegAdminCmd("sm_kick", Command_Kick, ADMFLAG_KICK, "sm_kick <#userid|name> [reason]");
RegAdminCmd("sm_map", Command_Map, ADMFLAG_CHANGEMAP, "sm_map <map>");
RegAdminCmd("sm_rcon", Command_Rcon, ADMFLAG_RCON, "sm_rcon <args>");
RegAdminCmd("sm_cvar", Command_Cvar, ADMFLAG_CONVARS, "sm_cvar <cvar> [value]");
RegAdminCmd("sm_resetcvar", Command_ResetCvar, ADMFLAG_CONVARS, "sm_resetcvar <cvar>");
RegAdminCmd("sm_execcfg", Command_ExecCfg, ADMFLAG_CONFIG, "sm_execcfg <filename>");
RegAdminCmd("sm_who", Command_Who, ADMFLAG_GENERIC, "sm_who [#userid|name]");
RegAdminCmd("sm_reloadadmins", Command_ReloadAdmins, ADMFLAG_BAN, "sm_reloadadmins");
RegAdminCmd("sm_cancelvote", Command_CancelVote, ADMFLAG_VOTE, "sm_cancelvote");
RegConsoleCmd("sm_revote", Command_ReVote);
/* Account for late loading */
TopMenu topmenu;
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != null))
{
OnAdminMenuReady(topmenu);
}
g_MapList = new Menu(MenuHandler_ChangeMap, MenuAction_Display);
g_MapList.SetTitle("%T", "Please select a map", LANG_SERVER);
g_MapList.ExitBackButton = true;
char mapListPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, mapListPath, sizeof(mapListPath), "configs/adminmenu_maplist.ini");
SetMapListCompatBind("sm_map menu", mapListPath);
g_ProtectedVars = new StringMap();
ProtectVar("rcon_password");
ProtectVar("sm_show_activity");
ProtectVar("sm_immunity_mode");
}
public void OnMapStart()
{
ParseConfigs();
}
public void OnConfigsExecuted()
{
LoadMapList(g_MapList);
}
void ProtectVar(const char[] cvar)
{
g_ProtectedVars.SetValue(cvar, 1);
}
bool IsVarProtected(const char[] cvar)
{
int dummy_value;
return g_ProtectedVars.GetValue(cvar, dummy_value);
}
bool IsClientAllowedToChangeCvar(int client, const char[] cvarname)
{
ConVar hndl = FindConVar(cvarname);
bool allowed = false;
int client_flags = client == 0 ? ADMFLAG_ROOT : GetUserFlagBits(client);
if (client_flags & ADMFLAG_ROOT)
{
allowed = true;
}
else
{
if (hndl.Flags & FCVAR_PROTECTED)
{
allowed = ((client_flags & ADMFLAG_PASSWORD) == ADMFLAG_PASSWORD);
}
else if (StrEqual(cvarname, "sv_cheats"))
{
allowed = ((client_flags & ADMFLAG_CHEATS) == ADMFLAG_CHEATS);
}
else if (!IsVarProtected(cvarname))
{
allowed = true;
}
}
return allowed;
}
public void OnAdminMenuReady(Handle aTopMenu)
{
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
/* Block us from being called twice */
if (topmenu == hTopMenu)
{
return;
}
/* Save the Handle */
hTopMenu = topmenu;
/* Build the "Player Commands" category */
TopMenuObject player_commands = hTopMenu.FindCategory(ADMINMENU_PLAYERCOMMANDS);
if (player_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_kick", AdminMenu_Kick, player_commands, "sm_kick", ADMFLAG_KICK);
hTopMenu.AddItem("sm_who", AdminMenu_Who, player_commands, "sm_who", ADMFLAG_GENERIC);
}
TopMenuObject server_commands = hTopMenu.FindCategory(ADMINMENU_SERVERCOMMANDS);
if (server_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_reloadadmins", AdminMenu_ReloadAdmins, server_commands, "sm_reloadadmins", ADMFLAG_BAN);
hTopMenu.AddItem("sm_map", AdminMenu_Map, server_commands, "sm_map", ADMFLAG_CHANGEMAP);
hTopMenu.AddItem("sm_execcfg", AdminMenu_ExecCFG, server_commands, "sm_execcfg", ADMFLAG_CONFIG);
}
TopMenuObject voting_commands = hTopMenu.FindCategory(ADMINMENU_VOTINGCOMMANDS);
if (voting_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_cancelvote", AdminMenu_CancelVote, voting_commands, "sm_cancelvote", ADMFLAG_VOTE);
}
}
public void OnLibraryRemoved(const char[] name)
{
if (strcmp(name, "adminmenu") == 0)
{
hTopMenu = null;
}
}
#define FLAG_STRINGS 14
char g_FlagNames[FLAG_STRINGS][20] =
{
"res",
"admin",
"kick",
"ban",
"unban",
"slay",
"map",
"cvars",
"cfg",
"chat",
"vote",
"pass",
"rcon",
"cheat"
};
int CustomFlagsToString(char[] buffer, int maxlength, int flags)
{
char joins[6][6];
int total;
for (int i=view_as<int>(Admin_Custom1); i<=view_as<int>(Admin_Custom6); i++)
{
if (flags & (1<<i))
{
IntToString(i - view_as<int>(Admin_Custom1) + 1, joins[total++], 6);
}
}
ImplodeStrings(joins, total, ",", buffer, maxlength);
return total;
}
void FlagsToString(char[] buffer, int maxlength, int flags)
{
char joins[FLAG_STRINGS+1][32];
int total;
for (int i=0; i<FLAG_STRINGS; i++)
{
if (flags & (1<<i))
{
strcopy(joins[total++], 32, g_FlagNames[i]);
}
}
char custom_flags[32];
if (CustomFlagsToString(custom_flags, sizeof(custom_flags), flags))
{
Format(joins[total++], 32, "custom(%s)", custom_flags);
}
ImplodeStrings(joins, total, ", ", buffer, maxlength);
}
public Action Command_Cvar(int client, int args)
{
if (args < 1)
{
if (client == 0)
{
ReplyToCommand(client, "[SM] Usage: sm_cvar <cvar|protect> [value]");
}
else
{
ReplyToCommand(client, "[SM] Usage: sm_cvar <cvar> [value]");
}
return Plugin_Handled;
}
char cvarname[64];
GetCmdArg(1, cvarname, sizeof(cvarname));
if (client == 0 && StrEqual(cvarname, "protect"))
{
if (args < 2)
{
ReplyToCommand(client, "[SM] Usage: sm_cvar <protect> <cvar>");
return Plugin_Handled;
}
GetCmdArg(2, cvarname, sizeof(cvarname));
ProtectVar(cvarname);
ReplyToCommand(client, "[SM] %t", "Cvar is now protected", cvarname);
return Plugin_Handled;
}
ConVar hndl = FindConVar(cvarname);
if (hndl == null)
{
ReplyToCommand(client, "[SM] %t", "Unable to find cvar", cvarname);
return Plugin_Handled;
}
if (!IsClientAllowedToChangeCvar(client, cvarname))
{
ReplyToCommand(client, "[SM] %t", "No access to cvar");
return Plugin_Handled;
}
char value[255];
if (args < 2)
{
hndl.GetString(value, sizeof(value));
ReplyToCommand(client, "[SM] %t", "Value of cvar", cvarname, value);
return Plugin_Handled;
}
GetCmdArg(2, value, sizeof(value));
// The server passes the values of these directly into ServerCommand, following exec. Sanitize.
if (StrEqual(cvarname, "servercfgfile", false) || StrEqual(cvarname, "lservercfgfile", false))
{
int pos = StrContains(value, ";", true);
if (pos != -1)
{
value[pos] = '\0';
}
}
if ((hndl.Flags & FCVAR_PROTECTED) != FCVAR_PROTECTED)
{
ShowActivity2(client, "[SM] ", "%t", "Cvar changed", cvarname, value);
}
else
{
ReplyToCommand(client, "[SM] %t", "Cvar changed", cvarname, value);
}
LogAction(client, -1, "\"%L\" changed cvar (cvar \"%s\") (value \"%s\")", client, cvarname, value);
hndl.SetString(value, true);
return Plugin_Handled;
}
public Action Command_ResetCvar(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_resetcvar <cvar>");
return Plugin_Handled;
}
char cvarname[64];
GetCmdArg(1, cvarname, sizeof(cvarname));
ConVar hndl = FindConVar(cvarname);
if (hndl == null)
{
ReplyToCommand(client, "[SM] %t", "Unable to find cvar", cvarname);
return Plugin_Handled;
}
if (!IsClientAllowedToChangeCvar(client, cvarname))
{
ReplyToCommand(client, "[SM] %t", "No access to cvar");
return Plugin_Handled;
}
hndl.RestoreDefault();
char value[255];
hndl.GetString(value, sizeof(value));
if ((hndl.Flags & FCVAR_PROTECTED) != FCVAR_PROTECTED)
{
ShowActivity2(client, "[SM] ", "%t", "Cvar changed", cvarname, value);
}
else
{
ReplyToCommand(client, "[SM] %t", "Cvar changed", cvarname, value);
}
LogAction(client, -1, "\"%L\" reset cvar (cvar \"%s\") (value \"%s\")", client, cvarname, value);
return Plugin_Handled;
}
public Action Command_Rcon(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_rcon <args>");
return Plugin_Handled;
}
char argstring[255];
GetCmdArgString(argstring, sizeof(argstring));
LogAction(client, -1, "\"%L\" console command (cmdline \"%s\")", client, argstring);
if (client == 0) // They will already see the response in the console.
{
ServerCommand("%s", argstring);
} else {
char responseBuffer[4096];
ServerCommandEx(responseBuffer, sizeof(responseBuffer), "%s", argstring);
ReplyToCommand(client, responseBuffer);
}
return Plugin_Handled;
}
public Action Command_ReVote(int client, int args)
{
if (client == 0)
{
ReplyToCommand(client, "[SM] %t", "Command is in-game only");
return Plugin_Handled;
}
if (!IsVoteInProgress())
{
ReplyToCommand(client, "[SM] %t", "Vote Not In Progress");
return Plugin_Handled;
}
if (!IsClientInVotePool(client))
{
ReplyToCommand(client, "[SM] %t", "Cannot participate in vote");
return Plugin_Handled;
}
if (!RedrawClientVoteMenu(client))
{
ReplyToCommand(client, "[SM] %t", "Cannot change vote");
}
return Plugin_Handled;
}

View File

@@ -0,0 +1,530 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Basic Info Triggers Plugin
* Implements basic information chat triggers like ff and timeleft.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <mapchooser>
#define REQUIRE_PLUGIN
#pragma newdecls required
public Plugin myinfo =
{
name = "Basic Info Triggers",
author = "AlliedModders LLC",
description = "Adds ff, timeleft, thetime, and others.",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
ConVar g_Cvar_TriggerShow;
ConVar g_Cvar_TimeleftInterval;
ConVar g_Cvar_FriendlyFire;
Handle g_Timer_TimeShow = null;
ConVar g_Cvar_WinLimit;
ConVar g_Cvar_FragLimit;
ConVar g_Cvar_MaxRounds;
#define TIMELEFT_ALL_ALWAYS 0 /* Print to all players */
#define TIMELEFT_ALL_MAYBE 1 /* Print to all players if sm_trigger_show allows */
#define TIMELEFT_ONE 2 /* Print to a single player */
bool mapchooser;
int g_TotalRounds;
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("basetriggers.phrases");
g_Cvar_TriggerShow = CreateConVar("sm_trigger_show", "0", "Display triggers message to all players? (0 off, 1 on, def. 0)", 0, true, 0.0, true, 1.0);
g_Cvar_TimeleftInterval = CreateConVar("sm_timeleft_interval", "0.0", "Display timeleft every x seconds. Default 0.", 0, true, 0.0, true, 1800.0);
g_Cvar_FriendlyFire = FindConVar("mp_friendlyfire");
RegConsoleCmd("timeleft", Command_Timeleft);
RegConsoleCmd("nextmap", Command_Nextmap);
RegConsoleCmd("motd", Command_Motd);
RegConsoleCmd("ff", Command_FriendlyFire);
g_Cvar_TimeleftInterval.AddChangeHook(ConVarChange_TimeleftInterval);
char folder[64];
GetGameFolderName(folder, sizeof(folder));
if (strcmp(folder, "insurgency") == 0)
{
HookEvent("game_newmap", Event_GameStart);
}
else
{
HookEvent("game_start", Event_GameStart);
}
if (strcmp(folder, "nucleardawn") == 0)
{
HookEvent("round_win", Event_RoundEnd);
}
else
{
HookEvent("round_end", Event_RoundEnd);
}
HookEventEx("teamplay_win_panel", Event_TeamPlayWinPanel);
HookEventEx("teamplay_restart_round", Event_TFRestartRound);
HookEventEx("arena_win_panel", Event_TeamPlayWinPanel);
g_Cvar_WinLimit = FindConVar("mp_winlimit");
g_Cvar_FragLimit = FindConVar("mp_fraglimit");
g_Cvar_MaxRounds = FindConVar("mp_maxrounds");
mapchooser = LibraryExists("mapchooser");
}
public void OnMapStart()
{
g_TotalRounds = 0;
}
/* Round count tracking */
public void Event_TFRestartRound(Event event, const char[] name, bool dontBroadcast)
{
/* Game got restarted - reset our round count tracking */
g_TotalRounds = 0;
}
public void Event_GameStart(Event event, const char[] name, bool dontBroadcast)
{
/* Game got restarted - reset our round count tracking */
g_TotalRounds = 0;
}
public void Event_TeamPlayWinPanel(Event event, const char[] name, bool dontBroadcast)
{
if (event.GetInt("round_complete") == 1 || StrEqual(name, "arena_win_panel"))
{
g_TotalRounds++;
}
}
/* You ask, why don't you just use team_score event? And I answer... Because CSS doesn't. */
public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
{
g_TotalRounds++;
}
public void OnLibraryRemoved(const char[] name)
{
if (StrEqual(name, "mapchooser"))
{
mapchooser = false;
}
}
public void OnLibraryAdded(const char[] name)
{
if (StrEqual(name, "mapchooser"))
{
mapchooser = true;
}
}
public void ConVarChange_TimeleftInterval(ConVar convar, const char[] oldValue, const char[] newValue)
{
float newval = StringToFloat(newValue);
if (newval < 1.0)
{
if (g_Timer_TimeShow != null)
{
KillTimer(g_Timer_TimeShow);
}
return;
}
if (g_Timer_TimeShow != null)
{
KillTimer(g_Timer_TimeShow);
g_Timer_TimeShow = CreateTimer(newval, Timer_DisplayTimeleft, _, TIMER_REPEAT);
}
else
g_Timer_TimeShow = CreateTimer(newval, Timer_DisplayTimeleft, _, TIMER_REPEAT);
}
public Action Timer_DisplayTimeleft(Handle timer)
{
ShowTimeLeft(0, TIMELEFT_ALL_ALWAYS);
}
public Action Command_Timeleft(int client, int args)
{
ShowTimeLeft(client, TIMELEFT_ONE);
return Plugin_Handled;
}
public Action Command_Nextmap(int client, int args)
{
if (client && !IsClientInGame(client))
return Plugin_Handled;
char map[PLATFORM_MAX_PATH];
GetNextMap(map, sizeof(map));
if (mapchooser && EndOfMapVoteEnabled() && !HasEndOfMapVoteFinished())
{
ReplyToCommand(client, "[SM] %t", "Pending Vote");
}
else
{
GetMapDisplayName(map, map, sizeof(map));
ReplyToCommand(client, "[SM] %t", "Next Map", map);
}
return Plugin_Handled;
}
public Action Command_Motd(int client, int args)
{
if (client == 0)
{
ReplyToCommand(client, "[SM] %t", "Command is in-game only");
return Plugin_Handled;
}
if (!IsClientInGame(client))
return Plugin_Handled;
ShowMOTDPanel(client, "Message Of The Day", "motd", MOTDPANEL_TYPE_INDEX);
return Plugin_Handled;
}
public Action Command_FriendlyFire(int client, int args)
{
if (client == 0)
{
ReplyToCommand(client, "[SM] %t", "Command is in-game only");
return Plugin_Handled;
}
if (!IsClientInGame(client))
return Plugin_Handled;
ShowFriendlyFire(client);
return Plugin_Handled;
}
public void OnClientSayCommand_Post(int client, const char[] command, const char[] sArgs)
{
if (strcmp(sArgs, "timeleft", false) == 0)
{
ShowTimeLeft(client, TIMELEFT_ALL_MAYBE);
}
else if (strcmp(sArgs, "thetime", false) == 0)
{
char ctime[64];
FormatTime(ctime, 64, NULL_STRING);
if (g_Cvar_TriggerShow.IntValue)
{
PrintToChatAll("[SM] %t", "Thetime", ctime);
}
else
{
PrintToChat(client,"[SM] %t", "Thetime", ctime);
}
}
else if (strcmp(sArgs, "ff", false) == 0)
{
ShowFriendlyFire(client);
}
else if (strcmp(sArgs, "currentmap", false) == 0)
{
char map[64];
GetCurrentMap(map, sizeof(map));
if (g_Cvar_TriggerShow.IntValue)
{
PrintToChatAll("[SM] %t", "Current Map", map);
}
else
{
PrintToChat(client,"[SM] %t", "Current Map", map);
}
}
else if (strcmp(sArgs, "nextmap", false) == 0)
{
char map[PLATFORM_MAX_PATH];
GetNextMap(map, sizeof(map));
GetMapDisplayName(map, map, sizeof(map));
if (g_Cvar_TriggerShow.IntValue)
{
if (mapchooser && EndOfMapVoteEnabled() && !HasEndOfMapVoteFinished())
{
PrintToChatAll("[SM] %t", "Pending Vote");
}
else
{
PrintToChatAll("[SM] %t", "Next Map", map);
}
}
else
{
if (mapchooser && EndOfMapVoteEnabled() && !HasEndOfMapVoteFinished())
{
PrintToChat(client, "[SM] %t", "Pending Vote");
}
else
{
PrintToChat(client, "[SM] %t", "Next Map", map);
}
}
}
else if (strcmp(sArgs, "motd", false) == 0)
{
ShowMOTDPanel(client, "Message Of The Day", "motd", MOTDPANEL_TYPE_INDEX);
}
}
void ShowTimeLeft(int client, int who)
{
bool lastround = false;
bool written = false;
bool notimelimit = false;
char finalOutput[1024];
if (who == TIMELEFT_ALL_ALWAYS
|| (who == TIMELEFT_ALL_MAYBE && g_Cvar_TriggerShow.IntValue))
{
client = 0;
}
int timeleft;
if (GetMapTimeLeft(timeleft))
{
int mins, secs;
int timelimit;
if (timeleft > 0)
{
mins = timeleft / 60;
secs = timeleft % 60;
written = true;
FormatEx(finalOutput, sizeof(finalOutput), "%T %d:%02d", "Timeleft", client, mins, secs);
}
else if (GetMapTimeLimit(timelimit) && timelimit == 0)
{
notimelimit = true;
}
else
{
/* 0 timeleft so this must be the last round */
lastround=true;
}
}
if (!lastround)
{
if (g_Cvar_WinLimit)
{
int winlimit = g_Cvar_WinLimit.IntValue;
if (winlimit > 0)
{
if (written)
{
int len = strlen(finalOutput);
if (len < sizeof(finalOutput))
{
if (winlimit > 1)
{
FormatEx(finalOutput[len], sizeof(finalOutput)-len, "%T", "WinLimitAppendPlural" ,client, winlimit);
}
else
{
FormatEx(finalOutput[len], sizeof(finalOutput)-len, "%T", "WinLimitAppend" ,client);
}
}
}
else
{
if (winlimit > 1)
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "WinLimitPlural", client, winlimit);
}
else
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "WinLimit", client);
}
written = true;
}
}
}
if (g_Cvar_FragLimit)
{
int fraglimit = g_Cvar_FragLimit.IntValue;
if (fraglimit > 0)
{
if (written)
{
int len = strlen(finalOutput);
if (len < sizeof(finalOutput))
{
if (fraglimit > 1)
{
FormatEx(finalOutput[len], sizeof(finalOutput)-len, "%T", "FragLimitAppendPlural", client, fraglimit);
}
else
{
FormatEx(finalOutput[len], sizeof(finalOutput)-len, "%T", "FragLimitAppend", client);
}
}
}
else
{
if (fraglimit > 1)
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "FragLimitPlural", client, fraglimit);
}
else
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "FragLimit", client);
}
written = true;
}
}
}
if (g_Cvar_MaxRounds)
{
int maxrounds = g_Cvar_MaxRounds.IntValue;
if (maxrounds > 0)
{
int remaining = maxrounds - g_TotalRounds;
if (written)
{
int len = strlen(finalOutput);
if (len < sizeof(finalOutput))
{
if (remaining > 1)
{
FormatEx(finalOutput[len], sizeof(finalOutput)-len, "%T", "MaxRoundsAppendPlural", client, remaining);
}
else
{
FormatEx(finalOutput[len], sizeof(finalOutput)-len, "%T", "MaxRoundsAppend", client);
}
}
}
else
{
if (remaining > 1)
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "MaxRoundsPlural", client, remaining);
}
else
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "MaxRounds", client);
}
written = true;
}
}
}
}
if (lastround)
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "LastRound", client);
}
else if (notimelimit && !written)
{
FormatEx(finalOutput, sizeof(finalOutput), "%T", "NoTimelimit", client);
}
if (who == TIMELEFT_ALL_ALWAYS
|| (who == TIMELEFT_ALL_MAYBE && g_Cvar_TriggerShow.IntValue))
{
PrintToChatAll("[SM] %s", finalOutput);
}
else if (client != 0 && IsClientInGame(client))
{
PrintToChat(client, "[SM] %s", finalOutput);
}
if (client == 0)
{
PrintToServer("[SM] %s", finalOutput);
}
}
void ShowFriendlyFire(int client)
{
if (g_Cvar_FriendlyFire)
{
char phrase[24];
if (g_Cvar_FriendlyFire.BoolValue)
{
strcopy(phrase, sizeof(phrase), "Friendly Fire On");
}
else
{
strcopy(phrase, sizeof(phrase), "Friendly Fire Off");
}
if (g_Cvar_TriggerShow.IntValue)
{
PrintToChatAll("[SM] %t", phrase);
}
else
{
PrintToChat(client,"[SM] %t", phrase);
}
}
}

418
scripting/temp/basevotes.sp Normal file
View File

@@ -0,0 +1,418 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Basic Votes Plugin
* Implements basic vote commands.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma newdecls required
public Plugin myinfo =
{
name = "Basic Votes",
author = "AlliedModders LLC",
description = "Basic Vote Commands",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
#define VOTE_NO "###no###"
#define VOTE_YES "###yes###"
Menu g_hVoteMenu = null;
ConVar g_Cvar_Limits[3] = {null, ...};
//ConVar g_Cvar_VoteSay = null;
enum voteType
{
map,
kick,
ban,
question
}
voteType g_voteType = question;
// Menu API does not provide us with a way to pass multiple peices of data with a single
// choice, so some globals are used to hold stuff.
//
#define VOTE_CLIENTID 0
#define VOTE_USERID 1
int g_voteClient[2]; /* Holds the target's client id and user id */
#define VOTE_NAME 0
#define VOTE_AUTHID 1
#define VOTE_IP 2
char g_voteInfo[3][65]; /* Holds the target's name, authid, and IP */
char g_voteArg[256]; /* Used to hold ban/kick reasons or vote questions */
TopMenu hTopMenu;
#include "basevotes/votekick.sp"
#include "basevotes/voteban.sp"
#include "basevotes/votemap.sp"
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("basevotes.phrases");
LoadTranslations("plugin.basecommands");
LoadTranslations("basebans.phrases");
RegAdminCmd("sm_votemap", Command_Votemap, ADMFLAG_VOTE|ADMFLAG_CHANGEMAP, "sm_votemap <mapname> [mapname2] ... [mapname5] ");
RegAdminCmd("sm_votekick", Command_Votekick, ADMFLAG_VOTE|ADMFLAG_KICK, "sm_votekick <player> [reason]");
RegAdminCmd("sm_voteban", Command_Voteban, ADMFLAG_VOTE|ADMFLAG_BAN, "sm_voteban <player> [reason]");
RegAdminCmd("sm_vote", Command_Vote, ADMFLAG_VOTE, "sm_vote <question> [Answer1] [Answer2] ... [Answer5]");
/*
g_Cvar_Show = FindConVar("sm_vote_show");
if (g_Cvar_Show == null)
{
g_Cvar_Show = CreateConVar("sm_vote_show", "1", "Show player's votes? Default on.", 0, true, 0.0, true, 1.0);
}
*/
g_Cvar_Limits[0] = CreateConVar("sm_vote_map", "0.60", "percent required for successful map vote.", 0, true, 0.05, true, 1.0);
g_Cvar_Limits[1] = CreateConVar("sm_vote_kick", "0.60", "percent required for successful kick vote.", 0, true, 0.05, true, 1.0);
g_Cvar_Limits[2] = CreateConVar("sm_vote_ban", "0.60", "percent required for successful ban vote.", 0, true, 0.05, true, 1.0);
/* Account for late loading */
TopMenu topmenu;
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != null))
{
OnAdminMenuReady(topmenu);
}
g_SelectedMaps = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH));
g_MapList = new Menu(MenuHandler_Map, MenuAction_DrawItem|MenuAction_Display);
g_MapList.SetTitle("%T", "Please select a map", LANG_SERVER);
g_MapList.ExitBackButton = true;
char mapListPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, mapListPath, sizeof(mapListPath), "configs/adminmenu_maplist.ini");
SetMapListCompatBind("sm_votemap menu", mapListPath);
}
public void OnConfigsExecuted()
{
g_mapCount = LoadMapList(g_MapList);
}
public void OnAdminMenuReady(Handle aTopMenu)
{
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
/* Block us from being called twice */
if (topmenu == hTopMenu)
{
return;
}
/* Save the Handle */
hTopMenu = topmenu;
/* Build the "Voting Commands" category */
TopMenuObject voting_commands = hTopMenu.FindCategory(ADMINMENU_VOTINGCOMMANDS);
if (voting_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_votekick", AdminMenu_VoteKick, voting_commands, "sm_votekick", ADMFLAG_VOTE|ADMFLAG_KICK);
hTopMenu.AddItem("sm_voteban", AdminMenu_VoteBan, voting_commands, "sm_voteban", ADMFLAG_VOTE|ADMFLAG_BAN);
hTopMenu.AddItem("sm_votemap", AdminMenu_VoteMap, voting_commands, "sm_votemap", ADMFLAG_VOTE|ADMFLAG_CHANGEMAP);
}
}
public Action Command_Vote(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_vote <question> [Answer1] [Answer2] ... [Answer5]");
return Plugin_Handled;
}
if (IsVoteInProgress())
{
ReplyToCommand(client, "[SM] %t", "Vote in Progress");
return Plugin_Handled;
}
if (!TestVoteDelay(client))
{
return Plugin_Handled;
}
char text[256];
GetCmdArgString(text, sizeof(text));
char answers[5][64];
int answerCount;
int len = BreakString(text, g_voteArg, sizeof(g_voteArg));
int pos = len;
while (args > 1 && pos != -1 && answerCount < 5)
{
pos = BreakString(text[len], answers[answerCount], sizeof(answers[]));
answerCount++;
if (pos != -1)
{
len += pos;
}
}
LogAction(client, -1, "\"%L\" initiated a generic vote.", client);
ShowActivity2(client, "[SM] ", "%t", "Initiate Vote", g_voteArg);
g_voteType = question;
g_hVoteMenu = new Menu(Handler_VoteCallback, MENU_ACTIONS_ALL);
g_hVoteMenu.SetTitle("%s?", g_voteArg);
if (answerCount < 2)
{
g_hVoteMenu.AddItem(VOTE_YES, "Yes");
g_hVoteMenu.AddItem(VOTE_NO, "No");
}
else
{
for (int i = 0; i < answerCount; i++)
{
g_hVoteMenu.AddItem(answers[i], answers[i]);
}
}
g_hVoteMenu.ExitButton = false;
g_hVoteMenu.DisplayVoteToAll(20);
return Plugin_Handled;
}
public int Handler_VoteCallback(Menu menu, MenuAction action, int param1, int param2)
{
if (action == MenuAction_End)
{
VoteMenuClose();
}
else if (action == MenuAction_Display)
{
if (g_voteType != question)
{
char title[64];
menu.GetTitle(title, sizeof(title));
char buffer[255];
Format(buffer, sizeof(buffer), "%T", title, param1, g_voteInfo[VOTE_NAME]);
Panel panel = view_as<Panel>(param2);
panel.SetTitle(buffer);
}
}
else if (action == MenuAction_DisplayItem)
{
char display[64];
menu.GetItem(param2, "", 0, _, display, sizeof(display));
if (strcmp(display, "No") == 0 || strcmp(display, "Yes") == 0)
{
char buffer[255];
Format(buffer, sizeof(buffer), "%T", display, param1);
return RedrawMenuItem(buffer);
}
}
/* else if (action == MenuAction_Select)
{
VoteSelect(menu, param1, param2);
}*/
else if (action == MenuAction_VoteCancel && param1 == VoteCancel_NoVotes)
{
PrintToChatAll("[SM] %t", "No Votes Cast");
}
else if (action == MenuAction_VoteEnd)
{
char item[64], display[64];
float percent, limit;
int votes, totalVotes;
GetMenuVoteInfo(param2, votes, totalVotes);
menu.GetItem(param1, item, sizeof(item), _, display, sizeof(display));
if (strcmp(item, VOTE_NO) == 0 && param1 == 1)
{
votes = totalVotes - votes; // Reverse the votes to be in relation to the Yes option.
}
percent = GetVotePercent(votes, totalVotes);
if (g_voteType != question)
{
limit = g_Cvar_Limits[g_voteType].FloatValue;
}
/* :TODO: g_voteClient[userid] needs to be checked */
// A multi-argument vote is "always successful", but have to check if its a Yes/No vote.
if ((strcmp(item, VOTE_YES) == 0 && FloatCompare(percent,limit) < 0 && param1 == 0) || (strcmp(item, VOTE_NO) == 0 && param1 == 1))
{
/* :TODO: g_voteClient[userid] should be used here and set to -1 if not applicable.
*/
LogAction(-1, -1, "Vote failed.");
PrintToChatAll("[SM] %t", "Vote Failed", RoundToNearest(100.0*limit), RoundToNearest(100.0*percent), totalVotes);
}
else
{
PrintToChatAll("[SM] %t", "Vote Successful", RoundToNearest(100.0*percent), totalVotes);
switch (g_voteType)
{
case (question):
{
if (strcmp(item, VOTE_NO) == 0 || strcmp(item, VOTE_YES) == 0)
{
strcopy(item, sizeof(item), display);
}
PrintToChatAll("[SM] %t", "Vote End", g_voteArg, item);
}
case (map):
{
// single-vote items don't use the display item
char displayName[PLATFORM_MAX_PATH];
GetMapDisplayName(item, displayName, sizeof(displayName));
LogAction(-1, -1, "Changing map to %s due to vote.", item);
PrintToChatAll("[SM] %t", "Changing map", displayName);
DataPack dp;
CreateDataTimer(5.0, Timer_ChangeMap, dp);
dp.WriteString(item);
}
case (kick):
{
if (g_voteArg[0] == '\0')
{
strcopy(g_voteArg, sizeof(g_voteArg), "Votekicked");
}
PrintToChatAll("[SM] %t", "Kicked target", "_s", g_voteInfo[VOTE_NAME]);
LogAction(-1, g_voteClient[VOTE_CLIENTID], "Vote kick successful, kicked \"%L\" (reason \"%s\")", g_voteClient[VOTE_CLIENTID], g_voteArg);
ServerCommand("kickid %d \"%s\"", g_voteClient[VOTE_USERID], g_voteArg);
}
case (ban):
{
if (g_voteArg[0] == '\0')
{
strcopy(g_voteArg, sizeof(g_voteArg), "Votebanned");
}
PrintToChatAll("[SM] %t", "Banned player", g_voteInfo[VOTE_NAME], 30);
LogAction(-1, g_voteClient[VOTE_CLIENTID], "Vote ban successful, banned \"%L\" (minutes \"30\") (reason \"%s\")", g_voteClient[VOTE_CLIENTID], g_voteArg);
BanClient(g_voteClient[VOTE_CLIENTID],
30,
BANFLAG_AUTO,
g_voteArg,
"Banned by vote",
"sm_voteban");
}
}
}
}
return 0;
}
/*
void VoteSelect(Menu menu, int param1, int param2 = 0)
{
if (g_Cvar_VoteShow.IntValue == 1)
{
char voter[64], junk[64], choice[64];
GetClientName(param1, voter, sizeof(voter));
menu.GetItem(param2, junk, sizeof(junk), _, choice, sizeof(choice));
PrintToChatAll("[SM] %T", "Vote Select", LANG_SERVER, voter, choice);
}
}
*/
void VoteMenuClose()
{
delete g_hVoteMenu;
g_hVoteMenu = null;
}
float GetVotePercent(int votes, int totalVotes)
{
return FloatDiv(float(votes),float(totalVotes));
}
bool TestVoteDelay(int client)
{
int delay = CheckVoteDelay();
if (delay > 0)
{
if (delay > 60)
{
ReplyToCommand(client, "[SM] %t", "Vote Delay Minutes", delay % 60);
}
else
{
ReplyToCommand(client, "[SM] %t", "Vote Delay Seconds", delay);
}
return false;
}
return true;
}
public Action Timer_ChangeMap(Handle timer, DataPack dp)
{
char mapname[65];
dp.Reset();
dp.ReadString(mapname, sizeof(mapname));
ForceChangeLevel(mapname, "sm_votemap Result");
return Plugin_Stop;
}

View File

@@ -0,0 +1,551 @@
#include <sdkhooks>
#include <tf2_stocks>
#include <tf2items>
#pragma newdecls required;
#define MODEL_SKELETON "models/bots/skeleton_sniper_boss/skeleton_sniper_boss.mdl"
#define PLUGIN_VERSION "1.2"
bool g_bSpecial[MAXPLAYERS + 1];
bool g_bSkeleton[MAXPLAYERS + 1];
TFTeam g_iOldTeam[MAXPLAYERS + 1];
Handle g_hCvarStompDamage;
public Plugin myinfo =
{
name = "[TF2] Be The Skeleton King!",
author = "Pelipoika",
description = "Spooky scary skeleton",
version = PLUGIN_VERSION,
url = ""
}
public void OnPluginStart()
{
AddTempEntHook("TFBlood", TempHook);
RegAdminCmd("sm_beskeleton", Command_Skeleton, ADMFLAG_ROOT);
HookEvent("post_inventory_application", Event_SkeletonDeath);
HookEvent("player_death", Event_SkeletonDeath, EventHookMode_Pre);
CreateConVar("tf2_beskeleton_version", PLUGIN_VERSION, "Be the Skeleton King version", FCVAR_NOTIFY|FCVAR_DONTRECORD|FCVAR_SPONLY);
g_hCvarStompDamage = CreateConVar("tf2_beskeleton_stompdamage", "120", "Movement speed penalty when carrying a bomb", FCVAR_NOTIFY|FCVAR_DONTRECORD, true, 0.0, true, 1.0);
for (int client = 1; client <= MaxClients; client++)
{
if(client > 0 && client <= MaxClients && IsClientInGame(client))
{
g_bSkeleton[client] = false;
g_bSpecial[client] = false;
g_iOldTeam[client] = TF2_GetClientTeam(client);
SDKHook(client, SDKHook_OnTakeDamageAlive, TakeDamage);
}
}
AddNormalSoundHook(SkeletonSH);
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("BeSkeletonKing_MakeSkeleton", Native_SetSkeleton);
CreateNative("BeSkeletonKing_IsSkeleton", Native_IsSkeleton);
RegPluginLibrary("beskeleton");
return APLRes_Success;
}
public Action TempHook(const char[] te_name, const Players[], int numClients, float delay)
{
int client = TE_ReadNum("entindex");
if (client > 0 && client <= MaxClients && IsClientInGame(client) && g_bSkeleton[client])
{
float m_vecOrigin[3];
m_vecOrigin[0] = TE_ReadFloat("m_vecOrigin[0]");
m_vecOrigin[1] = TE_ReadFloat("m_vecOrigin[1]");
m_vecOrigin[2] = TE_ReadFloat("m_vecOrigin[2]");
if(GetEntProp(client, Prop_Send, "m_iTeamNum") == 0)
{
CreateParticle("spell_skeleton_goop_green", m_vecOrigin);
}
else
{
switch(TF2_GetClientTeam(client))
{
case TFTeam_Red: CreateParticle("spell_pumpkin_mirv_goop_red", m_vecOrigin);
case TFTeam_Blue: CreateParticle("spell_pumpkin_mirv_goop_blue", m_vecOrigin);
}
}
return Plugin_Stop;
}
return Plugin_Continue;
}
public void OnMapStart()
{
PrecacheModel(MODEL_SKELETON);
PrecacheSound("misc/halloween/skeleton_break.wav");
}
public void OnClientPutInServer(int client)
{
g_bSkeleton[client] = false;
g_bSpecial[client] = false;
g_iOldTeam[client] = TFTeam_Spectator;
SDKHook(client, SDKHook_OnTakeDamageAlive, TakeDamage);
}
public Action Command_Skeleton(int client, int args)
{
char arg1[32], arg2[6];
GetCmdArg(1, arg1, sizeof(arg1));
GetCmdArg(2, arg2, sizeof(arg2));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS];
int 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;
}
for (int i = 0; i < target_count; i++)
{
int player = target_list[i];
if(player > 0 && player <= MaxClients && IsClientInGame(player) && IsPlayerAlive(player))
{
if(StringToInt(arg2) == 1)
MakeSkeleton(player, true);
else
MakeSkeleton(player);
}
}
return Plugin_Handled;
}
public Action GetMaxHealth(int client, int &MaxHealth)
{
if (client > 0 && client <= MaxClients && IsClientInGame(client))
{
MaxHealth = 1000;
return Plugin_Changed;
}
return Plugin_Continue;
}
public Action SetModel(int client, const char[] model)
{
SetVariantString(model);
AcceptEntityInput(client, "SetCustomModel");
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 1);
}
stock void MakeSkeleton(int client, bool spectator = false)
{
if(spectator)
{
g_iOldTeam[client] = TF2_GetClientTeam(client);
SetEntProp(client, Prop_Send, "m_bForcedSkin", 1);
SetEntProp(client, Prop_Send, "m_nForcedSkin", 2);
SetEntProp(client, Prop_Send, "m_iTeamNum", 0);
}
SetVariantString("2.0");
AcceptEntityInput(client, "SetModelScale");
SetModel(client, MODEL_SKELETON);
TF2_SetPlayerClass(client, TFClass_Sniper, _, false);
TF2_RemoveAllWearables(client);
TF2_RemoveAllWeapons(client);
Handle hWeaponFists = TF2Items_CreateItem(OVERRIDE_ALL);
TF2Items_SetClassname(hWeaponFists, "tf_weapon_club");
TF2Items_SetItemIndex(hWeaponFists, 3);
TF2Items_SetQuality(hWeaponFists, 6);
TF2Items_SetAttribute(hWeaponFists, 0, 15, 0.0);
TF2Items_SetAttribute(hWeaponFists, 1, 5, 1.65);
TF2Items_SetAttribute(hWeaponFists, 2, 402, 1.0);
TF2Items_SetNumAttributes(hWeaponFists, 3);
int iEntity = TF2Items_GiveNamedItem(client, hWeaponFists);
EquipPlayerWeapon(client, iEntity);
CloseHandle(hWeaponFists);
SetEntityRenderMode(iEntity, RENDER_TRANSCOLOR);
SetEntityRenderColor(iEntity, 255, 255, 255, 0);
SetEntProp(iEntity, Prop_Send, "m_fEffects", 16);
char anim[16];
Format(anim, 32, "spawn0%i", GetRandomInt(1, 7));
PlayAnimation(client, anim);
g_bSpecial[client] = true;
SetNextAttack(iEntity, 2.0);
SDKHook(client, SDKHook_GetMaxHealth, GetMaxHealth);
SetEntProp(client, Prop_Send, "m_iHealth", 1000);
g_bSkeleton[client] = true;
}
stock void PlayAnimation(int client, char[] anim)
{
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 0);
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 0);
SetEntityMoveType(client, MOVETYPE_NONE);
float vecOrigin[3], vecAngles[3];
GetClientAbsOrigin(client, vecOrigin);
GetClientAbsAngles(client, vecAngles);
vecAngles[0] = 0.0;
int animationentity = CreateEntityByName("prop_dynamic_override");
if(IsValidEntity(animationentity))
{
DispatchKeyValueVector(animationentity, "origin", vecOrigin);
DispatchKeyValueVector(animationentity, "angles", vecAngles);
DispatchKeyValue(animationentity, "model", MODEL_SKELETON);
DispatchKeyValue(animationentity, "defaultanim", anim);
DispatchSpawn(animationentity);
SetEntPropEnt(animationentity, Prop_Send, "m_hOwnerEntity", client);
if(GetEntProp(client, Prop_Send, "m_iTeamNum") == 0)
SetEntProp(animationentity, Prop_Send, "m_nSkin", GetEntProp(client, Prop_Send, "m_nForcedSkin"));
else
SetEntProp(animationentity, Prop_Send, "m_nSkin", GetClientTeam(client) - 2);
SetEntPropFloat(animationentity, Prop_Send, "m_flModelScale", 2.0);
SetVariantString("OnAnimationDone !self:KillHierarchy::0.0:1");
AcceptEntityInput(animationentity, "AddOutput");
HookSingleEntityOutput(animationentity, "OnAnimationDone", OnAnimationDone, true);
}
}
public void OnAnimationDone(const char[] output, int caller, int activator, float delay)
{
if(IsValidEntity(caller))
{
int client = GetEntPropEnt(caller, Prop_Send, "m_hOwnerEntity");
if(client > 0 && client <= MaxClients && IsClientInGame(client) && IsPlayerAlive(client))
{
SetEntityMoveType(client, MOVETYPE_WALK);
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 1);
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 255);
g_bSpecial[client] = false;
}
}
}
public Action OnPlayerRunCmd(int client, int &iButtons, int &iImpulse, float fVel[3], float fAng[3], int &iWeapon)
{
if (IsPlayerAlive(client))
{
if(iButtons & IN_ATTACK2 && !g_bSpecial[client] && g_bSkeleton[client] && GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") != -1)
{
SetNextAttack(GetPlayerWeaponSlot(client, TFWeaponSlot_Melee), 2.0);
PlayAnimation(client, "MELEE_swing3");
g_bSpecial[client] = true;
float vecAngles[3], vecOrigin[3];
GetClientAbsAngles(client, vecAngles);
GetClientAbsOrigin(client, vecOrigin);
vecAngles[0] = 0.0;
Handle pack;
CreateDataTimer(0.75, Timer_PerformStomp, pack, TIMER_FLAG_NO_MAPCHANGE);
WritePackCell(pack, client);
WritePackFloat(pack, vecOrigin[0]);
WritePackFloat(pack, vecOrigin[1]);
WritePackFloat(pack, vecOrigin[2]);
WritePackFloat(pack, vecAngles[0]);
WritePackFloat(pack, vecAngles[1]);
WritePackFloat(pack, vecAngles[2]);
}
}
return Plugin_Continue;
}
public Action Timer_PerformStomp(Handle timer, Handle pack)
{
ResetPack(pack);
int client = ReadPackCell(pack);
float vecAngles[3], vecOrigin[3];
vecOrigin[0] = ReadPackFloat(pack);
vecOrigin[1] = ReadPackFloat(pack);
vecOrigin[2] = ReadPackFloat(pack);
vecAngles[0] = ReadPackFloat(pack);
vecAngles[1] = ReadPackFloat(pack);
vecAngles[2] = ReadPackFloat(pack);
float vForward[3], vLeft[3];
GetAngleVectors(vecAngles, vForward, NULL_VECTOR, NULL_VECTOR);
GetAngleVectors(vecAngles, NULL_VECTOR, vLeft, NULL_VECTOR);
vecOrigin[0] += (vForward[0] * 55);
vecOrigin[1] += (vForward[1] * 55);
vecOrigin[2] += (vForward[2] * 55);
vecOrigin[0] += (vLeft[0] * -35);
vecOrigin[1] += (vLeft[1] * -35);
vecOrigin[2] += (vLeft[2] * -35);
CreateParticle("bomibomicon_ring", vecOrigin); //The effect actually comes out of his leg VALVE
float pos2[3], Vec[3], AngBuff[3];
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && IsPlayerAlive(i) && i != client && GetClientTeam(i) != GetClientTeam(client))
{
GetClientAbsOrigin(i, pos2);
if(GetVectorDistance(vecOrigin, pos2) <= 200.0)
{
MakeVectorFromPoints(vecOrigin, pos2, Vec);
GetVectorAngles(Vec, AngBuff);
AngBuff[0] -= 30.0;
GetAngleVectors(AngBuff, Vec, NULL_VECTOR, NULL_VECTOR);
NormalizeVector(Vec, Vec);
ScaleVector(Vec, 500.0);
Vec[2] += 250.0;
SDKHooks_TakeDamage(i, client, client, GetConVarFloat(g_hCvarStompDamage));
TeleportEntity(i, NULL_VECTOR, NULL_VECTOR, Vec);
}
}
}
}
public Action TakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype)
{
if(victim > 0 && victim <= MaxClients && IsClientInGame(victim)
&& attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker)
&& attacker != victim)
{
if(g_bSkeleton[attacker])
{
damage = GetRandomFloat(95.0, 120.0);
return Plugin_Changed;
}
}
return Plugin_Continue;
}
public Action Event_SkeletonDeath(Handle hEvent, char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(GetEventInt(hEvent, "userid"));
int attacker = GetEventInt(hEvent, "inflictor_entindex");
if(g_bSkeleton[client])
{
EmitSoundToAll("misc/halloween/skeleton_break.wav", client);
g_bSkeleton[client] = false;
g_bSpecial[client] = false;
SDKUnhook(client, SDKHook_GetMaxHealth, GetMaxHealth);
SetEntityMoveType(client, MOVETYPE_WALK);
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 1);
SetEntProp(client, Prop_Send, "m_bForcedSkin", 0);
if(GetEntProp(client, Prop_Send, "m_iTeamNum") == 0)
{
SetEntProp(client, Prop_Send, "m_iTeamNum", g_iOldTeam[client]);
g_iOldTeam[client] = TFTeam_Spectator;
}
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 255);
SetVariantString("");
AcceptEntityInput(client, "SetCustomModel");
SetVariantString("1.0");
AcceptEntityInput(client, "SetModelScale");
float vecOrigin[3];
GetClientAbsOrigin(client, vecOrigin);
//Drop a Rare spellbook
int spell = CreateEntityByName("tf_spell_pickup");
if(IsValidEntity(spell))
{
DispatchKeyValueVector(spell, "origin", vecOrigin);
DispatchKeyValueVector(spell, "basevelocity", view_as<float>({0.0, 0.0, 0.0}));
DispatchKeyValueVector(spell, "velocity", view_as<float>({0.0, 0.0, 0.0}));
DispatchKeyValue(spell, "powerup_model", "models/props_halloween/hwn_spellbook_upright_major.mdl");
DispatchKeyValue(spell, "OnPlayerTouch", "!self,Kill,,0,-1");
DispatchSpawn(spell);
SetVariantString("OnUser1 !self:kill::60:1");
AcceptEntityInput(spell, "AddOutput");
AcceptEntityInput(spell, "FireUser1");
SetEntPropEnt(spell, Prop_Send, "m_hOwnerEntity", client);
SetEntProp(spell, Prop_Data, "m_nTier", 1);
}
}
if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && g_bSkeleton[attacker])
{
SetEventInt(hEvent, "attacker", 0);
SetEventString(hEvent, "weapon", "spellbook_skeleton");
SetEventInt(hEvent, "customkill", 66);
SetEventString(hEvent, "weapon_logclassname", "spellbook_skeleton");
}
return Plugin_Continue;
}
public Action SkeletonSH(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)
{
if (entity > 0 && entity <= MaxClients && IsClientInGame(entity))
{
if (!g_bSkeleton[entity]) return Plugin_Continue;
if (StrContains(sample, "vo/sniper", false) != -1)
{
Format(sample, sizeof(sample), "misc/halloween/skeletons/skelly_giant_0%i.wav", GetRandomInt(1, 3));
PrecacheSound(sample);
EmitSoundToAll(sample, entity, channel, level, flags, volume);
return Plugin_Changed;
}
}
return Plugin_Continue;
}
stock void TF2_RemoveAllWearables(int client)
{
int wearable = -1;
while ((wearable = FindEntityByClassname(wearable, "tf_wearable*")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Send, "m_hOwnerEntity");
if (client == player)
{
TF2_RemoveWearable(client, wearable);
}
}
}
while ((wearable = FindEntityByClassname(wearable, "vgui_screen")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Data, "m_hOwnerEntity");
if (client == player)
{
AcceptEntityInput(wearable, "Kill");
}
}
}
while ((wearable = FindEntityByClassname(wearable, "tf_powerup_bottle")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Send, "m_hOwnerEntity");
if (client == player)
{
TF2_RemoveWearable(client, wearable);
}
}
}
while ((wearable = FindEntityByClassname(wearable, "tf_weapon_spellbook")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Send, "m_hOwnerEntity");
if (client == player)
{
TF2_RemoveWearable(client, wearable);
}
}
}
}
stock void SetNextAttack(int weapon, float duration = 0.0)
{
if (!IsValidEntity(weapon)) return;
float next = GetGameTime() + duration;
SetEntPropFloat(weapon, Prop_Send, "m_flNextPrimaryAttack", next);
SetEntPropFloat(weapon, Prop_Send, "m_flNextSecondaryAttack", next);
}
stock void CreateParticle(char[] particle, float pos[3])
{
int tblidx = FindStringTable("ParticleEffectNames");
char tmp[256];
int count = GetStringTableNumStrings(tblidx);
int stridx = INVALID_STRING_INDEX;
for(int i = 0; i < count; i++)
{
ReadStringTable(tblidx, i, tmp, sizeof(tmp));
if(StrEqual(tmp, particle, false))
{
stridx = i;
break;
}
}
for(int i = 1; i <= GetMaxClients(); i++)
{
if(!IsValidEntity(i)) continue;
if(!IsClientInGame(i)) continue;
TE_Start("TFParticleEffect");
TE_WriteFloat("m_vecOrigin[0]", pos[0]);
TE_WriteFloat("m_vecOrigin[1]", pos[1]);
TE_WriteFloat("m_vecOrigin[2]", pos[2]);
TE_WriteNum("m_iParticleSystemIndex", stridx);
TE_WriteNum("entindex", -1);
TE_WriteNum("m_iAttachType", 5); //Dont associate with any entity
TE_SendToClient(i, 0.0);
}
}
public int Native_SetSkeleton(Handle plugin, int args)
{
MakeSkeleton(GetNativeCell(1));
}
public int Native_IsSkeleton(Handle plugin, int args)
{
return g_bSkeleton[GetNativeCell(1)];
}

View File

@@ -0,0 +1,163 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Map Management Plugin
* Provides all map related functionality, including map changing, map voting,
* and nextmap.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#include <clientprefs>
#pragma newdecls required
public Plugin myinfo =
{
name = "Client Preferences",
author = "AlliedModders LLC",
description = "Client peferences and settings menu",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
public void OnPluginStart()
{
LoadTranslations("clientprefs.phrases");
RegConsoleCmd("sm_cookies", Command_Cookie, "sm_cookies <name> [value]");
RegConsoleCmd("sm_settings", Command_Settings);
}
public Action Command_Cookie(int client, int args)
{
if (args == 0)
{
ReplyToCommand(client, "[SM] Usage: sm_cookies <name> [value]");
ReplyToCommand(client, "[SM] %t", "Printing Cookie List");
/* Show list of cookies */
Handle iter = GetCookieIterator();
char name[30];
name[0] = '\0';
char description[255];
description[0] = '\0';
PrintToConsole(client, "%t:", "Cookie List");
CookieAccess access;
while (ReadCookieIterator(iter,
name,
sizeof(name),
access,
description,
sizeof(description)) != false)
{
if (access < CookieAccess_Private)
{
PrintToConsole(client, "%s - %s", name, description);
}
}
delete iter;
return Plugin_Handled;
}
if (client == 0)
{
PrintToServer("%T", "No Console", LANG_SERVER);
return Plugin_Handled;
}
char name[30];
name[0] = '\0';
GetCmdArg(1, name, sizeof(name));
Handle cookie = FindClientCookie(name);
if (cookie == null)
{
ReplyToCommand(client, "[SM] %t", "Cookie not Found", name);
return Plugin_Handled;
}
CookieAccess access = GetCookieAccess(cookie);
if (access == CookieAccess_Private)
{
ReplyToCommand(client, "[SM] %t", "Cookie not Found", name);
delete cookie;
return Plugin_Handled;
}
char value[100];
value[0] = '\0';
if (args == 1)
{
GetClientCookie(client, cookie, value, sizeof(value));
ReplyToCommand(client, "[SM] %t", "Cookie Value", name, value);
delete cookie;
return Plugin_Handled;
}
if (access == CookieAccess_Protected)
{
ReplyToCommand(client, "[SM] %t", "Protected Cookie", name);
delete cookie;
return Plugin_Handled;
}
/* Set the new value of the cookie */
GetCmdArg(2, value, sizeof(value));
SetClientCookie(client, cookie, value);
delete cookie;
ReplyToCommand(client, "[SM] %t", "Cookie Changed Value", name, value);
return Plugin_Handled;
}
public Action Command_Settings(int client, int args)
{
if (client == 0)
{
PrintToServer("%T", "No Console", LANG_SERVER);
return Plugin_Handled;
}
ShowCookieMenu(client);
return Plugin_Handled;
}

View File

@@ -0,0 +1,133 @@
#pragma semicolon 1
#include <sourcemod>
#define CHOICE1 "#choice1"
#define CHOICE2 "#choice2"
#define CHOICE3 "#choice3"
/**
* Public plugin information.
*/
public Plugin myinfo =
{
name = "Nova.tf Server Functions",
author = "Sir TonyBear",
description = "Allows public to use mandatory server commands",
version = "1.0.2",
url = "http://nova.tf/"
};
public void OnPluginStart()
{
LoadTranslations("serverinfo.phrases");
RegConsoleCmd("sm_forums", Command_ViewForums, "Load the forums page");
RegConsoleCmd("sm_donate", Command_DonateMenu, "Open Donate Dialog");
RegConsoleCmd("sm_group", Command_ViewGroup, "View our Steam Group");
RegConsoleCmd("sm_info", Command_ServerInfo, "View servers information");
}
public int MenuHandler1(Menu menu, MenuAction action, int client, int param2)
{
switch(action)
{
case MenuAction_Start:
{
}
case MenuAction_Display:
{
char buffer[255];
Format(buffer, sizeof(buffer), "%T", "Server Info", client);
Panel panel = view_as<Panel>(param2);
panel.SetTitle(buffer);
PrintToServer("Client %d was sent menu with panel %x", param2);
}
case MenuAction_Select:
{
char info[32];
menu.GetItem(param2, info, sizeof(info));
if (StrEqual(info, CHOICE1))
{
FakeClientCommand(client, "sm_forums");
}
if (StrEqual(info, CHOICE2))
{
FakeClientCommand(client, "sm_donate");
}
if (StrEqual(info, CHOICE3))
{
FakeClientCommand(client, "sm_group");
}
else
{
PrintToServer("Something went wrong.", param2);
}
}
case MenuAction_Cancel:
{
PrintToServer("Client %d's menu was cancelled for reason %d", param2);
}
case MenuAction_End:
{
delete menu;
}
case MenuAction_DrawItem:
{
int style;
char info[32];
menu.GetItem(param2, info, sizeof(info), style);
if (StrEqual(info, CHOICE1))
{
return style;
}
else
{
return style;
}
}
case MenuAction_DisplayItem:
{
int style;
char info[32];
menu.GetItem(param2, info, sizeof(info), style);
}
}
return 0;
}
public Action Command_ServerInfo(int client, int args)
{
Menu menu = new Menu(MenuHandler1, MENU_ACTIONS_ALL);
menu.SetTitle("%T", "Menu Title", LANG_SERVER);
menu.AddItem(CHOICE1, "View Forums");
menu.AddItem(CHOICE2, "Donate Items");
menu.AddItem(CHOICE3, "View Steam Group");
menu.ExitButton = true;
menu.Display(client, 20);
return Plugin_Handled;
}
public Action Command_ViewForums(int client, int args)
{
ShowMOTDPanel(client, "Nova.tf - Forums", "http://nova.tf/", MOTDPANEL_TYPE_URL);
return Plugin_Handled;
}
public Action Command_DonateMenu(int client, int args)
{
ShowMOTDPanel(client, "Nova.tf - Donate", "http://nova.tf/app.php/donation", MOTDPANEL_TYPE_URL);
return Plugin_Handled;
}
public Action Command_ViewGroup(int client, int args)
{
ShowMOTDPanel(client, "Nova.tf - Steam Group", "https://steamcommunity.com/groups/Nova_TF", MOTDPANEL_TYPE_URL);
}

View File

@@ -0,0 +1,28 @@
//Simple script setup
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <regex>
#define TSF_VERSION "1.0.0"
//Give plugin info
public Plugin:myinfo =
{
name = "Trade Server Features",
author = "Tonybear5",
description = "Shows client !features motd panel",
version = "TSF_VERSION",
url = "http://veterangiveaways.co.uk"
};
//Hook into server
public OnAllPluginsLoaded()
{
RegConsoleCmd("sm_features", Command_Features);
}
//Show the client the features
public Action:Command_Features(client, args)
{
ShowMOTDPanel(client, "Trade Server Features", "http://veterangiveaways.co.uk/showthread.php?tid=8&pid=10#pid10", MOTDPANEL_TYPE_URL);
}

View File

@@ -0,0 +1,299 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Basic Fun Commands Plugin
* Implements basic punishment commands.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma newdecls required
public Plugin myinfo =
{
name = "Fun Commands",
author = "AlliedModders LLC",
description = "Fun Commands",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
// Admin Menu
TopMenu hTopMenu;
// Sounds
char g_BlipSound[PLATFORM_MAX_PATH];
char g_BeepSound[PLATFORM_MAX_PATH];
char g_FinalSound[PLATFORM_MAX_PATH];
char g_BoomSound[PLATFORM_MAX_PATH];
char g_FreezeSound[PLATFORM_MAX_PATH];
// Following are model indexes for temp entities
int g_BeamSprite = -1;
int g_BeamSprite2 = -1;
int g_HaloSprite = -1;
int g_GlowSprite = -1;
int g_ExplosionSprite = -1;
// Basic color arrays for temp entities
int redColor[4] = {255, 75, 75, 255};
int orangeColor[4] = {255, 128, 0, 255};
int greenColor[4] = {75, 255, 75, 255};
int blueColor[4] = {75, 75, 255, 255};
int whiteColor[4] = {255, 255, 255, 255};
int greyColor[4] = {128, 128, 128, 255};
// UserMessageId for Fade.
UserMsg g_FadeUserMsgId;
// Serial Generator for Timer Safety
int g_Serial_Gen = 0;
EngineVersion g_GameEngine = Engine_Unknown;
// Flags used in various timers
#define DEFAULT_TIMER_FLAGS TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE
// Include various commands and supporting functions
#include "funcommands/beacon.sp"
#include "funcommands/timebomb.sp"
#include "funcommands/fire.sp"
#include "funcommands/ice.sp"
#include "funcommands/gravity.sp"
#include "funcommands/blind.sp"
#include "funcommands/noclip.sp"
#include "funcommands/drug.sp"
public void OnPluginStart()
{
if (FindPluginByFile("basefuncommands.smx") != null)
{
ThrowError("This plugin replaces basefuncommands. You cannot run both at once.");
}
LoadTranslations("common.phrases");
LoadTranslations("funcommands.phrases");
g_GameEngine = GetEngineVersion();
g_FadeUserMsgId = GetUserMessageId("Fade");
RegisterCvars();
RegisterCmds();
HookEvents();
/* Account for late loading */
TopMenu topmenu;
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != null))
{
OnAdminMenuReady(topmenu);
}
}
void RegisterCvars()
{
// beacon
g_Cvar_BeaconRadius = CreateConVar("sm_beacon_radius", "375", "Sets the radius for beacon's light rings.", 0, true, 50.0, true, 1500.0);
// timebomb
g_Cvar_TimeBombTicks = CreateConVar("sm_timebomb_ticks", "10.0", "Sets how long the timebomb fuse is.", 0, true, 5.0, true, 120.0);
g_Cvar_TimeBombRadius = CreateConVar("sm_timebomb_radius", "600", "Sets the bomb blast radius.", 0, true, 50.0, true, 3000.0);
g_Cvar_TimeBombMode = CreateConVar("sm_timebomb_mode", "0", "Who is killed by the timebomb? 0 = Target only, 1 = Target's team, 2 = Everyone", 0, true, 0.0, true, 2.0);
// fire
g_Cvar_BurnDuration = CreateConVar("sm_burn_duration", "20.0", "Sets the default duration of sm_burn and firebomb victims.", 0, true, 0.5, true, 20.0);
g_Cvar_FireBombTicks = CreateConVar("sm_firebomb_ticks", "10.0", "Sets how long the FireBomb fuse is.", 0, true, 5.0, true, 120.0);
g_Cvar_FireBombRadius = CreateConVar("sm_firebomb_radius", "600", "Sets the bomb blast radius.", 0, true, 50.0, true, 3000.0);
g_Cvar_FireBombMode = CreateConVar("sm_firebomb_mode", "0", "Who is targetted by the FireBomb? 0 = Target only, 1 = Target's team, 2 = Everyone", 0, true, 0.0, true, 2.0);
// ice
g_Cvar_FreezeDuration = CreateConVar("sm_freeze_duration", "10.0", "Sets the default duration for sm_freeze and freezebomb victims", 0, true, 1.0, true, 120.0);
g_Cvar_FreezeBombTicks = CreateConVar("sm_freezebomb_ticks", "10.0", "Sets how long the freezebomb fuse is.", 0, true, 5.0, true, 120.0);
g_Cvar_FreezeBombRadius = CreateConVar("sm_freezebomb_radius", "600", "Sets the freezebomb blast radius.", 0, true, 50.0, true, 3000.0);
g_Cvar_FreezeBombMode = CreateConVar("sm_freezebomb_mode", "0", "Who is targetted by the freezebomb? 0 = Target only, 1 = Target's team, 2 = Everyone", 0, true, 0.0, true, 2.0);
AutoExecConfig(true, "funcommands");
}
void RegisterCmds()
{
RegAdminCmd("sm_beacon", Command_Beacon, ADMFLAG_SLAY, "sm_beacon <#userid|name> [0/1]");
RegAdminCmd("sm_timebomb", Command_TimeBomb, ADMFLAG_SLAY, "sm_timebomb <#userid|name> [0/1]");
RegAdminCmd("sm_burn", Command_Burn, ADMFLAG_SLAY, "sm_burn <#userid|name> [time]");
RegAdminCmd("sm_firebomb", Command_FireBomb, ADMFLAG_SLAY, "sm_firebomb <#userid|name> [0/1]");
RegAdminCmd("sm_freeze", Command_Freeze, ADMFLAG_SLAY, "sm_freeze <#userid|name> [time]");
RegAdminCmd("sm_freezebomb", Command_FreezeBomb, ADMFLAG_SLAY, "sm_freezebomb <#userid|name> [0/1]");
RegAdminCmd("sm_gravity", Command_Gravity, ADMFLAG_SLAY, "sm_gravity <#userid|name> [amount] - Leave amount off to reset. Amount is 0.0 through 5.0");
RegAdminCmd("sm_blind", Command_Blind, ADMFLAG_SLAY, "sm_blind <#userid|name> [amount] - Leave amount off to reset.");
RegAdminCmd("sm_noclip", Command_NoClip, ADMFLAG_SLAY|ADMFLAG_CHEATS, "sm_noclip <#userid|name>");
RegAdminCmd("sm_drug", Command_Drug, ADMFLAG_SLAY, "sm_drug <#userid|name> [0/1]");
}
void HookEvents()
{
char folder[64];
GetGameFolderName(folder, sizeof(folder));
if (strcmp(folder, "tf") == 0)
{
HookEvent("teamplay_win_panel", Event_RoundEnd, EventHookMode_PostNoCopy);
HookEvent("teamplay_restart_round", Event_RoundEnd, EventHookMode_PostNoCopy);
HookEvent("arena_win_panel", Event_RoundEnd, EventHookMode_PostNoCopy);
}
else if (strcmp(folder, "nucleardawn") == 0)
{
HookEvent("round_win", Event_RoundEnd, EventHookMode_PostNoCopy);
}
else
{
HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy);
}
}
public void OnMapStart()
{
Handle gameConfig = LoadGameConfigFile("funcommands.games");
if (gameConfig == null)
{
SetFailState("Unable to load game config funcommands.games");
return;
}
if (GameConfGetKeyValue(gameConfig, "SoundBlip", g_BlipSound, sizeof(g_BlipSound)) && g_BlipSound[0])
{
PrecacheSound(g_BlipSound, true);
}
if (GameConfGetKeyValue(gameConfig, "SoundBeep", g_BeepSound, sizeof(g_BeepSound)) && g_BeepSound[0])
{
PrecacheSound(g_BeepSound, true);
}
if (GameConfGetKeyValue(gameConfig, "SoundFinal", g_FinalSound, sizeof(g_FinalSound)) && g_FinalSound[0])
{
PrecacheSound(g_FinalSound, true);
}
if (GameConfGetKeyValue(gameConfig, "SoundBoom", g_BoomSound, sizeof(g_BoomSound)) && g_BoomSound[0])
{
PrecacheSound(g_BoomSound, true);
}
if (GameConfGetKeyValue(gameConfig, "SoundFreeze", g_FreezeSound, sizeof(g_FreezeSound)) && g_FreezeSound[0])
{
PrecacheSound(g_FreezeSound, true);
}
char buffer[PLATFORM_MAX_PATH];
if (GameConfGetKeyValue(gameConfig, "SpriteBeam", buffer, sizeof(buffer)) && buffer[0])
{
g_BeamSprite = PrecacheModel(buffer);
}
if (GameConfGetKeyValue(gameConfig, "SpriteBeam2", buffer, sizeof(buffer)) && buffer[0])
{
g_BeamSprite2 = PrecacheModel(buffer);
}
if (GameConfGetKeyValue(gameConfig, "SpriteExplosion", buffer, sizeof(buffer)) && buffer[0])
{
g_ExplosionSprite = PrecacheModel(buffer);
}
if (GameConfGetKeyValue(gameConfig, "SpriteGlow", buffer, sizeof(buffer)) && buffer[0])
{
g_GlowSprite = PrecacheModel(buffer);
}
if (GameConfGetKeyValue(gameConfig, "SpriteHalo", buffer, sizeof(buffer)) && buffer[0])
{
g_HaloSprite = PrecacheModel(buffer);
}
delete gameConfig;
}
public void OnMapEnd()
{
KillAllBeacons();
KillAllTimeBombs();
KillAllFireBombs();
KillAllFreezes();
KillAllDrugs();
}
public Action Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
{
KillAllBeacons();
KillAllTimeBombs();
KillAllFireBombs();
KillAllFreezes();
KillAllDrugs();
}
public void OnAdminMenuReady(Handle aTopMenu)
{
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
/* Block us from being called twice */
if (topmenu == hTopMenu)
{
return;
}
/* Save the Handle */
hTopMenu = topmenu;
/* Find the "Player Commands" category */
TopMenuObject player_commands = hTopMenu.FindCategory(ADMINMENU_PLAYERCOMMANDS);
if (player_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_beacon", AdminMenu_Beacon, player_commands, "sm_beacon", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_timebomb", AdminMenu_TimeBomb, player_commands, "sm_timebomb", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_burn", AdminMenu_Burn, player_commands, "sm_burn", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_firebomb", AdminMenu_FireBomb, player_commands, "sm_firebomb", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_freeze", AdminMenu_Freeze, player_commands, "sm_freeze", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_freezebomb", AdminMenu_FreezeBomb, player_commands, "sm_freezebomb", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_gravity", AdminMenu_Gravity, player_commands, "sm_gravity", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_blind", AdminMenu_Blind, player_commands, "sm_blind", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_noclip", AdminMenu_NoClip, player_commands, "sm_noclip", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_drug", AdminMenu_Drug, player_commands, "sm_drug", ADMFLAG_SLAY);
}
}
void AddTranslatedMenuItem(Menu menu, const char[] opt, const char[] phrase, int client)
{
char buffer[128];
Format(buffer, sizeof(buffer), "%T", phrase, client);
menu.AddItem(opt, buffer);
}

326
scripting/temp/funvotes.sp Normal file
View File

@@ -0,0 +1,326 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Fun Votes Plugin
* Implements extra fun vote commands.
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma newdecls required
public Plugin myinfo =
{
name = "Fun Votes",
author = "AlliedModders LLC",
description = "Fun Vote Commands",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
#define VOTE_NO "###no###"
#define VOTE_YES "###yes###"
Menu g_hVoteMenu = null;
ConVar g_Cvar_Limits[5] = {null, ...};
ConVar g_Cvar_Gravity;
ConVar g_Cvar_Alltalk;
ConVar g_Cvar_FF;
// ConVar g_Cvar_Show = null;
enum voteType
{
gravity = 0,
burn,
slay,
alltalk,
ff
};
voteType g_voteType = gravity;
// Menu API does not provide us with a way to pass multiple peices of data with a single
// choice, so some globals are used to hold stuff.
//
#define VOTE_CLIENTID 0
#define VOTE_USERID 1
int g_voteClient[2]; /* Holds the target's client id and user id */
#define VOTE_NAME 0
#define VOTE_AUTHID 1
#define VOTE_IP 2
char g_voteInfo[3][65]; /* Holds the target's name, authid, and IP */
TopMenu hTopMenu;
#include "funvotes/votegravity.sp"
#include "funvotes/voteburn.sp"
#include "funvotes/voteslay.sp"
#include "funvotes/votealltalk.sp"
#include "funvotes/voteff.sp"
public void OnPluginStart()
{
if (FindPluginByFile("basefunvotes.smx") != null)
{
ThrowError("This plugin replaces basefuncommands. You cannot run both at once.");
}
LoadTranslations("common.phrases");
LoadTranslations("basevotes.phrases");
LoadTranslations("funvotes.phrases");
LoadTranslations("funcommands.phrases");
RegAdminCmd("sm_votegravity", Command_VoteGravity, ADMFLAG_VOTE, "sm_votegravity <amount> [amount2] ... [amount5]");
RegAdminCmd("sm_voteburn", Command_VoteBurn, ADMFLAG_VOTE|ADMFLAG_SLAY, "sm_voteburn <player>");
RegAdminCmd("sm_voteslay", Command_VoteSlay, ADMFLAG_VOTE|ADMFLAG_SLAY, "sm_voteslay <player>");
RegAdminCmd("sm_votealltalk", Command_VoteAlltalk, ADMFLAG_VOTE, "sm_votealltalk");
RegAdminCmd("sm_voteff", Command_VoteFF, ADMFLAG_VOTE, "sm_voteff");
g_Cvar_Limits[0] = CreateConVar("sm_vote_gravity", "0.60", "percent required for successful gravity vote.", 0, true, 0.05, true, 1.0);
g_Cvar_Limits[1] = CreateConVar("sm_vote_burn", "0.60", "percent required for successful burn vote.", 0, true, 0.05, true, 1.0);
g_Cvar_Limits[2] = CreateConVar("sm_vote_slay", "0.60", "percent required for successful slay vote.", 0, true, 0.05, true, 1.0);
g_Cvar_Limits[3] = CreateConVar("sm_vote_alltalk", "0.60", "percent required for successful alltalk vote.", 0, true, 0.05, true, 1.0);
g_Cvar_Limits[4] = CreateConVar("sm_vote_ff", "0.60", "percent required for successful friendly fire vote.", 0, true, 0.05, true, 1.0);
g_Cvar_Gravity = FindConVar("sv_gravity");
g_Cvar_Alltalk = FindConVar("sv_alltalk");
g_Cvar_FF = FindConVar("mp_friendlyfire");
/*
g_Cvar_Show = FindConVar("sm_vote_show");
if (g_Cvar_Show == null)
{
g_Cvar_Show = CreateConVar("sm_vote_show", "1", "Show player's votes? Default on.", 0, true, 0.0, true, 1.0);
}
*/
/* Account for late loading */
TopMenu topmenu;
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != null))
{
OnAdminMenuReady(topmenu);
}
}
public void OnAdminMenuReady(Handle aTopMenu)
{
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
/* Block us from being called twice */
if (topmenu == hTopMenu)
{
return;
}
/* Save the Handle */
hTopMenu = topmenu;
/* Build the "Voting Commands" category */
TopMenuObject voting_commands = hTopMenu.FindCategory(ADMINMENU_VOTINGCOMMANDS);
if (voting_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_votegravity", AdminMenu_VoteGravity, voting_commands, "sm_votegravity", ADMFLAG_VOTE);
hTopMenu.AddItem("sm_voteburn", AdminMenu_VoteBurn, voting_commands, "sm_voteburn", ADMFLAG_VOTE|ADMFLAG_SLAY);
hTopMenu.AddItem("sm_voteslay", AdminMenu_VoteSlay, voting_commands, "sm_voteslay", ADMFLAG_VOTE|ADMFLAG_SLAY);
hTopMenu.AddItem("sm_votealltalk", AdminMenu_VoteAllTalk, voting_commands, "sm_votealltalk", ADMFLAG_VOTE);
hTopMenu.AddItem("sm_voteff", AdminMenu_VoteFF, voting_commands, "sm_voteff", ADMFLAG_VOTE);
}
}
public int Handler_VoteCallback(Menu menu, MenuAction action, int param1, int param2)
{
if (action == MenuAction_End)
{
VoteMenuClose();
}
else if (action == MenuAction_Display)
{
char title[64];
menu.GetTitle(title, sizeof(title));
char buffer[255];
Format(buffer, sizeof(buffer), "%T", title, param1, g_voteInfo[VOTE_NAME]);
Panel panel = view_as<Panel>(param2);
panel.SetTitle(buffer);
}
else if (action == MenuAction_DisplayItem)
{
char display[64];
menu.GetItem(param2, "", 0, _, display, sizeof(display));
if (strcmp(display, VOTE_NO) == 0 || strcmp(display, VOTE_YES) == 0)
{
char buffer[255];
Format(buffer, sizeof(buffer), "%T", display, param1);
return RedrawMenuItem(buffer);
}
}
/* else if (action == MenuAction_Select)
{
VoteSelect(menu, param1, param2);
}*/
else if (action == MenuAction_VoteCancel && param1 == VoteCancel_NoVotes)
{
PrintToChatAll("[SM] %t", "No Votes Cast");
}
else if (action == MenuAction_VoteEnd)
{
char item[64];
float percent, limit;
int votes, totalVotes;
GetMenuVoteInfo(param2, votes, totalVotes);
menu.GetItem(param1, item, sizeof(item));
if (strcmp(item, VOTE_NO) == 0 && param1 == 1)
{
votes = totalVotes - votes; // Reverse the votes to be in relation to the Yes option.
}
percent = GetVotePercent(votes, totalVotes);
limit = g_Cvar_Limits[g_voteType].FloatValue;
/* :TODO: g_voteClient[userid] needs to be checked.
*/
// A multi-argument vote is "always successful", but have to check if its a Yes/No vote.
if ((strcmp(item, VOTE_YES) == 0 && FloatCompare(percent,limit) < 0 && param1 == 0) || (strcmp(item, VOTE_NO) == 0 && param1 == 1))
{
/* :TODO: g_voteClient[userid] should be used here and set to -1 if not applicable.
*/
LogAction(-1, -1, "Vote failed.");
PrintToChatAll("[SM] %t", "Vote Failed", RoundToNearest(100.0*limit), RoundToNearest(100.0*percent), totalVotes);
}
else
{
PrintToChatAll("[SM] %t", "Vote Successful", RoundToNearest(100.0*percent), totalVotes);
switch (g_voteType)
{
case (gravity):
{
PrintToChatAll("[SM] %t", "Cvar changed", "sv_gravity", item);
LogAction(-1, -1, "Changing gravity to %s due to vote.", item);
g_Cvar_Gravity.IntValue = StringToInt(item);
}
case (burn):
{
PrintToChatAll("[SM] %t", "Set target on fire", "_s", g_voteInfo[VOTE_NAME]);
LogAction(-1, g_voteClient[VOTE_CLIENTID], "Vote burn successful, igniting \"%L\"", g_voteClient[VOTE_CLIENTID]);
IgniteEntity(g_voteClient[VOTE_CLIENTID], 19.8);
}
case (slay):
{
PrintToChatAll("[SM] %t", "Slayed player", g_voteInfo[VOTE_NAME]);
LogAction(-1, g_voteClient[VOTE_CLIENTID], "Vote slay successful, slaying \"%L\"", g_voteClient[VOTE_CLIENTID]);
ExtinguishEntity(g_voteClient[VOTE_CLIENTID]);
ForcePlayerSuicide(g_voteClient[VOTE_CLIENTID]);
}
case (alltalk):
{
PrintToChatAll("[SM] %t", "Cvar changed", "sv_alltalk", (g_Cvar_Alltalk.BoolValue ? "0" : "1"));
LogAction(-1, -1, "Changing alltalk to %s due to vote.", (g_Cvar_Alltalk.BoolValue ? "0" : "1"));
g_Cvar_Alltalk.BoolValue = !g_Cvar_Alltalk.BoolValue;
}
case (ff):
{
PrintToChatAll("[SM] %t", "Cvar changed", "mp_friendlyfire", (g_Cvar_FF.BoolValue ? "0" : "1"));
LogAction(-1, -1, "Changing friendly fire to %s due to vote.", (g_Cvar_FF.BoolValue ? "0" : "1"));
g_Cvar_FF.BoolValue = !g_Cvar_FF.BoolValue;
}
}
}
}
return 0;
}
/*
void VoteSelect(Menu menu, int param1, int param2 = 0)
{
if (g_Cvar_VoteShow.IntValue == 1)
{
char voter[MAX_NAME_LENGTH], junk[64], choice[64];
GetClientName(param1, voter, sizeof(voter));
menu.GetItem(param2, junk, sizeof(junk), _, choice, sizeof(choice));
PrintToChatAll("[SM] %T", "Vote Select", LANG_SERVER, voter, choice);
}
}
*/
void VoteMenuClose()
{
delete g_hVoteMenu;
g_hVoteMenu = null;
}
float GetVotePercent(int votes, int totalVotes)
{
return FloatDiv(float(votes),float(totalVotes));
}
bool TestVoteDelay(int client)
{
int delay = CheckVoteDelay();
if (delay > 0)
{
if (delay > 60)
{
ReplyToCommand(client, "[SM] %t", "Vote Delay Minutes", delay % 60);
}
else
{
ReplyToCommand(client, "[SM] %t", "Vote Delay Seconds", delay);
}
return false;
}
return true;
}

398
scripting/temp/fusrodah.sp Normal file
View File

@@ -0,0 +1,398 @@
// base grab code taken from http://forums.alliedmods.net/showthread.php?t=157075 and https://forums.alliedmods.net/showthread.php?p=1946774
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <morecolors>
#define DRAGONBORN "shout/dragonborn.wav" // grab
#define FUSRODAH "shout/fusrodah.wav" // throw
#define THROW_FORCE 10000.0
#define GRAB_DISTANCE 250.0
#define PLUGIN_NAME "Dovah Shout!"
#define PLUGIN_AUTHOR "DovahkiinYT / TheXeon"
#define PLUGIN_VERSION "2.0.2"
#define PLUGIN_DESCRIP "Allows Dovah to Grab Stuff"
#define PLUGIN_CONTACT "http://steamcommunity.com/groups/FireHostv2"
public Plugin myinfo = {
name = PLUGIN_NAME,
author = PLUGIN_AUTHOR,
description = PLUGIN_DESCRIP,
version = PLUGIN_VERSION,
url = PLUGIN_CONTACT
}
int g_grabbed[MAXPLAYERS+10]; // track client's grabbed object
float gDistance[MAXPLAYERS+10]; // track distance of grabbed object
//////////////////////////////////////////////////////////////////////
///////////// Setup /////////////
//////////////////////////////////////////////////////////////////////
public void OnPluginStart()
{
CreateConVar("tf_dovahgrab_version", PLUGIN_VERSION, PLUGIN_NAME, FCVAR_REPLICATED|FCVAR_NOTIFY|FCVAR_SPONLY);
PrecacheSound(FUSRODAH, true);
PrecacheSound(DRAGONBORN, true);
AddFileToDownloadsTable("sound/shout/fusrodah.wav");
AddFileToDownloadsTable("sound/shout/dragonborn.wav");
RegConsoleCmd("sm_SetTarget", Command_Dragonborn, "Attempt to be the Dragonborn");
RegConsoleCmd("sm_FusRoDah", Command_FusRoDah, "The Dragonborn's Words");
RegConsoleCmd("sm_Disarm", Command_Disarm, "Disarm the pursuing");
HookEvent("player_death", OnPlayerSpawn);
HookEvent("player_spawn", OnPlayerSpawn);
HookEvent("player_team", OnPlayerSpawn);
//Some code was here, but it was marked as unnecessary and removed.
}
stock bool:IsTargetInSightRange(client, target, Float:angle=90.0, Float:distance=0.0, bool:heightcheck=true, bool:negativeangle=false)
{
if(angle > 360.0 || angle < 0.0)
ThrowError("Angle Max : 360 & Min : 0. %d isn't proper angle.", angle);
if(!IsValidClient(client))
ThrowError("Client is not Alive.");
if(!IsValidClient(target))
ThrowError("Target is not Alive.");
decl Float:clientpos[3], Float:targetpos[3], Float:anglevector[3], Float:targetvector[3], Float:resultangle, Float:resultdistance;
GetClientEyeAngles(client, anglevector);
anglevector[0] = anglevector[2] = 0.0;
GetAngleVectors(anglevector, anglevector, NULL_VECTOR, NULL_VECTOR);
NormalizeVector(anglevector, anglevector);
if(negativeangle)
NegateVector(anglevector);
GetClientAbsOrigin(client, clientpos);
GetClientAbsOrigin(target, targetpos);
if(heightcheck && distance > 0)
resultdistance = GetVectorDistance(clientpos, targetpos);
clientpos[2] = targetpos[2] = 0.0;
MakeVectorFromPoints(clientpos, targetpos, targetvector);
NormalizeVector(targetvector, targetvector);
resultangle = RadToDeg(ArcCosine(GetVectorDotProduct(targetvector, anglevector)));
if(resultangle <= angle/2)
{
if(distance > 0)
{
if(!heightcheck)
resultdistance = GetVectorDistance(clientpos, targetpos);
if(distance >= resultdistance)
return true;
else
return false;
}
else
return true;
}
else
return false;
}
public void OnMapStart()
{
for (int client = 1; client <= MaxClients; client++)
{
g_grabbed[client] = INVALID_ENT_REFERENCE;
PrecacheSound(FUSRODAH, true);
PrecacheSound(DRAGONBORN, true);
AddFileToDownloadsTable("sound/shout/fusrodah.wav");
AddFileToDownloadsTable("sound/shout/dragonborn.wav");
}
}
public void OnClientPutInServer(int client)
{
g_grabbed[client] = INVALID_ENT_REFERENCE;
}
//////////////////////////////////////////////////////////////////////
///////////// Commands /////////////
//////////////////////////////////////////////////////////////////////
public Action Command_Dragonborn(int client, int target)
{
char player_authid[32];
GetClientAuthId(client, AuthId_Steam2, player_authid, sizeof(player_authid));
if IsTargetInSightRange(client, target) *then
{
SDKHook(target, SDKHook_PreThink, OnPreThink);
GrabObject(target);
int grabbed = EntRefToEntIndex(g_grabbed[client]);
if(grabbed != INVALID_ENT_REFERENCE)
{
CPrintToChat(client, "{orange}Arngeir: {green}You now have an entity in your sights! Now, type !FusRoDah to use the power of the Voice.");
EmitSoundToClient(client, DRAGONBORN);
EmitSoundToClient(client, DRAGONBORN);
return Plugin_Handled;
}
else
{
CPrintToChat(client, "{orange}Arngeir: {red}My dear Dragonborn, you have done something wrong! Were you not aimed at a valid target?");
return Plugin_Handled;
}
}
else
{
CPrintToChat(client, "{orange}Arngeir: {red}You don't understand the power of the Voice.");
return Plugin_Handled;
}
}
public Action Command_FusRoDah(int client, int args)
{
if (!IsValidClient(client))
{
return Plugin_Handled;
}
char player_authid[32];
GetClientAuthId(client, AuthId_Steam2, player_authid, sizeof(player_authid));
if (!StrEqual(player_authid, "STEAM_0:1:69132908", false))
{
CPrintToChat(client, "{orange}Arngeir: {red}Only the true Dragonborn can speak these words!");
return Plugin_Handled;
}
if(IsValidClient(client))
{
int grabbed = EntRefToEntIndex(g_grabbed[client]);
if(grabbed != INVALID_ENT_REFERENCE)
{
ThrowObject(client, grabbed, true);
EmitSoundToAll(FUSRODAH);
CPrintToChatAll("{fullred}Dovahkiin: {aqua}FUS RO DAH!!!!");
}
else
{
CPrintToChat(client, "{orange}Arngeir: {red}I'm sorry Dragonborn, but you must first prepare this shout. Aim at something, and then try !SetTarget.");
return Plugin_Handled;
}
}
return Plugin_Handled;
}
public Action Command_Disarm(int client, int args)
{
if (!IsValidClient(client))
{
return Plugin_Handled;
}
char player_authid[32];
GetClientAuthId(client, AuthId_Steam2, player_authid, sizeof(player_authid));
if (!StrEqual(player_authid, "STEAM_0:1:69132908", false))
{
CPrintToChat(client, "{orange}Arngeir: {red}I'm sorry, but only the true Dragonborn may release an entity.");
return Plugin_Handled;
}
if(IsValidClient(client))
{
int grabbed = EntRefToEntIndex(g_grabbed[client]);
if(grabbed != INVALID_ENT_REFERENCE)
{
ThrowObject(client, grabbed, false);
CPrintToChat(client, "{orange}Arngeir: {green}You have stopped pursuing your target! Use !SetTarget to choose a new target.");
return Plugin_Handled;
}
}
return Plugin_Handled;
}
void GrabObject(int client)
{
int grabbed = TraceToObject(client); // -1 for no collision, 0 for world
if (grabbed > 0)
{
if(grabbed > MaxClients)
{
char classname[13];
GetEntityClassname(grabbed, classname, 13);
if(StrEqual(classname, "prop_physics"))
{
int grabber = GetEntPropEnt(grabbed, Prop_Data, "m_hPhysicsAttacker");
if(grabber > 0 && grabber <= MaxClients && IsClientInGame(grabber))
{
return; // another client is grabbing this object
}
SetEntPropEnt(grabbed, Prop_Data, "m_hPhysicsAttacker", client);
AcceptEntityInput(grabbed, "EnableMotion");
}
SetEntityMoveType(grabbed, MOVETYPE_VPHYSICS);
}
else
{
SetEntityMoveType(grabbed, MOVETYPE_WALK);
PrintHintText(client,"Compelling %N",grabbed);
PrintHintText(grabbed,"%N is about to FUS RO DAH you!",client);
}
if(GetClientButtons(client) & IN_ATTACK2) // Store and maintain distance
{
float VecPos_grabbed[3], VecPos_client[3];
GetEntPropVector(grabbed, Prop_Send, "m_vecOrigin", VecPos_grabbed);
GetClientEyePosition(client, VecPos_client);
gDistance[client] = GetVectorDistance(VecPos_grabbed, VecPos_client);
}
else
{
gDistance[client] = GRAB_DISTANCE; // Use prefab distance
}
float fVelocity[3] = { 0.0, 0.0, 0.0 };
TeleportEntity(grabbed, NULL_VECTOR, NULL_VECTOR, fVelocity);
g_grabbed[client] = EntIndexToEntRef(grabbed);
}
}
void ThrowObject(int client, int grabbed, bool fusrodah)
{
if(fusrodah)
{
float vecView[3], vecFwd[3], vecPos[3], vecVel[3];
GetClientEyeAngles(client, vecView);
GetAngleVectors(vecView, vecFwd, NULL_VECTOR, NULL_VECTOR);
GetClientEyePosition(client, vecPos);
vecPos[0]+=vecFwd[0]*THROW_FORCE;
vecPos[1]+=vecFwd[1]*THROW_FORCE;
vecPos[2]+=vecFwd[2]*THROW_FORCE;
GetEntPropVector(grabbed, Prop_Send, "m_vecOrigin", vecFwd);
SubtractVectors(vecPos, vecFwd, vecVel);
ScaleVector(vecVel, 10.0);
TeleportEntity(grabbed, NULL_VECTOR, NULL_VECTOR, vecVel);
}
g_grabbed[client] = INVALID_ENT_REFERENCE;
if(grabbed > MaxClients)
{
char classname[13];
GetEntityClassname(grabbed, classname, 13);
if(StrEqual(classname, "prop_physics"))
{
SetEntPropEnt(grabbed, Prop_Data, "m_hPhysicsAttacker", 0);
}
}
}
//////////////////////////////////////////////////////////////////////
///////////// Prethink /////////////
//////////////////////////////////////////////////////////////////////
public void OnPreThink(int client)
{
int grabbed = EntRefToEntIndex(g_grabbed[client]);
if (grabbed != INVALID_ENT_REFERENCE)
{
float vecView[3], vecFwd[3], vecPos[3], vecVel[3];
GetClientEyeAngles(client, vecView);
GetAngleVectors(vecView, vecFwd, NULL_VECTOR, NULL_VECTOR);
GetClientEyePosition(client, vecPos);
vecPos[0]+=vecFwd[0]*gDistance[client];
vecPos[1]+=vecFwd[1]*gDistance[client];
vecPos[2]+=vecFwd[2]*gDistance[client];
GetEntPropVector(grabbed, Prop_Send, "m_vecOrigin", vecFwd);
SubtractVectors(vecPos, vecFwd, vecVel);
ScaleVector(vecVel, 10.0);
TeleportEntity(grabbed, NULL_VECTOR, NULL_VECTOR, vecVel);
}
}
//////////////////////////////////////////////////////////////////////
///////////// Events /////////////
//////////////////////////////////////////////////////////////////////
public void OnPlayerSpawn(Handle event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(GetEventInt(event, "userid"));
if(IsValidClient(client))
{
for(int i = 1; i <= MaxClients; i++)
{
if(EntRefToEntIndex(g_grabbed[i]) == client)
{
g_grabbed[i] = INVALID_ENT_REFERENCE; // Clear grabs on them
}
}
}
return;
}
//////////////////////////////////////////////////////////////////////
///////////// Trace /////////////
//////////////////////////////////////////////////////////////////////
public int TraceToObject(int client)
{
float vecClientEyePos[3], vecClientEyeAng[3];
GetClientEyePosition(client, vecClientEyePos);
GetClientEyeAngles(client, vecClientEyeAng);
TR_TraceRayFilter(vecClientEyePos, vecClientEyeAng, MASK_PLAYERSOLID, RayType_Infinite, TraceRayGrab, client);
return TR_GetEntityIndex(INVALID_HANDLE);
}
public bool TraceRayGrab(int entityhit, int mask, any self)
{
if(entityhit > 0 && entityhit <= MaxClients)
{
if(IsPlayerAlive(entityhit) && entityhit != self)
{
return true;
}
else
{
return false;
}
}
else
{
char classname[13];
if(GetEntityClassname(entityhit, classname, 13) && (StrEqual(classname, "prop_physics") || StrEqual(classname, "tf_ammo_pack") || StrContains(classname, "tf_projectile") || StrContains(classname, "prop_") || StrContains(classname, "func_tracktrain") || StrEqual(classname, "prop_physics_override")))
{
return true;
}
}
return false;
}
public bool IsValidClient (int target)
{
if(target > 4096) target = EntRefToEntIndex(target);
if(target < 1 || target > MaxClients) return false;
if(!IsClientInGame(target)) return false;
if(IsFakeClient(target)) return false;
if(GetEntProp(target, Prop_Send, "m_bIsCoaching")) return false;
return true;
}

615
scripting/temp/goomba.sp Normal file
View File

@@ -0,0 +1,615 @@
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <clientprefs>
#define PL_NAME "Goomba Stomp Core"
#define PL_DESC "Goomba Stomp core plugin"
#define PL_VERSION "2.0.2"
#define STOMP_SOUND "goomba/stomp.wav"
#define REBOUND_SOUND "goomba/rebound.wav"
#define GOOMBA_IMMUNFLAG_NONE 0
#define GOOMBA_IMMUNFLAG_ATTACKER (1 << 0)
#define GOOMBA_IMMUNFLAG_VICTIM (1 << 1)
public Plugin:myinfo =
{
name = PL_NAME,
author = "Flyflo",
description = PL_DESC,
version = PL_VERSION,
url = "http://www.geek-gaming.fr"
}
new Handle:g_hForwardOnStomp;
new Handle:g_hForwardOnStompPost;
new Handle:g_Cvar_JumpPower = INVALID_HANDLE;
new Handle:g_Cvar_PluginEnabled = INVALID_HANDLE;
new Handle:g_Cvar_ParticlesEnabled = INVALID_HANDLE;
new Handle:g_Cvar_SoundsEnabled = INVALID_HANDLE;
new Handle:g_Cvar_ImmunityEnabled = INVALID_HANDLE;
new Handle:g_Cvar_StompMinSpeed = INVALID_HANDLE;
new Handle:g_Cvar_DamageLifeMultiplier = INVALID_HANDLE;
new Handle:g_Cvar_DamageAdd = INVALID_HANDLE;
// Snippet from psychonic (http://forums.alliedmods.net/showpost.php?p=1294224&postcount=2)
new Handle:sv_tags;
new Handle:g_Cookie_ClientPref;
new Goomba_Fakekill[MAXPLAYERS+1];
// Thx to Pawn 3-pg (https://forums.alliedmods.net/showthread.php?p=1140480#post1140480)
new bool:g_TeleportAtFrameEnd[MAXPLAYERS+1] = false;
new Float:g_TeleportAtFrameEnd_Vel[MAXPLAYERS+1][3];
public APLRes:AskPluginLoad2(Handle:hMySelf, bool:bLate, String:strError[], iMaxErrors)
{
RegPluginLibrary("goomba");
CreateNative("GoombaStomp", GoombaStomp);
CreateNative("CheckStompImmunity", CheckStompImmunity);
CreateNative("PlayStompSound", PlayStompSound);
CreateNative("PlayStompReboundSound", PlayStompReboundSound);
CreateNative("EmitStompParticles", EmitStompParticles);
return APLRes_Success;
}
public OnPluginStart()
{
LoadTranslations("goomba.phrases");
g_Cvar_PluginEnabled = CreateConVar("goomba_enabled", "1.0", "Plugin On/Off", 0, true, 0.0, true, 1.0);
g_Cvar_SoundsEnabled = CreateConVar("goomba_sounds", "1", "Enable or disable sounds of the plugin", 0, true, 0.0, true, 1.0);
g_Cvar_ParticlesEnabled = CreateConVar("goomba_particles", "1", "Enable or disable particles of the plugin", 0, true, 0.0, true, 1.0);
g_Cvar_ImmunityEnabled = CreateConVar("goomba_immunity", "1", "Enable or disable the immunity system", 0, true, 0.0, true, 1.0);
g_Cvar_JumpPower = CreateConVar("goomba_rebound_power", "300.0", "Goomba jump power", 0, true, 0.0);
g_Cvar_StompMinSpeed = CreateConVar("goomba_minspeed", "360.0", "Minimum falling speed to kill", 0, true, 0.0, false, 0.0);
// To remove the warning about this variable not being used
GetConVarFloat(g_Cvar_StompMinSpeed);
g_Cvar_DamageLifeMultiplier = CreateConVar("goomba_dmg_lifemultiplier", "1.0", "How much damage the victim will receive based on its actual life", 0, true, 0.0, false, 0.0);
g_Cvar_DamageAdd = CreateConVar("goomba_dmg_add", "50.0", "Add this amount of damage after goomba_dmg_lifemultiplier calculation", 0, true, 0.0, false, 0.0);
AutoExecConfig(true, "goomba");
CreateConVar("goomba_version", PL_VERSION, PL_NAME, FCVAR_PLUGIN | FCVAR_SPONLY | FCVAR_REPLICATED | FCVAR_NOTIFY | FCVAR_DONTRECORD);
g_Cookie_ClientPref = RegClientCookie("goomba_client_pref", "", CookieAccess_Private);
RegConsoleCmd("goomba_toggle", Cmd_GoombaToggle, "Toggle the goomba immunity client's pref.");
RegConsoleCmd("goomba_status", Cmd_GoombaStatus, "Give the current goomba immunity setting.");
RegConsoleCmd("goomba_on", Cmd_GoombaOn, "Enable stomp.");
RegConsoleCmd("goomba_off", Cmd_GoombaOff, "Disable stomp.");
HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre);
HookEvent("player_spawn", Event_PlayerSpawn);
decl String:modName[32];
GetGameFolderName(modName, sizeof(modName));
HookEventEx("post_inventory_application", Event_LockerTouch);
g_hForwardOnStomp = CreateGlobalForward("OnStomp", ET_Event, Param_Cell, Param_Cell, Param_FloatByRef, Param_FloatByRef, Param_FloatByRef);
g_hForwardOnStompPost = CreateGlobalForward("OnStompPost", ET_Ignore, Param_Cell, Param_Cell, Param_Float, Param_Float, Param_Float);
// sv_tags stuff
sv_tags = FindConVar("sv_tags");
MyAddServerTag("stomp");
HookConVarChange(g_Cvar_PluginEnabled, OnPluginChangeState);
// Support for plugin late loading
for (new client = 1; client <= MaxClients; client++)
{
if(IsClientInGame(client))
{
OnClientPutInServer(client);
}
}
}
public OnPluginEnd()
{
MyRemoveServerTag("stomp");
}
public OnMapStart()
{
PrecacheSound(STOMP_SOUND, true);
PrecacheSound(REBOUND_SOUND, true);
decl String:stompSoundServerPath[128];
decl String:reboundSoundServerPath[128];
Format(stompSoundServerPath, sizeof(stompSoundServerPath), "sound/%s", STOMP_SOUND);
Format(reboundSoundServerPath, sizeof(reboundSoundServerPath), "sound/%s", REBOUND_SOUND);
AddFileToDownloadsTable(stompSoundServerPath);
AddFileToDownloadsTable(reboundSoundServerPath);
}
public OnPluginChangeState(Handle:cvar, const String:oldVal[], const String:newVal[])
{
if(GetConVarBool(g_Cvar_PluginEnabled))
{
MyAddServerTag("stomp");
}
else
{
MyRemoveServerTag("stomp");
}
}
public OnClientPutInServer(client)
{
SDKHook(client, SDKHook_PreThinkPost, OnPreThinkPost);
}
public CheckStompImmunity(Handle:hPlugin, numParams)
{
if(numParams != 2)
{
return 3;
}
new client = GetNativeCell(1);
new victim = GetNativeCell(2);
new result = GOOMBA_IMMUNFLAG_NONE;
if(GetConVarBool(g_Cvar_ImmunityEnabled))
{
decl String:strCookieClient[16];
GetImmunityCookie(client, g_Cookie_ClientPref, strCookieClient, sizeof(strCookieClient));
decl String:strCookieVictim[16];
GetImmunityCookie(victim, g_Cookie_ClientPref, strCookieVictim, sizeof(strCookieVictim));
if(StrEqual(strCookieClient, "on") || StrEqual(strCookieClient, "next_off"))
{
result |= GOOMBA_IMMUNFLAG_ATTACKER;
}
if(StrEqual(strCookieVictim, "on") || StrEqual(strCookieVictim, "next_off"))
{
result |= GOOMBA_IMMUNFLAG_VICTIM;
}
}
return result;
}
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
new victim = GetClientOfUserId(GetEventInt(event, "userid"));
if(Goomba_Fakekill[victim] == 1)
{
SetEventBool(event, "goomba", true);
}
return Plugin_Continue;
}
public Action:OnPreStomp(attacker, victim, &Float:damageMultiplier, &Float:damageBonus, &Float:reboundPower)
{
return Plugin_Continue;
}
public GoombaStomp(Handle:hPlugin, numParams)
{
// If the plugin is disabled stop here
if(!GetConVarBool(g_Cvar_PluginEnabled))
{
return false;
}
if(numParams < 2 || numParams > 5)
{
return false;
}
// Retrieve the parameters
new client = GetNativeCell(1);
new victim = GetNativeCell(2);
new Float:damageMultiplier = GetConVarFloat(g_Cvar_DamageLifeMultiplier);
new Float:damageBonus = GetConVarFloat(g_Cvar_DamageAdd);
new Float:jumpPower = GetConVarFloat(g_Cvar_JumpPower);
switch(numParams)
{
case 3:
damageMultiplier = GetNativeCellRef(3);
case 4:
damageBonus = GetNativeCellRef(4);
case 5:
jumpPower = GetNativeCellRef(5);
}
new Float:modifiedDamageMultiplier = damageMultiplier;
new Float:modifiedDamageBonus = damageBonus;
new Float:modifiedJumpPower = jumpPower;
// Launch forward
decl Action:stompForwardResult;
Call_StartForward(g_hForwardOnStomp);
Call_PushCell(client);
Call_PushCell(victim);
Call_PushFloatRef(modifiedDamageMultiplier);
Call_PushFloatRef(modifiedDamageBonus);
Call_PushFloatRef(modifiedJumpPower);
Call_Finish(stompForwardResult);
if(stompForwardResult == Plugin_Changed)
{
damageMultiplier = modifiedDamageMultiplier;
damageBonus = modifiedDamageBonus;
jumpPower = modifiedJumpPower;
}
else if(stompForwardResult == Plugin_Handled)
{
return false;
}
if(jumpPower > 0.0)
{
decl Float:vecAng[3], Float:vecVel[3];
GetClientEyeAngles(client, vecAng);
GetEntPropVector(client, Prop_Data, "m_vecVelocity", vecVel);
vecAng[0] = DegToRad(vecAng[0]);
vecAng[1] = DegToRad(vecAng[1]);
vecVel[0] = jumpPower * Cosine(vecAng[0]) * Cosine(vecAng[1]);
vecVel[1] = jumpPower * Cosine(vecAng[0]) * Sine(vecAng[1]);
vecVel[2] = jumpPower + 100.0;
g_TeleportAtFrameEnd[client] = true;
g_TeleportAtFrameEnd_Vel[client] = vecVel;
}
new victim_health = GetClientHealth(victim);
Goomba_Fakekill[victim] = 1;
SDKHooks_TakeDamage(victim,
client,
client,
victim_health * damageMultiplier + damageBonus,
DMG_PREVENT_PHYSICS_FORCE | DMG_CRUSH | DMG_ALWAYSGIB);
Goomba_Fakekill[victim] = 0;
// Launch forward
Call_StartForward(g_hForwardOnStompPost);
Call_PushCell(client);
Call_PushCell(victim);
Call_PushFloat(damageMultiplier);
Call_PushFloat(damageBonus);
Call_PushFloat(jumpPower);
Call_Finish();
return true;
}
public PlayStompReboundSound(Handle:hPlugin, numParams)
{
if(numParams != 1)
{
return;
}
new client = GetNativeCell(1);
if (IsClientInGame(client))
{
if(GetConVarBool(g_Cvar_SoundsEnabled))
{
EmitSoundToAll(REBOUND_SOUND, client);
}
}
}
public PlayStompSound(Handle:hPlugin, numParams)
{
if(numParams != 1)
{
return;
}
new client = GetNativeCell(1);
if (IsClientInGame(client))
{
if(GetConVarBool(g_Cvar_SoundsEnabled))
{
EmitSoundToClient(client, STOMP_SOUND, client);
}
}
}
public EmitStompParticles(Handle:hPlugin, numParams)
{
if(numParams != 1)
{
return;
}
new client = GetNativeCell(1);
if(GetConVarBool(g_Cvar_ParticlesEnabled))
{
new particle = AttachParticle(client, "mini_fireworks");
if(particle != -1)
{
CreateTimer(5.0, Timer_DeleteParticle, EntIndexToEntRef(particle), TIMER_FLAG_NO_MAPCHANGE);
}
}
}
public OnPreThinkPost(client)
{
if (IsClientInGame(client) && IsPlayerAlive(client))
{
if(g_TeleportAtFrameEnd[client])
{
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, g_TeleportAtFrameEnd_Vel[client]);
if(GetConVarBool(g_Cvar_SoundsEnabled))
{
EmitSoundToAll(REBOUND_SOUND, client);
}
}
}
g_TeleportAtFrameEnd[client] = false;
}
stock GetImmunityCookie(client, Handle:cookie, String:strCookie[], maxlen)
{
if(!AreClientCookiesCached(client))
{
strcopy(strCookie, maxlen, "off");
}
else
{
GetClientCookie(client, g_Cookie_ClientPref, strCookie, maxlen);
}
}
public Action:Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
// Delay the update so class specific cfg are applied.
CreateTimer(0.1, Timer_UpdateImmunity, client);
}
public Action:Event_LockerTouch(Handle:event, const String:name[], bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
// Delay the update so class specific cfg are applied (maybe not usefull for this event).
CreateTimer(0.1, Timer_UpdateImmunity, client);
}
public Action:Timer_UpdateImmunity(Handle:timer, any:client)
{
decl String:strCookie[16];
GetImmunityCookie(client, g_Cookie_ClientPref, strCookie, sizeof(strCookie));
//-----------------------------------------------------
// on = Immunity enabled
// off = Immunity disabled
// next_on = Immunity enabled on respawn
// next_off = Immunity disabled on respawn
//-----------------------------------------------------
if(StrEqual(strCookie, ""))
{
SetClientCookie(client, g_Cookie_ClientPref, "off");
}
else if(StrEqual(strCookie, "next_off"))
{
SetClientCookie(client, g_Cookie_ClientPref, "off");
}
else if(StrEqual(strCookie, "next_on"))
{
SetClientCookie(client, g_Cookie_ClientPref, "on");
}
}
public Action:Cmd_GoombaToggle(client, args)
{
if(GetConVarBool(g_Cvar_ImmunityEnabled))
{
decl String:strCookie[16];
GetImmunityCookie(client, g_Cookie_ClientPref, strCookie, sizeof(strCookie));
if(StrEqual(strCookie, "off") || StrEqual(strCookie, "next_off"))
{
SetClientCookie(client, g_Cookie_ClientPref, "next_on");
ReplyToCommand(client, "%t", "Immun On");
}
else
{
SetClientCookie(client, g_Cookie_ClientPref, "next_off");
ReplyToCommand(client, "%t", "Immun Off");
}
}
else
{
ReplyToCommand(client, "%t", "Immun Disabled");
}
return Plugin_Handled;
}
public Action:Cmd_GoombaOn(client, args)
{
if(GetConVarBool(g_Cvar_ImmunityEnabled))
{
decl String:strCookie[16];
GetImmunityCookie(client, g_Cookie_ClientPref, strCookie, sizeof(strCookie));
if(!StrEqual(strCookie, "off"))
{
SetClientCookie(client, g_Cookie_ClientPref, "next_off");
ReplyToCommand(client, "%t", "Immun Off");
}
}
else
{
ReplyToCommand(client, "%t", "Immun Disabled");
}
return Plugin_Handled;
}
public Action:Cmd_GoombaOff(client, args)
{
if(GetConVarBool(g_Cvar_ImmunityEnabled))
{
decl String:strCookie[16];
GetImmunityCookie(client, g_Cookie_ClientPref, strCookie, sizeof(strCookie));
if(!StrEqual(strCookie, "on"))
{
SetClientCookie(client, g_Cookie_ClientPref, "next_on");
ReplyToCommand(client, "%t", "Immun On");
}
}
else
{
ReplyToCommand(client, "%t", "Immun Disabled");
}
return Plugin_Handled;
}
public Action:Cmd_GoombaStatus(client, args)
{
if(GetConVarBool(g_Cvar_ImmunityEnabled))
{
decl String:strCookie[16];
GetImmunityCookie(client, g_Cookie_ClientPref, strCookie, sizeof(strCookie));
if(StrEqual(strCookie, "on"))
{
ReplyToCommand(client, "%t", "Status Off");
}
if(StrEqual(strCookie, "off"))
{
ReplyToCommand(client, "%t", "Status On");
}
if(StrEqual(strCookie, "next_off"))
{
ReplyToCommand(client, "%t", "Status Next On");
}
if(StrEqual(strCookie, "next_on"))
{
ReplyToCommand(client, "%t", "Status Next Off");
}
}
else
{
ReplyToCommand(client, "%t", "Immun Disabled");
}
return Plugin_Handled;
}
public Action:Timer_DeleteParticle(Handle:timer, any:ref)
{
new particle = EntRefToEntIndex(ref);
DeleteParticle(particle);
}
stock AttachParticle(entity, String:particleType[])
{
new particle = CreateEntityByName("info_particle_system");
decl String:tName[128];
if(IsValidEdict(particle))
{
decl Float:pos[3] ;
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
pos[2] += 74;
TeleportEntity(particle, pos, NULL_VECTOR, NULL_VECTOR);
Format(tName, sizeof(tName), "target%i", entity);
DispatchKeyValue(entity, "targetname", tName);
DispatchKeyValue(particle, "targetname", "tf2particle");
DispatchKeyValue(particle, "parentname", tName);
DispatchKeyValue(particle, "effect_name", particleType);
DispatchSpawn(particle);
SetVariantString(tName);
SetVariantString("flag");
ActivateEntity(particle);
AcceptEntityInput(particle, "start");
return particle;
}
return -1;
}
stock DeleteParticle(any:particle)
{
if (particle > MaxClients && IsValidEntity(particle))
{
decl String:classname[256];
GetEdictClassname(particle, classname, sizeof(classname));
if (StrEqual(classname, "info_particle_system", false))
{
AcceptEntityInput(particle, "Kill");
}
}
}
stock MyAddServerTag(const String:tag[])
{
decl String:currtags[128];
if (sv_tags == INVALID_HANDLE)
{
return;
}
GetConVarString(sv_tags, currtags, sizeof(currtags));
if (StrContains(currtags, tag) > -1)
{
// already have tag
return;
}
decl String:newtags[128];
Format(newtags, sizeof(newtags), "%s%s%s", currtags, (currtags[0]!=0)?",":"", tag);
new flags = GetConVarFlags(sv_tags);
SetConVarFlags(sv_tags, flags & ~FCVAR_NOTIFY);
SetConVarString(sv_tags, newtags);
SetConVarFlags(sv_tags, flags);
}
stock MyRemoveServerTag(const String:tag[])
{
decl String:newtags[128];
if (sv_tags == INVALID_HANDLE)
{
return;
}
GetConVarString(sv_tags, newtags, sizeof(newtags));
if (StrContains(newtags, tag) == -1)
{
// tag isn't on here, just bug out
return;
}
ReplaceString(newtags, sizeof(newtags), tag, "");
ReplaceString(newtags, sizeof(newtags), ",,", "");
new flags = GetConVarFlags(sv_tags);
SetConVarFlags(sv_tags, flags & ~FCVAR_NOTIFY);
SetConVarString(sv_tags, newtags);
SetConVarFlags(sv_tags, flags);
}

1225
scripting/temp/mapchooser.sp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
/****************************************
* mckayupdater.sp
*
* This file is used in Dr. McKay's plugins for Updater integration
* For more info on Dr. McKay's plugins, see http://www.doctormckay.com
* For more info on Updater, see https://forums.alliedmods.net/showthread.php?t=169095
* You may copy and use this file, but please be sure to change the URL to your own!
*
* This file does the following tasks:
* - Adds the plugin to Updater's updating pool (using UPDATER_BASE_URL/UPDATE_FILE (UPDATE_FILE should be defined prior to including this file))
* - Creates a cvar CONVAR_PREFIX_auto_update to control whether Updater is enabled (CONVAR_PREFIX should be defined prior to including this file)
* - Creates a version cvar CONVAR_PREFIX_version (CONVAR_PREFIX should be defined prior to including this file)
* - Dynamically adds "A" to the version cvar based on whether Updater is installed and working
*
* If you need to put code into OnAllPluginsLoaded, define ALL_PLUGINS_LOADED_FUNC with a function (doesn't need to be public) to be called inside of OnAllPluginsLoaded
* For example, #define ALL_PLUGINS_LOADED_FUNC AllPluginsLoaded
* AllPluginsLoaded() { ... }
*
* If you need to put code into OnLibraryAdded, define LIBRARY_ADDED_FUNC with a function (doesn't need to be public) to be called inside of OnLibraryAdded
* For example, #define LIBRARY_ADDED_FUNC LibraryAdded
* LibraryAdded(const String:name[]) { ... }
*
* If you need to put code into OnLibraryRemoved, define LIBRARY_REMOVED_FUNC with a function (doesn't need to be public) to be called inside of OnLibraryRemoved
* For example, #define LIBRARY_REMOVED_FUNC LibraryRemoved
* LibraryRemoved(const String:name[]) { ... }
*
* Define RELOAD_ON_UPDATE and the plugin will reload itself upon being updated
*
*/
#if defined _mckay_updater_included
#endinput
#endif
#define _mckay_updater_included
#if defined REQUIRE_PLUGIN
#undef REQUIRE_PLUGIN
#endif
#include <updater>
#define REQUIRE_PLUGIN
#define UPDATER_BASE_URL "http://hg.doctormckay.com/public-plugins/raw/default"
new Handle:cvarEnableUpdater;
new Handle:cvarVersion;
public OnAllPluginsLoaded() {
decl String:cvarName[64];
Format(cvarName, sizeof(cvarName), "%s_auto_update", CONVAR_PREFIX);
cvarEnableUpdater = CreateConVar(cvarName, "1", "Enables automatic updating (has no effect if Updater is not installed)");
Format(cvarName, sizeof(cvarName), "%s_version", CONVAR_PREFIX);
cvarVersion = CreateConVar(cvarName, PLUGIN_VERSION, "Plugin Version", FCVAR_DONTRECORD|FCVAR_CHEAT|FCVAR_NOTIFY);
HookConVarChange(cvarEnableUpdater, CheckUpdaterStatus);
HookConVarChange(cvarVersion, CheckUpdaterStatus);
CheckUpdaterStatus(INVALID_HANDLE, "", "");
#if defined ALL_PLUGINS_LOADED_FUNC
ALL_PLUGINS_LOADED_FUNC();
#endif
}
public OnLibraryAdded(const String:name[]) {
CheckUpdaterStatus(INVALID_HANDLE, "", "");
#if defined LIBRARY_ADDED_FUNC
LIBRARY_ADDED_FUNC(name);
#endif
}
public OnLibraryRemoved(const String:name[]) {
CheckUpdaterStatus(INVALID_HANDLE, "", "");
#if defined LIBRARY_REMOVED_FUNC
LIBRARY_REMOVED_FUNC(name);
#endif
}
public CheckUpdaterStatus(Handle:convar, const String:name[], const String:value[]) {
if(cvarVersion == INVALID_HANDLE) {
return; // Version cvar not created yet
}
if(LibraryExists("updater") && GetConVarBool(cvarEnableUpdater)) {
decl String:url[512], String:version[12];
Format(url, sizeof(url), "%s/%s", UPDATER_BASE_URL, UPDATE_FILE);
Updater_AddPlugin(url); // Has no effect if we're already in Updater's pool
Format(version, sizeof(version), "%sA", PLUGIN_VERSION);
SetConVarString(cvarVersion, version);
} else {
SetConVarString(cvarVersion, PLUGIN_VERSION);
}
}
public Action:Updater_OnPluginChecking() {
if(!GetConVarBool(cvarEnableUpdater)) {
return Plugin_Handled;
}
return Plugin_Continue;
}
#if defined RELOAD_ON_UPDATE
public Updater_OnPluginUpdated() {
ReloadPlugin();
}
#endif

230
scripting/temp/nextmap.sp Normal file
View File

@@ -0,0 +1,230 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Nextmap Plugin
* Adds sm_nextmap cvar for changing map and nextmap chat trigger.
*
* SourceMod (C)2004-2014 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <sourcemod>
#include "include/nextmap.inc"
#pragma semicolon 1
#pragma newdecls required
public Plugin myinfo =
{
name = "Nextmap",
author = "AlliedModders LLC",
description = "Provides nextmap and sm_nextmap",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
int g_MapPos = -1;
ArrayList g_MapList = null;
int g_MapListSerial = -1;
int g_CurrentMapStartTime;
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
char game[128];
GetGameFolderName(game, sizeof(game));
if (StrEqual(game, "left4dead", false)
|| StrEqual(game, "dystopia", false)
|| StrEqual(game, "synergy", false)
|| StrEqual(game, "left4dead2", false)
|| StrEqual(game, "garrysmod", false)
|| StrEqual(game, "swarm", false)
|| StrEqual(game, "bms", false)
|| GetEngineVersion() == Engine_Insurgency)
{
strcopy(error, err_max, "Nextmap is incompatible with this game");
return APLRes_SilentFailure;
}
return APLRes_Success;
}
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("nextmap.phrases");
int size = ByteCountToCells(PLATFORM_MAX_PATH);
g_MapList = new ArrayList(size);
RegAdminCmd("sm_maphistory", Command_MapHistory, ADMFLAG_CHANGEMAP, "Shows the most recent maps played");
RegConsoleCmd("listmaps", Command_List);
// Set to the current map so OnMapStart() will know what to do
char currentMap[PLATFORM_MAX_PATH];
GetCurrentMap(currentMap, sizeof(currentMap));
SetNextMap(currentMap);
}
public void OnMapStart()
{
g_CurrentMapStartTime = GetTime();
}
public void OnConfigsExecuted()
{
char lastMap[PLATFORM_MAX_PATH], currentMap[PLATFORM_MAX_PATH];
GetNextMap(lastMap, sizeof(lastMap));
GetCurrentMap(currentMap, sizeof(currentMap));
// Why am I doing this? If we switched to a new map, but it wasn't what we expected (Due to sm_map, sm_votemap, or
// some other plugin/command), we don't want to scramble the map cycle. Or for example, admin switches to a custom map
// not in mapcyclefile. So we keep it set to the last expected nextmap. - ferret
if (strcmp(lastMap, currentMap) == 0)
{
FindAndSetNextMap();
}
}
public Action Command_List(int client, int args)
{
PrintToConsole(client, "Map Cycle:");
int mapCount = g_MapList.Length;
char mapName[PLATFORM_MAX_PATH];
for (int i = 0; i < mapCount; i++)
{
g_MapList.GetString(i, mapName, sizeof(mapName));
PrintToConsole(client, "%s", mapName);
}
return Plugin_Handled;
}
void FindAndSetNextMap()
{
if (ReadMapList(g_MapList,
g_MapListSerial,
"mapcyclefile",
MAPLIST_FLAG_CLEARARRAY|MAPLIST_FLAG_NO_DEFAULT)
== null)
{
if (g_MapListSerial == -1)
{
LogError("FATAL: Cannot load map cycle. Nextmap not loaded.");
SetFailState("Mapcycle Not Found");
}
}
int mapCount = g_MapList.Length;
char mapName[PLATFORM_MAX_PATH];
if (g_MapPos == -1)
{
char current[PLATFORM_MAX_PATH];
GetCurrentMap(current, sizeof(current));
for (int i = 0; i < mapCount; i++)
{
g_MapList.GetString(i, mapName, sizeof(mapName));
if (FindMap(mapName, mapName, sizeof(mapName)) != FindMap_NotFound &&
strcmp(current, mapName, false) == 0)
{
g_MapPos = i;
break;
}
}
if (g_MapPos == -1)
g_MapPos = 0;
}
g_MapPos++;
if (g_MapPos >= mapCount)
g_MapPos = 0;
g_MapList.GetString(g_MapPos, mapName, sizeof(mapName));
SetNextMap(mapName);
}
public Action Command_MapHistory(int client, int args)
{
int mapCount = GetMapHistorySize();
char mapName[PLATFORM_MAX_PATH];
char changeReason[100];
char timeString[100];
char playedTime[100];
int startTime;
int lastMapStartTime = g_CurrentMapStartTime;
PrintToConsole(client, "Map History:\n");
PrintToConsole(client, "Map : Started : Played Time : Reason for ending");
GetCurrentMap(mapName, sizeof(mapName));
PrintToConsole(client, "%02i. %s (Current Map)", 0, mapName);
for (int i=0; i<mapCount; i++)
{
GetMapHistory(i, mapName, sizeof(mapName), changeReason, sizeof(changeReason), startTime);
FormatTimeDuration(timeString, sizeof(timeString), GetTime() - startTime);
FormatTimeDuration(playedTime, sizeof(playedTime), lastMapStartTime - startTime);
PrintToConsole(client, "%02i. %s : %s ago : %s : %s", i+1, mapName, timeString, playedTime, changeReason);
lastMapStartTime = startTime;
}
return Plugin_Handled;
}
int FormatTimeDuration(char[] buffer, int maxlen, int time)
{
int days = time / 86400;
int hours = (time / 3600) % 24;
int minutes = (time / 60) % 60;
int seconds = time % 60;
if (days > 0)
{
return Format(buffer, maxlen, "%id %ih %im", days, hours, (seconds >= 30) ? minutes+1 : minutes);
}
else if (hours > 0)
{
return Format(buffer, maxlen, "%ih %im", hours, (seconds >= 30) ? minutes+1 : minutes);
}
else if (minutes > 0)
{
return Format(buffer, maxlen, "%im", (seconds >= 30) ? minutes+1 : minutes);
}
else
{
return Format(buffer, maxlen, "%is", seconds);
}
}

View File

@@ -0,0 +1,435 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Rock The Vote Plugin
* Creates a map vote when the required number of players have requested one.
*
* SourceMod (C)2004-2014 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <sourcemod>
#include <mapchooser>
#pragma semicolon 1
#pragma newdecls required
public Plugin myinfo =
{
name = "Map Nominations",
author = "AlliedModders LLC",
description = "Provides Map Nominations",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
ConVar g_Cvar_ExcludeOld;
ConVar g_Cvar_ExcludeCurrent;
Menu g_MapMenu = null;
ArrayList g_MapList = null;
int g_mapFileSerial = -1;
#define MAPSTATUS_ENABLED (1<<0)
#define MAPSTATUS_DISABLED (1<<1)
#define MAPSTATUS_EXCLUDE_CURRENT (1<<2)
#define MAPSTATUS_EXCLUDE_PREVIOUS (1<<3)
#define MAPSTATUS_EXCLUDE_NOMINATED (1<<4)
StringMap g_mapTrie = null;
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("nominations.phrases");
int arraySize = ByteCountToCells(PLATFORM_MAX_PATH);
g_MapList = new ArrayList(arraySize);
g_Cvar_ExcludeOld = CreateConVar("sm_nominate_excludeold", "1", "Specifies if the current map should be excluded from the Nominations list", 0, true, 0.00, true, 1.0);
g_Cvar_ExcludeCurrent = CreateConVar("sm_nominate_excludecurrent", "1", "Specifies if the MapChooser excluded maps should also be excluded from Nominations", 0, true, 0.00, true, 1.0);
RegConsoleCmd("sm_nominate", Command_Nominate);
RegAdminCmd("sm_nominate_addmap", Command_Addmap, ADMFLAG_CHANGEMAP, "sm_nominate_addmap <mapname> - Forces a map to be on the next mapvote.");
g_mapTrie = new StringMap();
}
public void OnConfigsExecuted()
{
if (ReadMapList(g_MapList,
g_mapFileSerial,
"nominations",
MAPLIST_FLAG_CLEARARRAY|MAPLIST_FLAG_MAPSFOLDER)
== null)
{
if (g_mapFileSerial == -1)
{
SetFailState("Unable to create a valid map list.");
}
}
BuildMapMenu();
}
public void OnNominationRemoved(const char[] map, int owner)
{
int status;
char resolvedMap[PLATFORM_MAX_PATH];
FindMap(map, resolvedMap, sizeof(resolvedMap));
/* Is the map in our list? */
if (!g_mapTrie.GetValue(resolvedMap, status))
{
return;
}
/* Was the map disabled due to being nominated */
if ((status & MAPSTATUS_EXCLUDE_NOMINATED) != MAPSTATUS_EXCLUDE_NOMINATED)
{
return;
}
g_mapTrie.SetValue(resolvedMap, MAPSTATUS_ENABLED);
}
public Action Command_Addmap(int client, int args)
{
if (args < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_nominate_addmap <mapname>");
return Plugin_Handled;
}
char mapname[PLATFORM_MAX_PATH];
char resolvedMap[PLATFORM_MAX_PATH];
GetCmdArg(1, mapname, sizeof(mapname));
if (FindMap(mapname, resolvedMap, sizeof(resolvedMap)) == FindMap_NotFound)
{
// We couldn't resolve the map entry to a filename, so...
ReplyToCommand(client, "%t", "Map was not found", mapname);
return Plugin_Handled;
}
char displayName[PLATFORM_MAX_PATH];
GetMapDisplayName(resolvedMap, displayName, sizeof(displayName));
int status;
if (!g_mapTrie.GetValue(resolvedMap, status))
{
ReplyToCommand(client, "%t", "Map was not found", displayName);
return Plugin_Handled;
}
NominateResult result = NominateMap(resolvedMap, true, 0);
if (result > Nominate_Replaced)
{
/* We assume already in vote is the casue because the maplist does a Map Validity check and we forced, so it can't be full */
ReplyToCommand(client, "%t", "Map Already In Vote", displayName);
return Plugin_Handled;
}
g_mapTrie.SetValue(resolvedMap, MAPSTATUS_DISABLED|MAPSTATUS_EXCLUDE_NOMINATED);
ReplyToCommand(client, "%t", "Map Inserted", displayName);
LogAction(client, -1, "\"%L\" inserted map \"%s\".", client, mapname);
return Plugin_Handled;
}
public void OnClientSayCommand_Post(int client, const char[] command, const char[] sArgs)
{
if (!client)
{
return;
}
if (strcmp(sArgs, "nominate", false) == 0)
{
ReplySource old = SetCmdReplySource(SM_REPLY_TO_CHAT);
AttemptNominate(client);
SetCmdReplySource(old);
}
}
public Action Command_Nominate(int client, int args)
{
if (!client)
{
return Plugin_Handled;
}
if (args == 0)
{
AttemptNominate(client);
return Plugin_Handled;
}
char mapname[PLATFORM_MAX_PATH];
GetCmdArg(1, mapname, sizeof(mapname));
if (FindMap(mapname, mapname, sizeof(mapname)) == FindMap_NotFound)
{
// We couldn't resolve the map entry to a filename, so...
ReplyToCommand(client, "%t", "Map was not found", mapname);
return Plugin_Handled;
}
char displayName[PLATFORM_MAX_PATH];
GetMapDisplayName(mapname, displayName, sizeof(displayName));
int status;
if (!g_mapTrie.GetValue(mapname, status))
{
ReplyToCommand(client, "%t", "Map was not found", displayName);
return Plugin_Handled;
}
if ((status & MAPSTATUS_DISABLED) == MAPSTATUS_DISABLED)
{
if ((status & MAPSTATUS_EXCLUDE_CURRENT) == MAPSTATUS_EXCLUDE_CURRENT)
{
ReplyToCommand(client, "[SM] %t", "Can't Nominate Current Map");
}
if ((status & MAPSTATUS_EXCLUDE_PREVIOUS) == MAPSTATUS_EXCLUDE_PREVIOUS)
{
ReplyToCommand(client, "[SM] %t", "Map in Exclude List");
}
if ((status & MAPSTATUS_EXCLUDE_NOMINATED) == MAPSTATUS_EXCLUDE_NOMINATED)
{
ReplyToCommand(client, "[SM] %t", "Map Already Nominated");
}
return Plugin_Handled;
}
NominateResult result = NominateMap(mapname, false, client);
if (result > Nominate_Replaced)
{
if (result == Nominate_AlreadyInVote)
{
ReplyToCommand(client, "%t", "Map Already In Vote", displayName);
}
else
{
ReplyToCommand(client, "[SM] %t", "Map Already Nominated");
}
return Plugin_Handled;
}
/* Map was nominated! - Disable the menu item and update the trie */
g_mapTrie.SetValue(mapname, MAPSTATUS_DISABLED|MAPSTATUS_EXCLUDE_NOMINATED);
char name[MAX_NAME_LENGTH];
GetClientName(client, name, sizeof(name));
PrintToChatAll("[SM] %t", "Map Nominated", name, displayName);
return Plugin_Continue;
}
void AttemptNominate(int client)
{
g_MapMenu.SetTitle("%T", "Nominate Title", client);
g_MapMenu.Display(client, MENU_TIME_FOREVER);
return;
}
void BuildMapMenu()
{
delete g_MapMenu;
g_mapTrie.Clear();
g_MapMenu = new Menu(Handler_MapSelectMenu, MENU_ACTIONS_DEFAULT|MenuAction_DrawItem|MenuAction_DisplayItem);
char map[PLATFORM_MAX_PATH];
ArrayList excludeMaps;
char currentMap[PLATFORM_MAX_PATH];
if (g_Cvar_ExcludeOld.BoolValue)
{
excludeMaps = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH));
GetExcludeMapList(excludeMaps);
}
if (g_Cvar_ExcludeCurrent.BoolValue)
{
GetCurrentMap(currentMap, sizeof(currentMap));
}
for (int i = 0; i < g_MapList.Length; i++)
{
int status = MAPSTATUS_ENABLED;
g_MapList.GetString(i, map, sizeof(map));
FindMap(map, map, sizeof(map));
char displayName[PLATFORM_MAX_PATH];
GetMapDisplayName(map, displayName, sizeof(displayName));
if (g_Cvar_ExcludeCurrent.BoolValue)
{
if (StrEqual(map, currentMap))
{
status = MAPSTATUS_DISABLED|MAPSTATUS_EXCLUDE_CURRENT;
}
}
/* Dont bother with this check if the current map check passed */
if (g_Cvar_ExcludeOld.BoolValue && status == MAPSTATUS_ENABLED)
{
if (excludeMaps.FindString(map) != -1)
{
status = MAPSTATUS_DISABLED|MAPSTATUS_EXCLUDE_PREVIOUS;
}
}
g_MapMenu.AddItem(map, displayName);
g_mapTrie.SetValue(map, status);
}
g_MapMenu.ExitButton = true;
delete excludeMaps;
}
public int Handler_MapSelectMenu(Menu menu, MenuAction action, int param1, int param2)
{
switch (action)
{
case MenuAction_Select:
{
char map[PLATFORM_MAX_PATH], name[MAX_NAME_LENGTH], displayName[PLATFORM_MAX_PATH];
menu.GetItem(param2, map, sizeof(map), _, displayName, sizeof(displayName));
GetClientName(param1, name, sizeof(name));
NominateResult result = NominateMap(map, false, param1);
/* Don't need to check for InvalidMap because the menu did that already */
if (result == Nominate_AlreadyInVote)
{
PrintToChat(param1, "[SM] %t", "Map Already Nominated");
return 0;
}
else if (result == Nominate_VoteFull)
{
PrintToChat(param1, "[SM] %t", "Max Nominations");
return 0;
}
g_mapTrie.SetValue(map, MAPSTATUS_DISABLED|MAPSTATUS_EXCLUDE_NOMINATED);
if (result == Nominate_Replaced)
{
PrintToChatAll("[SM] %t", "Map Nomination Changed", name, displayName);
return 0;
}
PrintToChatAll("[SM] %t", "Map Nominated", name, displayName);
}
case MenuAction_DrawItem:
{
char map[PLATFORM_MAX_PATH];
menu.GetItem(param2, map, sizeof(map));
int status;
if (!g_mapTrie.GetValue(map, status))
{
LogError("Menu selection of item not in trie. Major logic problem somewhere.");
return ITEMDRAW_DEFAULT;
}
if ((status & MAPSTATUS_DISABLED) == MAPSTATUS_DISABLED)
{
return ITEMDRAW_DISABLED;
}
return ITEMDRAW_DEFAULT;
}
case MenuAction_DisplayItem:
{
char map[PLATFORM_MAX_PATH], displayName[PLATFORM_MAX_PATH];
menu.GetItem(param2, map, sizeof(map), _, displayName, sizeof(displayName));
int status;
if (!g_mapTrie.GetValue(map, status))
{
LogError("Menu selection of item not in trie. Major logic problem somewhere.");
return 0;
}
char display[PLATFORM_MAX_PATH + 64];
if ((status & MAPSTATUS_DISABLED) == MAPSTATUS_DISABLED)
{
if ((status & MAPSTATUS_EXCLUDE_CURRENT) == MAPSTATUS_EXCLUDE_CURRENT)
{
Format(display, sizeof(display), "%s (%T)", displayName, "Current Map", param1);
return RedrawMenuItem(display);
}
if ((status & MAPSTATUS_EXCLUDE_PREVIOUS) == MAPSTATUS_EXCLUDE_PREVIOUS)
{
Format(display, sizeof(display), "%s (%T)", displayName, "Recently Played", param1);
return RedrawMenuItem(display);
}
if ((status & MAPSTATUS_EXCLUDE_NOMINATED) == MAPSTATUS_EXCLUDE_NOMINATED)
{
Format(display, sizeof(display), "%s (%T)", displayName, "Nominated", param1);
return RedrawMenuItem(display);
}
}
return 0;
}
}
return 0;
}

View File

@@ -0,0 +1,98 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod Player Commands Plugin
* Implements slap and slay commands
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma newdecls required
public Plugin myinfo =
{
name = "Player Commands",
author = "AlliedModders LLC",
description = "Misc. Player Commands",
version = SOURCEMOD_VERSION,
url = "http://www.sourcemod.net/"
};
TopMenu hTopMenu;
/* Used to get the SDK / Engine version. */
#include "playercommands/slay.sp"
#include "playercommands/slap.sp"
#include "playercommands/rename.sp"
public void OnPluginStart()
{
LoadTranslations("common.phrases");
LoadTranslations("playercommands.phrases");
RegAdminCmd("sm_slap", Command_Slap, ADMFLAG_SLAY, "sm_slap <#userid|name> [damage]");
RegAdminCmd("sm_slay", Command_Slay, ADMFLAG_SLAY, "sm_slay <#userid|name>");
RegAdminCmd("sm_rename", Command_Rename, ADMFLAG_SLAY, "sm_rename <#userid|name>");
/* Account for late loading */
TopMenu topmenu;
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != null))
{
OnAdminMenuReady(topmenu);
}
}
public void OnAdminMenuReady(Handle aTopMenu)
{
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
/* Block us from being called twice */
if (topmenu == hTopMenu)
{
return;
}
/* Save the Handle */
hTopMenu = topmenu;
/* Find the "Player Commands" category */
TopMenuObject player_commands = hTopMenu.FindCategory(ADMINMENU_PLAYERCOMMANDS);
if (player_commands != INVALID_TOPMENUOBJECT)
{
hTopMenu.AddItem("sm_slay", AdminMenu_Slay, player_commands, "sm_slay", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_slap", AdminMenu_Slap, player_commands, "sm_slap", ADMFLAG_SLAY);
hTopMenu.AddItem("sm_rename", AdminMenu_Rename, player_commands, "sm_rename", ADMFLAG_SLAY);
}
}