Skip to content

Instantly share code, notes, and snippets.

@shavitush
Created August 11, 2017 23:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shavitush/e9d707b3b92bab6d4668aba1cabb50dc to your computer and use it in GitHub Desktop.
Save shavitush/e9d707b3b92bab6d4668aba1cabb50dc to your computer and use it in GitHub Desktop.
#include <sourcemod>
#include <sdktools>
#pragma semicolon 1
#pragma newdecls required
#define PLUGIN_VERSION "1.0"
public Plugin myinfo =
{
name = "Simple AFK Captchas",
author = "shavit",
description = "Allows admins to send captchas to AFK players.",
version = PLUGIN_VERSION,
url = "http://forums.alliedmods.net/member.php?u=163134"
}
// Variables.
bool gB_Late;
char gS_LogFile[1024];
char gS_BeepSound[PLATFORM_MAX_PATH];
char gS_Answer[MAXPLAYERS+1][128];
// Handles.
Menu gH_MenuHandle[MAXPLAYERS+1];
Handle gH_CaptchaTimer[MAXPLAYERS+1];
Handle gH_AFKTimer[MAXPLAYERS+1];
bool gB_AFK[MAXPLAYERS+1];
ConVar gCV_Logging = null;
ArrayList gA_AFKers = null;
ArrayList gA_Solvers = null;
// Enumerator.
enum Captcha(+=1)
{
Captcha_XKCD,
Captcha_Multiplication,
Captcha_Additive
};
// Captcha types.
char gS_CaptchaTypes[][] =
{
"XKCD (random words)",
"Simple math (multiplication)",
"Simple math (addition)"
};
// Big list, I know.
char gS_WordList[][] =
{
"ability", "able", "aboard", "about", "above", "accept", "accident", "according",
"account", "accurate", "acres", "across", "act", "action", "active", "activity",
"actual", "actually", "add", "addition", "additional", "adjective", "adult", "adventure",
"advice", "affect", "afraid", "after", "afternoon", "again", "against", "age",
"ago", "agree", "ahead", "aid", "air", "airplane", "alike", "alive",
"all", "allow", "almost", "alone", "along", "aloud", "alphabet", "already",
"also", "although", "am", "among", "amount", "ancient", "angle", "angry",
"animal", "announced", "another", "answer", "ants", "any", "anybody", "anyone",
"anything", "anyway", "anywhere", "apart", "apartment", "appearance", "apple", "applied",
"appropriate", "are", "area", "arm", "army", "around", "arrange", "arrangement",
"arrive", "arrow", "art", "article", "as", "aside", "ask", "asleep",
"at", "ate", "atmosphere", "atom", "atomic", "attached", "attack", "attempt",
"attention", "audience", "author", "automobile", "available", "average", "avoid", "aware",
"away", "baby", "back", "bad", "badly", "bag", "balance", "ball",
"balloon", "band", "bank", "bar", "bare", "bark", "barn", "base",
"baseball", "basic", "basis", "basket", "bat", "battle", "be", "bean",
"bear", "beat", "beautiful", "beauty", "became", "because", "become", "becoming",
"bee", "been", "before", "began", "beginning", "begun", "behavior", "behind",
"being", "believed", "bell", "belong", "below", "belt", "bend", "beneath",
"bent", "beside", "best", "bet", "better", "between", "beyond", "bicycle",
"bigger", "biggest", "bill", "birds", "birth", "birthday", "bit", "bite",
"black", "blank", "blanket", "blew", "blind", "block", "blood", "blow",
"blue", "board", "boat", "body", "bone", "book", "border", "born",
"both", "bottle", "bottom", "bound", "bow", "bowl", "box", "boy",
"brain", "branch", "brass", "brave", "bread", "break", "breakfast", "breath",
"breathe", "breathing", "breeze", "brick", "bridge", "brief", "bright", "bring",
"broad", "broke", "broken", "brother", "brought", "brown", "brush", "buffalo",
"build", "building", "built", "buried", "burn", "burst", "bus", "bush",
"business", "busy", "but", "butter", "buy", "by", "cabin", "cage",
"cake", "call", "calm", "came", "camera", "camp", "can", "canal",
"cannot", "cap", "capital", "captain", "captured", "car", "carbon", "card",
"care", "careful", "carefully", "carried", "carry", "case", "cast", "castle",
"cat", "catch", "cattle", "caught", "cause", "cave", "cell", "cent",
"center", "central", "century", "certain", "certainly", "chain", "chair", "chamber",
"chance", "change", "changing", "chapter", "character", "characteristic", "charge", "chart",
"check", "cheese", "chemical", "chest", "chicken", "chief", "child", "children",
"choice", "choose", "chose", "chosen", "church", "circle", "circus", "citizen",
"city", "class", "classroom", "claws", "clay", "clean", "clear", "clearly",
"climate", "climb", "clock", "close", "closely", "closer", "cloth", "clothes",
"clothing", "cloud", "club", "coach", "coal", "coast", "coat", "coffee",
"cold", "collect", "college", "colony", "color", "column", "combination", "combine",
"come", "comfortable", "coming", "command", "common", "community", "company", "compare",
"compass", "complete", "completely", "complex", "composed", "composition", "compound", "concerned",
"condition", "congress", "connected", "consider", "consist", "consonant", "constantly", "construction",
"contain", "continent", "continued", "contrast", "control", "conversation", "cook", "cookies",
"cool", "copper", "copy", "corn", "corner", "correct", "correctly", "cost",
"cotton", "could", "count", "country", "couple", "courage", "course", "court",
"cover", "cow", "cowboy", "crack", "cream", "create", "creature", "crew",
"crop", "cross", "crowd", "cry", "cup", "curious", "current", "curve",
"customs", "cut", "cutting", "daily", "damage", "dance", "danger", "dangerous",
"dark", "darkness", "date", "daughter", "dawn", "day", "dead", "deal",
"dear", "death", "decide", "declared", "deep", "deeply", "deer", "definition",
"degree", "depend", "depth", "describe", "desert", "design", "desk", "detail",
"determine", "develop", "development", "diagram", "diameter", "did", "die", "differ",
"difference", "different", "difficult", "difficulty", "dig", "dinner", "direct", "direction",
"directly", "dirt", "dirty", "disappear", "discover", "discovery", "discuss", "discussion",
"disease", "dish", "distance", "distant", "divide", "division", "do", "doctor",
"does", "dog", "doing", "doll", "dollar", "done", "donkey", "door",
"dot", "double", "doubt", "down", "dozen", "draw", "drawn", "dream",
"dress", "drew", "dried", "drink", "drive", "driven", "driver", "driving",
"drop", "dropped", "drove", "dry", "duck", "due", "dug", "dull",
"during", "dust", "duty", "each", "eager", "ear", "earlier", "early",
"earn", "earth", "easier", "easily", "east", "easy", "eat", "eaten",
"edge", "education", "effect", "effort", "egg", "eight", "either", "electric",
"electricity", "element", "elephant", "eleven", "else", "empty", "end", "enemy",
"energy", "engine", "engineer", "enjoy", "enough", "enter", "entire", "entirely",
"environment", "equal", "equally", "equator", "equipment", "escape", "especially", "essential",
"establish", "even", "evening", "event", "eventually", "ever", "every", "everybody",
"everyone", "everything", "everywhere", "evidence", "exact", "exactly", "examine", "example",
"excellent", "except", "exchange", "excited", "excitement", "exciting", "exclaimed", "exercise",
"exist", "expect", "experience", "experiment", "explain", "explanation", "explore", "express",
"expression", "extra", "eye", "face", "facing", "fact", "factor", "factory",
"failed", "fair", "fairly", "fall", "fallen", "familiar", "family", "famous",
"far", "farm", "farmer", "farther", "fast", "fastened", "faster", "fat",
"father", "favorite", "fear", "feathers", "feature", "fed", "feed", "feel",
"feet", "fell", "fellow", "felt", "fence", "few", "fewer", "field",
"fierce", "fifteen", "fifth", "fifty", "fight", "fighting", "figure", "fill",
"film", "final", "finally", "find", "fine", "finest", "finger", "finish",
"fire", "fireplace", "firm", "first", "fish", "five", "fix", "flag",
"flame", "flat", "flew", "flies", "flight", "floating", "floor", "flow",
"flower", "fly", "fog", "folks", "follow", "food", "foot", "football",
"for", "force", "foreign", "forest", "forget", "forgot", "forgotten", "form",
"former", "fort", "forth", "forty", "forward", "fought", "found", "four",
"fourth", "fox", "frame", "free", "freedom", "frequently", "fresh", "friend",
"friendly", "frighten", "frog", "from", "front", "frozen", "fruit", "fuel",
"full", "fully", "fun", "function", "funny", "fur", "furniture", "further",
"future", "gain", "game", "garage", "garden", "gas", "gasoline", "gate",
"gather", "gave", "general", "generally", "gentle", "gently", "get", "getting",
"giant", "gift", "girl", "give", "given", "giving", "glad", "glass",
"globe", "go", "goes", "gold", "golden", "gone", "good", "goose",
"got", "government", "grabbed", "grade", "gradually", "grain", "grandfather", "grandmother",
"graph", "grass", "gravity", "gray", "great", "greater", "greatest", "greatly",
"green", "grew", "ground", "group", "grow", "grown", "growth", "guard",
"guess", "guide", "gulf", "gun", "habit", "had", "hair", "half",
"halfway", "hall", "hand", "handle", "handsome", "hang", "happen", "happened",
"happily", "happy", "harbor", "hard", "harder", "hardly", "has", "hat",
"have", "having", "hay", "he", "headed", "heading", "health", "heard",
"hearing", "heart", "heat", "heavy", "height", "held", "hello", "help",
"helpful", "her", "herd", "here", "herself", "hidden", "hide", "high",
"higher", "highest", "highway", "hill", "him", "himself", "his", "history",
"hit", "hold", "hole", "hollow", "home", "honor", "hope", "horn",
"horse", "hospital", "hot", "hour", "house", "how", "however", "huge",
"human", "hundred", "hung", "hungry", "hunt", "hunter", "hurried", "hurry",
"hurt", "husband", "ice", "idea", "identity", "if", "ill", "image",
"imagine", "immediately", "importance", "important", "impossible", "improve", "in", "inch",
"include", "including", "income", "increase", "indeed", "independent", "indicate", "individual",
"industrial", "industry", "influence", "information", "inside", "instance", "instant", "instead",
"instrument", "interest", "interior", "into", "introduced", "invented", "involved", "iron",
"is", "island", "it", "its", "itself", "jack", "jar", "jet",
"job", "join", "joined", "journey", "joy", "judge", "jump", "jungle",
"just", "keep", "kept", "key", "kids", "kill", "kind", "kitchen",
"knew", "knife", "know", "knowledge", "known", "label", "labor", "lack",
"lady", "laid", "lake", "lamp", "land", "language", "large", "larger",
"largest", "last", "late", "later", "laugh", "law", "lay", "layers",
"lead", "leader", "leaf", "learn", "least", "leather", "leave", "leaving",
"led", "left", "leg", "length", "lesson", "let", "letter", "level",
"library", "lie", "life", "lift", "light", "like", "likely", "limited",
"line", "lion", "lips", "liquid", "list", "listen", "little", "live",
"living", "load", "local", "locate", "location", "log", "lonely", "long",
"longer", "look", "loose", "lose", "loss", "lost", "lot", "loud",
"love", "lovely", "low", "lower", "luck", "lucky", "lunch", "lungs",
"lying", "machine", "machinery", "mad", "made", "magic", "magnet", "mail",
"main", "mainly", "major", "make", "making", "man", "managed", "manner",
"manufacturing", "many", "map", "mark", "market", "married", "mass", "massage",
"master", "material", "mathematics", "matter", "may", "maybe", "me", "meal",
"mean", "means", "meant", "measure", "meat", "medicine", "meet", "melted",
"member", "memory", "men", "mental", "merely", "met", "metal", "method",
"mice", "middle", "might", "mighty", "mile", "military", "milk", "mill",
"mind", "mine", "minerals", "minute", "mirror", "missing", "mission", "mistake",
"mix", "mixture", "model", "modern", "molecular", "moment", "money", "monkey",
"month", "mood", "moon", "more", "morning", "most", "mostly", "mother",
"motion", "motor", "mountain", "mouse", "mouth", "move", "movement", "movie",
"moving", "mud", "muscle", "music", "musical", "must", "my", "myself",
"mysterious", "nails", "name", "nation", "national", "native", "natural", "naturally",
"nature", "near", "nearby", "nearer", "nearest", "nearly", "necessary", "neck",
"needed", "needle", "needs", "negative", "neighbor", "neighborhood", "nervous", "nest",
"never", "new", "news", "newspaper", "next", "nice", "night", "nine",
"no", "nobody", "nodded", "noise", "none", "noon", "nor", "north",
"nose", "not", "note", "noted", "nothing", "notice", "noun", "now",
"number", "numeral", "nuts", "object", "observe", "obtain", "occasionally", "occur",
"ocean", "of", "off", "offer", "office", "officer", "official", "oil",
"old", "older", "oldest", "on", "once", "one", "only", "onto",
"open", "operation", "opinion", "opportunity", "opposite", "or", "orange", "orbit",
"order", "ordinary", "organization", "organized", "origin", "original", "other", "ought",
"our", "ourselves", "out", "outer", "outline", "outside", "over", "own",
"owner", "oxygen", "pack", "package", "page", "paid", "pain", "paint",
"pair", "palace", "pale", "pan", "paper", "paragraph", "parallel", "parent",
"park", "part", "particles", "particular", "particularly", "partly", "parts", "party",
"pass", "passage", "past", "path", "pattern", "pay", "peace", "pen",
"pencil", "people", "per", "percent", "perfect", "perfectly", "perhaps", "period",
"person", "personal", "pet", "phrase", "physical", "piano", "pick", "picture",
"pictured", "pie", "piece", "pig", "pile", "pilot", "pine", "pink",
"pipe", "pitch", "place", "plain", "plan", "plane", "planet", "planned",
"planning", "plant", "plastic", "plate", "plates", "play", "pleasant", "please",
"pleasure", "plenty", "plural", "plus", "pocket", "poem", "poet", "poetry",
"point", "pole", "police", "policeman", "political", "pond", "pony", "pool",
"poor", "popular", "population", "porch", "port", "position", "positive", "possible",
"possibly", "post", "pot", "potatoes", "pound", "pour", "powder", "power",
"powerful", "practical", "practice", "prepare", "present", "president", "press", "pressure",
"pretty", "prevent", "previous", "price", "pride", "primitive", "principal", "principle",
"printed", "private", "prize", "probably", "problem", "process", "produce", "product",
"production", "program", "progress", "promised", "proper", "properly", "property", "protection",
"proud", "prove", "provide", "public", "pull", "pupil", "pure", "purple",
"purpose", "push", "put", "putting", "quarter", "queen", "question", "quick",
"quickly", "quiet", "quietly", "quite", "rabbit", "race", "radio", "railroad",
"rain", "raise", "ran", "ranch", "range", "rapidly", "rate", "rather",
"raw", "rays", "reach", "read", "reader", "ready", "real", "realize",
"rear", "reason", "recall", "receive", "recent", "recently", "recognize", "record",
"red", "refer", "refused", "region", "regular", "related", "relationship", "religious",
"remain", "remarkable", "remember", "remove", "repeat", "replace", "replied", "report",
"represent", "require", "research", "respect", "rest", "result", "return", "review",
"rhyme", "rhythm", "rice", "rich", "ride", "riding", "right", "ring",
"rise", "rising", "river", "road", "roar", "rock", "rocket", "rocky",
"rod", "roll", "roof", "room", "root", "rope", "rose", "rough",
"round", "route", "row", "rubbed", "rubber", "rule", "ruler", "run",
"running", "rush", "sad", "saddle", "safe", "safety", "said", "sail",
"sale", "salmon", "salt", "same", "sand", "sang", "sat", "satellites",
"satisfied", "save", "saved", "saw", "say", "scale", "scared", "scene",
"school", "science", "scientific", "scientist", "score", "screen", "sea", "search",
"season", "seat", "second", "secret", "section", "see", "seed", "seeing",
"seems", "seen", "seldom", "select", "selection", "sell", "send", "sense",
"sent", "sentence", "separate", "series", "serious", "serve", "service", "sets",
"setting", "settle", "settlers", "seven", "several", "shade", "shadow", "shake",
"shaking", "shall", "shallow", "shape", "share", "sharp", "she", "sheep",
"sheet", "shelf", "shells", "shelter", "shine", "shinning", "ship", "shirt",
"shoe", "shoot", "shop", "shore", "short", "shorter", "shot", "should",
"shoulder", "shout", "show", "shown", "shut", "sick", "sides", "sight",
"sign", "signal", "silence", "silent", "silk", "silly", "silver", "similar",
"simple", "simplest", "simply", "since", "sing", "single", "sink", "sister",
"sit", "sitting", "situation", "six", "size", "skill", "skin", "sky",
"slabs", "slave", "sleep", "slept", "slide", "slight", "slightly", "slip",
"slipped", "slope", "slow", "slowly", "small", "smaller", "smallest", "smell",
"smile", "smoke", "smooth", "snake", "snow", "so", "soap", "social",
"society", "soft", "softly", "soil", "solar", "sold", "soldier", "solid",
"solution", "solve", "some", "somebody", "somehow", "someone", "something", "sometime",
"somewhere", "son", "song", "soon", "sort", "sound", "source", "south",
"southern", "space", "speak", "special", "species", "specific", "speech", "speed",
"spell", "spend", "spent", "spider", "spin", "spirit", "spite", "split",
"spoken", "sport", "spread", "spring", "square", "stage", "stairs", "stand",
"standard", "star", "stared", "start", "state", "statement", "station", "stay",
"steady", "steam", "steel", "steep", "stems", "step", "stepped", "stick",
"stiff", "still", "stock", "stomach", "stone", "stood", "stop", "stopped",
"store", "storm", "story", "stove", "straight", "strange", "stranger", "straw",
"stream", "street", "strength", "stretch", "strike", "string", "strip", "strong",
"stronger", "struck", "structure", "struggle", "stuck", "student", "studied", "studying",
"subject", "substance", "success", "successful", "such", "sudden", "suddenly", "sugar",
"suggest", "suit", "sum", "summer", "sun", "sunlight", "supper", "supply",
"support", "suppose", "sure", "surface", "surprise", "surrounded", "swam", "sweet",
"swept", "swim", "swimming", "swing", "swung", "syllable", "symbol", "system",
"table", "tail", "take", "taken", "tales", "talk", "tall", "tank",
"tape", "task", "taste", "taught", "tax", "tea", "teach", "teacher",
"team", "tears", "teeth", "telephone", "television", "tell", "temperature", "ten",
"tent", "term", "terrible", "test", "than", "thank", "that", "thee",
"them", "themselves", "then", "theory", "there", "therefore", "these", "they",
"thick", "thin", "thing", "think", "third", "thirty", "this", "those",
"thou", "though", "thought", "thousand", "thread", "three", "threw", "throat",
"through", "throughout", "throw", "thrown", "thumb", "thus", "thy", "tide",
"tie", "tight", "tightly", "till", "time", "tin", "tiny", "tip",
"tired", "title", "to", "tobacco", "today", "together", "told", "tomorrow",
"tone", "tongue", "tonight", "too", "took", "tool", "top", "topic",
"torn", "total", "touch", "toward", "tower", "town", "toy", "trace",
"track", "trade", "traffic", "trail", "train", "transportation", "trap", "travel",
"treated", "tree", "triangle", "tribe", "trick", "tried", "trip", "troops",
"tropical", "trouble", "truck", "trunk", "truth", "try", "tube", "tune",
"turn", "twelve", "twenty", "twice", "two", "type", "typical", "uncle",
"under", "underline", "understanding", "unhappy", "union", "unit", "universe", "unknown",
"unless", "until", "unusual", "up", "upon", "upper", "upward", "us",
"use", "useful", "using", "usual", "usually", "valley", "valuable", "value",
"vapor", "variety", "various", "vast", "vegetable", "verb", "vertical", "very",
"vessels", "victory", "view", "village", "visit", "visitor", "voice", "volume",
"vote", "vowel", "voyage", "wagon", "wait", "walk", "wall", "want",
"war", "warm", "warn", "was", "wash", "waste", "watch", "water",
"wave", "way", "we", "weak", "wealth", "wear", "weather", "week",
"weigh", "weight", "welcome", "well", "went", "were", "west", "western",
"wet", "whale", "what", "whatever", "wheat", "wheel", "when", "whenever",
"where", "wherever", "whether", "which", "while", "whispered", "whistle", "white",
"who", "whole", "whom", "whose", "why", "wide", "widely", "wife",
"wild", "will", "willing", "win", "wind", "window", "wing", "winter",
"wire", "wise", "wish", "with", "within", "without", "wolf", "women",
"won", "wonder", "wonderful", "wood", "wooden", "wool", "word", "wore",
"work", "worker", "world", "worried", "worry", "worse", "worth", "would",
"wrapped", "write", "writer", "writing", "written", "wrong", "wrote", "yard",
"year", "yellow", "yes", "yesterday", "yet", "you", "young", "younger",
"your", "yourself", "youth", "zero", "zoo"
};
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
gB_Late = late;
return APLRes_Success;
}
public void OnPluginStart()
{
// Late-load support.
if(gB_Late)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClientTiny(i))
{
OnClientPutInServer(i);
}
}
}
// Console variables.
CreateConVar("afk_captcha_version", PLUGIN_VERSION, "Plugin version.", FCVAR_NOTIFY|FCVAR_DONTRECORD);
gCV_Logging = CreateConVar("afk_captcha_logging", "1", "Log kicks to \"addons/sourcemod/logs/afk_captcha.log\"?");
AutoExecConfig();
// Commands.
RegConsoleCmd("sm_afk", Command_AFK, "Marks yourself as away for a certain amount of time, up to 90 seconds. Usage: sm_afk <duration>");
RegConsoleCmd("sm_idle", Command_AFK, "Marks yourself as away for a certain amount of time, up to 90 seconds. Usage: sm_idle <duration> (alias for \"sm_afk\")");
RegConsoleCmd("sm_away", Command_AFK, "Marks yourself as away for a certain amount of time, up to 90 seconds. Usage: sm_away <duration> (alias for \"sm_afk\")");
RegAdminCmd("sm_captcha", Command_Captcha, ADMFLAG_KICK, "Sends a captcha to an idle player. Usage: sm_captcha <target>");
// Translations.
LoadTranslations("common.phrases");
// Logging.
BuildPath(Path_SM, gS_LogFile, 1024, "logs/afk_captcha.log");
// Advertise !afk command.
CreateTimer(600.0, Timer_Advertise, 0, TIMER_REPEAT);
// Arrays.
gA_AFKers = new ArrayList(32);
gA_Solvers = new ArrayList(32);
}
public void OnMapStart()
{
// Beep sounds.
Handle hConfig = LoadGameConfigFile("funcommands.games");
if(hConfig == null)
{
SetFailState("Unable to load game config funcommands.games");
return;
}
if(GameConfGetKeyValue(hConfig, "SoundBeep", gS_BeepSound, PLATFORM_MAX_PATH) && gS_BeepSound[0])
{
PrecacheSound(gS_BeepSound, true);
}
// Clear arrays list.
gA_AFKers.Clear();
gA_Solvers.Clear();
}
public void OnClientDisconnect(int client)
{
FinishCaptcha(client, false);
}
public void OnClientPutInServer(int client)
{
FinishCaptcha(client, false);
}
public Action Timer_Advertise(Handle timer)
{
PrintToChatAll("\x04[SM]\x01 You may write \x05!afk [seconds]\x01 to mark yourself as AFK for a certain time, up to 90 seconds. During that time, captchas will not be forced on you!");
return Plugin_Continue;
}
public Action Timer_NukeClient(Handle timer, any data)
{
int client = GetClientFromSerial(data);
if(client == 0)
{
return;
}
if(gCV_Logging.BoolValue)
{
LogToFile(gS_LogFile, "%L - Kicked for being AFK or not solving the captcha in time.", client);
}
KickClient(client, "You were kicked for being AFK or not solving the captcha in time.");
gH_CaptchaTimer[client] = null;
gH_MenuHandle[client] = null;
}
public Action Command_AFK(int client, int args)
{
if(client == 0)
{
return Plugin_Handled;
}
char[] authid = new char[32];
GetClientAuthId(client, AuthId_Steam3, authid, 32);
if(gA_AFKers.FindString(authid) != -1 || gB_AFK[client])
{
ReplyToCommand(client, "[SM] You have already marked yourself as AFK before.");
return Plugin_Handled;
}
if(args == 0)
{
char[] sCommand = new char[16];
GetCmdArg(0, sCommand, 16);
ReplyToCommand(client, "[SM] Usage: %s <duration>", sCommand);
ReplyToCommand(client, "[SM] Warning: This command can be only used once per map!");
return Plugin_Handled;
}
char[] sTime = new char[8];
GetCmdArg(1, sTime, 8);
float seconds = StringToFloat(sTime);
if(seconds >= 90.0 || seconds < 15.0)
{
ReplyToCommand(client, "[SM] You cannot mark yourself as AFK for more than 90 seconds or less than 15 seconds.");
return Plugin_Handled;
}
gA_AFKers.PushString(authid);
gH_AFKTimer[client] = CreateTimer(seconds, Timer_AFK, GetClientSerial(client));
gB_AFK[client] = true;
PrintToChatAll("\x04[SM] \x03%N\x01 has marked themselves as AFK for \x04%d seconds\x01.", client, RoundToFloor(seconds));
return Plugin_Handled;
}
public Action Timer_AFK(Handle timer, any data)
{
int client = GetClientFromSerial(data);
if(client > 0)
{
gB_AFK[client] = false;
gH_AFKTimer[client] = null;
PrintToChat(client, "\x04[SM]\x01 You are not marked as AFK anymore.");
}
return Plugin_Stop;
}
public Action Command_Captcha(int client, int args)
{
if(args == 0)
{
char[] sCommand = new char[16];
GetCmdArg(0, sCommand, 16);
ReplyToCommand(client, "[SM] Usage: %s <target>", sCommand);
return Plugin_Handled;
}
char[] sTarget = new char[MAX_TARGET_LENGTH];
GetCmdArgString(sTarget, MAX_TARGET_LENGTH);
int target = FindTarget(client, sTarget, true, false);
if(target == -1)
{
return Plugin_Handled;
}
if(CheckCommandAccess(target, "afk-captcha", ADMFLAG_KICK))
{
ReplyToCommand(client, "[SM] \x03%N\x01 is immune to captchas.", target);
return Plugin_Handled;
}
char[] authid = new char[32];
GetClientAuthId(target, AuthId_Steam3, authid, 32);
if(gA_Solvers.FindString(authid) != -1)
{
ReplyToCommand(client, "[SM] \x03%N\x01 has already solved a captcha, you may not make them solve another one.", target);
return Plugin_Handled;
}
if(gB_AFK[target])
{
ReplyToCommand(client, "[SM] \x03%N\x01 had declared themselves as AFK, you may not make them solve a captcha.", target);
return Plugin_Handled;
}
SendCaptcha(client, target);
return Plugin_Handled;
}
void SendCaptcha(int client, int target)
{
ShowActivity(client, "Sent a captcha to %N.", target);
LogAction(client, target, "%L has sent a captcha to %L.", client, target);
float pos[3];
GetClientEyePosition(target, pos);
EmitAmbientSound(gS_BeepSound, pos, target, SNDLEVEL_RAIDSIREN);
gH_MenuHandle[target] = new Menu(MenuHandler_Captcha);
gH_MenuHandle[target].SetTitle("[Captcha] You have been hit by a captcha!\n\nSolve it by replying in chat, failure to solve the captcha in 30 seconds\nwill result in getting kicked from the game server.\n");
Captcha captcha = view_as<Captcha>(RealRandomInt(0, 2));
char[] type = new char[64];
FormatEx(type, 64, "Captcha type: %s\n", gS_CaptchaTypes[captcha]);
gH_MenuHandle[target].AddItem("0", type);
switch(captcha)
{
case Captcha_XKCD:
{
GenerateXKCD(gS_Answer[target], 128);
char[] sDisplay = new char[192];
FormatEx(sDisplay, 192, "Write the following phrase: %s", gS_Answer[target]);
gH_MenuHandle[target].AddItem("0", sDisplay);
PrintToChat(target, "\x04[SM] CAPTCHA! \x05Write the following phrase in 30 seconds: \x03%s\x05", gS_Answer[target]);
}
case Captcha_Additive, Captcha_Multiplication:
{
int num1 = RealRandomInt(1, 9);
int num2 = RealRandomInt(1, 9);
if(captcha == Captcha_Additive)
{
IntToString(num1 + num2, gS_Answer[target], 128);
}
else
{
IntToString(num1 * num2, gS_Answer[target], 128);
}
char[] sQuestion = new char[16];
FormatEx(sQuestion, 16, "%d %c %d = ?", num1, (captcha == Captcha_Additive)? '+':'*', num2);
char[] sDisplay = new char[192];
FormatEx(sDisplay, 192, "Solve the following: %s", sQuestion);
gH_MenuHandle[target].AddItem("0", sDisplay);
PrintToChat(target, "\x04[SM] CAPTCHA! \x05Solve the following question in 30 seconds: \x03%s", sQuestion);
}
}
gH_MenuHandle[target].ExitButton = false;
gH_MenuHandle[target].Display(target, 30);
gH_CaptchaTimer[target] = CreateTimer(30.0, Timer_NukeClient, GetClientSerial(target), TIMER_FLAG_NO_MAPCHANGE);
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs)
{
if(strlen(gS_Answer[client]) > 0)
{
if(StrEqual(sArgs, gS_Answer[client]))
{
FinishCaptcha(client, true);
}
return Plugin_Handled;
}
return Plugin_Continue;
}
void FinishCaptcha(int client, bool solved)
{
if(gH_MenuHandle[client] != null)
{
delete gH_MenuHandle[client];
gH_MenuHandle[client] = null;
}
if(gH_CaptchaTimer[client] != null)
{
delete gH_CaptchaTimer[client];
gH_CaptchaTimer[client] = null;
}
if(gH_AFKTimer[client] != null)
{
delete gH_AFKTimer[client];
gH_AFKTimer[client] = null;
}
gB_AFK[client] = false;
strcopy(gS_Answer[client], 128, "");
if(solved && IsValidClientTiny(client))
{
PrintToChat(client, "[SM] Thank you for solving the captcha! You will not receive any captchas for the current map anymore.");
char[] authid = new char[32];
GetClientAuthId(client, AuthId_Steam3, authid, 32);
gA_Solvers.PushString(authid);
}
}
public int MenuHandler_Captcha(Menu menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_End)
{
delete menu;
}
return 0;
}
/* int RealRandomInt(int min, int max)
Generates an XKCD-styled phrase made of 3 random oftenly used words.
*/
void GenerateXKCD(char[] buffer, int size)
{
strcopy(buffer, size, "");
for(int i = 1; i <= 3; i++)
{
Format(buffer, size, "%s%s ", buffer, gS_WordList[RealRandomInt(0, sizeof(gS_WordList))]);
}
TrimString(buffer);
}
/* int RealRandomInt(int min, int max)
Generates a completely random number. Can be safely ran multiple times per tick!
*/
int RealRandomInt(int min, int max)
{
int random = GetURandomInt();
if(random == 0)
{
random++;
}
return RoundToCeil(float(random) / (float(2147483647) / float(max - min + 1))) + min - 1;
}
/* bool IsValidClientTiny(int client, bool alive)
Checks validity for clients. Those clients will rarely throw errors when used in fuctions, if ever.
*/
stock bool IsValidClientTiny(int client)
{
return IsClientConnected(client) && IsClientInGame(client);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment