#include "bzfsAPI.h" #include #include #include #include #include #include BZ_GET_PLUGIN_VERSION class progFlag : public bz_EventHandler, public bz_CustomSlashCommandHandler { public: virtual void process(bz_EventData *eventData); virtual bool handle(int playerID, bzApiString msg, bzApiString cmd, bzAPIStringList*); bool oops; int levels[256]; std::string flags [256]; int kills[256]; int level[256]; int queue[256]; int maxLevel; bool giveOnTK; std::string deathmsg[4]; bool rogueTK; int dontGive[256]; int delay; void giveFlag(int playerID); bool readConf(const char* confFile); void readArg(std::string arg); std::vector* explode(std::string src, char s); int strToInt(std::string src, int returnIfError); void trim(std::string& str); void removeBlanks(std::vector& arr); std::string strtoupper(std::string str); const char* flagName(std::string flagAbbrev); int getTimeInSeconds(); void str_replace(std::string& string, const char* _find, const char* _replace); }; progFlag pf; BZF_PLUGIN_CALL int bz_Load (const char* confFile) { pf.maxLevel = 2; pf.giveOnTK = false; pf.deathmsg[0] = "Level %level%: %flag% (%kills% more kill%s% until level %nextlev%)"; pf.deathmsg[1] = "Level %level% (%kills% more kill%s% until level %nextlev%)"; pf.deathmsg[2] = "Level %level%: %flag% (Pwnage!)"; pf.deathmsg[3] = "Level %level% (Still pwning!)"; pf.rogueTK = false; delay = 30; if (pf.readConf(confFile)) { bz_registerCustomSlashCommand("pf", &pf); bz_registerEvent(bz_ePlayerDieEvent, &pf); bz_registerEvent(bz_ePlayerJoinEvent, &pf); bz_registerEvent(bz_ePlayerSpawnEvent, &pf); bz_registerEvent(bz_eTickEvent, &pf); bz_debugMessage(0, "Progressive Flag Plug-in: Loaded"); bz_setMaxWaitTime(0.1f); } else { bz_debugMessage(0, "Progressive Flag Plug-in: Could not be loaded, configuration file error"); pf.oops = true; } return 0; } BZF_PLUGIN_CALL int bz_Unload (void) { if (!pf.oops) { bz_removeCustomSlashCommand("pf"); bz_removeEvent(bz_ePlayerDieEvent, &pf); bz_removeEvent(bz_ePlayerJoinEvent, &pf); bz_removeEvent(bz_ePlayerSpawnEvent, &pf); bz_removeEvent(bz_eTickEvent, &pf); bz_debugMessage(0, "Progressive Flag Plug-in: Unloaded"); } return 0; } void progFlag::process(bz_EventData *eventData) { if (eventData->eventType == bz_ePlayerDieEvent) { bz_PlayerDieEventData *dieData = (bz_PlayerDieEventData*)eventData; bz_PlayerRecord *pr = bz_getPlayerByIndex(dieData->killerID); bool dontGive; if (!pr) { bz_freePlayerRecord(pr); return; } if (dieData->killerID == dieData->playerID) { // Do nothing. } else if (dieData->killerTeam == dieData->team && (dieData->team != eRogueTeam || pf.rogueTK)) { if (pf.level[dieData->killerID] > -1) { pf.kills[dieData->killerID] = -1; pf.level[dieData->killerID] = -1; } else { --pf.kills[dieData->killerID]; } if (pf.giveOnTK && pr->spawned) { if (pf.queue[dieData->killerID] == 0) pf.queue[dieData->killerID] = 1; } } else { if (++pf.kills[dieData->killerID] == pf.levels[pf.level[dieData->killerID] + 2]) { pf.kills[dieData->killerID] = 0; ++pf.level[dieData->killerID]; if (pr->spawned) { if (pr->currentFlag == "Oscillation Overthruster (+OO)" || pr->currentFlag == "Red team flag" || pr->currentFlag == "Green team flag" || pr->currentFlag == "Blue team flag" || pr->currentFlag == "Purple team flag" ) { if (pf.dontGive[dieData->killerID] == 0) pf.dontGive[dieData->killerID] = 1; pf.giveFlag(dieData->killerID); } else if (pr->currentFlag == "") { pf.giveFlag(dieData->killerID); } else { if (pf.queue[dieData->killerID] == 0) pf.queue[dieData->killerID] = 1; } } } else { pf.giveFlag(dieData->killerID); } } bz_freePlayerRecord(pr); } else if (eventData->eventType == bz_ePlayerJoinEvent) { bz_PlayerJoinPartEventData *joinData = (bz_PlayerJoinPartEventData*)eventData; pf.kills[joinData->playerID] = 0; pf.level[joinData->playerID] = 0; pf.queue[joinData->playerID] = 0; pf.dontGive[joinData->playerID] = 0; } else if (eventData->eventType == bz_ePlayerSpawnEvent) { bz_PlayerSpawnEventData *spawnData = (bz_PlayerSpawnEventData*)eventData; if (pf.dontGive[spawnData->playerID] == 1) pf.dontGive[spawnData->playerID] = 0; if (pf.level[spawnData->playerID] > -1) { pf.kills[spawnData->playerID] = 0; pf.level[spawnData->playerID] = 0; } pf.giveFlag(spawnData->playerID); } else if (eventData->eventType == bz_eTickEvent) { for (int i = 0; i < 256; i++) { if (pf.queue[i] >= pf.delay) { pf.giveFlag(i); pf.queue[i] = 0; } else if (pf.queue[i] > 0) { if (pf.dontGive[i] == 0) bz_removePlayerFlag(i); pf.queue[i]++; } } } return; } bool progFlag::handle(int playerID, bzApiString msg, bzApiString cmd, bzAPIStringList*) { if (cmd == "on") { if (pf.dontGive[playerID] != 2) { bz_sendTextMessage(BZ_SERVER, playerID, "The plug-in will stop giving new flags to you."); pf.dontGive[playerID] = 2; } else { bz_sendTextMessage(BZ_SERVER, playerID, "The plug-in already stopped giving new flags to you."); } } else if (cmd == "off") { if (pf.dontGive[playerID] == 2) { bz_sendTextMessage(BZ_SERVER, playerID, "The plug-in will start giving new flags to you."); pf.dontGive[playerID] = 0; } else { bz_sendTextMessage(BZ_SERVER, playerID, "The plug-in already gives new flags to you."); } } else { bz_sendTextMessage(BZ_SERVER, playerID, "Usage: /pf on|off"); } return true; } void progFlag::giveFlag(int playerID) { bz_PlayerRecord *pr = bz_getPlayerByIndex(playerID); if (!pr) { bz_freePlayerRecord(pr); return; } else { bool spawned = (pr->spawned); bz_freePlayerRecord(pr); if (!spawned) return; } int kills = pf.kills[playerID]; int level = pf.level[playerID]; std::string message; if (level > -1) { std::string flag; int nextkills = pf.levels[level + 2] - kills; int nextlevel = level + 1; const char* plural = (nextkills == 1) ? "" : "s"; if (kills == 0) { std::string::size_type multiFlags = pf.flags[level + 1].find(' ', 0); if (multiFlags == std::string::npos) { flag = pf.flags[level + 1]; } else { srand((unsigned)pf.getTimeInSeconds()); std::vector* flags = pf.explode(pf.flags[level + 1], ' '); pf.removeBlanks(*flags); int random = rand() % flags->size(); flag = flags->at(random); delete flags; } if (pf.levels[level + 2] > 0) { message = pf.deathmsg[0]; } else { message = pf.deathmsg[2]; } if (pf.dontGive[playerID] == 0) { bz_givePlayerFlag(playerID, flag.c_str(), false); } else if (pf.dontGive[playerID] == 1) { pf.dontGive[playerID] = 0; } } else { if (pf.levels[level + 2] > 0) { message = pf.deathmsg[1]; } else { message = pf.deathmsg[3]; } } pf.str_replace(message, "%level%", bz_format("%d", level)); pf.str_replace(message, "%flag%", pf.flagName(flag)); pf.str_replace(message, "%kills%", bz_format("%d", nextkills)); pf.str_replace(message, "%s%", plural); pf.str_replace(message, "%nextlev%", bz_format("%d", nextlevel)); bz_sendTextMessage(BZ_SERVER, playerID, message.c_str()); } else { int nextlevel = kills + 1; std::string _flag; std::string _flagAbbrev; std::string::size_type multiFlags = pf.flags[level + 1].find(' ', 0); if (multiFlags == std::string::npos) { _flagAbbrev = pf.flags[level + 1]; } else { srand((unsigned)pf.getTimeInSeconds()); std::vector* flags = pf.explode(pf.flags[level + 1], ' '); pf.removeBlanks(*flags); int random = rand() % flags->size(); _flagAbbrev = flags->at(random); delete flags; } bz_givePlayerFlag(playerID, _flagAbbrev.c_str(), false); std::string message = pf.deathmsg[0]; pf.str_replace(message, "%level%", bz_format("%d", kills)); pf.str_replace(message, "%flag%", pf.flagName(_flagAbbrev)); pf.str_replace(message, "%kills%", "1"); pf.str_replace(message, "%s%", ""); pf.str_replace(message, "%nextlev%", bz_format("%d", level + 1)); bz_sendTextMessage(BZ_SERVER, playerID, message.c_str()); } return; } bool progFlag::readConf(const char* confFile) { /***************** * THANKS L4M3R! * *****************/ std::ifstream conf; conf.open(confFile); if (!conf.is_open()) { std::string error = "Progressive Flag Plug-in: Fatal Error: Configuration file \"" + (std::string)confFile + "\" could not be opened."; bz_debugMessage(0, error.c_str()); return false; } else { std::string curLine; std::vector* curLineArgs; while (getline(conf, curLine)) { std::string::size_type index = curLine.find('#'); if (index != std::string::npos) { curLine = curLine.substr(0, index); } curLineArgs = pf.explode(curLine, '='); pf.trim(curLineArgs->at(0)); if (curLineArgs->at(0) != "") { std::string error = "Progressive Flag Plug-in: Warning (" + curLineArgs->at(0) + "): Invalid. (Ignoring)"; bz_debugMessage(0, error.c_str()); } for (unsigned int x = 1; x < curLineArgs->size(); x++) { pf.trim(curLineArgs->at(x)); if (curLineArgs->at(x) != "") { pf.readArg(curLineArgs->at(x)); } } delete curLineArgs; } conf.close(); if (pf.maxLevel == 2) { std::string error = "Progressive Flag Plug-in: Error: Configuration file \"" + (std::string)confFile + "\" contains no levels."; bz_debugMessage(0, error.c_str()); return false; } } return true; } void progFlag::readArg(std::string arg) { /***************** * THANKS L4M3R! * *****************/ std::vector* params = pf.explode(arg, ' '); pf.removeBlanks(*params); if (params->size() == 0) { return; } if (params->at(0) == "addlevel") { if (params->size() < 2) { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Wrong number of parameters. (Ignoring)"; bz_debugMessage(0, error.c_str()); } else { int kills = pf.strToInt(params->at(1), 1); if (kills < 1) kills = 1; pf.levels[pf.maxLevel] = kills; for (unsigned int i = 3; i < params->size(); i++) { std::string flag = pf.strtoupper(params->at(i)); if (pf.flagName(flag) != "No Flag") { if (pf.flags[pf.maxLevel] == "") { pf.flags[pf.maxLevel] = flag; } else { pf.flags[pf.maxLevel] += " " + flag; } } else { std::string error = "Progressive Flag Plug-in: Warning (=" + arg + "): Invalid flag " + flag + ". (Ignoring)"; bz_debugMessage(0, error.c_str()); } } ++pf.maxLevel; } } else if (params->at(0) == "addflag") { if (params->size() < 3) { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Wrong number of parameters. (Ignoring)"; bz_debugMessage(0, error.c_str()); } else { int level = pf.strToInt(params->at(1), -1) + 1; if (level > pf.maxLevel || level < -1) level = -1 + 1; for (unsigned int i = 2; i < params->size(); i++) { std::string flag = pf.strtoupper(params->at(i)); if (pf.flagName(flag) != "No Flag") { if (pf.flags[level] == "") { pf.flags[level] = flag; } else { pf.flags[level] += " " + flag; } } else { std::string error = "Progressive Flag Plug-in: Warning (=" + arg + "): Invalid flag " + flag + ". (Ignoring)"; bz_debugMessage(0, error.c_str()); } } } } else if (params->at(0) == "tk") { if (params->size() > 1) { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Wrong number of parameters. (Ignoring)"; bz_debugMessage(0, error.c_str()); } else { if (!pf.giveOnTK) { pf.giveOnTK = true; } else { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Already set. (Ignoring)"; bz_debugMessage(0, error.c_str()); } } } else if (params->at(0).substr(0, 7) == "message") { if (params->size() == 1) { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Wrong number of parameters. (Ignoring)"; bz_debugMessage(0, error.c_str()); } else { for (unsigned int i = 0; i < 4; i++) { if (params->at(0) == (std::string)bz_format("message%d", i + 1)) { std::string message; for (unsigned int j = 1; j < params->size(); j++) { message += params->at(j) + " "; } pf.deathmsg[i] = message; } } } } else if (params->at(0) == "rogue") { if (params->size() > 1) { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Wrong number of parameters. (Ignoring)"; bz_debugMessage(0, error.c_str()); } else { if (!pf.rogueTK) { pf.rogueTK = true; } else { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Already set. (Ignoring)"; bz_debugMessage(0, error.c_str()); } } } else if (params->at(0) == "delay") { if (params->size() > 2) { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Wrong number of parameters. (Ignoring)"; bz_debugMessage(0, error.c_str()); } else { pf.delay = pf.strToInt(params->at(1), pf.delay); } } else { std::string error = "Progressive Flag Plug-in: Error (=" + arg + "): Invalid argument. (Ignoring)"; bz_debugMessage(0, error.c_str()); } delete params; } std::vector* progFlag::explode(std::string src, char s) { /***************** * THANKS L4M3R! * *****************/ std::vector* list = new std::vector; int index = 0; list->push_back(""); for (unsigned int x = 0; x < src.length(); x++) { if (src[x] == s) { index++; list->push_back(""); } else { list->at(index) += src[x]; } } return list; } int progFlag::strToInt(std::string src, int returnIfError) { /********************************************************************************** * THANKS L4M3R! * * Modified for negatives and a value to return if it doesn't consist of numbers. * **********************************************************************************/ bool negative = false; int val = 0; int digit; for (unsigned int x = 0; x < src.length(); x++) { if (x == 0 && src[x] == '-') { negative = true; } else { if (src[x] < '0' || src[x] > '9') { return returnIfError; } digit = static_cast(src[x] - '0'); val *= 10; val += digit; } } if (negative) val = 0 - val; return val; } void progFlag::trim(std::string &str) { /***************** * THANKS L4M3R! * *****************/ if (str == "") return; int x; for (x = str.length() - 1; x >= 0; x--) { if (str[x] != ' ') { if (x != str.length() - 1) str = str.substr(0, x + 1); break; } } if (x < 0) { str = ""; return; } for (unsigned int y = 0; y < str.length(); y++) { if (str[y] != ' ') { if (y != 0) str = str.substr(y); break; } } } void progFlag::removeBlanks(std::vector &arr) { /******************* * THANKIES L4M3R! * *******************/ for (std::vector::iterator x = arr.begin(); x != arr.end(); x++) { if (*x == "") arr.erase(x); } } std::string progFlag::strtoupper(std::string str) { std::string string = ""; for (unsigned int i = 0; i < str.length(); i++) { string += toupper(str[i]); } return string; } const char* progFlag::flagName(std::string flagAbbrev) { std::string flag = pf.strtoupper(flagAbbrev); if (flag == "A") { return "Agility"; } else if (flag == "B") { return "Blindness"; } else if (flag == "B*") { return "Blue Team Flag"; } else if (flag == "BU") { return "Burrow"; } else if (flag == "BY") { return "Bouncy"; } else if (flag == "CB") { return "Colorblindness"; } else if (flag == "CL") { return "Cloaking"; } else if (flag == "F") { return "Rapid Fire"; } else if (flag == "FO") { return "Forward Only"; } else if (flag == "G") { return "Genocide"; } else if (flag == "G*") { return "Green Team Flag"; } else if (flag == "GM") { return "Guided Missile"; } else if (flag == "IB") { return "Invisible Bullet"; } else if (flag == "ID") { return "Identify"; } else if (flag == "JM") { return "Jamming"; } else if (flag == "JP") { return "Jumping"; } else if (flag == "L") { return "Laser"; } else if (flag == "LT") { return "Left Turn Only"; } else if (flag == "M") { return "Momentum"; } else if (flag == "MG") { return "Machine Gun"; } else if (flag == "MQ") { return "Masquerade"; } else if (flag == "N") { return "Narrow"; } else if (flag == "NJ") { return "No Jumping"; } else if (flag == "O") { return "Obesity"; } else if (flag == "OO") { return "Oscillation Overthruster"; } else if (flag == "P*") { return "Purple Team Flag"; } else if (flag == "PZ") { return "Phantom Zone"; } else if (flag == "QT") { return "Quick Turn"; } else if (flag == "R") { return "Ricochet"; } else if (flag == "R*") { return "Red Team Flag"; } else if (flag == "RC") { return "Reverse Controls"; } else if (flag == "RO") { return "Reverse Only"; } else if (flag == "RT") { return "Right Turn Only"; } else if (flag == "SB") { return "Super Bullet"; } else if (flag == "SE") { return "Seer"; } else if (flag == "SH") { return "Shield"; } else if (flag == "SR") { return "Steamroller"; } else if (flag == "ST") { return "Stealth"; } else if (flag == "SW") { return "Shockwave"; } else if (flag == "T") { return "Tiny"; } else if (flag == "TH") { return "Thief"; } else if (flag == "TR") { return "Trigger Happy"; } else if (flag == "US") { return "Useless"; } else if (flag == "V") { return "High Speed"; } else if (flag == "WA") { return "Wide Angle"; } else if (flag == "WG") { return "Wings"; } else { return "No Flag"; } } int progFlag::getTimeInSeconds(void) { bz_localTime time; bz_getLocaltime(&time); return time.day * 86400 + time.hour * 3600 + time.minute * 60 + time.second; } void progFlag::str_replace(std::string& string, const char* _find, const char* _replace) { std::string find = (std::string)_find; std::string replace = (std::string)_replace; std::string::size_type pos = string.find(find, 0); if (pos != std::string::npos) { string.erase(pos, find.length()); string.insert(pos, replace); } return; }