diff --git a/plugins/basecomm.sp b/plugins/basecomm.sp new file mode 100644 index 00000000..a1b02019 --- /dev/null +++ b/plugins/basecomm.sp @@ -0,0 +1,414 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Communication Plugin + * Provides fucntionality for controlling communication on the server + * + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include +#include + +#pragma semicolon 1 + +public Plugin:myinfo = +{ + name = "Basic Comm Control", + author = "AlliedModders LLC", + description = "Provides methods of controllingg communication.", + version = SOURCEMOD_VERSION, + url = "http://www.sourcemod.net/" +}; + +new bool:g_Muted[MAXPLAYERS+1]; // Is the player muted? +new bool:g_Gagged[MAXPLAYERS+1]; // Is the player gagged? + +new Handle:g_Cvar_Deadtalk = INVALID_HANDLE; // Holds the handle for sm_deadtalk +new Handle:g_Cvar_Alltalk = INVALID_HANDLE; // Holds the handle for sv_alltalk +new bool:g_Hooked = false; // Tracks if we've hooked events for deadtalk + +public 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"); + + RegConsoleCmd("say", Command_Say); + RegConsoleCmd("say_team", Command_Say); + + RegAdminCmd("sm_mute", Command_Mute, ADMFLAG_CHAT, "sm_mute - Removes a player's ability to use voice."); + RegAdminCmd("sm_gag", Command_Gag, ADMFLAG_CHAT, "sm_gag - Removes a player's ability to use chat."); + RegAdminCmd("sm_silence", Command_Silence, ADMFLAG_CHAT, "sm_silence - Removes a player's ability to use voice or chat."); + + RegAdminCmd("sm_unmute", Command_Unmute, ADMFLAG_CHAT, "sm_unmute - Restores a player's ability to use voice."); + RegAdminCmd("sm_ungag", Command_Ungag, ADMFLAG_CHAT, "sm_ungag - Restores a player's ability to use chat."); + RegAdminCmd("sm_unsilence", Command_Unsilence, ADMFLAG_CHAT, "sm_unsilence - Restores a player's ability to use voice and chat."); + + HookConVarChange(g_Cvar_Deadtalk, ConVarChange_Deadtalk); +} + +public ConVarChange_Deadtalk(Handle:convar, const String:oldValue[], const String:newValue[]) +{ + if (GetConVarInt(g_Cvar_Deadtalk)) + { + 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(client, String:rejectmsg[], maxlen) +{ + g_Gagged[client] = false; + g_Muted[client] = false; + + return true; +} + +public Action:Command_Say(client, args) +{ + if (client) + { + if (g_Gagged[client]) + { + return Plugin_Handled; + } + } + + return Plugin_Continue; +} + +public Action:Command_Mute(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "[SM] Usage: sm_mute "); + return Plugin_Handled; + } + + decl String:arg[64]; + GetCmdArg(1, arg, sizeof(arg)); + + new target = FindTarget(client, arg); + if (target == -1) + { + return Plugin_Handled; + } + + if (g_Muted[target]) + { + ReplyToCommand(client, "%t", "Already Muted"); + return Plugin_Handled; + } + + g_Muted[target] = true; + SetClientListeningFlags(target, VOICE_MUTED); + + decl String:name[64]; + GetClientName(target, name, sizeof(name)); + + ShowActivity(client, "%t", "Player Muted", name); + ReplyToCommand(client, "%t", "Player Muted", name); + LogAction(client, target, "\"%L\" muted \"%L\"", client, target); + + return Plugin_Handled; +} + +public Action:Command_Gag(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "[SM] Usage: sm_gag "); + return Plugin_Handled; + } + + decl String:arg[64]; + GetCmdArg(1, arg, sizeof(arg)); + + new target = FindTarget(client, arg); + if (target == -1) + { + return Plugin_Handled; + } + + if (g_Gagged[target]) + { + ReplyToCommand(client, "%t", "Already Gagged"); + return Plugin_Handled; + } + + g_Gagged[target] = true; + + decl String:name[64]; + GetClientName(target, name, sizeof(name)); + + ShowActivity(client, "%t", "Player Gagged", name); + ReplyToCommand(client, "%t", "Player Gagged", name); + LogAction(client, target, "\"%L\" gagged \"%L\"", client, target); + + return Plugin_Handled; +} + +public Action:Command_Silence(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "[SM] Usage: sm_silence "); + return Plugin_Handled; + } + + decl String:arg[64]; + GetCmdArg(1, arg, sizeof(arg)); + + new target = FindTarget(client, arg); + if (target == -1) + { + return Plugin_Handled; + } + + if (g_Gagged[target] && g_Muted[target]) + { + ReplyToCommand(client, "%t", "Already Silenced"); + return Plugin_Handled; + } + + decl String:name[64]; + GetClientName(target, name, sizeof(name)); + + if (!g_Gagged[target]) + { + g_Gagged[target] = true; + + ShowActivity(client, "%t", "Player Gagged", name); + ReplyToCommand(client, "%t", "Player Gagged", name); + LogAction(client, target, "\"%L\" gagged \"%L\"", client, target); + } + + if (!g_Muted[target]) + { + g_Muted[target] = true; + SetClientListeningFlags(target, VOICE_MUTED); + + ShowActivity(client, "%t", "Player Muted", name); + ReplyToCommand(client, "%t", "Player Muted", name); + LogAction(client, target, "\"%L\" muted \"%L\"", client, target); + } + + return Plugin_Handled; +} + +public Action:Command_Unmute(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "[SM] Usage: sm_unmute "); + return Plugin_Handled; + } + + decl String:arg[64]; + GetCmdArg(1, arg, sizeof(arg)); + + new target = FindTarget(client, arg); + if (target == -1) + { + return Plugin_Handled; + } + + if (!g_Muted[target]) + { + ReplyToCommand(client, "%t", "Player Not Muted"); + return Plugin_Handled; + } + + g_Muted[target] = false; + if (GetConVarInt(g_Cvar_Deadtalk) == 1 && !IsPlayerAlive(target)) + { + SetClientListeningFlags(target, VOICE_LISTENALL); + } + else if (GetConVarInt(g_Cvar_Deadtalk) == 2 && !IsPlayerAlive(target)) + { + SetClientListeningFlags(target, VOICE_TEAM); + } + else + { + SetClientListeningFlags(target, VOICE_NORMAL); + } + + decl String:name[64]; + GetClientName(target, name, sizeof(name)); + + ShowActivity(client, "%t", "Player Unmuted", name); + ReplyToCommand(client, "%t", "Player Unmuted", name); + LogAction(client, target, "\"%L\" unmuted \"%L\"", client, target); + + return Plugin_Handled; +} + +public Action:Command_Ungag(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "[SM] Usage: sm_ungag "); + return Plugin_Handled; + } + + decl String:arg[64]; + GetCmdArg(1, arg, sizeof(arg)); + + new target = FindTarget(client, arg); + if (target == -1) + { + return Plugin_Handled; + } + + if (!g_Gagged[target]) + { + ReplyToCommand(client, "%t", "Player Not Gagged"); + return Plugin_Handled; + } + + g_Gagged[target] = false; + + decl String:name[64]; + GetClientName(target, name, sizeof(name)); + + ShowActivity(client, "%t", "Player Ungagged", name); + ReplyToCommand(client, "%t", "Player Ungagged", name); + LogAction(client, target, "\"%L\" ungagged \"%L\"", client, target); + + return Plugin_Handled; +} + +public Action:Command_Unsilence(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "[SM] Usage: sm_unsilence "); + return Plugin_Handled; + } + + decl String:arg[64]; + GetCmdArg(1, arg, sizeof(arg)); + + new target = FindTarget(client, arg); + if (target == -1) + { + return Plugin_Handled; + } + + if (!g_Gagged[target] && !g_Muted[target]) + { + ReplyToCommand(client, "%t", "Player Not Silenced"); + return Plugin_Handled; + } + + decl String:name[64]; + GetClientName(target, name, sizeof(name)); + + if (g_Gagged[target]) + { + g_Gagged[target] = false; + + ShowActivity(client, "%t", "Player Ungagged", name); + ReplyToCommand(client, "%t", "Player Ungagged", name); + LogAction(client, target, "\"%L\" ungagged \"%L\"", client, target); + } + + if (g_Muted[target]) + { + g_Muted[target] = false; + + if (GetConVarInt(g_Cvar_Deadtalk) == 1 && !IsPlayerAlive(target)) + { + SetClientListeningFlags(target, VOICE_LISTENALL); + } + else if (GetConVarInt(g_Cvar_Deadtalk) == 2 && !IsPlayerAlive(target)) + { + SetClientListeningFlags(target, VOICE_TEAM); + } + else + { + SetClientListeningFlags(target, VOICE_NORMAL); + } + + ShowActivity(client, "%t", "Player Unmuted", name); + ReplyToCommand(client, "%t", "Player Unmuted", name); + LogAction(client, target, "\"%L\" unmuted \"%L\"", client, target); + } + + return Plugin_Handled; +} + +public Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) +{ + new client = GetClientOfUserId(GetEventInt(event, "userid")); + + if (g_Muted[client]) + { + SetClientListeningFlags(client, VOICE_MUTED); + } + else + { + SetClientListeningFlags(client, VOICE_NORMAL); + } +} + +public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) +{ + new client = GetClientOfUserId(GetEventInt(event, "userid")); + + if (g_Muted[client]) + { + SetClientListeningFlags(client, VOICE_MUTED); + return; + } + + if (GetConVarBool(g_Cvar_Alltalk)) + { + SetClientListeningFlags(client, VOICE_NORMAL); + return; + } + + if (GetConVarInt(g_Cvar_Deadtalk) == 1) + { + SetClientListeningFlags(client, VOICE_LISTENALL); + } + else if (GetConVarInt(g_Cvar_Deadtalk) == 2) + { + SetClientListeningFlags(client, VOICE_TEAM); + } +} \ No newline at end of file diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 26f88171..95096c24 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -669,3 +669,14 @@ native bool:CheckCommandAccess(client, const String:command[], flags, bool:override_only=false); + +/** + * Returns true if the supplied character is valid in a ConVar name. + * + * @param c Character to validate. + * @return True is valid for ConVars, false otherwise + */ +stock bool:IsValidConVarChar(c) +{ + return (c == '_' || IsCharAlpha(c) || IsCharNumeric(c)); +} diff --git a/plugins/randomcycle.sp b/plugins/randomcycle.sp new file mode 100644 index 00000000..8eb1cc81 --- /dev/null +++ b/plugins/randomcycle.sp @@ -0,0 +1,189 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Random Map Cycle Plugin + * Randomly picks a map from the mapcycle. + * + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#pragma semicolon 1 +#include + +public Plugin:myinfo = +{ + name = "RandomCycle", + author = "AlliedModders LLC", + description = "Randomly chooses the next map.", + version = SOURCEMOD_VERSION, + url = "http://www.sourcemod.net/" +}; + +new Handle:g_Cvar_Nextmap = INVALID_HANDLE; +new Handle:g_Cvar_Mapfile = INVALID_HANDLE; +new Handle:g_Cvar_ExcludeMaps = INVALID_HANDLE; + +new Handle:g_MapList = INVALID_HANDLE; +new Handle:g_OldMapList = INVALID_HANDLE; +new g_mapFileTime; + +public OnPluginStart() +{ + g_MapList = CreateArray(33); + g_OldMapList = CreateArray(33); + + g_Cvar_Mapfile = CreateConVar("sm_randomcycle_file", "configs/maps.ini", "Map file to use. (Def sourcemod/configs/maps.ini)"); + g_Cvar_ExcludeMaps = CreateConVar("sm_randomcycle_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0); + + AutoExecConfig(true, "randomcycle"); +} + +public OnMapStart() +{ + g_Cvar_Nextmap = FindConVar("sm_nextmap"); + + if (g_Cvar_Nextmap == INVALID_HANDLE) + { + LogError("FATAL: Cannot find sm_nextmap cvar. RandomCycle not loaded."); + SetFailState("sm_nextmap not found"); + } + + if (LoadMaps()) + { + CreateTimer(5.0, Timer_RandomizeNextmap); // Small delay to give Nextmap time to complete OnMapStart() + } +} + +public Action:Timer_RandomizeNextmap(Handle:timer) +{ + decl String:map[32]; + + new bool:oldMaps = false; + if (GetArraySize(g_MapList) > GetConVarInt(g_Cvar_ExcludeMaps)) + { + oldMaps = true; + } + + new b = GetRandomInt(0, GetArraySize(g_MapList) - 1); + GetArrayString(g_MapList, b, map, sizeof(map)); + + while (oldMaps && IsStringInArray(g_OldMapList, map)) + { + b = GetRandomInt(0, GetArraySize(g_MapList) - 1); + GetArrayString(g_MapList, b, map, sizeof(map)); + } + + SetConVarString(g_Cvar_Nextmap, map); + PushArrayString(g_OldMapList, map); + + if (GetArraySize(g_OldMapList) > GetConVarInt(g_Cvar_ExcludeMaps)) + { + RemoveFromArray(g_OldMapList, 0); + } + + LogMessage("RandomCycle has chosen %s for the nextmap.", map); + + return Plugin_Stop; +} + +LoadMaps() +{ + new bool:fileFound; + + decl String:mapPath[256], String:mapFile[64]; + GetConVarString(g_Cvar_Mapfile, mapFile, 64); + BuildPath(Path_SM, mapPath, sizeof(mapFile), mapFile); + fileFound = FileExists(mapPath); + if (!fileFound) + { + new Handle:mapCycleFile = FindConVar("mapcyclefile"); + GetConVarString(mapCycleFile, mapPath, sizeof(mapPath)); + fileFound = FileExists(mapPath); + } + + if (!fileFound) + { + LogError("Unable to locate sm_randomcycle_file or mapcyclefile, no maps loaded."); + + if (g_MapList != INVALID_HANDLE) + { + ClearArray(g_MapList); + } + + return 0; + } + + // If the file hasn't changed, there's no reason to reload + // all of the maps. + new fileTime = GetFileTime(mapPath, FileTime_LastChange); + if (g_mapFileTime == fileTime) + { + return GetArraySize(g_MapList); + } + + g_mapFileTime = fileTime; + + // Reset the array + if (g_MapList != INVALID_HANDLE) + { + ClearArray(g_MapList); + } + + LogMessage("[SM] Loading Random Cycle map file [%s]", mapPath); + + new Handle:file = OpenFile(mapPath, "rt"); + if (file == INVALID_HANDLE) + { + LogError("[SM] Could not open file: %s", mapPath); + return 0; + } + + decl String:currentMap[32]; + GetCurrentMap(currentMap, sizeof(currentMap)); + + decl String:buffer[64], len; + while (!IsEndOfFile(file) && ReadFileLine(file, buffer, sizeof(buffer))) + { + TrimString(buffer); + + if ((len = StrContains(buffer, ".bsp", false)) != -1) + { + buffer[len] = '\0'; + } + + if (buffer[0] == '\0' || !IsValidConVarChar(buffer[0]) || !IsMapValid(buffer) + || strcmp(currentMap, buffer, false) == 0) + { + continue; + } + + PushArrayString(g_MapList, buffer); + } + + CloseHandle(file); + return GetArraySize(g_MapList); +} \ No newline at end of file diff --git a/translations/basecomm.phrases.txt b/translations/basecomm.phrases.txt new file mode 100644 index 00000000..ef3484c2 --- /dev/null +++ b/translations/basecomm.phrases.txt @@ -0,0 +1,66 @@ +"Phrases" +{ + "Already Muted" + { + "en" "Target player is already muted." + "de" "Gewählte Zielperson ist bereits stummgeschaltet." + } + + "Player Muted" + { + "#format" "{1:s}" + "en" "{1} has been muted." + "de" "{1} wurde stummgeschaltet." + } + + "Player Not Muted" + { + "en" "Target player is not muted." + "de" "Gewählte Zielperson ist nicht stummgeschaltet." + } + + "Player Unmuted" + { + "#format" "{1:s}" + "en" "{1} has been unmuted." + "de" "{1} wurde die Sprache wiedergegeben." + } + + "Already Gagged" + { + "en" "Target player is already gagged." + "de" "Zielperson ist bereits geknebelt." + } + + "Player Gagged" + { + "#format" "{1:s}" + "en" "{1} has been gagged." + "de" "{1} wurde geknebelt." + } + + "Player Not Gagged" + { + "en" "Target player is not gagged." + "de" "Zielperson ist nicht geknebelt." + } + + "Player Ungagged" + { + "#format" "{1:s}" + "en" "{1} has been ungagged." + "de" "{1} wurde der Chat wieder freigeschaltet." + } + + "Already Silenced" + { + "en" "Target player is already silenced." + "de" "Zielperson schweigt bereites." + } + + "Player Not Silenced" + { + "en" "Target player is not silenced." + "de" "Zielperson ist schweigt nicht." + } +} \ No newline at end of file