Ir para conteúdo
  • Cadastre-se

Posts Recomendados

Queria saber como ativa a opção de quando a stamina estiver full o exp gain rate fique com 150%
Tipo assim:

stamina de 40 a 42: 150%

stamina abaixo de 40: 100%

Mas queria isso mostrando no indicador EXP Gain Rate
Desde já agradeço!

Link para o post
Compartilhar em outros sites

Necessita de modificações na sources para receber os bytes enviados pelo cliente e para enviar bytes do servidor para o cliente.

Não é algo tão simples assim...

 

@This life is filled with hurt

When happiness doesn't work

Trust me and take my hand

When the lights go out you will understand

Link para o post
Compartilhar em outros sites
5 horas atrás, login12 disse:

Necessita de modificações na sources para receber os bytes enviados pelo cliente e para enviar bytes do servidor para o cliente.

Não é algo tão simples assim...

tu tem algum modo pra me explicar isso? eu manjo um pouco, em qual source devo mexer?

@login12

Link para o post
Compartilhar em outros sites

Em data/events/scripts/player.lua procure pela função:

function Player:onGainExperience(source, exp, rawExp)

 

Se eu não me engano ele já tem um sistema de stamina, e é só você editar. Mas caso não, é só adicionar:

local staminaMin = player:getStamina()
if(staminaMin >= 40) then
	exp = exp * 1.5
end

 

Link para o post
Compartilhar em outros sites
4 horas atrás, MaTTch disse:

Em data/events/scripts/player.lua procure pela função:


function Player:onGainExperience(source, exp, rawExp)

 

Se eu não me engano ele já tem um sistema de stamina, e é só você editar. Mas caso não, é só adicionar:


local staminaMin = player:getStamina()
if(staminaMin >= 40) then
	exp = exp * 1.5
end

 

 

Isso não é o que ele pediu :p.

 

@This life is filled with hurt

When happiness doesn't work

Trust me and take my hand

When the lights go out you will understand

Link para o post
Compartilhar em outros sites
6 horas atrás, login12 disse:

 

Isso não é o que ele pediu :p.

Teria como me dar uma luz, não?

@login12

13 horas atrás, MaTTch disse:

Em data/events/scripts/player.lua procure pela função:


function Player:onGainExperience(source, exp, rawExp)

 

Se eu não me engano ele já tem um sistema de stamina, e é só você editar. Mas caso não, é só adicionar:


local staminaMin = player:getStamina()
if(staminaMin >= 40) then
	exp = exp * 1.5
end

 

Agradeço a ajuda, mas não é exatamente isso que procuro!

Link para o post
Compartilhar em outros sites
  • 1 year later...
10 horas atrás, FlavioHulk disse:

Óbvio haha, qual sua dúvida?

 

Então meninão, eu to usando a src do maluco, como tu disse o padrão é ficar 150% com stamina full e 100% ela abaixo de 40h

Sendo que, a source dele por algum motivo tu já loga com 42% de leve, pra começar a brincadeira.

Ela fica FIXO, 42% e toda vez que eu upo o level ela vai pra 7,200, varia dependendo do level.

Eu testei outras sources, a menos bugada foi uma bem antiga que eu achei aqui, que ela começa com 42%, eu mato um monstro e ela vai pra 150% continuo matando ela fica fixa, porém quando eu upo 1 level ela dispara pra 2,800.

a menos bugada que eu achei foi uma do membro aqui do forum 

essa que também é bugada pois ela só fica 300% FIXO, SEMPRE, upando, desupando, pegando qlq tipo de exp, ela mantém 300.

 

unknown.png

 

unknown.png

 

unknown.png

 

unknown.png

Link para o post
Compartilhar em outros sites
25 minutos atrás, FlavioHulk disse:

Jobs, poderia postar teu protocolgame.cpp aqui?

 



