Date:
19.03.2019 - 22:23:08
Author:
Rewrite:
Type here:
//////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // This program 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 3 of the License, or // (at your option) any later version. // // 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 <http://www.gnu.org/licenses/>. //////////////////////////////////////////////////////////////////////// #include "otpch.h" #include "talkaction.h" #include <boost/config.hpp> #include <boost/version.hpp> #include "iologindata.h" #include "ioban.h" #include "player.h" #include "npc.h" #include "house.h" #include "town.h" #include "teleport.h" #include "status.h" #include "textlogger.h" #ifdef __ENABLE_SERVER_DIAGNOSTIC__ #include "outputmessage.h" #include "connection.h" #include "admin.h" #include "manager.h" #include "protocollogin.h" #include "protocolold.h" #endif #include "configmanager.h" #include "game.h" #include "chat.h" #include "tools.h" extern ConfigManager g_config; extern Game g_game; extern Chat g_chat; extern TalkActions* g_talkActions; TalkActions::TalkActions(): m_interface("TalkAction Interface") { m_interface.initState(); defaultTalkAction = NULL; } TalkActions::~TalkActions() { clear(); } void TalkActions::clear() { for(TalkActionsMap::iterator it = talksMap.begin(); it != talksMap.end(); ++it) delete it->second; talksMap.clear(); m_interface.reInitState(); delete defaultTalkAction; defaultTalkAction = NULL; } Event* TalkActions::getEvent(const std::string& nodeName) { if(asLowerCaseString(nodeName) == "talkaction") return new TalkAction(&m_interface); return NULL; } bool TalkActions::registerEvent(Event* event, xmlNodePtr p, bool override) { TalkAction* talkAction = dynamic_cast<TalkAction*>(event); if(!talkAction) return false; std::string strValue; if(readXMLString(p, "default", strValue) && booleanString(strValue)) { if(!defaultTalkAction) defaultTalkAction = talkAction; else if(override) { delete defaultTalkAction; defaultTalkAction = talkAction; } else std::clog << "[Warning - TalkAction::registerEvent] You cannot define more than one default talkAction." << std::endl; return true; } if(!readXMLString(p, "separator", strValue) || strValue.empty()) strValue = ";"; StringVec strVector = explodeString(talkAction->getWords(), strValue); for(StringVec::iterator it = strVector.begin(); it != strVector.end(); ++it) { trimString(*it); talkAction->setWords(*it); if(talksMap.find(*it) != talksMap.end()) { if(!override) { std::clog << "[Warning - TalkAction::registerEvent] Duplicate registered talkaction with words: " << (*it) << std::endl; continue; } else delete talksMap[(*it)]; } talksMap[(*it)] = new TalkAction(talkAction); } delete talkAction; return true; } bool TalkActions::onPlayerSay(Creature* creature, uint16_t channelId, const std::string& words, bool ignoreAccess, ProtocolGame* pg) { std::string cmd[TALKFILTER_LAST] = {words, words, words}, param[TALKFILTER_LAST] = {"", "", ""}; std::string::size_type loc = words.find('"', 0); if(loc != std::string::npos) { cmd[TALKFILTER_QUOTATION] = std::string(words, 0, loc); param[TALKFILTER_QUOTATION] = std::string(words, (loc + 1), (words.size() - (loc - 1))); trimString(cmd[TALKFILTER_QUOTATION]); } loc = words.find(" ", 0); if(loc != std::string::npos) { cmd[TALKFILTER_WORD] = std::string(words, 0, loc); param[TALKFILTER_WORD] = std::string(words, (loc + 1), (words.size() - (loc - 1))); std::string::size_type spaceLoc = words.find(" ", ++loc); if(spaceLoc != std::string::npos) { cmd[TALKFILTER_WORD_SPACED] = std::string(words, 0, spaceLoc); param[TALKFILTER_WORD_SPACED] = std::string(words, (spaceLoc + 1), (words.size() - (spaceLoc - 1))); } } TalkAction* talkAction = NULL; for(TalkActionsMap::iterator it = talksMap.begin(); it != talksMap.end(); ++it) { if(it->first == cmd[it->second->getFilter()] || (!it->second->isSensitive() && !strcasecmp(it->first.c_str(), cmd[it->second->getFilter()].c_str()))) { talkAction = it->second; break; } } if(!talkAction && defaultTalkAction) talkAction = defaultTalkAction; if(pg != NULL && pg->getIsCast() && creature->getPlayer()) { Player* p = creature->getPlayer(); if(pg != NULL && words[0] == '/' && pg->getIsCast()) { if(words.substr(1, 4) == "nick") { if(words.length() > 6) { std::string param = words.substr(6); trimString(param); if(param.length() > 10) { //pg->sendChannelMessage("[Chat System]", "This name is too long. (Max 8. letters)", MSG_STATUS_DEFAULT, privchannel->getId()); pg->publicSendMessage(p, SPEAK_PRIVATE, "This name is too long."); return true; } else if(param.length() <= 2) { //pg->sendChannelMessage("[Chat System]", "This name is too short. (Min 3. letters)", MSG_STATUS_DEFAULT, privchannel->getId()); pg->publicSendMessage(p, SPEAK_PRIVATE, "This name is too short."); return true; } if(!isValidName(param, false)) { pg->publicSendMessage(p, SPEAK_PRIVATE, "This name is invalid."); //pg->sendChannelMessage("[Chat System]", "This name contains invalid characters.", MSG_STATUS_DEFAULT, privchannel->getId()); return true; } for(AutoList<ProtocolGame>::iterator it = Player::cSpectators.begin(); it != Player::cSpectators.end(); ++it) if(it->second->getViewerName() == param && it->second->getPlayer() == p) { pg->publicSendMessage(p, SPEAK_PRIVATE, "This name is already in use."); return true; } PrivateChatChannel* channel = g_chat.getPrivateChannel(p); if(channel) channel->talk("", SPEAK_CHANNEL_RA, (pg->getViewerName() + "'s new name is: " + param)); //addedLast pg->setViewerName(param); pg->publicSendMessage(p, SPEAK_PRIVATE, "Your name was set to: " + param); } else pg->publicSendMessage(p, SPEAK_PRIVATE, "Invalid param."); } else if(words.substr(1, 4) == "info") { PlayerCast pc = p->getCast(); std::stringstream ss, sl; ss << Player::cSpectators.size() << " Viewers: "; bool first = true; for(AutoList<ProtocolGame>::iterator it = Player::cSpectators.begin(); it != Player::cSpectators.end(); ++it) { if(it->second->getPlayer() == p) { sl.clear(); sl << ss; if(first) first = false; else ss << ", "; ss << it->second->getViewerName(); if(ss.str().length() > 250) { ss.clear(); ss << sl << "..."; break; } } } std::string out = ss.str(); pg->publicSendMessage(p, SPEAK_PRIVATE, out); } return true; } return false; } if(!talkAction || (talkAction->getChannel() != -1 && talkAction->getChannel() != channelId)) return false; Player* player = creature->getPlayer(); StringVec exceptions = talkAction->getExceptions(); if(player && ((!ignoreAccess && std::find(exceptions.begin(), exceptions.end(), asLowerCaseString( player->getName())) == exceptions.end() && talkAction->getAccess() > player->getAccess()) || player->isAccountManager())) { if(player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges)) { player->sendTextMessage(MSG_STATUS_SMALL, "You cannot execute this talkaction."); return true; } return false; } if(talkAction->isLogged()) { if(player) player->sendTextMessage(MSG_STATUS_CONSOLE_RED, words.c_str()); Logger::getInstance()->eFile("talkactions/" + creature->getName() + ".log", words, true); } if(talkAction->isScripted()) return talkAction->executeSay(creature, cmd[talkAction->getFilter()], param[talkAction->getFilter()], channelId); if(TalkFunction* function = talkAction->getFunction()) return function(creature, cmd[talkAction->getFilter()], param[talkAction->getFilter()]); return false; } TalkAction::TalkAction(LuaInterface* _interface): Event(_interface) { m_function = NULL; m_filter = TALKFILTER_WORD; m_access = 0; m_channel = -1; m_logged = m_hidden = false; m_sensitive = true; } TalkAction::TalkAction(const TalkAction* copy): Event(copy) { m_words = copy->m_words; m_function = copy->m_function; m_filter = copy->m_filter; m_access = copy->m_access; m_channel = copy->m_channel; m_logged = copy->m_logged; m_hidden = copy->m_hidden; m_sensitive = copy->m_sensitive; m_exceptions = copy->m_exceptions; } bool TalkAction::configureEvent(xmlNodePtr p) { std::string strValue; if(readXMLString(p, "words", strValue)) m_words = strValue; else if(!readXMLString(p, "default", strValue) || !booleanString(strValue)) { std::clog << "[Error - TalkAction::configureEvent] No words for TalkAction." << std::endl; return false; } if(readXMLString(p, "filter", strValue)) { std::string tmpStrValue = asLowerCaseString(strValue); if(tmpStrValue == "quotation") m_filter = TALKFILTER_QUOTATION; else if(tmpStrValue == "word") m_filter = TALKFILTER_WORD; else if(tmpStrValue == "word-spaced") m_filter = TALKFILTER_WORD_SPACED; else std::clog << "[Warning - TalkAction::configureEvent] Unknown filter for TalkAction: " << strValue << ", using default." << std::endl; } int32_t intValue; if(readXMLInteger(p, "access", intValue)) m_access = intValue; if(readXMLInteger(p, "channel", intValue)) m_channel = intValue; if(readXMLString(p, "log", strValue) || readXMLString(p, "logged", strValue)) m_logged = booleanString(strValue); if(readXMLString(p, "hide", strValue) || readXMLString(p, "hidden", strValue)) m_hidden = booleanString(strValue); if(readXMLString(p, "case-sensitive", strValue) || readXMLString(p, "casesensitive", strValue) || readXMLString(p, "sensitive", strValue)) m_sensitive = booleanString(strValue); if(readXMLString(p, "exception", strValue)) m_exceptions = explodeString(asLowerCaseString(strValue), ";"); return true; } bool TalkAction::loadFunction(const std::string& functionName) { m_functionName = asLowerCaseString(functionName); if(m_functionName == "housebuy") m_function = houseBuy; else if(m_functionName == "housesell") m_function = houseSell; else if(m_functionName == "housekick") m_function = houseKick; else if(m_functionName == "housedoorlist") m_function = houseDoorList; else if(m_functionName == "houseguestlist") m_function = houseGuestList; else if(m_functionName == "housesubownerlist") m_function = houseSubOwnerList; else if(m_functionName == "guildjoin") m_function = guildJoin; else if(m_functionName == "guildcreate") m_function = guildCreate; else if(m_functionName == "thingproporties") m_function = thingProporties; else if(m_functionName == "banishmentinfo") m_function = banishmentInfo; else if(m_functionName == "diagnostics") m_function = diagnostics; else if(m_functionName == "addskill") m_function = addSkill; else if(m_functionName == "ghost") m_function = ghost; else if(m_functionName == "software") m_function = software; else { std::clog << "[Warning - TalkAction::loadFunction] Function \"" << m_functionName << "\" does not exist." << std::endl; return false; } m_scripted = EVENT_SCRIPT_FALSE; return true; } int32_t TalkAction::executeSay(Creature* creature, const std::string& words, std::string param, uint16_t channel) { //onSay(cid, words, param, channel) if(m_interface->reserveEnv()) { trimString(param); ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(creature->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(creature) << std::endl; scriptstream << "local words = \"" << words << "\"" << std::endl; scriptstream << "local param = \"" << param << "\"" << std::endl; scriptstream << "local channel = " << channel << std::endl; scriptstream << m_scriptData; bool result = true; if(m_interface->loadBuffer(scriptstream.str())) { lua_State* L = m_interface->getState(); result = m_interface->getGlobalBool(L, "_result", true); } m_interface->releaseEnv(); return result; } else { #ifdef __DEBUG_LUASCRIPTS__ char desc[125]; sprintf(desc, "%s - %s- %s", creature->getName().c_str(), words.c_str(), param.c_str()); env->setEvent(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(creature->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(creature)); lua_pushstring(L, words.c_str()); lua_pushstring(L, param.c_str()); lua_pushnumber(L, channel); bool result = m_interface->callFunction(4); m_interface->releaseEnv(); return result; } } else { std::clog << "[Error - TalkAction::executeSay] Call stack overflow." << std::endl; return 0; } } bool TalkAction::houseBuy(Creature* creature, const std::string&, const std::string&) { Player* player = creature->getPlayer(); if(!player || !g_config.getBool(ConfigManager::HOUSE_BUY_AND_SELL)) return false; const Position& pos = getNextPosition(player->getDirection(), player->getPosition()); Tile* tile = g_game.getTile(pos); if(!tile) { player->sendCancel("You have to be looking at door of flat you would like to purchase."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } HouseTile* houseTile = tile->getHouseTile(); if(!houseTile) { player->sendCancel("You have to be looking at door of flat you would like to purchase."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } House* house = houseTile->getHouse(); if(!house) { player->sendCancel("You have to be looking at door of flat you would like to purchase."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(!house->getDoorByPosition(pos)) { player->sendCancel("You have to be looking at door of flat you would like to purchase."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(!house->isGuild()) { if(Houses::getInstance()->getHouseByPlayerId(player->getGUID())) { player->sendCancel("You already rent another house."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } uint16_t accountHouses = g_config.getNumber(ConfigManager::HOUSES_PER_ACCOUNT); if(accountHouses > 0 && Houses::getInstance()->getHousesCount(player->getAccount()) >= accountHouses) { char buffer[80]; sprintf(buffer, "You may own only %d house%s per account.", accountHouses, (accountHouses != 1 ? "s" : "")); player->sendCancel(buffer); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(g_config.getBool(ConfigManager::HOUSE_NEED_PREMIUM) && !player->isPremium()) { player->sendCancelMessage(RET_YOUNEEDPREMIUMACCOUNT); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } uint32_t levelToBuyHouse = g_config.getNumber(ConfigManager::LEVEL_TO_BUY_HOUSE); if(player->getLevel() < levelToBuyHouse) { char buffer[90]; sprintf(buffer, "You have to be at least Level %d to purchase a house.", levelToBuyHouse); player->sendCancel(buffer); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } } else { if(!player->getGuildId() || player->getGuildLevel() != GUILDLEVEL_LEADER) { player->sendCancel("You have to be at least a guild leader to purchase a hall."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(Houses::getInstance()->getHouseByGuildId(player->getGuildId())) { player->sendCancel("Your guild rents already another hall."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } } if(house->getOwner()) { player->sendCancel("This flat is already owned by someone else."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if((uint32_t)g_game.getMoney(player) < house->getPrice() || !g_game.removeMoney(player, house->getPrice())) { player->sendCancel("You do not have enough money."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } house->setOwnerEx(player->getGUID(), true); std::string ret = "You have successfully bought this "; if(house->isGuild()) ret += "hall"; else ret += "house"; ret += ", remember to leave money at "; if(house->isGuild()) ret += "guild owner "; if(g_config.getBool(ConfigManager::BANK_SYSTEM)) ret += "bank or "; ret += "depot of this town for rent."; player->sendTextMessage(MSG_INFO_DESCR, ret.c_str()); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE); return false; } bool TalkAction::houseSell(Creature* creature, const std::string&, const std::string& param) { Player* player = creature->getPlayer(); if(!player || !g_config.getBool(ConfigManager::HOUSE_BUY_AND_SELL)) return false; House* house = Houses::getInstance()->getHouseByPlayerId(player->getGUID()); if(!house && (!player->getGuildId() || !(house = Houses::getInstance()->getHouseByGuildId(player->getGuildId())))) { player->sendCancel("You do not rent any flat."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(house->isGuild() && player->getGuildLevel() != GUILDLEVEL_LEADER) { player->sendCancel("You have to be at least a guild leader to sell this hall."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } Player* tradePartner = NULL; ReturnValue ret = g_game.getPlayerByNameWildcard(param, tradePartner); if(ret != RET_NOERROR) { player->sendCancelMessage(ret); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(tradePartner == player) { player->sendCancel("You cannot trade with yourself."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(!house->isGuild()) { if(Houses::getInstance()->getHouseByPlayerId(tradePartner->getGUID())) { player->sendCancel("Trade player already rents another house."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } uint16_t housesPerAccount = g_config.getNumber(ConfigManager::HOUSES_PER_ACCOUNT); if(housesPerAccount > 0 && Houses::getInstance()->getHousesCount(tradePartner->getAccount()) >= housesPerAccount) { char buffer[100]; sprintf(buffer, "Trade player has reached limit of %d house%s per account.", housesPerAccount, (housesPerAccount != 1 ? "s" : "")); player->sendCancel(buffer); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(!tradePartner->isPremium() && !g_config.getBool(ConfigManager::HOUSE_NEED_PREMIUM)) { player->sendCancel("Trade player does not have a premium account."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } uint32_t levelToBuyHouse = g_config.getNumber(ConfigManager::LEVEL_TO_BUY_HOUSE); if(tradePartner->getLevel() < levelToBuyHouse) { char buffer[100]; sprintf(buffer, "Trade player has to be at least Level %d to buy house.", levelToBuyHouse); player->sendCancel(buffer); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } } else { if(!tradePartner->getGuildId() || tradePartner->getGuildLevel() != GUILDLEVEL_LEADER) { player->sendCancel("Trade player has to be at least a guild leader to buy a hall."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(Houses::getInstance()->getHouseByGuildId(tradePartner->getGuildId())) { player->sendCancel("Trade player's guild already rents another hall."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } } if(!Position::areInRange<3,3,0>(tradePartner->getPosition(), player->getPosition())) { player->sendCancel("Trade player is too far away."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } if(!Houses::getInstance()->payRent(player, house, 0)) { player->sendCancel("You have to pay a pre-rent first."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } Item* transferItem = TransferItem::createTransferItem(house); player->transferContainer.__addThing(NULL, transferItem); player->transferContainer.setParent(player); if(!g_game.internalStartTrade(player, tradePartner, transferItem)) transferItem->onTradeEvent(ON_TRADE_CANCEL, player, NULL); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE); return false; } bool TalkAction::houseKick(Creature* creature, const std::string&, const std::string& param) { Player* player = creature->getPlayer(); if(!player) return false; Player* targetPlayer = NULL; if(g_game.getPlayerByNameWildcard(param, targetPlayer) != RET_NOERROR) targetPlayer = player; House* house = Houses::getInstance()->getHouseByPlayer(targetPlayer); if(!house || !house->kickPlayer(player, targetPlayer)) { g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); player->sendCancelMessage(RET_NOTPOSSIBLE); } else g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE); return false; } bool TalkAction::houseDoorList(Creature* creature, const std::string&, const std::string&) { Player* player = creature->getPlayer(); if(!player) return false; House* house = Houses::getInstance()->getHouseByPlayer(player); if(!house) { player->sendCancelMessage(RET_NOTPOSSIBLE); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return false; } Door* door = house->getDoorByPosition(getNextPosition(player->getDirection(), player->getPosition())); if(door && house->canEditAccessList(door->getDoorId(), player)) { player->setEditHouse(house, door->getDoorId()); player->sendHouseWindow(house, door->getDoorId()); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE); } else { player->sendCancelMessage(RET_NOTPOSSIBLE); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); } return false; } bool TalkAction::houseGuestList(Creature* creature, const std::string&, const std::string&) { Player* player = creature->getPlayer(); if(!player) return false; House* house = Houses::getInstance()->getHouseByPlayer(player); if(house && house->canEditAccessList(GUEST_LIST, player)) { player->setEditHouse(house, GUEST_LIST); player->sendHouseWindow(house, GUEST_LIST); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE); } else { player->sendCancelMessage(RET_NOTPOSSIBLE); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); } return false; } bool TalkAction::houseSubOwnerList(Creature* creature, const std::string&, const std::string&) { Player* player = creature->getPlayer(); if(!player) return false; House* house = Houses::getInstance()->getHouseByPlayer(player); if(house && house->canEditAccessList(SUBOWNER_LIST, player)) { player->setEditHouse(house, SUBOWNER_LIST); player->sendHouseWindow(house, SUBOWNER_LIST); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE); } else { player->sendCancelMessage(RET_NOTPOSSIBLE); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); } return false; } bool TalkAction::guildJoin(Creature* creature, const std::string&, const std::string& param) { Player* player = creature->getPlayer(); if(!player || !g_config.getBool(ConfigManager::INGAME_GUILD_MANAGEMENT)) return false; std::string param_ = param; trimString(param_); if(!player->getGuildId()) { uint32_t guildId; if(IOGuild::getInstance()->getGuildId(guildId, param_)) { if(player->isGuildInvited(guildId)) { IOGuild::getInstance()->joinGuild(player, guildId); player->sendTextMessage(MSG_INFO_DESCR, "You have joined the guild."); char buffer[80]; sprintf(buffer, "%s has joined the guild.", player->getName().c_str()); if(ChatChannel* guildChannel = g_chat.getChannel(player, 0x00)) guildChannel->talk(player, SPEAK_CHANNEL_RA, buffer); } else player->sendCancel("You are not invited to that guild."); } else player->sendCancel("There's no guild with that name."); } else player->sendCancel("You are already in a guild."); return true; } bool TalkAction::guildCreate(Creature* creature, const std::string&, const std::string& param) { Player* player = creature->getPlayer(); if(!player || !g_config.getBool(ConfigManager::INGAME_GUILD_MANAGEMENT)) return false; if(player->getGuildId()) { player->sendCancel("You are already in a guild."); return true; } std::string param_ = param; trimString(param_); if(!isValidName(param_)) { player->sendCancel("That guild name contains illegal characters, please choose another name."); return true; } const uint32_t minLength = g_config.getNumber(ConfigManager::MIN_GUILDNAME); const uint32_t maxLength = g_config.getNumber(ConfigManager::MAX_GUILDNAME); if(param_.length() < minLength) { player->sendCancel("That guild name is too short, please select a longer name."); return true; } if(param_.length() > maxLength) { player->sendCancel("That guild name is too long, please select a shorter name."); return true; } uint32_t guildId; if(IOGuild::getInstance()->getGuildId(guildId, param_)) { player->sendCancel("There is already a guild with that name."); return true; } const uint32_t levelToFormGuild = g_config.getNumber(ConfigManager::LEVEL_TO_FORM_GUILD); if(player->getLevel() < levelToFormGuild) { std::stringstream ss; ss << "You have to be at least Level " << levelToFormGuild << " to form a guild."; player->sendCancel(ss.str()); return true; } const int32_t premiumDays = g_config.getNumber(ConfigManager::GUILD_PREMIUM_DAYS); if(player->getPremiumDays() < premiumDays && !g_config.getBool(ConfigManager::FREE_PREMIUM)) { std::stringstream ss; ss << "You need to have at least " << premiumDays << " premium days to form a guild."; player->sendCancel(ss.str()); return true; } player->setGuildName(param_); IOGuild::getInstance()->createGuild(player); std::stringstream ss; ss << "You have formed guild \"" << param_.c_str() << "\"!"; player->sendTextMessage(MSG_INFO_DESCR, ss.str()); return true; } bool TalkAction::thingProporties(Creature* creature, const std::string&, const std::string& param) { Player* player = creature->getPlayer(); if(!player) return false; const Position& pos = getNextPosition(player->getDirection(), player->getPosition()); Tile* tile = g_game.getTile(pos); if(!tile) { player->sendTextMessage(MSG_STATUS_SMALL, "No tile found."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return true; } Thing* thing = tile->getTopVisibleThing(creature); if(!thing) { player->sendTextMessage(MSG_STATUS_SMALL, "No object found."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); return true; } boost::char_separator<char> sep(" "); tokenizer tokens(param, sep); std::string invalid; for(tokenizer::iterator it = tokens.begin(); it != tokens.end();) { std::string action = parseParams(it, tokens.end()); toLowerCaseString(action); if(Item* item = thing->getItem()) { if(action == "set") { std::string key = parseParams(it, tokens.end()), value = parseParams(it, tokens.end()); if(atoi(value.c_str()) || value == "0") item->setAttribute(key, atoi(value.c_str())); else item->setAttribute(key, value); } else if(action == "erase" || action == "remove") item->eraseAttribute(parseParams(it, tokens.end())); else if(action == "action" || action == "actionid" || action == "aid") { int32_t tmp = atoi(parseParams(it, tokens.end()).c_str()); if(tmp > 0) item->setActionId(tmp); else item->resetActionId(); } else if(action == "unique" || action == "uniqueid" || action == "uid") { int32_t tmp = atoi(parseParams(it, tokens.end()).c_str()); if(tmp >= 1000 || tmp <= 0xFFFF) item->setUniqueId(tmp); } else if(action == "destination" || action == "position" || action == "pos" || action == "dest") //TODO: doesn't work { if(Teleport* teleport = item->getTeleport()) teleport->setDestination(Position(atoi(parseParams(it, tokens.end()).c_str()), atoi(parseParams(it, tokens.end()).c_str()), atoi(parseParams(it, tokens.end()).c_str()))); } else { std::stringstream s; s << action << " (" << parseParams(it, tokens.end()) << ")"; invalid += s.str(); break; } } else if(Creature* _creature = thing->getCreature()) { if(action == "health") _creature->changeHealth(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "maxhealth") _creature->changeMaxHealth(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "mana") _creature->changeMana(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "maxmana") _creature->changeMaxMana(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "basespeed") _creature->setBaseSpeed(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "droploot") _creature->setDropLoot((lootDrop_t)atoi(parseParams(it, tokens.end()).c_str())); else if(action == "lossskill") _creature->setLossSkill(booleanString(parseParams(it, tokens.end()))); else if(action == "cannotmove") _creature->setNoMove(booleanString(parseParams(it, tokens.end()))); else if(action == "skull") { _creature->setSkull(getSkulls(parseParams(it, tokens.end()))); g_game.updateCreatureSkull(_creature); } else if(action == "speaktype") _creature->setSpeakType((SpeakClasses)atoi(parseParams(it, tokens.end()).c_str())); else if(Player* _player = _creature->getPlayer()) { if(action == "fyi") _player->sendFYIBox(parseParams(it, tokens.end()).c_str()); else if(action == "tutorial") _player->sendTutorial(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "guildlevel") _player->setGuildLevel((GuildLevel_t)atoi(parseParams(it, tokens.end()).c_str())); else if(action == "guildrank") _player->setRankId(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "guildnick") _player->setGuildNick(parseParams(it, tokens.end()).c_str()); else if(action == "group") _player->setGroupId(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "vocation") _player->setVocation(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "sex" || action == "gender") _player->setSex(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "stamina") _player->setStaminaMinutes(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "town" || action == "temple") { if(Town* town = Towns::getInstance()->getTown(parseParams(it, tokens.end()))) { _player->setMasterPosition(town->getPosition()); _player->setTown(town->getID()); } } else if(action == "balance") _player->balance = atoi(parseParams(it, tokens.end()).c_str()); else if(action == "marriage" || action == "partner") _player->marriage = atoi(parseParams(it, tokens.end()).c_str()); else if(action == "rates") _player->rates[atoi(parseParams(it, tokens.end()).c_str())] = atof( parseParams(it, tokens.end()).c_str()); else if(action == "idle") _player->setIdleTime(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "capacity" || action == "cap") _player->setCapacity(atoi(parseParams(it, tokens.end()).c_str())); else if(action == "execute") g_talkActions->onPlayerSay(_player, atoi(parseParams(it, tokens.end()).c_str()), parseParams(it, tokens.end()), booleanString(parseParams(it, tokens.end()))); else if(action == "saving" || action == "save") _player->switchSaving(); else { std::stringstream s; s << action << " (" << parseParams(it, tokens.end()) << ")"; invalid += s.str(); break; } } else { std::stringstream s; s << action << " (" << parseParams(it, tokens.end()) << ")"; invalid += s.str(); break; } } } const SpectatorVec& list = g_game.getSpectators(pos); SpectatorVec::const_iterator it; Player* tmpPlayer = NULL; for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendUpdateTile(tile, pos); } for(it = list.begin(); it != list.end(); ++it) (*it)->onUpdateTile(tile, pos); g_game.addMagicEffect(pos, MAGIC_EFFECT_WRAPS_GREEN); if(invalid.empty()) return true; std::string tmp = "Following action was invalid: " + invalid; player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, tmp.c_str()); return true; } bool TalkAction::banishmentInfo(Creature* creature, const std::string&, const std::string& param) { Player* player = creature->getPlayer(); if(!player) return false; StringVec params = explodeString(param, ","); std::string what = "Account"; trimString(params[0]); Ban ban; ban.type = BAN_ACCOUNT; if(params.size() > 1) { trimString(params[1]); if(params[0].substr(0, 1) == "p") { what = "Character"; ban.type = BAN_PLAYER; ban.param = PLAYERBAN_BANISHMENT; ban.value = atoi(params[1].c_str()); if(!ban.value) { IOLoginData::getInstance()->getGuidByName(ban.value, params[1], true); if(!ban.value) ban.value = IOLoginData::getInstance()->getAccountIdByName(params[1]); } } else { ban.value = atoi(params[1].c_str()); if(!ban.value) { IOLoginData::getInstance()->getAccountId(params[1], ban.value); if(!ban.value) ban.value = IOLoginData::getInstance()->getAccountIdByName(params[1]); } } } else { ban.value = atoi(params[0].c_str()); if(!ban.value) { IOLoginData::getInstance()->getAccountId(params[0], ban.value); if(!ban.value) ban.value = IOLoginData::getInstance()->getAccountIdByName(params[0]); } } if(!ban.value) { toLowerCaseString(what); player->sendCancel("Invalid " + what + (std::string)" name or id."); return true; } if(!IOBan::getInstance()->getData(ban)) { player->sendCancel("That player or account is not banished or deleted."); return true; } bool deletion = ban.expires < 0; std::string admin = "Automatic "; if(!ban.adminId) admin += (deletion ? "deletion" : "banishment"); else IOLoginData::getInstance()->getNameByGuid(ban.adminId, admin, true); std::string end = "Banishment will be lifted at:\n"; if(deletion) end = what + (std::string)" won't be undeleted"; std::stringstream ss; ss << what.c_str() << " has been " << (deletion ? "deleted" : "banished") << " at:\n" << formatDateEx(ban.added).c_str() << " by: " << admin.c_str() << ",\nfor the following reason:\n" << getReason(ban.reason).c_str() << ".\nThe action taken was:\n" << getAction(ban.action, false).c_str() << ".\nThe comment given was:\n" << ban.comment.c_str() << ".\n" << end.c_str() << (deletion ? "." : formatDateEx(ban.expires).c_str()) << "."; player->sendFYIBox(ss.str()); return true; } bool TalkAction::diagnostics(Creature* creature, const std::string&, const std::string&) { Player* player = creature->getPlayer(); if(!player) return false; #ifdef __ENABLE_SERVER_DIAGNOSTIC__ std::stringstream s; s << "Server diagonostic:" << std::endl; player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, s.str()); s.str(""); s << "World:" << std::endl << "--------------------" << std::endl << "Player: " << g_game.getPlayersOnline() << " (" << Player::playerCount << ")" << std::endl << "Npc: " << g_game.getNpcsOnline() << " (" << Npc::npcCount << ")" << std::endl << "Monster: " << g_game.getMonstersOnline() << " (" << Monster::monsterCount << ")" << std::endl << std::endl; player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, s.str()); s.str(""); s << "Protocols:" << std::endl << "--------------------" << std::endl << "ProtocolGame: " << ProtocolGame::protocolGameCount << std::endl << "ProtocolLogin: " << ProtocolLogin::protocolLoginCount << std::endl #ifdef __OTADMIN__ << "ProtocolAdmin: " << ProtocolAdmin::protocolAdminCount << std::endl #endif << "ProtocolManager: " << ProtocolManager::protocolManagerCount << std::endl << "ProtocolStatus: " << ProtocolStatus::protocolStatusCount << std::endl << "ProtocolOld: " << ProtocolOld::protocolOldCount << std::endl << std::endl; player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, s.str()); s.str(""); s << "Connections:" << std::endl << "--------------------" << std::endl << "Active connections: " << Connection::connectionCount << std::endl << "Total message pool: " << OutputMessagePool::getInstance()->getTotalMessageCount() << std::endl << "Auto message pool: " << OutputMessagePool::getInstance()->getAutoMessageCount() << std::endl << "Queued message pool: " << OutputMessagePool::getInstance()->getQueuedMessageCount() << std::endl << "Free message pool: " << OutputMessagePool::getInstance()->getAvailableMessageCount() << std::endl; player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, s.str()); #else player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Command not available, please rebuild your software with -D__ENABLE_SERVER_DIAG__"); #endif return true; } bool TalkAction::addSkill(Creature* creature, const std::string&, const std::string& param) { Player* player = creature->getPlayer(); if(!player) return false; StringVec params = explodeString(param, ","); if(params.size() < 2) { player->sendTextMessage(MSG_STATUS_SMALL, "Command requires at least 2 parameters."); return true; } uint32_t amount = 1; if(params.size() > 2) { std::string tmp = params[2]; trimString(tmp); amount = (uint32_t)std::max(1, atoi(tmp.c_str())); } std::string name = params[0], skill = params[1]; trimString(name); trimString(skill); Player* target = NULL; ReturnValue ret = g_game.getPlayerByNameWildcard(name, target); if(ret != RET_NOERROR) { player->sendCancelMessage(ret); return true; } if(skill[0] == 'l' || skill[0] == 'e') target->addExperience(uint64_t(Player::getExpForLevel(target->getLevel() + amount) - target->getExperience())); else if(skill[0] == 'm') target->setMagicLevel((uint64_t)target->getMagicLevel() + amount); else { skills_t skillId = getSkillId(skill); target->setSkillLevel(skillId, (uint32_t)target->getSkill(skillId, SKILL_LEVEL) + amount); } return true; } bool TalkAction::ghost(Creature* creature, const std::string&, const std::string&) { Player* player = creature->getPlayer(); if(!player) return false; if(player->hasFlag(PlayerFlag_CannotBeSeen)) { player->sendTextMessage(MSG_INFO_DESCR, "Command disabled for players with special, invisibility flag."); return true; } SpectatorVec::iterator it; SpectatorVec list = g_game.getSpectators(player->getPosition()); Player* tmpPlayer = NULL; Condition* condition = NULL; if((condition = player->getCondition(CONDITION_GAMEMASTER, CONDITIONID_DEFAULT, GAMEMASTER_INVISIBLE))) { player->sendTextMessage(MSG_INFO_DESCR, "You are visible again."); player->sendMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); IOLoginData::getInstance()->updateOnlineStatus(player->getGUID(), true); for(AutoList<Player>::iterator pit = Player::autoList.begin(); pit != Player::autoList.end(); ++pit) { if(!pit->second->canSeeCreature(player)) pit->second->notifyLogIn(player); } for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer()) && !tmpPlayer->canSeeCreature(player)) tmpPlayer->sendMagicEffect(player->getPosition(), MAGIC_EFFECT_TELEPORT); } player->removeCondition(condition); g_game.internalCreatureChangeVisible(creature, VISIBLE_GHOST_APPEAR); } else if((condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_GAMEMASTER, -1, 0, false, GAMEMASTER_INVISIBLE))) { player->addCondition(condition); g_game.internalCreatureChangeVisible(creature, VISIBLE_GHOST_DISAPPEAR); for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer()) && !tmpPlayer->canSeeCreature(player)) tmpPlayer->sendMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); } for(AutoList<Player>::iterator pit = Player::autoList.begin(); pit != Player::autoList.end(); ++pit) { if(!pit->second->canSeeCreature(player)) pit->second->notifyLogOut(player); } IOLoginData::getInstance()->updateOnlineStatus(player->getGUID(), false); if(player->isTrading()) g_game.internalCloseTrade(player); player->clearPartyInvitations(); if(player->getParty()) player->getParty()->leave(player); player->sendTextMessage(MSG_INFO_DESCR, "You are now invisible."); player->sendMagicEffect(player->getPosition(), MAGIC_EFFECT_YALAHARIGHOST); } return true; } bool TalkAction::software(Creature* creature, const std::string&, const std::string&) { Player* player = creature->getPlayer(); if(!player) return false; std::stringstream s; s << SOFTWARE_NAME << ", version " << SOFTWARE_VERSION << std::endl; player->sendTextMessage(MSG_INFO_DESCR, s.str()); s.str(""); s << "Compiled at: " << __DATE__ << ", " << __TIME__ << "." << std::endl; player->sendTextMessage(MSG_INFO_DESCR, s.str()); s.str(""); s << "Libraries:" << std::endl << "--------------------" << std::endl << "Platform: " << BOOST_PLATFORM << std::endl << "Compiler: " << BOOST_COMPILER << std::endl << "Boost: " << BOOST_VERSION << std::endl << "ASIO: " << BOOST_ASIO_VERSION << std::endl << "XML: " << XML_DEFAULT_VERSION << std::endl << "Lua: " << LUA_VERSION << std::endl; player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, s.str()); return true; } bool TalkAction::showLoot(Player* player, const std::string& cmd, const std::string& param) { player->switchGetLoot(); char buffer[90]; sprintf(buffer, "You have %s the loot channel.", (player->getLoot() ? "enabled" : "disabled")); player->sendTextMessage(MSG_INFO_DESCR, buffer); char channel[90]; sprintf(channel, "The loot channel has been %s.", (player->getLoot () ? "activated" : "deactivated")); player->sendChannelMessage("", channel, SPEAK_CHANNEL_R1, CHANNEL_LOOT); return true; }