/* * The Mana Server * Copyright (C) 2008-2010 The Mana World Development Team * * This file is part of The Mana Server. * * The Mana Server is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * The Mana Server 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 The Mana Server. If not, see . */ #include #include "game-server/commandhandler.hpp" #include "game-server/accountconnection.hpp" #include "game-server/character.hpp" #include "game-server/gamehandler.hpp" #include "game-server/inventory.hpp" #include "game-server/item.hpp" #include "game-server/itemmanager.hpp" #include "game-server/mapmanager.hpp" #include "game-server/monster.hpp" #include "game-server/monstermanager.hpp" #include "game-server/state.hpp" #include "common/permissionmanager.hpp" #include "common/transaction.hpp" #include "utils/string.hpp" struct CmdRef { const char *cmd; const char *usage; const char *help; void (*func)(Character*, std::string&) ; }; static void handleHelp(Character*, std::string&); static void handleReport(Character*, std::string&); static void handleWhere(Character*, std::string&); static void handleRights(Character*, std::string&); static void handleWarp(Character*, std::string&); static void handleGoto(Character*, std::string&); static void handleRecall(Character*, std::string&); static void handleBan(Character*, std::string&); static void handleItem(Character*, std::string&); static void handleDrop(Character*, std::string&); static void handleMoney(Character*, std::string&); static void handleSpawn(Character*, std::string&); static void handleAttribute(Character*, std::string&); static void handleReload(Character*, std::string&); static void handleGivePermission(Character*, std::string&); static void handleTakePermission(Character*, std::string&); static void handleAnnounce(Character*, std::string&); static void handleHistory(Character*, std::string&); static CmdRef const cmdRef[] = { {"help", "[command]" , "Lists all available commands or a detailed help for a command", &handleHelp }, {"report", "" , "Sends a bug or abuse reports a bug to the server administration", &handleReport}, {"where", "" , "Tells you your location in the game world", &handleWhere}, {"rights", "" , "Tells you your current permissions", &handleRights}, {"warp", " ", "Teleports your character to a different location in the game world", &handleWarp}, {"goto", "", "Teleports you to the location of another character", &handleGoto}, {"recall", "", "Teleports another character to your location", &handleRecall}, {"ban", " ", "Bans the character and all characters on the same account from the game", &handleBan}, {"item", " ", "Creates a number of items in the inventory of a character", &handleItem}, {"drop", " ", "Drops a stack of items on the ground at your current location", &handleDrop}, {"money", " ", "Changes the money a character possesses", &handleMoney}, {"spawn", " ", "Creates a number of monsters near your location", &handleSpawn}, {"attribute", " ", "Changes the character attributes of a character", &handleAttribute}, {"reload", "", "Makes the server reload all configuration files", &handleReload}, {"givepermission", " ", "Gives a permission class to the account a character belongs to", &handleGivePermission}, {"takepermission", " ", "Takes a permission class from the account a character belongs to", &handleTakePermission}, {"announce", "", "Sends a chat message to all characters in the game", &handleAnnounce}, {"history", "", "Shows the last transactions", &handleHistory}, {NULL, NULL, NULL, NULL} }; static void say(const std::string error, Character *player) { GameState::sayTo(player, NULL, error); } /* static bool checkPermission(Character *player, unsigned int permissions) { if (player->getAccountLevel() & permissions) { return true; } say("Invalid permissions", player); return false; }*/ static std::string getArgument(std::string &args) { std::string argument = ""; std::string::size_type pos = args.find(' '); if (pos != std::string::npos) { argument = args.substr(0, pos); args = args.substr(pos+1); } else { argument = args.substr(0); args = ""; } return argument; } static Character* getPlayer(const std::string &player) { // get character, via the client, as they may be // on a different game server GameClient *client = gameHandler->getClientByNameSlow(player); if (!client) { return NULL; } if (client->status != CLIENT_CONNECTED) { return NULL; } return client->character; } static void handleHelp(Character *player, std::string &args) { if (args == "") { // short list of all commands say("=Available Commands=", player); std::list commands = PermissionManager::getPermissionList(player); for (std::list::iterator i = commands.begin(); i != commands.end(); i++) { say((*i), player); } } else { // don't show help for commands the player may not use if (PermissionManager::checkPermission(player, "@"+args) == PermissionManager::PMR_DENIED) { say("Why do you want to know? You can't use it anyway!", player); return; } // detailed description of single command for (size_t j = 0; cmdRef[j].cmd != NULL; j++) { if (cmdRef[j].cmd == args) { std::string msg; msg.append("@"); msg.append(cmdRef[j].cmd); msg.append(" "); msg.append(cmdRef[j].usage); say(msg, player); say(cmdRef[j].help, player); return; } } say("There is no command @"+args, player); } } static void handleWarp(Character *player, std::string &args) { int x, y; MapComposite *map; Character *other; // get the arguments std::string character = getArgument(args); std::string mapstr = getArgument(args); std::string xstr = getArgument(args); std::string ystr = getArgument(args); // if any of them are empty strings, no argument was given if (character == "" || mapstr == "" || xstr == "" || ystr == "") { say("Invalid number of arguments given.", player); say("Usage: @warp ", player); return; } // if it contains # then it means the player if (character == "#") { other = player; } else { // check for valid player other = getPlayer(character); if (!other) { say("Invalid character, or they are offline", player); return; } } // if it contains # then it means the player's map if (mapstr == "#") { map = player->getMap(); } else { // check for valid map id int id; if (!utils::isNumeric(mapstr)) { say("Invalid map", player); return; } id = utils::stringToInt(mapstr); // get the map map = MapManager::getMap(id); if (!map) { say("Invalid map", player); return; } } if (!utils::isNumeric(xstr)) { say("Invalid x", player); return; } if (!utils::isNumeric(ystr)) { say("Invalid y", player); return; } // change the x and y to integers x = utils::stringToInt(xstr); y = utils::stringToInt(ystr); // now warp the player GameState::warp(other, map, x, y); // log transaction std::string msg = "User warped to " + xstr + "x" + ystr; accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_WARP, msg); } static void handleItem(Character *player, std::string &args) { Character *other; ItemClass *ic; int value; int id; // get arguments std::string character = getArgument(args); std::string itemclass = getArgument(args); std::string valuestr = getArgument(args); // check all arguments are there if (character == "" || itemclass == "" || valuestr == "") { say("Invalid number of arguments given.", player); say("Usage: @item ", player); return; } // if it contains # that means the player if (character == "#") { other = player; } else { // check for valid player other = getPlayer(character); if (!other) { say("Invalid character or they are offline", player); return; } } // check we have a valid item if (!utils::isNumeric(itemclass)) { say("Invalid item", player); return; } // put the itemclass id into an integer id = utils::stringToInt(itemclass); // check for valid item class ic = ItemManager::getItem(id); if (!ic) { say("Invalid item", player); return; } if (!utils::isNumeric(valuestr)) { say("Invalid value", player); return; } value = utils::stringToInt(valuestr); if (value < 0) { say("Invalid amount", player); return; } // insert the item into the inventory Inventory(other).insert(ic->getDatabaseID(), value); // log transaction std::stringstream str; str << "User created item " << ic->getDatabaseID(); accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_ITEM, str.str()); } static void handleDrop(Character *player, std::string &args) { ItemClass *ic; int value, id; // get arguments std::string itemclass = getArgument(args); std::string valuestr = getArgument(args); // check all arguments are there if (itemclass == "" || valuestr == "") { say("Invalid number of arguments given.", player); say("Usage: @drop ", player); return; } // check that itemclass id and value are really integers if (!utils::isNumeric(itemclass) || !utils::isNumeric(valuestr)) { say("Invalid arguments passed.", player); return; } // put the item class id into an integer id = utils::stringToInt(itemclass); // check for valid item ic = ItemManager::getItem(id); if (!ic) { say("Invalid item", player); return; } // put the value into an integer value = utils::stringToInt(valuestr); if (value < 0) { say("Invalid amount", player); return; } // create the integer and put it on the map Item *item = new Item(ic, value); item->setMap(player->getMap()); item->setPosition(player->getPosition()); GameState::insertSafe(item); // log transaction std::stringstream str; str << "User created item " << ic->getDatabaseID(); accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_DROP, str.str()); } static void handleMoney(Character *player, std::string &args) { Character *other; int value; // get arguments std::string character = getArgument(args); std::string valuestr = getArgument(args); // check all arguments are there if (character == "" || valuestr == "") { say("Invalid number of arguments given", player); say("Usage: @money ", player); return; } // check if its the player itself if (character == "#") { other = player; } else { // check for valid player other = getPlayer(character); if (!other) { say("Invalid character or they are offline", player); return; } } // check value is an integer if (!utils::isNumeric(valuestr)) { say("Invalid argument", player); return; } // change value into an integer value = utils::stringToInt(valuestr); // change how much money the player has Inventory(other).changeMoney(value); // log transaction std::string msg = "User created " + valuestr + " money"; accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_MONEY, msg); } static void handleSpawn(Character *player, std::string &args) { MonsterClass *mc; MapComposite *map = player->getMap(); const Point &pos = player->getPosition(); int value, id; // get the arguments std::string monsterclass = getArgument(args); std::string valuestr = getArgument(args); // check all arguments are there if (monsterclass == "" || valuestr == "") { say("Invalid amount of arguments given.", player); say("Usage: @spawn ", player); return; } // check they are really numbers if (!utils::isNumeric(monsterclass) || !utils::isNumeric(valuestr)) { say("Invalid arguments", player); return; } // put the monster class id into an integer id = utils::stringToInt(monsterclass); // check for valid monster mc = MonsterManager::getMonster(id); if (!mc) { say("Invalid monster", player); return; } // put the amount into an integer value = utils::stringToInt(valuestr); if (value < 0) { say("Invalid amount", player); return; } // create the monsters and put them on the map for (int i = 0; i < value; ++i) { Being *monster = new Monster(mc); monster->setMap(map); monster->setPosition(pos); monster->clearDestination(); if (!GameState::insertSafe(monster)) { // The map is full. Break out. break; } // log transaction std::string msg = "User created monster " + monster->getName(); accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_SPAWN, msg); } } static void handleGoto(Character *player, std::string &args) { Character *other; // get the arguments std::string character = getArgument(args); // check all arguments are there if (character == "") { say("Invalid amount of arguments given.", player); say("Usage: @goto ", player); return; } // check for valid player other = getPlayer(character); if (!other) { say("Invalid character, or they are offline.", player); return; } // move the player to where the other player is MapComposite *map = other->getMap(); const Point &pos = other->getPosition(); GameState::warp(player, map, pos.x, pos.y); } static void handleRecall(Character *player, std::string &args) { Character *other; // get the arguments std::string character = getArgument(args); // check all arguments are there if (character == "") { say("Invalid amount of arguments given.", player); say("Usage: @recall ", player); return; } // check for valid player other = getPlayer(character); if (!other) { say("Invalid character, or they are offline.", player); return; } // move the other player to where the player is MapComposite *map = player->getMap(); const Point &pos = player->getPosition(); GameState::warp(other, map, pos.x, pos.y); } static void handleReload(Character *player, std::string &args) { // reload the items and monsters ItemManager::reload(); MonsterManager::reload(); } static void handleBan(Character *player, std::string &args) { Character *other; int length; // get arguments std::string character = getArgument(args); std::string valuestr = getArgument(args); // check all arguments are there if (character == "" || valuestr == "") { say("Invalid number of arguments given.", player); say("Usage: @ban ", player); return; } // check for valid player other = getPlayer(character); if (!other) { say("Invalid character", player); return; } // check the length is really an integer if (!utils::isNumeric(valuestr)) { say("Invalid argument", player); return; } // change the length to an integer length = utils::stringToInt(valuestr); if (length < 0) { say("Invalid length", player); return; } // ban the player accountHandler->banCharacter(other, length); // log transaction std::string msg = "User banned " + other->getName(); accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_BAN, msg); } static void handleGivePermission(Character *player, std::string &args) { Character *other; // get the arguments std::string character = getArgument(args); std::string strPermission = getArgument(args); // check all arguments are there if (character == "" || strPermission == "") { say("Invalid number of arguments given.", player); say("Usage: @givepermission ", player); return; } // check if its to effect the player if (character == "#") { other = player; } else { // check for valid player other = getPlayer(character); if (!other) { say("Invalid character", player); return; } } unsigned char permission = PermissionManager::getMaskFromAlias(strPermission); if (permission == 0x00) { say ("Unknown permission class: "+strPermission, player); return; } if (permission & other->getAccountLevel()) { say(player->getName()+" already has the permission "+strPermission, player); } else { permission += other->getAccountLevel(); // change the player's account level other->setAccountLevel(permission); accountHandler->changeAccountLevel(other, permission); // log transaction std::string msg = "User gave right " + strPermission + " to " + other->getName(); accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_SETGROUP, msg); say("Congratulations, "+player->getName()+" gave you the rights of a "+strPermission, other); } } static void handleTakePermission(Character *player, std::string &args) { Character *other; // get the arguments std::string character = getArgument(args); std::string strPermission = getArgument(args); // check all arguments are there if (character == "" || strPermission == "") { say("Invalid number of arguments given.", player); say("Usage: @takepermission ", player); return; } // check if its to effect the player if (character == "#") { other = player; } else { // check for valid player other = getPlayer(character); if (!other) { say("Invalid character", player); return; } } unsigned char permission = PermissionManager::getMaskFromAlias(strPermission); if (permission == 0x00) { say("Unknown permission class: "+strPermission, player); return; } if (!(permission & other->getAccountLevel())) { say(player->getName()+" hasn't got the permission "+strPermission, player); } else { permission = other->getAccountLevel() - permission; // change the player's account level other->setAccountLevel(permission); accountHandler->changeAccountLevel(other, permission); // log transaction std::string msg = "User took right " + strPermission + " to " + other->getName(); accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_SETGROUP, msg); say("Sorry, "+player->getName()+" revoked your rights of a "+strPermission, other); } } static void handleAttribute(Character *player, std::string &args) { Character *other; int attr, value; // get arguments std::string character = getArgument(args); std::string attrstr = getArgument(args); std::string valuestr = getArgument(args); // check all arguments are there if (character == "" || valuestr == "" || attrstr == "") { say("Invalid number of arguments given.", player); say("Usage: @attribute ", player); return; } // check if its the player or another player if (character == "#") { other = player; } else { // check for valid player other = getPlayer(character); if (!other) { say("Invalid character", player); return; } } // check they are really integers if (!utils::isNumeric(valuestr) || !utils::isNumeric(attrstr)) { say("Invalid argument", player); return; } // put the attribute into an integer attr = utils::stringToInt(attrstr); if (attr < 0) { say("Invalid Attribute", player); return; } // put the value into an integer value = utils::stringToInt(valuestr); if (value < 0) { say("Invalid amount", player); return; } // change the player's attribute other->setAttribute(attr, value); } static void handleReport(Character *player, std::string &args) { std::string bugReport = getArgument(args); if (bugReport == "") { say("Invalid number of arguments given.", player); say("Usage: @report ", player); return; } // TODO: Send the report to a developer or something } static void handleAnnounce(Character *player, std::string &msg) { if (msg == "") { say("Invalid number of arguments given.", player); say("Usage: @announce ", player); return; } GameState::sayToAll(msg); } static void handleWhere(Character *player, std::string &args) { std::stringstream str; str << "Your current location is map " << player->getMapId() << " [" << player->getPosition().x << ":" << player->getPosition().y << "]"; say (str.str(), player); } static void handleRights(Character *player, std::string &args) { std::listclasses; classes = PermissionManager::getClassList(player); std::stringstream str; str << "Your rights level is: " << (unsigned int)player->getAccountLevel() << " ( "; for (std::list::iterator i = classes.begin(); i != classes.end(); i++) { str << (*i) << " "; } str << ")"; say(str.str(), player); } static void handleHistory(Character *player, std::string &args) { // TODO: Get args number of transactions and show them to the player } void CommandHandler::handleCommand(Character *player, const std::string &command) { // get command type, and arguments // remove first character (the @) std::string::size_type pos = command.find(' '); std::string type(command, 1, pos == std::string::npos ? pos : pos - 1); std::string args(command, pos == std::string::npos ? command.size() : pos + 1); PermissionManager::Result r = PermissionManager::checkPermission(player, "@"+type); switch (r) { case PermissionManager::PMR_DENIED: say("Permissions denied!", player); break; case PermissionManager::PMR_UNKNOWN: say("Unknown command. Enter @help to view the list of available commands.", player); break; case PermissionManager::PMR_ALLOWED: // handle the command for (size_t i = 0; cmdRef[i].cmd != NULL; i++) { if (cmdRef[i].cmd == type) { cmdRef[i].func(player,args); return; }; } say("Command not implemented.", player); break; } }