/** * The Forgotten Server - a free and open-source MMORPG server emulator * Copyright (C) 2017 Mark Samman <[email protected]> * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "otpch.h" #include <boost/range/adaptor/reversed.hpp> #include "protocolgame.h" #include "outputmessage.h" #include "player.h" #include "configmanager.h" #include "actions.h" #include "game.h" #include "iologindata.h" #include "iomarket.h" #include "waitlist.h" #include "ban.h" #include "scheduler.h" #include "databasetasks.h" #include "modules.h" extern Game g_game; extern ConfigManager g_config; extern Actions actions; extern CreatureEvents* g_creatureEvents; extern Chat* g_chat; extern Modules* g_modules; ProtocolGame::LiveCastsMap ProtocolGame::liveCasts; void ProtocolGame::release() { //dispatcher thread stopLiveCast(); if (player && player->client == shared_from_this()) { if (player->getTile() && (player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) || !player->hasCondition(CONDITION_INFIGHT))) { logout(true, true); } player->client.reset(); player->decrementReferenceCounter(); player = nullptr; } OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this()); Protocol::release(); } void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem) { //dispatcher thread Player* foundPlayer = g_game.getPlayerByName(name); if (!foundPlayer || g_config.getBoolean(ConfigManager::ALLOW_CLONES)) { player = new Player(getThis()); player->setName(name); player->incrementReferenceCounter(); player->setID(); if (!IOLoginData::preloadPlayer(player, name)) { disconnectClient("Your character could not be loaded."); return; } if (IOBan::isPlayerNamelocked(player->getGUID())) { disconnectClient("Your character has been namelocked."); return; } if (g_game.getGameState() == GAME_STATE_CLOSING && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("The game is just going down.\nPlease try again later."); return; } if (g_game.getGameState() == GAME_STATE_CLOSED && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("Server is currently closed.\nPlease try again later."); return; } if (g_config.getBoolean(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && player->getAccountType() < ACCOUNT_TYPE_GAMEMASTER && g_game.getPlayerByAccount(player->getAccount())) { disconnectClient("You may only login with one character\nof your account at the same time."); return; } if (!player->hasFlag(PlayerFlag_CannotBeBanned)) { BanInfo banInfo; if (IOBan::isAccountBanned(accountId, banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; if (banInfo.expiresAt > 0) { ss << "Your account has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; } else { ss << "Your account has been permanently banned by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; } disconnectClient(ss.str()); return; } } WaitingList& waitingList = WaitingList::getInstance(); if (!waitingList.clientLogin(player)) { uint32_t currentSlot = waitingList.getClientSlot(player); uint32_t retryTime = WaitingList::getTime(currentSlot); std::ostringstream ss; ss << "Too many players online.\nYou are at place " << currentSlot << " on the waiting list."; auto output = OutputMessagePool::getOutputMessage(); output->addByte(0x16); output->addString(ss.str()); output->addByte(retryTime); send(output); disconnect(); return; } if (!IOLoginData::loadPlayerById(player, player->getGUID())) { disconnectClient("Your character could not be loaded."); return; } // Prey System IOLoginData::loadPlayerPreyById(player, player->getGUID()); player->setOperatingSystem(operatingSystem); if (!g_game.placeCreature(player, player->getLoginPosition())) { if (!g_game.placeCreature(player, player->getTemplePosition(), false, true)) { disconnectClient("Temple position is wrong. Contact the administrator."); return; } } if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) { player->registerCreatureEvent("ExtendedOpcode"); } player->lastIP = player->getIP(); player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1); acceptPackets = true; } else { if (eventConnect != 0 || !g_config.getBoolean(ConfigManager::REPLACE_KICK_ON_LOGIN)) { //Already trying to connect disconnectClient("You are already logged in."); return; } if (foundPlayer->client) { foundPlayer->disconnect(); foundPlayer->isConnecting = true; eventConnect = g_scheduler.addEvent(createSchedulerTask(1000, std::bind(&ProtocolGame::connect, getThis(), foundPlayer->getID(), operatingSystem))); } else { connect(foundPlayer->getID(), operatingSystem); } } OutputMessagePool::getInstance().addProtocolToAutosend(shared_from_this()); } void ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem) { eventConnect = 0; Player* foundPlayer = g_game.getPlayerByID(playerId); if (!foundPlayer || foundPlayer->client) { disconnectClient("You are already logged in."); return; } if (isConnectionExpired()) { //ProtocolGame::release() has been called at this point and the Connection object //no longer exists, so we return to prevent leakage of the Player. return; } player = foundPlayer; player->incrementReferenceCounter(); g_chat->removeUserFromAllChannels(*player); player->clearModalWindows(); player->setOperatingSystem(operatingSystem); player->isConnecting = false; player->client = getThis(); sendAddCreature(player, player->getPosition(), 0, false); player->lastIP = player->getIP(); player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1); acceptPackets = true; } void ProtocolGame::logout(bool displayEffect, bool forced) { //dispatcher thread if (!player) { return; } if (!player->isRemoved()) { if (!forced) { if (!player->isAccessPlayer()) { if (player->getTile()->hasFlag(TILESTATE_NOLOGOUT)) { player->sendCancelMessage(RETURNVALUE_YOUCANNOTLOGOUTHERE); return; } if (!player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) && player->hasCondition(CONDITION_INFIGHT)) { player->sendCancelMessage(RETURNVALUE_YOUMAYNOTLOGOUTDURINGAFIGHT); return; } } //scripting event - onLogout if (!g_creatureEvents->playerLogout(player)) { //Let the script handle the error message return; } } if (displayEffect && player->getHealth() > 0) { g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF); } } stopLiveCast(); disconnect(); g_game.removeCreature(player); } bool ProtocolGame::startLiveCast(const std::string& password /*= ""*/) { auto connection = getConnection(); if (!g_config.getBoolean(ConfigManager::ENABLE_LIVE_CASTING) || isLiveCaster() || !player || player->isRemoved() || !connection || liveCasts.size() >= getMaxLiveCastCount()) { return false; } { std::lock_guard<decltype(liveCastLock)> lock{ liveCastLock }; //DO NOT do any send operations here liveCastName = player->getName(); liveCastPassword = password; isCaster.store(true, std::memory_order_relaxed); } liveCasts.insert(std::make_pair(player, getThis())); registerLiveCast(); //Send a "dummy" channel sendChannel(CHANNEL_CAST, LIVE_CAST_CHAT_NAME, nullptr, nullptr); return true; } bool ProtocolGame::stopLiveCast() { //dispatcher if (!isLiveCaster()) { return false; } CastSpectatorVec spectators; { std::lock_guard<decltype(liveCastLock)> lock{ liveCastLock }; //DO NOT do any send operations here std::swap(this->spectators, spectators); isCaster.store(false, std::memory_order_relaxed); } liveCasts.erase(player); for (auto& spectator : spectators) { spectator->onLiveCastStop(); } unregisterLiveCast(); return true; } void ProtocolGame::clearLiveCastInfo() { static std::once_flag flag; std::call_once(flag, []() { assert(g_game.getGameState() == GAME_STATE_INIT); std::ostringstream query; query << "TRUNCATE TABLE `live_casts`;"; g_databaseTasks.addTask(query.str()); }); } void ProtocolGame::registerLiveCast() { std::ostringstream query; query << "INSERT into `live_casts` (`player_id`, `cast_name`, `password`) VALUES (" << player->getGUID() << ", '" << getLiveCastName() << "', " << isPasswordProtected() << ");"; g_databaseTasks.addTask(query.str()); } void ProtocolGame::unregisterLiveCast() { std::ostringstream query; query << "DELETE FROM `live_casts` WHERE `player_id`=" << player->getGUID() << ";"; g_databaseTasks.addTask(query.str()); } void ProtocolGame::updateLiveCastInfo() { std::ostringstream query; query << "UPDATE `live_casts` SET `cast_name`='" << getLiveCastName() << "', `password`=" << isPasswordProtected() << ", `spectators`=" << getSpectatorCount() << " WHERE `player_id`=" << player->getGUID() << ";"; g_databaseTasks.addTask(query.str()); } void ProtocolGame::addSpectator(ProtocolSpectator_ptr spectatorClient) { std::lock_guard<decltype(liveCastLock)> lock(liveCastLock); //DO NOT do any send operations here spectators.emplace_back(spectatorClient); updateLiveCastInfo(); } void ProtocolGame::removeSpectator(ProtocolSpectator_ptr spectatorClient) { std::lock_guard<decltype(liveCastLock)> lock(liveCastLock); //DO NOT do any send operations here auto it = std::find(spectators.begin(), spectators.end(), spectatorClient); if (it != spectators.end()) { spectators.erase(it); updateLiveCastInfo(); } } void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { disconnect(); return; } OperatingSystem_t operatingSystem = static_cast<OperatingSystem_t>(msg.get<uint16_t>()); version = msg.get<uint16_t>(); if (version >= 1111) { enableCompact(); } msg.skipBytes(7); // U32 client version, U8 client type, U16 dat revision if (!Protocol::RSA_decrypt(msg)) { disconnect(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) { NetworkMessage opcodeMessage; opcodeMessage.addByte(0x32); opcodeMessage.addByte(0x00); opcodeMessage.add<uint16_t>(0x00); writeToOutputBuffer(opcodeMessage); } msg.skipBytes(1); // gamemaster flag std::string sessionKey = msg.getString(); size_t pos = sessionKey.find('\n'); if (pos == std::string::npos) { disconnectClient("You must enter your account name."); return; } std::string accountName = sessionKey.substr(0, pos); if (accountName.empty()) { disconnectClient("You must enter your account name."); return; } std::string password = sessionKey.substr(pos + 1); std::string characterName = msg.getString(); uint32_t timeStamp = msg.get<uint32_t>(); uint8_t randNumber = msg.getByte(); if (challengeTimestamp != timeStamp || challengeRandom != randNumber) { disconnect(); return; } if (version < g_config.getNumber(ConfigManager::VERSION_MIN) || version > g_config.getNumber(ConfigManager::VERSION_MAX)) { std::ostringstream ss; ss << "Only clients with protocol " << g_config.getString(ConfigManager::VERSION_STR) << " allowed!"; disconnectClient(ss.str()); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient("Gameworld is under maintenance. Please re-connect in a while."); return; } BanInfo banInfo; if (IOBan::isIpBanned(getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; disconnectClient(ss.str()); return; } uint32_t accountId = IOLoginData::gameworldAuthentication(accountName, password, characterName); if (accountId == 0) { disconnectClient("Account name or password is not correct."); return; } g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem))); } void ProtocolGame::disconnectClient(const std::string& message) const { auto output = OutputMessagePool::getOutputMessage(); output->addByte(0x14); output->addString(message); send(output); disconnect(); } void ProtocolGame::writeToOutputBuffer(const NetworkMessage& msg, bool broadcast /*= true*/) { if (!broadcast && isLiveCaster()) { //We're casting and we need to send a packet that's not supposed to be broadcast so we need a new messasge. //This shouldn't impact performance by a huge amount as most packets can be broadcast. auto out = OutputMessagePool::getOutputMessage(); out->append(msg); send(std::move(out)); } else { auto out = getOutputBuffer(msg.getLength()); if (isLiveCaster()) { out->setBroadcastMsg(true); } out->append(msg); } } void ProtocolGame::parsePacket(NetworkMessage& msg) { if (!acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getLength() <= 0) { return; } uint8_t recvbyte = msg.getByte(); //a dead player can not perform actions if (!player || player->isRemoved() || player->getHealth() <= 0) { auto this_ptr = getThis(); g_dispatcher.addTask(createTask([this_ptr]() { this_ptr->stopLiveCast(); })); if (recvbyte == 0x0F) { // we need to make the player pointer != null in this part, game.cpp release is the first step // login(player->getName(), player->getAccount(), player->operatingSystem); disconnect(); return; } if (recvbyte != 0x14) { return; } } g_dispatcher.addTask(createTask(std::bind(&Modules::executeOnRecvbyte, g_modules, player, msg, recvbyte))); switch (recvbyte) { case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break; case 0x1D: addGameTask(&Game::playerReceivePingBack, player->getID()); break; case 0x1E: addGameTask(&Game::playerReceivePing, player->getID()); break; case 0x32: parseExtendedOpcode(msg); break; //otclient extended opcode case 0x64: parseAutoWalk(msg); break; case 0x65: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); break; case 0x66: addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); break; case 0x67: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); break; case 0x68: addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); break; case 0x69: addGameTask(&Game::playerStopAutoWalk, player->getID()); break; case 0x6A: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); break; case 0x6B: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); break; case 0x6C: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); break; case 0x6D: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); break; case 0x6F: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_NORTH); break; case 0x70: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_EAST); break; case 0x71: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_SOUTH); break; case 0x72: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_WEST); break; case 0x78: parseThrow(msg); break; case 0x79: parseLookInShop(msg); break; case 0x7A: parsePlayerPurchase(msg); break; case 0x7B: parsePlayerSale(msg); break; case 0x7C: addGameTask(&Game::playerCloseShop, player->getID()); break; case 0x7D: parseRequestTrade(msg); break; case 0x7E: parseLookInTrade(msg); break; case 0x7F: addGameTask(&Game::playerAcceptTrade, player->getID()); break; case 0x80: addGameTask(&Game::playerCloseTrade, player->getID()); break; case 0x82: parseUseItem(msg); break; case 0x83: parseUseItemEx(msg); break; case 0x84: parseUseWithCreature(msg); break; case 0x85: parseRotateItem(msg); break; case 0x87: parseCloseContainer(msg); break; case 0x88: parseUpArrowContainer(msg); break; case 0x89: parseTextWindow(msg); break; case 0x8A: parseHouseWindow(msg); break; case 0x8B: parseWrapableItem(msg); break; case 0x8C: parseLookAt(msg); break; case 0x8D: parseLookInBattleList(msg); break; case 0x8E: /* join aggression */ break; case 0x96: parseSay(msg); break; case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break; case 0x98: parseOpenChannel(msg); break; case 0x99: parseCloseChannel(msg); break; case 0x9A: parseOpenPrivateChannel(msg); break; case 0x9E: addGameTask(&Game::playerCloseNpcChannel, player->getID()); break; case 0xA0: parseFightModes(msg); break; case 0xA1: parseAttack(msg); break; case 0xA2: parseFollow(msg); break; case 0xA3: parseInviteToParty(msg); break; case 0xA4: parseJoinParty(msg); break; case 0xA5: parseRevokePartyInvite(msg); break; case 0xA6: parsePassPartyLeadership(msg); break; case 0xA7: addGameTask(&Game::playerLeaveParty, player->getID()); break; case 0xA8: parseEnableSharedPartyExperience(msg); break; case 0xAA: addGameTask(&Game::playerCreatePrivateChannel, player->getID()); break; case 0xAB: parseChannelInvite(msg); break; case 0xAC: parseChannelExclude(msg); break; case 0xBE: addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); break; case 0xC9: /* update tile */ break; case 0xCA: parseUpdateContainer(msg); break; case 0xCB: parseBrowseField(msg); break; case 0xCC: parseSeekInContainer(msg); break; case 0xD2: addGameTask(&Game::playerRequestOutfit, player->getID()); break; case 0xD3: parseSetOutfit(msg); break; case 0xD4: parseToggleMount(msg); break; case 0xDC: parseAddVip(msg); break; case 0xDD: parseRemoveVip(msg); break; case 0xDE: parseEditVip(msg); break; case 0xE6: parseBugReport(msg); break; case 0xE7: /* thank you */ break; case 0xE8: parseDebugAssert(msg); break; case 0xEF: if (!g_config.getBoolean(ConfigManager::STOREMODULES)) { parseCoinTransfer(msg); } break; /* premium coins transfer */ case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break; case 0xF1: parseQuestLine(msg); break; case 0xF2: parseRuleViolationReport(msg); break; case 0xF3: /* get object info */ break; case 0xF4: parseMarketLeave(); break; case 0xF5: parseMarketBrowse(msg); break; case 0xF6: parseMarketCreateOffer(msg); break; case 0xF7: parseMarketCancelOffer(msg); break; case 0xF8: parseMarketAcceptOffer(msg); break; case 0xF9: parseModalWindowAnswer(msg); break; case 0xFA: if (!g_config.getBoolean(ConfigManager::STOREMODULES)) { parseStoreOpen(msg); } break; case 0xFB: if (!g_config.getBoolean(ConfigManager::STOREMODULES)) { parseStoreRequestOffers(msg); } break; case 0xFC: if (!g_config.getBoolean(ConfigManager::STOREMODULES)) { parseStoreBuyOffer(msg); } break; // case 0xFD: parseStoreOpenTransactionHistory(msg); break; // case 0xFE: parseStoreRequestTransactionHistory(msg); break; //case 0x77 Equip Hotkey. //case 0xDF, 0xE0, 0xE1, 0xFB, 0xFC, 0xFD, 0xFE Premium Shop. default: // std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl; break; } if (msg.isOverrun()) { disconnect(); } } // Parse methods 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::parseOpenChannel(NetworkMessage& msg) { uint16_t channelId = msg.get<uint16_t>(); addGameTask(&Game::playerOpenChannel, player->getID(), channelId); } void ProtocolGame::parseCloseChannel(NetworkMessage& msg) { uint16_t channelId = msg.get<uint16_t>(); addGameTask(&Game::playerCloseChannel, player->getID(), channelId); } void ProtocolGame::parseOpenPrivateChannel(NetworkMessage& msg) { const std::string receiver = msg.getString(); addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver); } void ProtocolGame::parseAutoWalk(NetworkMessage& msg) { uint8_t numdirs = msg.getByte(); if (numdirs == 0 || (msg.getBufferPosition() + numdirs) != (msg.getLength() + 8)) { return; } msg.skipBytes(numdirs); std::forward_list<Direction> path; for (uint8_t i = 0; i < numdirs; ++i) { uint8_t rawdir = msg.getPreviousByte(); switch (rawdir) { case 1: path.push_front(DIRECTION_EAST); break; case 2: path.push_front(DIRECTION_NORTHEAST); break; case 3: path.push_front(DIRECTION_NORTH); break; case 4: path.push_front(DIRECTION_NORTHWEST); break; case 5: path.push_front(DIRECTION_WEST); break; case 6: path.push_front(DIRECTION_SOUTHWEST); break; case 7: path.push_front(DIRECTION_SOUTH); break; case 8: path.push_front(DIRECTION_SOUTHEAST); break; default: break; } } if (path.empty()) { return; } addGameTask(&Game::playerAutoWalk, player->getID(), path); } void ProtocolGame::parseSetOutfit(NetworkMessage& msg) { Outfit_t newOutfit; newOutfit.lookType = msg.get<uint16_t>(); newOutfit.lookHead = msg.getByte(); newOutfit.lookBody = msg.getByte(); newOutfit.lookLegs = msg.getByte(); newOutfit.lookFeet = msg.getByte(); newOutfit.lookAddons = msg.getByte(); newOutfit.lookMount = msg.get<uint16_t>(); addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit); } void ProtocolGame::parseToggleMount(NetworkMessage& msg) { bool mount = msg.getByte() != 0; addGameTask(&Game::playerToggleMount, player->getID(), mount); } void ProtocolGame::parseUseItem(NetworkMessage& msg) { Position pos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t stackpos = msg.getByte(); uint8_t index = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItem, player->getID(), pos, stackpos, index, spriteId); } void ProtocolGame::parseUseItemEx(NetworkMessage& msg) { Position fromPos = msg.getPosition(); uint16_t fromSpriteId = msg.get<uint16_t>(); uint8_t fromStackPos = msg.getByte(); Position toPos = msg.getPosition(); uint16_t toSpriteId = msg.get<uint16_t>(); uint8_t toStackPos = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItemEx, player->getID(), fromPos, fromStackPos, fromSpriteId, toPos, toStackPos, toSpriteId); } void ProtocolGame::parseUseWithCreature(NetworkMessage& msg) { Position fromPos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t fromStackPos = msg.getByte(); uint32_t creatureId = msg.get<uint32_t>(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseWithCreature, player->getID(), fromPos, fromStackPos, creatureId, spriteId); } 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::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.get<uint16_t>(); uint8_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(); msg.skipBytes(2); // spriteId uint8_t stackpos = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, stackpos); } void ProtocolGame::parseLookInBattleList(NetworkMessage& msg) { uint32_t creatureId = msg.get<uint32_t>(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInBattleList, player->getID(), creatureId); } void ProtocolGame::parseSay(NetworkMessage& msg) { std::string receiver; uint16_t channelId; SpeakClasses type = static_cast<SpeakClasses>(msg.getByte()); switch (type) { case TALKTYPE_PRIVATE_TO: case TALKTYPE_PRIVATE_RED_TO: receiver = msg.getString(); channelId = 0; break; case TALKTYPE_CHANNEL_Y: case TALKTYPE_CHANNEL_R1: channelId = msg.get<uint16_t>(); break; default: channelId = 0; break; } const std::string text = msg.getString(); if (text.length() > 255) { return; } addGameTask(&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 // uint8_t rawPvpMode = msg.getByte(); // pvp mode introduced in 10.0 fightMode_t fightMode; if (rawFightMode == 1) { fightMode = FIGHTMODE_ATTACK; } else if (rawFightMode == 2) { fightMode = FIGHTMODE_BALANCED; } else { fightMode = FIGHTMODE_DEFENSE; } addGameTask(&Game::playerSetFightModes, player->getID(), fightMode, rawChaseMode != 0, rawSecureMode != 0); } void ProtocolGame::parseAttack(NetworkMessage& msg) { uint32_t creatureId = msg.get<uint32_t>(); // msg.get<uint32_t>(); creatureId (same as above) addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId); } void ProtocolGame::parseFollow(NetworkMessage& msg) { uint32_t creatureId = msg.get<uint32_t>(); // msg.get<uint32_t>(); creatureId (same as above) addGameTask(&Game::playerFollowCreature, player->getID(), creatureId); } void ProtocolGame::parseTextWindow(NetworkMessage& msg) { uint32_t windowTextId = msg.get<uint32_t>(); 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.get<uint32_t>(); const std::string text = msg.getString(); addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text); } void ProtocolGame::parseLookInShop(NetworkMessage& msg) { uint16_t id = msg.get<uint16_t>(); uint8_t count = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInShop, player->getID(), id, count); } void ProtocolGame::parsePlayerPurchase(NetworkMessage& msg) { uint16_t id = msg.get<uint16_t>(); uint8_t count = msg.getByte(); uint8_t amount = msg.getByte(); bool ignoreCap = msg.getByte() != 0; bool inBackpacks = msg.getByte() != 0; addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerPurchaseItem, player->getID(), id, count, amount, ignoreCap, inBackpacks); } void ProtocolGame::parsePlayerSale(NetworkMessage& msg) { uint16_t id = msg.get<uint16_t>(); uint8_t count = msg.getByte(); uint8_t amount = msg.getByte(); bool ignoreEquipped = msg.getByte() != 0; addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount, ignoreEquipped); } void ProtocolGame::parseRequestTrade(NetworkMessage& msg) { Position pos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t stackpos = msg.getByte(); uint32_t playerId = msg.get<uint32_t>(); addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId); } void ProtocolGame::parseLookInTrade(NetworkMessage& msg) { bool counterOffer = (msg.getByte() == 0x01); uint8_t index = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInTrade, player->getID(), counterOffer, index); } void ProtocolGame::parseAddVip(NetworkMessage& msg) { const std::string name = msg.getString(); addGameTask(&Game::playerRequestAddVip, player->getID(), name); } void ProtocolGame::parseRemoveVip(NetworkMessage& msg) { uint32_t guid = msg.get<uint32_t>(); addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid); } void ProtocolGame::parseEditVip(NetworkMessage& msg) { uint32_t guid = msg.get<uint32_t>(); const std::string description = msg.getString(); uint32_t icon = std::min<uint32_t>(10, msg.get<uint32_t>()); // 10 is max icon in 9.63 bool notify = msg.getByte() != 0; addGameTask(&Game::playerRequestEditVip, player->getID(), guid, description, icon, notify); } void ProtocolGame::parseRotateItem(NetworkMessage& msg) { Position pos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t stackpos = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerRotateItem, player->getID(), pos, stackpos, spriteId); } void ProtocolGame::parseWrapableItem(NetworkMessage& msg) { Position pos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t stackpos = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerWrapableItem, player->getID(), pos, stackpos, spriteId); } void ProtocolGame::parseRuleViolationReport(NetworkMessage &msg) { uint8_t reportType = msg.getByte(); uint8_t reportReason = msg.getByte(); const std::string& targetName = msg.getString(); const std::string& comment = msg.getString(); std::string translation; if (reportType == REPORT_TYPE_NAME) { translation = msg.getString(); } else if (reportType == REPORT_TYPE_STATEMENT) { translation = msg.getString(); msg.get<uint32_t>(); // statement id, used to get whatever player have said, we don't log that. } addGameTask(&Game::playerReportRuleViolationReport, player->getID(), targetName, reportType, reportReason, comment, translation); } void ProtocolGame::parseBugReport(NetworkMessage& msg) { uint8_t category = msg.getByte(); std::string message = msg.getString(); Position position; if (category == BUG_CATEGORY_MAP) { position = msg.getPosition(); } addGameTask(&Game::playerReportBug, player->getID(), message, position, category); } void ProtocolGame::parseDebugAssert(NetworkMessage& msg) { if (debugAssertSent) { return; } debugAssertSent = true; std::string assertLine = msg.getString(); std::string date = msg.getString(); std::string description = msg.getString(); std::string comment = msg.getString(); addGameTask(&Game::playerDebugAssert, player->getID(), assertLine, date, description, comment); } void ProtocolGame::parseInviteToParty(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerInviteToParty, player->getID(), targetId); } void ProtocolGame::parseJoinParty(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerJoinParty, player->getID(), targetId); } void ProtocolGame::parseRevokePartyInvite(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId); } void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId); } void ProtocolGame::parseEnableSharedPartyExperience(NetworkMessage& msg) { bool sharedExpActive = msg.getByte() == 1; addGameTask(&Game::playerEnableSharedPartyExperience, player->getID(), sharedExpActive); } void ProtocolGame::parseQuestLine(NetworkMessage& msg) { uint16_t questId = msg.get<uint16_t>(); addGameTask(&Game::playerShowQuestLine, player->getID(), questId); } void ProtocolGame::parseMarketLeave() { addGameTask(&Game::playerLeaveMarket, player->getID()); } void ProtocolGame::parseMarketBrowse(NetworkMessage& msg) { uint16_t browseId = msg.get<uint16_t>(); if (browseId == MARKETREQUEST_OWN_OFFERS) { addGameTask(&Game::playerBrowseMarketOwnOffers, player->getID()); } else if (browseId == MARKETREQUEST_OWN_HISTORY) { addGameTask(&Game::playerBrowseMarketOwnHistory, player->getID()); } else { addGameTask(&Game::playerBrowseMarket, player->getID(), browseId); } } void ProtocolGame::parseStoreOpen(NetworkMessage &msg) { uint8_t serviceType = msg.getByte(); addGameTaskTimed(600,&Game::playerStoreOpen, player->getID(), serviceType); } void ProtocolGame::parseStoreRequestOffers(NetworkMessage &message) { //StoreService_t serviceType = SERVICE_STANDARD; message.getByte(); // discard service type byte // version >= 1092 std::string categoryName = message.getString(); const int16_t index = g_game.gameStore.getCategoryIndexByName(categoryName); if(index >= 0) { addGameTaskTimed(350, &Game::playerShowStoreCategoryOffers, player->getID(), g_game.gameStore.getCategoryOffers().at(index)); } else { std::cout << "[Warning - ProtocolGame::parseStoreRequestOffers] requested category: \""<< categoryName <<"\" doesn't exists" << std::endl; } } void ProtocolGame::parseStoreBuyOffer(NetworkMessage &message) { uint32_t offerId = message.get<uint32_t>(); uint8_t productType = message.getByte(); //used only in return of a namechange offer request std::string additionalInfo; if(productType == ADDITIONALINFO) { additionalInfo = message.getString(); } addGameTaskTimed(350, &Game::playerBuyStoreOffer, player->getID(), offerId, productType, additionalInfo); } void ProtocolGame::parseStoreOpenTransactionHistory(NetworkMessage& msg) { uint8_t entriesPerPage = msg.getByte(); if(entriesPerPage>0 && entriesPerPage!=GameStore::HISTORY_ENTRIES_PER_PAGE) { GameStore::HISTORY_ENTRIES_PER_PAGE=entriesPerPage; } addGameTaskTimed(2000, &Game::playerStoreTransactionHistory, player->getID(), 1); } void ProtocolGame::parseStoreRequestTransactionHistory(NetworkMessage& msg) { uint32_t pageNumber = msg.get<uint32_t>(); addGameTaskTimed(2000,&Game::playerStoreTransactionHistory,player->getID(), pageNumber); } void ProtocolGame::parseCoinTransfer(NetworkMessage& msg) { std::string receiverName =msg.getString(); uint32_t amount = msg.get<uint32_t>(); if(amount > 0) addGameTaskTimed(350, &Game::playerCoinTransfer, player->getID(), receiverName, amount); } void ProtocolGame::parseMarketCreateOffer(NetworkMessage& msg) { uint8_t type = msg.getByte(); uint16_t spriteId = msg.get<uint16_t>(); uint16_t amount = msg.get<uint16_t>(); uint32_t price = msg.get<uint32_t>(); bool anonymous = (msg.getByte() != 0); if(amount>0 && price >0) addGameTask(&Game::playerCreateMarketOffer, player->getID(), type, spriteId, amount, price, anonymous); } void ProtocolGame::parseMarketCancelOffer(NetworkMessage& msg) { uint32_t timestamp = msg.get<uint32_t>(); uint16_t counter = msg.get<uint16_t>(); if(counter > 0) addGameTask(&Game::playerCancelMarketOffer, player->getID(), timestamp, counter); } void ProtocolGame::parseMarketAcceptOffer(NetworkMessage& msg) { uint32_t timestamp = msg.get<uint32_t>(); uint16_t counter = msg.get<uint16_t>(); uint16_t amount = msg.get<uint16_t>(); if(amount > 0 && counter > 0) addGameTask(&Game::playerAcceptMarketOffer, player->getID(), timestamp, counter, amount); } void ProtocolGame::parseModalWindowAnswer(NetworkMessage& msg) { uint32_t id = msg.get<uint32_t>(); uint8_t button = msg.getByte(); uint8_t choice = msg.getByte(); addGameTask(&Game::playerAnswerModalWindow, player->getID(), id, button, choice); } void ProtocolGame::parseBrowseField(NetworkMessage& msg) { const Position& pos = msg.getPosition(); addGameTask(&Game::playerBrowseField, player->getID(), pos); } void ProtocolGame::parseSeekInContainer(NetworkMessage& msg) { uint8_t containerId = msg.getByte(); uint16_t index = msg.get<uint16_t>(); addGameTask(&Game::playerSeekInContainer, player->getID(), containerId, index); } // Send methods void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver) { NetworkMessage msg; msg.addByte(0xAD); msg.addString(receiver); writeToOutputBuffer(msg); } void ProtocolGame::sendChannelEvent(uint16_t channelId, const std::string& playerName, ChannelEvent_t channelEvent) { NetworkMessage msg; msg.addByte(0xF3); msg.add<uint16_t>(channelId); msg.addString(playerName); msg.addByte(channelEvent); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x8E); msg.add<uint32_t>(creature->getID()); AddOutfit(msg, outfit); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureWalkthrough(const Creature* creature, bool walkthrough) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x92); msg.add<uint32_t>(creature->getID()); msg.addByte(walkthrough ? 0x00 : 0x01); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureShield(const Creature* creature) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x91); msg.add<uint32_t>(creature->getID()); msg.addByte(player->getPartyShield(creature->getPlayer())); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureSkull(const Creature* creature) { if (g_game.getWorldType() != WORLD_TYPE_PVP) { return; } if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x90); msg.add<uint32_t>(creature->getID()); msg.addByte(player->getSkullClient(creature)); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureType(const Creature* creature, uint8_t creatureType) { NetworkMessage msg; msg.addByte(0x95); msg.add<uint32_t>(creature->getID()); msg.addByte(creatureType); if (player->getOperatingSystem() == CLIENTOS_WINDOWS && player->getProtocolVersion() >= 1120) { msg.addByte(creatureType); // type or any byte idk } if (creatureType == CREATURETYPE_SUMMONPLAYER && player->getProtocolVersion() >= 1120) { const Creature* master = creature->getMaster(); if (master) { msg.add<uint32_t>(master->getID()); } } writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureHelpers(uint32_t creatureId, uint16_t helpers) { NetworkMessage msg; msg.addByte(0x94); msg.add<uint32_t>(creatureId); msg.add<uint16_t>(helpers); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureSquare(const Creature* creature, SquareColor_t color) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x93); msg.add<uint32_t>(creature->getID()); msg.addByte(0x01); msg.addByte(color); writeToOutputBuffer(msg); } void ProtocolGame::sendTutorial(uint8_t tutorialId) { NetworkMessage msg; msg.addByte(0xDC); msg.addByte(tutorialId); writeToOutputBuffer(msg); } void ProtocolGame::sendAddMarker(const Position& pos, uint8_t markType, const std::string& desc) { NetworkMessage msg; msg.addByte(0xDD); msg.addPosition(pos); msg.addByte(markType); msg.addString(desc); writeToOutputBuffer(msg); } void ProtocolGame::sendReLoginWindow(uint8_t unfairFightReduction) { NetworkMessage msg; msg.addByte(0x28); msg.addByte(0x00); msg.addByte(unfairFightReduction); if (version >= 1120) { msg.addByte(0x00); //Use death redemption } writeToOutputBuffer(msg); } void ProtocolGame::sendTextMessage(const TextMessage& message) { NetworkMessage msg; msg.addByte(0xB4); msg.addByte(message.type); switch (message.type) { case MESSAGE_DAMAGE_DEALT: case MESSAGE_DAMAGE_RECEIVED: case MESSAGE_DAMAGE_OTHERS: { msg.addPosition(message.position); msg.add<uint32_t>(message.primary.value); msg.addByte(message.primary.color); msg.add<uint32_t>(message.secondary.value); msg.addByte(message.secondary.color); break; } case MESSAGE_HEALED: case MESSAGE_HEALED_OTHERS: case MESSAGE_EXPERIENCE: case MESSAGE_EXPERIENCE_OTHERS: { msg.addPosition(message.position); msg.add<uint32_t>(message.primary.value); msg.addByte(message.primary.color); break; } case MESSAGE_GUILD: case MESSAGE_PARTY_MANAGEMENT: case MESSAGE_PARTY: msg.add<uint16_t>(message.channelId); break; default: { break; } } msg.addString(message.text); writeToOutputBuffer(msg); } void ProtocolGame::sendClosePrivate(uint16_t channelId) { NetworkMessage msg; msg.addByte(0xB3); msg.add<uint16_t>(channelId); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName) { NetworkMessage msg; msg.addByte(0xB2); msg.add<uint16_t>(channelId); msg.addString(channelName); msg.add<uint16_t>(0x01); msg.addString(player->getName()); msg.add<uint16_t>(0x00); writeToOutputBuffer(msg); } void ProtocolGame::sendChannelsDialog() { NetworkMessage msg; msg.addByte(0xAB); const ChannelList& list = g_chat->getChannelList(*player); msg.addByte(list.size()); for (ChatChannel* channel : list) { msg.add<uint16_t>(channel->getId()); msg.addString(channel->getName()); } writeToOutputBuffer(msg); } void ProtocolGame::sendIcons(uint16_t icons) { NetworkMessage msg; msg.addByte(0xA2); if(version >= 1140) // TODO: verify compatibility of the new icon range ( 16-31 ) msg.add<uint32_t>(icons); else msg.add<uint16_t>(icons); writeToOutputBuffer(msg); } void ProtocolGame::sendShop(Npc* npc, const ShopInfoList& itemList) { NetworkMessage msg; msg.addByte(0x7A); msg.addString(npc->getName()); uint16_t itemsToSend = std::min<size_t>(itemList.size(), std::numeric_limits<uint16_t>::max()); msg.add<uint16_t>(itemsToSend); uint16_t i = 0; for (auto it = itemList.begin(); i < itemsToSend; ++it, ++i) { AddShopItem(msg, *it); } writeToOutputBuffer(msg); } void ProtocolGame::sendCloseShop() { NetworkMessage msg; msg.addByte(0x7C); writeToOutputBuffer(msg); } void ProtocolGame::sendClientCheck() { NetworkMessage msg; msg.addByte(0x63); msg.add<uint32_t>(1); msg.addByte(1); writeToOutputBuffer(msg); } void ProtocolGame::sendGameNews() { NetworkMessage msg; msg.addByte(0x98); msg.add<uint32_t>(1); // unknown msg.addByte(1); //(0 = open | 1 = highlight) writeToOutputBuffer(msg); } void ProtocolGame::sendResourceBalance(uint64_t money, uint64_t bank) { NetworkMessage msg; msg.addByte(0xEE); msg.addByte(0x00); msg.add<uint64_t>(bank); msg.addByte(0xEE); msg.addByte(0x01); msg.add<uint64_t>(money); writeToOutputBuffer(msg); } void ProtocolGame::sendSaleItemList(const std::list<ShopInfo>& shop) { if (player->getProtocolVersion() >= 1100) { sendResourceBalance(player->getMoney(), player->getBankBalance()); } NetworkMessage msg; msg.addByte(0x7B); msg.add<uint64_t>(player->getMoney() + player->getBankBalance()); std::map<uint16_t, uint32_t> saleMap; if (shop.size() <= 5) { // For very small shops it's not worth it to create the complete map for (const ShopInfo& shopInfo : shop) { if (shopInfo.sellPrice == 0) { continue; } int8_t subtype = -1; const ItemType& itemType = Item::items[shopInfo.itemId]; if (itemType.hasSubType() && !itemType.stackable) { subtype = (shopInfo.subType == 0 ? -1 : shopInfo.subType); } uint32_t count = player->getItemTypeCount(shopInfo.itemId, subtype); if (count > 0) { saleMap[shopInfo.itemId] = count; } } } else { // Large shop, it's better to get a cached map of all item counts and use it // We need a temporary map since the finished map should only contain items // available in the shop std::map<uint32_t, uint32_t> tempSaleMap; player->getAllItemTypeCount(tempSaleMap); // We must still check manually for the special items that require subtype matches // (That is, fluids such as potions etc., actually these items are very few since // health potions now use their own ID) for (const ShopInfo& shopInfo : shop) { if (shopInfo.sellPrice == 0) { continue; } int8_t subtype = -1; const ItemType& itemType = Item::items[shopInfo.itemId]; if (itemType.hasSubType() && !itemType.stackable) { subtype = (shopInfo.subType == 0 ? -1 : shopInfo.subType); } if (subtype != -1) { uint32_t count; if (!itemType.isFluidContainer() && !itemType.isSplash()) { count = player->getItemTypeCount(shopInfo.itemId, subtype); // This shop item requires extra checks } else { count = subtype; } if (count > 0) { saleMap[shopInfo.itemId] = count; } } else { std::map<uint32_t, uint32_t>::const_iterator findIt = tempSaleMap.find(shopInfo.itemId); if (findIt != tempSaleMap.end() && findIt->second > 0) { saleMap[shopInfo.itemId] = findIt->second; } } } } uint8_t itemsToSend = std::min<size_t>(saleMap.size(), std::numeric_limits<uint8_t>::max()); msg.addByte(itemsToSend); uint8_t i = 0; for (std::map<uint16_t, uint32_t>::const_iterator it = saleMap.begin(); i < itemsToSend; ++it, ++i) { msg.addItemId(it->first); msg.addByte(std::min<uint32_t>(it->second, std::numeric_limits<uint8_t>::max())); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketEnter(uint32_t depotId) { NetworkMessage msg; msg.addByte(0xF6); msg.add<uint64_t>(player->getBankBalance()); msg.addByte(std::min<uint32_t>(IOMarket::getPlayerOfferCount(player->getGUID()), std::numeric_limits<uint8_t>::max())); DepotLocker* depotLocker = player->getDepotLocker(depotId); if (!depotLocker) { msg.add<uint16_t>(0x00); writeToOutputBuffer(msg); return; } player->setInMarket(true); std::map<uint16_t, uint32_t> depotItems; std::forward_list<Container*> containerList{depotLocker}; do { Container* container = containerList.front(); containerList.pop_front(); for (Item* item : container->getItemList()) { Container* c = item->getContainer(); if (c && !c->empty()) { containerList.push_front(c); continue; } const ItemType& itemType = Item::items[item->getID()]; if (itemType.wareId == 0) { continue; } if (c && (!itemType.isContainer() || c->capacity() != itemType.maxItems)) { continue; } if (!item->hasMarketAttributes()) { continue; } depotItems[itemType.wareId] += Item::countByType(item, -1); } } while (!containerList.empty()); uint16_t itemsToSend = std::min<size_t>(depotItems.size(), std::numeric_limits<uint16_t>::max()); msg.add<uint16_t>(itemsToSend); uint16_t i = 0; for (std::map<uint16_t, uint32_t>::const_iterator it = depotItems.begin(); i < itemsToSend; ++it, ++i) { msg.add<uint16_t>(it->first); msg.add<uint16_t>(std::min<uint32_t>(0xFFFF, it->second)); } writeToOutputBuffer(msg); updateCoinBalance(); sendResourceBalance(player->getMoney(), player->getBankBalance()); } void ProtocolGame::updateCoinBalance() { NetworkMessage msg; msg.addByte(0xF2); msg.addByte(0x00); writeToOutputBuffer(msg); g_dispatcher.addTask( createTask(std::bind([](ProtocolGame_ptr client) { client->sendCoinBalance(); }, getThis())) ); } void ProtocolGame::sendCoinBalance() { Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `coins` FROM `accounts` WHERE `id`=" + std::to_string(player->getAccount()); DBResult_ptr result = db.storeQuery(query.str()); if (!result) { return; } NetworkMessage msg; msg.addByte(0xF2); msg.addByte(0x01); msg.addByte(0xDF); msg.addByte(0x01); msg.add<uint32_t>(result->getNumber<uint32_t>("coins")); //total coins msg.add<uint32_t>(result->getNumber<uint32_t>("coins")); //transferable coins writeToOutputBuffer(msg); } void ProtocolGame::sendMarketLeave() { NetworkMessage msg; msg.addByte(0xF7); writeToOutputBuffer(msg); } void ProtocolGame::sendMarketBrowseItem(uint16_t itemId, const MarketOfferList& buyOffers, const MarketOfferList& sellOffers) { NetworkMessage msg; msg.addByte(0xF9); msg.addItemId(itemId); msg.add<uint32_t>(buyOffers.size()); for (const MarketOffer& offer : buyOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); } msg.add<uint32_t>(sellOffers.size()); for (const MarketOffer& offer : sellOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketAcceptOffer(const MarketOfferEx& offer) { NetworkMessage msg; msg.addByte(0xF9); msg.addItemId(offer.itemId); if (offer.type == MARKETACTION_BUY) { msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); msg.add<uint32_t>(0x00); } else { msg.add<uint32_t>(0x00); msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketBrowseOwnOffers(const MarketOfferList& buyOffers, const MarketOfferList& sellOffers) { NetworkMessage msg; msg.addByte(0xF9); msg.add<uint16_t>(MARKETREQUEST_OWN_OFFERS); msg.add<uint32_t>(buyOffers.size()); for (const MarketOffer& offer : buyOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); } msg.add<uint32_t>(sellOffers.size()); for (const MarketOffer& offer : sellOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketCancelOffer(const MarketOfferEx& offer) { NetworkMessage msg; msg.addByte(0xF9); msg.add<uint16_t>(MARKETREQUEST_OWN_OFFERS); if (offer.type == MARKETACTION_BUY) { msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.add<uint32_t>(0x00); } else { msg.add<uint32_t>(0x00); msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketBrowseOwnHistory(const HistoryMarketOfferList& buyOffers, const HistoryMarketOfferList& sellOffers) { uint32_t i = 0; std::map<uint32_t, uint16_t> counterMap; uint32_t buyOffersToSend = std::min<uint32_t>(buyOffers.size(), 810 + std::max<int32_t>(0, 810 - sellOffers.size())); uint32_t sellOffersToSend = std::min<uint32_t>(sellOffers.size(), 810 + std::max<int32_t>(0, 810 - buyOffers.size())); NetworkMessage msg; msg.addByte(0xF9); msg.add<uint16_t>(MARKETREQUEST_OWN_HISTORY); msg.add<uint32_t>(buyOffersToSend); for (auto it = buyOffers.begin(); i < buyOffersToSend; ++it, ++i) { msg.add<uint32_t>(it->timestamp); msg.add<uint16_t>(counterMap[it->timestamp]++); msg.addItemId(it->itemId); msg.add<uint16_t>(it->amount); msg.add<uint32_t>(it->price); msg.addByte(it->state); } counterMap.clear(); i = 0; msg.add<uint32_t>(sellOffersToSend); for (auto it = sellOffers.begin(); i < sellOffersToSend; ++it, ++i) { msg.add<uint32_t>(it->timestamp); msg.add<uint16_t>(counterMap[it->timestamp]++); msg.addItemId(it->itemId); msg.add<uint16_t>(it->amount); msg.add<uint32_t>(it->price); msg.addByte(it->state); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketDetail(uint16_t itemId) { NetworkMessage msg; msg.addByte(0xF8); msg.addItemId(itemId); const ItemType& it = Item::items[itemId]; if (it.armor != 0) { msg.addString(std::to_string(it.armor)); } else { msg.add<uint16_t>(0x00); } if (it.attack != 0) { // TODO: chance to hit, range // example: // "attack +x, chance to hit +y%, z fields" if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0) { std::ostringstream ss; ss << it.attack << " physical +" << it.abilities->elementDamage << ' ' << getCombatName(it.abilities->elementType); msg.addString(ss.str()); } else { msg.addString(std::to_string(it.attack)); } } else { msg.add<uint16_t>(0x00); } if (it.isContainer()) { msg.addString(std::to_string(it.maxItems)); } else { msg.add<uint16_t>(0x00); } if (it.defense != 0) { if (it.extraDefense != 0) { std::ostringstream ss; ss << it.defense << ' ' << std::showpos << it.extraDefense << std::noshowpos; msg.addString(ss.str()); } else { msg.addString(std::to_string(it.defense)); } } else { msg.add<uint16_t>(0x00); } if (!it.description.empty()) { const std::string& descr = it.description; if (descr.back() == '.') { msg.addString(std::string(descr, 0, descr.length() - 1)); } else { msg.addString(descr); } } else { msg.add<uint16_t>(0x00); } if (it.decayTime != 0) { std::ostringstream ss; ss << it.decayTime << " seconds"; msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } if (it.abilities) { std::ostringstream ss; bool separator = false; for (size_t i = 0; i < COMBAT_COUNT; ++i) { if (it.abilities->absorbPercent == 0) { continue; } if (separator) { ss << ", "; } else { separator = true; } ss << getCombatName(indexToCombatType(i)) << ' ' << std::showpos << it.abilities->absorbPercent << std::noshowpos << '%'; } msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } if (it.minReqLevel != 0) { msg.addString(std::to_string(it.minReqLevel)); } else { msg.add<uint16_t>(0x00); } if (it.minReqMagicLevel != 0) { msg.addString(std::to_string(it.minReqMagicLevel)); } else { msg.add<uint16_t>(0x00); } msg.addString(it.vocationString); msg.addString(it.runeSpellName); if (it.abilities) { std::ostringstream ss; bool separator = false; for (uint8_t i = SKILL_FIRST; i <= SKILL_FISHING; i++) { if (!it.abilities->skills) { continue; } if (separator) { ss << ", "; } else { separator = true; } ss << getSkillName(i) << ' ' << std::showpos << it.abilities->skills << std::noshowpos; } for (uint8_t i = SKILL_CRITICAL_HIT_CHANCE; i <= SKILL_LAST; i++) { if (!it.abilities->skills) { continue; } if (separator) { ss << ", "; } else { separator = true; } ss << getSkillName(i) << ' ' << std::showpos << it.abilities->skills << std::noshowpos << '%'; } if (it.abilities->stats[STAT_MAGICPOINTS] != 0) { if (separator) { ss << ", "; } else { separator = true; } ss << "magic level " << std::showpos << it.abilities->stats[STAT_MAGICPOINTS] << std::noshowpos; } if (it.abilities->speed != 0) { if (separator) { ss << ", "; } ss << "speed " << std::showpos << (it.abilities->speed >> 1) << std::noshowpos; } msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } if (it.charges != 0) { msg.addString(std::to_string(it.charges)); } else { msg.add<uint16_t>(0x00); } std::string weaponName = getWeaponName(it.weaponType); if (it.slotPosition & SLOTP_TWO_HAND) { if (!weaponName.empty()) { weaponName += ", two-handed"; } else { weaponName = "two-handed"; } } msg.addString(weaponName); if (it.weight != 0) { std::ostringstream ss; if (it.weight < 10) { ss << "0.0" << it.weight; } else if (it.weight < 100) { ss << "0." << it.weight; } else { std::string weightString = std::to_string(it.weight); weightString.insert(weightString.end() - 2, '.'); ss << weightString; } ss << " oz"; msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } if (version > 1099) { msg.add<uint16_t>(0x00); // imbuement detail } MarketStatistics* statistics = IOMarket::getInstance().getPurchaseStatistics(itemId); if (statistics) { msg.addByte(0x01); msg.add<uint32_t>(statistics->numTransactions); msg.add<uint32_t>(std::min<uint64_t>(std::numeric_limits<uint32_t>::max(), statistics->totalPrice)); msg.add<uint32_t>(statistics->highestPrice); msg.add<uint32_t>(statistics->lowestPrice); } else { msg.addByte(0x00); } statistics = IOMarket::getInstance().getSaleStatistics(itemId); if (statistics) { msg.addByte(0x01); msg.add<uint32_t>(statistics->numTransactions); msg.add<uint32_t>(std::min<uint64_t>(std::numeric_limits<uint32_t>::max(), statistics->totalPrice)); msg.add<uint32_t>(statistics->highestPrice); msg.add<uint32_t>(statistics->lowestPrice); } else { msg.addByte(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendQuestTracker() { NetworkMessage msg; msg.addByte(0xD0); // byte quest tracker msg.addByte(1); // send quests of quest log ?? msg.add<uint16_t>(1); // unknown writeToOutputBuffer(msg); } void ProtocolGame::sendQuestLog() { NetworkMessage msg; msg.addByte(0xF0); msg.add<uint16_t>(g_game.quests.getQuestsCount(player)); for (const Quest& quest : g_game.quests.getQuests()) { if (quest.isStarted(player)) { msg.add<uint16_t>(quest.getID()); msg.addString(quest.getName()); msg.addByte(quest.isCompleted(player)); } } writeToOutputBuffer(msg); } void ProtocolGame::sendQuestLine(const Quest* quest) { NetworkMessage msg; msg.addByte(0xF1); msg.add<uint16_t>(quest->getID()); msg.addByte(quest->getMissionsCount(player)); for (const Mission& mission : quest->getMissions()) { if (mission.isStarted(player)) { if (player->getProtocolVersion() >= 1120){ msg.add<uint16_t>(quest->getID()); } msg.addString(mission.getName(player)); msg.addString(mission.getDescription(player)); } } if (player->operatingSystem == CLIENTOS_NEW_WINDOWS) { sendQuestTracker(); } writeToOutputBuffer(msg); } void ProtocolGame::sendTradeItemRequest(const std::string& traderName, const Item* item, bool ack) { NetworkMessage msg; if (ack) { msg.addByte(0x7D); } else { msg.addByte(0x7E); } msg.addString(traderName); if (const Container* tradeContainer = item->getContainer()) { std::list<const Container*> listContainer {tradeContainer}; std::list<const Item*> itemList {tradeContainer}; while (!listContainer.empty()) { const Container* container = listContainer.front(); listContainer.pop_front(); for (Item* containerItem : container->getItemList()) { Container* tmpContainer = containerItem->getContainer(); if (tmpContainer) { listContainer.push_back(tmpContainer); } itemList.push_back(containerItem); } } msg.addByte(itemList.size()); for (const Item* listItem : itemList) { msg.addItem(listItem); } } else { msg.addByte(0x01); msg.addItem(item); } writeToOutputBuffer(msg); } void ProtocolGame::sendCloseTrade() { NetworkMessage msg; msg.addByte(0x7F); writeToOutputBuffer(msg); } void ProtocolGame::sendCloseContainer(uint8_t cid) { NetworkMessage msg; msg.addByte(0x6F); msg.addByte(cid); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureTurn(const Creature* creature, uint32_t stackPos) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(creature->getPosition()); msg.addByte(stackPos); msg.add<uint16_t>(0x63); msg.add<uint32_t>(creature->getID()); msg.addByte(creature->getDirection()); msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, const Position* pos/* = nullptr*/) { NetworkMessage msg; msg.addByte(0xAA); static uint32_t statementId = 0; msg.add<uint32_t>(++statementId); msg.addString(creature->getName()); //Add level only for players if (const Player* speaker = creature->getPlayer()) { msg.add<uint16_t>(speaker->getLevel()); } else { msg.add<uint16_t>(0x00); } msg.addByte(type); if (pos) { msg.addPosition(*pos); } else { msg.addPosition(creature->getPosition()); } msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId) { NetworkMessage msg; msg.addByte(0xAA); static uint32_t statementId = 0; msg.add<uint32_t>(++statementId); if (!creature) { msg.add<uint32_t>(0x00); } else if (type == TALKTYPE_CHANNEL_R2) { msg.add<uint32_t>(0x00); type = TALKTYPE_CHANNEL_R1; } else { msg.addString(creature->getName()); //Add level only for players if (const Player* speaker = creature->getPlayer()) { msg.add<uint16_t>(speaker->getLevel()); } else { msg.add<uint16_t>(0x00); } } msg.addByte(type); msg.add<uint16_t>(channelId); msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendPrivateMessage(const Player* speaker, SpeakClasses type, const std::string& text) { NetworkMessage msg; msg.addByte(0xAA); static uint32_t statementId = 0; msg.add<uint32_t>(++statementId); if (speaker) { msg.addString(speaker->getName()); msg.add<uint16_t>(speaker->getLevel()); } else { msg.add<uint32_t>(0x00); } msg.addByte(type); msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendCancelTarget() { NetworkMessage msg; msg.addByte(0xA3); msg.add<uint32_t>(0x00); writeToOutputBuffer(msg); } void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed) { NetworkMessage msg; msg.addByte(0x8F); msg.add<uint32_t>(creature->getID()); msg.add<uint16_t>(creature->getBaseSpeed() / 2); msg.add<uint16_t>(speed / 2); writeToOutputBuffer(msg); } void ProtocolGame::sendDistanceShoot(const Position& from, const Position& to, uint8_t type) { NetworkMessage msg; msg.addByte(0x85); msg.addPosition(from); msg.addPosition(to); msg.addByte(type); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureHealth(const Creature* creature) { NetworkMessage msg; msg.addByte(0x8C); msg.add<uint32_t>(creature->getID()); if (creature->isHealthHidden()) { msg.addByte(0x00); } else { msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100)); } writeToOutputBuffer(msg); } void ProtocolGame::sendFYIBox(const std::string& message) { NetworkMessage msg; msg.addByte(0x15); msg.addString(message); writeToOutputBuffer(msg); } //tile void ProtocolGame::sendAddTileItem(const Position& pos, uint32_t stackpos, const Item* item) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); msg.addByte(stackpos); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendUpdateTileItem(const Position& pos, uint32_t stackpos, const Item* item) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(pos); msg.addByte(stackpos); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendRemoveTileThing(const Position& pos, uint32_t stackpos) { if (!canSee(pos)) { return; } NetworkMessage msg; RemoveTileThing(msg, pos, stackpos); writeToOutputBuffer(msg); } void ProtocolGame::sendFightModes() { NetworkMessage msg; msg.addByte(0xA7); msg.addByte(player->fightMode); msg.addByte(player->chaseMode); msg.addByte(player->secureMode); msg.addByte(PVP_MODE_DOVE); writeToOutputBuffer(msg); } void ProtocolGame::sendMoveCreature(const Creature* creature, const Position& newPos, int32_t newStackPos, const Position& oldPos, int32_t oldStackPos, bool teleport) { if (creature == player) { if (oldStackPos >= 10) { sendMapDescription(newPos); } else if (teleport) { NetworkMessage msg; RemoveTileThing(msg, oldPos, oldStackPos); writeToOutputBuffer(msg); sendMapDescription(newPos); } else { NetworkMessage msg; if (oldPos.z == 7 && newPos.z >= 8) { RemoveTileThing(msg, oldPos, oldStackPos); } else { msg.addByte(0x6D); msg.addPosition(oldPos); msg.addByte(oldStackPos); msg.addPosition(newPos); } if (newPos.z > oldPos.z) { MoveDownCreature(msg, creature, newPos, oldPos); } else if (newPos.z < oldPos.z) { MoveUpCreature(msg, creature, newPos, oldPos); } 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); } writeToOutputBuffer(msg); } } else if (canSee(oldPos) && canSee(creature->getPosition())) { if (teleport || (oldPos.z == 7 && newPos.z >= 8) || oldStackPos >= 10) { sendRemoveTileThing(oldPos, oldStackPos); sendAddCreature(creature, newPos, newStackPos, false); } else { NetworkMessage msg; msg.addByte(0x6D); msg.addPosition(oldPos); msg.addByte(oldStackPos); msg.addPosition(creature->getPosition()); writeToOutputBuffer(msg); } } else if (canSee(oldPos)) { sendRemoveTileThing(oldPos, oldStackPos); } else if (canSee(creature->getPosition())) { sendAddCreature(creature, newPos, newStackPos, false); } } void ProtocolGame::sendAddContainerItem(uint8_t cid, uint16_t slot, const Item* item) { NetworkMessage msg; msg.addByte(0x70); msg.addByte(cid); msg.add<uint16_t>(slot); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint16_t slot, const Item* item) { NetworkMessage msg; msg.addByte(0x71); msg.addByte(cid); msg.add<uint16_t>(slot); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint16_t slot, const Item* lastItem) { NetworkMessage msg; msg.addByte(0x72); msg.addByte(cid); msg.add<uint16_t>(slot); if (lastItem) { msg.addItem(lastItem); } else { msg.add<uint16_t>(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxlen, bool canWrite) { NetworkMessage msg; msg.addByte(0x96); msg.add<uint32_t>(windowTextId); msg.addItem(item); if (canWrite) { msg.add<uint16_t>(maxlen); msg.addString(item->getText()); } else { const std::string& text = item->getText(); msg.add<uint16_t>(text.size()); msg.addString(text); } const std::string& writer = item->getWriter(); if (!writer.empty()) { msg.addString(writer); } else { msg.add<uint16_t>(0x00); } time_t writtenDate = item->getDate(); if (writtenDate != 0) { msg.addString(formatDateShort(writtenDate)); } else { msg.add<uint16_t>(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text) { NetworkMessage msg; msg.addByte(0x96); msg.add<uint32_t>(windowTextId); msg.addItem(itemId, 1); msg.add<uint16_t>(text.size()); msg.addString(text); msg.add<uint16_t>(0x00); msg.add<uint16_t>(0x00); writeToOutputBuffer(msg); } void ProtocolGame::sendHouseWindow(uint32_t windowTextId, const std::string& text) { NetworkMessage msg; msg.addByte(0x97); msg.addByte(0x00); msg.add<uint32_t>(windowTextId); msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendOutfitWindow() { NetworkMessage msg; msg.addByte(0xC8); Outfit_t currentOutfit = player->getDefaultOutfit(); Mount* currentMount = g_game.mounts.getMountByID(player->getCurrentMount()); if (currentMount) { currentOutfit.lookMount = currentMount->clientId; } AddOutfit(msg, currentOutfit); std::vector<ProtocolOutfit> protocolOutfits; if (player->isAccessPlayer()) { static const std::string gamemasterOutfitName = "Game Master"; protocolOutfits.emplace_back(gamemasterOutfitName, 75, 0); static const std::string gmCustomerSupport = "Customer Support"; protocolOutfits.emplace_back(gmCustomerSupport, 266, 0); static const std::string communityManager = "Community Manager"; protocolOutfits.emplace_back(communityManager, 302, 0); } const auto& outfits = Outfits::getInstance().getOutfits(player->getSex()); protocolOutfits.reserve(outfits.size()); for (const Outfit& outfit : outfits) { uint8_t addons; if (!player->getOutfitAddons(outfit, addons)) { continue; } protocolOutfits.emplace_back(outfit.name, outfit.lookType, addons); if (protocolOutfits.size() == 150) { // Game client doesn't allow more than 100 outfits break; } } msg.addByte(protocolOutfits.size()); for (const ProtocolOutfit& outfit : protocolOutfits) { msg.add<uint16_t>(outfit.lookType); msg.addString(outfit.name); msg.addByte(outfit.addons); } std::vector<const Mount*> mounts; for (const Mount& mount : g_game.mounts.getMounts()) { if (player->hasMount(&mount)) { mounts.push_back(&mount); } } msg.addByte(mounts.size()); for (const Mount* mount : mounts) { msg.add<uint16_t>(mount->clientId); msg.addString(mount->name); } writeToOutputBuffer(msg); } void ProtocolGame::sendUpdatedVIPStatus(uint32_t guid, VipStatus_t newStatus) { NetworkMessage msg; msg.addByte(0xD3); msg.add<uint32_t>(guid); msg.addByte(newStatus); writeToOutputBuffer(msg); } void ProtocolGame::sendSpellCooldown(uint8_t spellId, uint32_t time) { NetworkMessage msg; msg.addByte(0xA4); if (player->getProtocolVersion() < 1120 && spellId >= 170) { spellId = 150; } msg.addByte(spellId); msg.add<uint32_t>(time); writeToOutputBuffer(msg); } void ProtocolGame::sendSpellGroupCooldown(SpellGroup_t groupId, uint32_t time) { NetworkMessage msg; msg.addByte(0xA5); msg.addByte(groupId); msg.add<uint32_t>(time); writeToOutputBuffer(msg); } void ProtocolGame::sendCoinBalanceUpdating(bool updating) { //by jlcvp NetworkMessage msg; msg.addByte(0xF2); msg.addByte(0x00); writeToOutputBuffer(msg); if(updating) { sendUpdatedCoinBalance(); } } void ProtocolGame::sendUpdatedCoinBalance() { NetworkMessage msg; msg.addByte(0xF2); //balanceupdating msg.addByte(0x01); //this is not the end msg.addByte(0xDF); //coinBalance opcode msg.addByte(0x01); //as follows uint32_t playerCoinBalance = IOAccount::getCoinBalance(player->getAccount()); msg.add<uint32_t>(playerCoinBalance); msg.add<uint32_t>(playerCoinBalance); //I don't know why this duplicated entry is needed but... better keep it there writeToOutputBuffer(msg); } void ProtocolGame::sendOpenStore(uint8_t) { NetworkMessage msg; msg.addByte(0xFB); //open store msg.addByte(0x00); //add categories uint16_t categoriesCount = g_game.gameStore.getCategoryOffers().size(); msg.add<uint16_t>(categoriesCount); for(StoreCategory* category : g_game.gameStore.getCategoryOffers()) { msg.addString(category->name); msg.addString(category->description); uint8_t stateByte; switch(category->state) { case NORMAL: stateByte=0; break; case NEW: stateByte=1; break; case SALE: stateByte=2; break; case LIMITED_TIME: stateByte=3; break; default: stateByte=0; break; } msg.addByte(stateByte); msg.addByte((uint8_t)category->icons.size()); for(std::string iconStr : category->icons) { msg.addString(iconStr); } msg.addString(""); //TODO: parentCategory } writeToOutputBuffer(msg); sendCoinBalanceUpdating(true); addGameTaskTimed(350, &Game::playerShowStoreCategoryOffers, player->getID(), g_game.gameStore.getCategoryOffers().at(0)); } void ProtocolGame::sendStoreCategoryOffers(StoreCategory* category) { NetworkMessage msg; msg.addByte(0xFC); //StoreOffers msg.addString(category->name); msg.add<uint16_t>(category->offers.size()); for(BaseOffer* offer : category->offers) { msg.add<uint32_t>(offer->id); std::stringstream offername; if(offer->type==Offer_t::ITEM || offer->type == Offer_t::STACKABLE_ITEM) { if(((ItemOffer*)offer)->count > 1) { offername << ((ItemOffer*)offer)->count << "x "; } } offername << offer->name; msg.addString(offername.str()); msg.addString(offer->description); msg.add<uint32_t>(offer->price); msg.addByte((uint8_t) offer->state); //outfits uint8_t disabled = 0; std::stringstream disabledReason; disabledReason <<""; if(offer->type == OUTFIT || offer->type == OUTFIT_ADDON) { OutfitOffer* outfitOffer = (OutfitOffer*) offer; uint16_t looktype = (player->getSex() == PLAYERSEX_MALE) ? outfitOffer->maleLookType : outfitOffer->femaleLookType; uint8_t addons = outfitOffer->addonNumber; if(player->canWear(looktype, addons)) { //player can wear the offer already disabled=1; if(addons == 0) { //addons == 0 //oufit-only offer and player already has it disabledReason << "You already have this outfit."; } else { disabledReason << "You already have this outfit/addon."; } } else { if(outfitOffer->type == OUTFIT_ADDON && !player->canWear(looktype,0)) { //addon offer and player doesnt have the base outfit disabled=1; disabledReason << "You don't have the outfit, you can't buy the addon."; } } } else if(offer->type == MOUNT) { MountOffer* mountOffer = (MountOffer*) offer; Mount* m = g_game.mounts.getMountByID(mountOffer->mountId); if(player->hasMount(m)) { disabled=1; disabledReason << "You already have this mount."; } } else if(offer->type == PROMOTION) { if(player->isPromoted() || !player->isPremium()) { //TODO: add support to multiple promotion levels disabled=1; disabledReason << "You can't get this promotion"; } } msg.addByte(disabled); if(disabled) { msg.addString(disabledReason.str()); } //add icons msg.addByte((uint8_t)offer->icons.size()); for(std::string iconName : offer->icons ) { msg.addString(iconName); } msg.add<uint16_t>(0); //TODO: add support to suboffers } writeToOutputBuffer(msg); } void ProtocolGame::sendStoreError(GameStoreError_t error, const std::string& message) { NetworkMessage msg; msg.addByte(0xE0); //storeError msg.addByte(error); msg.addString(message); writeToOutputBuffer(msg); } void ProtocolGame::sendStorePurchaseSuccessful(const std::string& message, const uint32_t coinBalance) { NetworkMessage msg; msg.addByte(0xFE); //CompletePurchase msg.addByte(0x00); msg.addString(message); msg.add<uint32_t>(coinBalance); //dont know why the client needs it duplicated. But ok... msg.add<uint32_t>(coinBalance); writeToOutputBuffer(msg); } void ProtocolGame::sendStoreRequestAdditionalInfo(uint32_t offerId, ClientOffer_t clientOfferType) { NetworkMessage msg; msg.addByte(0xE1); //RequestPurchaseData msg.add<uint32_t>(offerId); msg.addByte(clientOfferType); writeToOutputBuffer(msg); } void ProtocolGame::sendStoreTrasactionHistory(HistoryStoreOfferList &list, uint32_t page, uint8_t entriesPerPage) { NetworkMessage msg; uint32_t isLastPage = (list.size() <= entriesPerPage) ? 0x01:0x00; //TODO: Support multiple pages isLastPage=0x01; //FIXME page=0x00; //////////////////////// msg.addByte(0xFD); //BrowseTransactionHistory msg.add<uint32_t>(page); //which page msg.add<uint32_t>(isLastPage); //is the last page? / msg.addByte((uint8_t)list.size()); //how many elements follows for(HistoryStoreOffer offer:list) { msg.add<uint32_t>(offer.time); msg.addByte(offer.mode); msg.add<uint32_t>(offer.amount); //FIXME: investigate why it doesn't send the price properly msg.addString(offer.description); } writeToOutputBuffer(msg); } void ProtocolGame::sendModalWindow(const ModalWindow& modalWindow) { NetworkMessage msg; msg.addByte(0xFA); msg.add<uint32_t>(modalWindow.id); msg.addString(modalWindow.title); msg.addString(modalWindow.message); msg.addByte(modalWindow.buttons.size()); for (const auto& it : modalWindow.buttons) { msg.addString(it.first); msg.addByte(it.second); } msg.addByte(modalWindow.choices.size()); for (const auto& it : modalWindow.choices) { msg.addString(it.first); msg.addByte(it.second); } msg.addByte(modalWindow.defaultEscapeButton); msg.addByte(modalWindow.defaultEnterButton); msg.addByte(modalWindow.priority ? 0x01 : 0x00); writeToOutputBuffer(msg); } ////////////// Add common messages void ProtocolGame::MoveUpCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos) { if (creature != player) { return; } //floor change up msg.addByte(0xBE); //going to surface if (newPos.z == 7) { 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); } } //underground, going one floor up (still underground) else if (newPos.z > 7) { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, oldPos.getZ() - 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 - 5, 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& msg, const Creature* creature, const Position& newPos, const Position& oldPos) { if (creature != player) { return; } //floor change down msg.addByte(0xBF); //going from surface to underground if (newPos.z == 8) { 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); } } //going further down else if (newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) { 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 - 7, newPos.z, 1, 14, msg); //south msg.addByte(0x67); GetMapDescription(oldPos.x - 8, oldPos.y + 7, newPos.z, 18, 1, msg); } void ProtocolGame::AddShopItem(NetworkMessage& msg, const ShopInfo& item) { const ItemType& it = Item::items[item.itemId]; msg.add<uint16_t>(it.clientId); if (it.isSplash() || it.isFluidContainer()) { msg.addByte(serverFluidToClient(item.subType)); } else { msg.addByte(0x00); } msg.addString(item.realName); msg.add<uint32_t>(it.weight); msg.add<uint32_t>(item.buyPrice == 4294967295 ? 0 : item.buyPrice); msg.add<uint32_t>(item.sellPrice == 4294967295 ? 0 : item.sellPrice); } void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg) { uint8_t opcode = msg.getByte(); const std::string& buffer = msg.getString(); // process additional opcodes via lua script event addGameTask(&Game::parsePlayerExtendedOpcode, player->getID(), opcode, buffer); }

ae meninão

Link para o post
Compartilhar em outros sites
6 horas atrás, FlavioHulk disse:

Só ver o PR adicionado ao projeto do OTX, e me retornar qualquer erro ou coisa do tipo, que farei correção...

 

https://github.com/malucooo/otxserver-new/pull/69

 

Eu testei aqui, agora ele saiu dos 42% e já loga com 150%, show de bola, mas quando eu upo qualquer level ele ainda pula pra 4,200 e antes quando eu pegava quaisquer EXP, de um rat que seja, ele retornava pra 150, agora ele ta ficando fixo em 4200.

Link para o post
Compartilhar em outros sites

Tu fez as modificações corretamente? Porque não há como o script que fiz alterar pra esse valor.... Porém vou rever e ver porque isso tá acontecendo..

O que faz a modificação por exp de criatura é event/players.lua, você fez a modificação correta?

Link para o post
Compartilhar em outros sites

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.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emojis são permitidos.

×   Seu link foi automaticamente incorporado.   Mostrar como link

×   Seu conteúdo anterior foi restaurado.   Limpar o editor

×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.


  • Conteúdo Similar

    • Por Jaurez
      .
    • Por Cat
      Em alguns casos, o tibia 8.60 comum não abre de jeito nenhum no map editor, mesmo desmarcando check file signatures e configurando o path corretamente.
       
      Este é o client 8.60 adaptado para o Remere's Map Editor. Resolvi postar já que ele foi removido do site oficial do RME. (ficou apenas a versão para linux lá)
      Se estiver tendo problemas para abrir a versão 8.60, tente utilizar este.
                                                                                                                     
      Baixar o Tibia Client 8.60 que funciona no Remere’s Map Editor
      Essa versão do Tibia 8.60 client resolve o erro unsupported client version ou Could not locate tibia.dat and/or tibia.spr, please navigate to your tibia 8.60 installation folder.
       
      Downloads
      https://tibiaking.com/applications/core/interface/file/attachment.php?id=47333

      Scan: https://www.virustotal.com/gui/file/333e172ac49ba2028db9eb5889994509e7d2de28ebccfa428c04e86defbe15cc
       
    • Por danilo belato
      Fala Galera To Com um problema aki 
       
      quero exporta umas sprites de um server para colocar em outro 
       
      eu clico na sprites ai aparece tds a forma delas do lado de la >>
       
      ai eu clico nela e ponho a opiçao de export mais quando salvo a sprite ela n abri 
       
      aparece isso quando tento vê-la 
       
      visualização não disponível ( no formatos png e bitmap)
       
      Agora no formato idc fala que o paint n pode ler 
       
      me ajudem ae...
    • Por Vitor Bicaleto
      Galera to com o script do addon doll aqui, quando eu digito apenas "!addon" ele aparece assim: Digite novamente, algo está errado!"
      quando digito por exemplo: "!addon citizen" ele não funciona e não da nenhum erro
       
      mesma coisa acontece com o mount doll.. 
    • Por Ayron5
      Substitui uma stone no serve, deu tudo certo fora  esse  erro ajudem  Valendo  Rep+  Grato  

      Erro: data/actions/scripts/boost.lua:557: table index is nil
       [Warning - Event::loadScript] Cannot load script (data/actions/scripts/boost.lua)

      Script:
×
×
  • Criar Novo...

Informação Importante

Confirmação de Termo