/* * TK Police v1.0beta * * Author: <[NN]>Soul (sefanja_severin@hotmail.com, http://nn.kicks-ass.net/) * Ideas and code borrowed from Bud-froggy and [WHO]Them, all honor to them ;) * * Protects your server from lame TKers. * * * * Short description: * - Detect and response to team kills (TK) and team hurts (TH). * - Let the victim decide what to do with his TKer: kill, slap or forgive. * - Slay the TKer when he has reached the TK limit, and ban him (for a few * minutes) when he has exceeded the limit. * - By default, 100hp team damage triggers 1 extra TK warning. * * IMPORTANT: mp_logdetail should be set to 0, 2 or 3 if you want this script * IMPORTANT: to detect TH as well. * */ #include <core> #include <console> #include <string> #include <admin> #include <adminlib> #define ACCESS_CONSOLE 131072 #define ACCESS_FORGIVE 256 // Edit these // #define BAN_TIME 1 // Ban the TKer for ... minutes. 0 means permanent ban #define TH_DAMAGE_LIMIT 100 // Amount of health (not armor) a THer may damage before he gets an extra TK warning #define TK_LIMIT 3 // Number of unforgiven TKs that will be tolerated on your server during one map // // Stop editing new STRING_VERSION[MAX_DATA_LENGTH] = "1.0beta"; new TkCount[MAX_PLAYERS] = {0,...}; // Number of TK warnings (per player) new ThDamage[MAX_PLAYERS] = {0,...}; // Amount of hp damage caused (per player) new Attacker1 = 0; // PlayerIndex of player with most recent TK warning new Victim1 = 0; // PlayerIndex of most recent TK victim (not TH victim) new Attacker2 = 0; // PlayerIndex of player with 2nd most recent TK warning new Victim2 = 0; // PlayerIndex of 2nd most recent TK victim (not TH victim) /* * * * * * * * * * * * Helper Functions * * * * * * * * * * * */ forgiveTker(i) { // Description of this function: Forgive attacker // - Determine whom to forgive: attacker1 or attacker2 // - Check to see if both the victim and the attacker exist // - Substract 1 TK warning from the attacker's number of warnings so far // - Display a chat message: [TKPOLICE] <victim> has forgiven <attacker>. Warnings left: <i> // - Display the amount of warnings left, in the attacker's screen: Warnings left: <i> // - Let the server forget the victim as a victim, and the attacker as an attacker; they're ordinary players again new iIDA; new iIDV; new iSessionIDA; new sSessionIDA[MAX_NUMBER_LENGTH]; new NameA[MAX_NAME_LENGTH]; new NameV[MAX_NAME_LENGTH]; new Message[MAX_TEXT_LENGTH]; if (i==1) { iIDA = Attacker1; iIDV = Victim1; } else { iIDA = Attacker2; iIDV = Victim2; } if (iIDA == 0 || iIDV == 0) { return PLUGIN_CONTINUE; } if ( !playerinfo(iIDA,NameA,MAX_NAME_LENGTH,iSessionIDA) ) { return PLUGIN_CONTINUE; } numtostr(iSessionIDA, sSessionIDA); if ( !playerinfo(iIDV,NameV,MAX_NAME_LENGTH) ) { return PLUGIN_CONTINUE; } TkCount[iIDA] -= 1; snprintf(Message, MAX_TEXT_LENGTH, "[TKPOLICE] %s has forgiven %s. Warnings left: %i", NameV, NameA, TK_LIMIT - TkCount[iIDA]); say(Message); snprintf(Message, MAX_TEXT_LENGTH, "Warnings left: %i", TK_LIMIT - TkCount[iIDA]); messageex(sSessionIDA, Message, print_tty); if (i==1) { Victim1 = Victim2; Attacker1 = Attacker2; } Attacker2 = 0; Victim2 = 0; return PLUGIN_CONTINUE; } killTker(i) { // Description of this function: Slay attacker // - Determine whom to slay: attacker1 or attacker2 // - Check to see if both the victim and the attacker exist // - Slay the atacker // - Display a chat message: [TKPOLICE] <victim> decided to kill <attacker> for TK revenge // - Let the server forget the victim as a victim, and the attacker as an attacker; they're ordinary players again new iIDA; new iIDV; new iSessionIDA; new sSessionIDA[MAX_NUMBER_LENGTH]; new NameA[MAX_NAME_LENGTH]; new NameV[MAX_NAME_LENGTH]; new Message[MAX_TEXT_LENGTH]; if (i==1) { iIDA = Attacker1; iIDV = Victim1; } else { iIDA = Attacker2; iIDV = Victim2; } if (iIDA == 0 || iIDV == 0) { return PLUGIN_CONTINUE; } if ( !playerinfo(iIDA,NameA,MAX_NAME_LENGTH,iSessionIDA) ) { return PLUGIN_CONTINUE; } numtostr(iSessionIDA, sSessionIDA); if ( !playerinfo(iIDV,NameV,MAX_NAME_LENGTH) ) { return PLUGIN_CONTINUE; } slay(sSessionIDA); snprintf(Message,MAX_TEXT_LENGTH,"[TKPOLICE] %s decided to kill %s for TK revenge", NameV, NameA); say(Message); if (i==1) { Victim1 = Victim2; Attacker1 = Attacker2; } Attacker2 = 0; Victim2 = 0; return PLUGIN_CONTINUE; } slapTker(i) { // Description of this function: Slap attacker // - Determine whom to slap: attacker1 or attacker2 // - Check to see if both the victim and the attacker exist // - Slap the attacker 5 times / 30 hp // - Display a chat message: [TKPOLICE] <victim> decided to slap <attacker> 30 hp for TK revenge // - Let the server forget the victim as a victim, and the attacker as an attacker; they're ordinary players again new iIDA; new iIDV; new iSessionIDA; new sSessionIDA[MAX_NUMBER_LENGTH]; new NameA[MAX_NAME_LENGTH]; new NameV[MAX_NAME_LENGTH]; new Message[MAX_TEXT_LENGTH]; if (i==1) { iIDA = Attacker1; iIDV = Victim1; } else { iIDA = Attacker2; iIDV = Victim2; } if (iIDA == 0 || iIDV == 0) { return PLUGIN_CONTINUE; } if ( !playerinfo(iIDA,NameA,MAX_NAME_LENGTH,iSessionIDA) ) { return PLUGIN_CONTINUE; } numtostr(iSessionIDA, sSessionIDA); if ( !playerinfo(iIDV,NameV,MAX_NAME_LENGTH) ) { return PLUGIN_CONTINUE; } slap(sSessionIDA); slap(sSessionIDA); slap(sSessionIDA); slap(sSessionIDA); slap(sSessionIDA); slap(sSessionIDA); snprintf(Message,MAX_TEXT_LENGTH,"[TKPOLICE] %s decided to slap %s 30hp for TK revenge", NameV, NameA); say(Message); if (i==1) { Victim1 = Victim2; Attacker1 = Attacker2; } Attacker2 = 0; Victim2 = 0; return PLUGIN_CONTINUE; } thPunish(iIDA) { // Description of this function: Punish THer // - Add 1 TK warning to the attacker's number of TK warnings // - Based on the number of TK warnings, perform one the folowwing actions: // o Less then TK_LIMIT: Display a warning // o TK_LIMIT reached: kill the attacker // o TK_LIMIT exceeded: ban the attacker for BAN_TIME minutes new iSessionIDA; new sSessionIDA[MAX_NUMBER_LENGTH]; new NameA[MAX_NAME_LENGTH]; new Message[MAX_TEXT_LENGTH]; if ( !playerinfo(iIDA,NameA,MAX_NAME_LENGTH,iSessionIDA) ) { return PLUGIN_CONTINUE; } numtostr(iSessionIDA, sSessionIDA); TkCount[iIDA] += 1; if (TkCount[iIDA] < TK_LIMIT) { snprintf(Message, MAX_TEXT_LENGTH, "[TKPOLICE] %s: TK warning %i of %i (%ihp team damage)", NameA, TkCount[iIDA], TK_LIMIT, TH_DAMAGE_LIMIT); say(Message); snprintf(Message, MAX_TEXT_LENGTH, "TK warning %i of %i (%ihp team damage)", TkCount[iIDA], TK_LIMIT, TH_DAMAGE_LIMIT); messageex(sSessionIDA, Message, print_tty); } else if (TkCount[iIDA] == TK_LIMIT) { slay(NameA); snprintf(Message, MAX_TEXT_LENGTH, "[TKPOLICE] %s violated %i TK warnings (%ihp team damage)", NameA, TK_LIMIT, TH_DAMAGE_LIMIT); say(Message); snprintf(Message, MAX_TEXT_LENGTH, "You violated %i TK warnings (%ihp team damage)", TK_LIMIT, TH_DAMAGE_LIMIT); messageex(sSessionIDA, Message, print_tty); } else { snprintf(Message, MAX_TEXT_LENGTH, "[TKPOLICE] %s exceeded %i TK warnings (%ihp team damage)", NameA, TK_LIMIT, TH_DAMAGE_LIMIT); messageex(sSessionIDA, Message, print_console); say(Message); ban(sSessionIDA,BAN_TIME); } return PLUGIN_CONTINUE; } tkPunish(iIDA,iIDV) { // Description of this function: Punish TKer // - Add 1 TK warning to the attacker's number of TK warnings // - Based on the number of TK warnings, perform one the folowwing actions: // o Less than TK_LIMIT: Display a warning // o TK_LIMIT reached: kill the attacker // o TK_LIMIT exceeded: ban the attacker for BAN_TIME minutes // - Tell the server who are the last attacker and victim (so it knows on whom to perform future actions, like slap, slay or forgive) new iSessionIDA; new iSessionIDV; new sSessionIDA[MAX_NUMBER_LENGTH]; new sSessionIDV[MAX_NUMBER_LENGTH]; new NameA[MAX_NAME_LENGTH]; new NameV[MAX_NAME_LENGTH]; new Message[MAX_TEXT_LENGTH]; if ( !playerinfo(iIDA, NameA, MAX_NAME_LENGTH, iSessionIDA) ) { return PLUGIN_CONTINUE; } numtostr(iSessionIDA,sSessionIDA); if ( !playerinfo(iIDV, NameV, MAX_NAME_LENGTH, iSessionIDV) ) { return PLUGIN_CONTINUE; } numtostr(iSessionIDV,sSessionIDV); TkCount[iIDA] += 1; if (TkCount[iIDA] < TK_LIMIT) { snprintf(Message, MAX_TEXT_LENGTH, "[TKPOLICE] %s: TK warning %i of %i. %s may say !SLAP, !KILL or !FORGIVE.", NameA, TkCount[iIDA], TK_LIMIT, NameV); say(Message); snprintf(Message, MAX_TEXT_LENGTH, "TK warning %i of %i", TkCount[iIDA], TK_LIMIT); messageex(sSessionIDA, Message, print_tty); messageex(sSessionIDV, "Say !SLAP, !KILL or !FORGIVE", print_tty); } else if (TkCount[iIDA] == TK_LIMIT) { slay(sSessionIDA); snprintf(Message, MAX_TEXT_LENGTH, "[TKPOLICE] %s violated %i TK warnings. %s may say !FORGIVE.", NameA, TK_LIMIT, NameV); say(Message); snprintf(Message, MAX_TEXT_LENGTH, "You violated %i TK warnings", TK_LIMIT); messageex(sSessionIDA, Message, print_tty); messageex(sSessionIDV, "You may say !FORGIVE", print_tty); } else { snprintf(Message, MAX_TEXT_LENGTH, "[TKPOLICE] %s exceeded %i TK warnings", NameA, TK_LIMIT); messageex(sSessionIDA, Message, print_console); say(Message); ban(sSessionIDA,BAN_TIME); } Attacker2 = Attacker1; Victim2 = Victim1; Attacker1 = iIDA; Victim1 = iIDV; return PLUGIN_CONTINUE; } /* * * * * * * * * * * LogD Functions * * * * * * * * * * */ public logd_ThDetect(HLCommand,HLData,HLUserName,UserIndex) { // Description of this function: POLICE TH // - Fires when one player attacks another // - Reads the log line, and determines if it really was a team attack // - Adds the amount of hp damaged to the amount of hp the attacker already has damaged // - If the hp damage exceeds TH_DAmAGE_LIMIT, thPunish() is called // - TH damage of the attacker is reset to 0 new Data[MAX_DATA_LENGTH]; new iIDA; new iIDV; new sIDA[MAX_NUMBER_LENGTH]; new sIDV[MAX_NUMBER_LENGTH]; new Name[MAX_NAME_LENGTH]; new SessionID; new WONID; new TeamA; new TeamV; new iDamage; new sDamage[MAX_NUMBER_LENGTH]; new dummy[MAX_DATA_LENGTH]; new dummy1[MAX_DATA_LENGTH]; convert_string(HLData, Data, MAX_DATA_LENGTH); strsplit(Data, "#", dummy,MAX_DATA_LENGTH, dummy1,MAX_DATA_LENGTH); strsplit(dummy, " ", sIDA,MAX_NUMBER_LENGTH, sIDV,MAX_NUMBER_LENGTH); strsplit(dummy1, " ", sDamage,MAX_NUMBER_LENGTH); iIDA = strtonum(sIDA); iIDV = strtonum(sIDV); iDamage = strtonum(sDamage); if (iIDA == iIDV) { return PLUGIN_HANDLED; } if ( !playerinfo(iIDA,Name,MAX_NAME_LENGTH,SessionID,WONID,TeamA) ) { return PLUGIN_HANDLED; } if ( !playerinfo(iIDV,Name,MAX_NAME_LENGTH,SessionID,WONID,TeamV) ) { return PLUGIN_HANDLED; } if (TeamV != TeamA) { return PLUGIN_HANDLED; } ThDamage[iIDA] = ThDamage[iIDA] + iDamage; if (ThDamage[iIDA] > TH_DAMAGE_LIMIT) { thPunish(iIDA); ThDamage[iIDA] = 0; } return PLUGIN_HANDLED; } public logd_TkDetect(HLCommand,HLData,HLUserName,UserIndex) { // Description of this function: Detect TK // - Fires when one player kills another // - Reads the log line, and determines if it really was a TK // - tkPunish() is called new Data[MAX_DATA_LENGTH]; new iIDA; new iIDV; new sIDA[MAX_NUMBER_LENGTH]; new sIDV[MAX_NUMBER_LENGTH]; new Name[MAX_NAME_LENGTH]; new SessionID; new WONID; new TeamA; new TeamV; convert_string(HLData,Data,MAX_DATA_LENGTH); strsplit(Data, " ", sIDA,MAX_NUMBER_LENGTH, sIDV,MAX_NUMBER_LENGTH); iIDA = strtonum(sIDA); iIDV = strtonum(sIDV); if (iIDA == iIDV) { return PLUGIN_HANDLED; } if ( !playerinfo(iIDA,Name,MAX_NAME_LENGTH,SessionID,WONID,TeamA) ) { return PLUGIN_HANDLED; } if ( !playerinfo(iIDV,Name,MAX_NAME_LENGTH,SessionID,WONID,TeamV) ) { return PLUGIN_HANDLED; } if (TeamV != TeamA) { return PLUGIN_HANDLED; } tkPunish(iIDA,iIDV); return PLUGIN_HANDLED; } /* * * * * * * * * * * * * Admin Mod Functions * * * * * * * * * * * * */ public admin_forgivetk(HLCommand,HLData,HLUserName,UserIndex) { // Description of this function: Forgive attacker // - Determines whom to forgive: attacker1 or attacker2 // - forgiveTker() is called // - Echos the command as a chat message on the server new Command[MAX_COMMAND_LENGTH]; new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; convert_string(HLCommand, Command, MAX_COMMAND_LENGTH); convert_string(HLData, Data, MAX_DATA_LENGTH); convert_string(HLUserName, User, MAX_NAME_LENGTH); if ( strcmp(Data,"new") ) { forgiveTker(1); } else if ( strcmp(Data,"old") ) { forgiveTker(2); } else { selfmessage("Syntax: admin_forgivetk <old|new>"); return PLUGIN_HANDLED; } say_command(User,Command,Data); return PLUGIN_HANDLED; } /* * * * * * * * * * * * Handle Functions * * * * * * * * * * * */ public HandleSay(HLCommand,HLData,HLUserName,UserIndex) { // Description of this function: Let the victim decide what to do with his TKer // - Fires when a player says something // - Reads what the user says, if he says !slap, !kill or !forgive: // - The server will determine if the user really is a victim // - The right function will be called to perform an action on the victim's attacker new Data[MAX_DATA_LENGTH]; convert_string(HLData, Data, MAX_DATA_LENGTH); strstripquotes(Data); if (Data[0] != '!') { return PLUGIN_CONTINUE; } if ( strcasecmp(Data,"!forgive") == 0 ) { if (UserIndex == Victim1) { forgiveTker(1); } else if (UserIndex == Victim2) { forgiveTker(2); } } else if ( strcasecmp(Data,"!kill") == 0 ) { if (UserIndex == Victim1) { killTker(1); } else if (UserIndex == Victim2) { killTker(2); } } else if ( strcasecmp(Data,"!slap") == 0 ) { if (UserIndex == Victim1) { slapTker(1); } else if (UserIndex == Victim2) { slapTker(2); } } return PLUGIN_CONTINUE; } public plugin_connect(HLUserName, HLIP, UserIndex) { // Description of this function: Reset certain variables as players connect // - As players join the server, their TK warnings and stuff will be reset (actually not their own TK warnings, but the TK warnings of their slot) if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS) { TkCount[UserIndex] = 0; ThDamage[UserIndex] = 0; if (UserIndex == Attacker1 || UserIndex == Victim1) { Attacker1 = 0; Victim1 = 0; } if (UserIndex == Attacker2 || UserIndex == Victim2) { Attacker2 = 0; Victim2 = 0; } } return PLUGIN_CONTINUE; } public plugin_disconnect(HLUserName, UserIndex) { // Description of this function: Reset certain variables as players disconnect // - As players leave the server, their TK warnings and stuff will be reset (actually not their own TK warnings, but the TK warnings of their slot) if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS) { TkCount[UserIndex] = 0; ThDamage[UserIndex] = 0; if (UserIndex == Attacker1 || UserIndex == Victim1) { Attacker1 = 0; Victim1 = 0; } if (UserIndex == Attacker2 || UserIndex == Victim2) { Attacker2 = 0; Victim2 = 0; } } return PLUGIN_CONTINUE; } public plugin_init() { // Description of this function: Initialize this script // - Some plugin-register stuff // - Check the value of cvar mp_logdetail, and correct it if needed (this will not affect the server's log) new MpLogdetail; plugin_registerinfo("TK Police - by <[NN]>Soul", "Protects your server from lame TKers.", STRING_VERSION); plugin_registercmd("logd_TkDetect", "logd_TkDetect", ACCESS_CONSOLE, ""); plugin_registercmd("logd_ThDetect", "logd_ThDetect", ACCESS_CONSOLE, ""); plugin_registercmd("admin_forgivetk", "admin_forgivetk", ACCESS_FORGIVE, "admin_forgivetk <new|old>: forgives most or 2nd most recent TKer."); plugin_registercmd("say", "HandleSay", ACCESS_ALL, "say !kill, !slap or !forgive: what shall we do with your TKer?"); exec("logd_reg 57 admin_command logd_TkDetect"); exec("logd_reg 58 admin_command logd_ThDetect"); MpLogdetail = getvar("mp_logdetail"); if (MpLogdetail == 0) { setstrvar("mp_logdetail","2"); } else if (MpLogdetail == 1) { log("[TKPOLICE] Warning: mp_logdetail is set to 1. Please set it to 0, 2 or 3 so I can detect team hurts as well."); } return PLUGIN_CONTINUE; }