Ir para conteúdo
  • Cadastre-se

Posts Recomendados

.Qual servidor ou website você utiliza como base? 

SOURCE OTX BY WOOX 

Qual o motivo deste tópico? 

QUERO ADICIONAR HP E MANA POR POCENTAGEM MAS SEMPRE DA ERRO ( ESTOU USANDO LINUX) 

Spoiler

METODOS NO PROTOCOLGAME.CPP

 

1° 

void ProtocolGame::AddPlayerStats(OutputMessage_ptr msg)
{
    msg->addByte(0xA0);
    msg->add<uint16_t>(player->getHealth());
    if (player->getPlayerInfo(PLAYERINFO_MAXHEALTH) > 0)
    {
        msg->put<uint16_t>(uint16_t(player->getHealth() * 100 / player->getPlayerInfo(PLAYERINFO_MAXHEALTH)));
        msg->put<uint16_t>(100);
    }
    else
    {
        msg->put<uint16_t>(0);
        msg->put<uint16_t>(0);  
    }
    uint64_t experience = player->getExperience();
    if(experience > 0x7FFFFFFF)
        msg->add<uint32_t>(0x7FFFFFFF);
    else
        msg->add<uint32_t>(experience);

    msg->add<uint16_t>(player->getPlayerInfo(PLAYERINFO_LEVEL));
    msg->addByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT));
 if (player->getPlayerInfo(PLAYERINFO_MAXMANA) > 0)
    {
        msg->put<uint16_t>(player->getPlayerInfo(PLAYERINFO_MANA) * 100 / player->getPlayerInfo(PLAYERINFO_MAXMANA));
        msg->put<uint16_t>(100);
    }
    else
    {
        msg->put<uint16_t>(0);
        msg->put<uint16_t>(0);
    }
    msg->addByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVEL));
    msg->addByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT));
    msg->addByte(player->getPlayerInfo(PLAYERINFO_SOUL));
    msg->add<uint16_t>(player->getStaminaMinutes());
}

 

 

SEGUNDO METODO 


void ProtocolGame::AddPlayerStats(OutputMessage_ptr msg)
{
	msg->put<char>(0xA0);
if (player->getPlayerInfo(PLAYERINFO_MAXHEALTH) > 0)
    {
        msg->put<uint16_t>(uint16_t(player->getHealth() * 100 / player->getPlayerInfo(PLAYERINFO_MAXHEALTH)));
        msg->put<uint16_t>(100);
    }
    else
    {
        msg->put<uint16_t>(0);
        msg->put<uint16_t>(0);  
    } 
	msg->put<uint32_t>(uint32_t(player->getFreeCapacity() * 100));
	uint64_t experience = player->getExperience();
	if(experience > 0x7FFFFFFF) // client debugs after 2,147,483,647 exp
		msg->put<uint32_t>(0x7FFFFFFF);
	else
		msg->put<uint32_t>(experience);

	msg->put<uint16_t>(player->getPlayerInfo(PLAYERINFO_LEVEL));
	msg->put<char>(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT));
if (player->getPlayerInfo(PLAYERINFO_MAXMANA) > 0)
    {
        msg->put<uint16_t>(player->getPlayerInfo(PLAYERINFO_MANA) * 100 / player->getPlayerInfo(PLAYERINFO_MAXMANA));
        msg->put<uint16_t>(100);
    }
    else
    {
        msg->put<uint16_t>(0);
        msg->put<uint16_t>(0);
    } 
	msg->put<char>(player->getPlayerInfo(PLAYERINFO_MAGICLEVEL));
	msg->put<char>(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT));
	msg->put<char>(player->getPlayerInfo(PLAYERINFO_SOUL));
	msg->put<uint16_t>(player->getStaminaMinutes());
}

 

TERCEIRO METODO


    msg->put<uint16_t>(player->getHealth());
    msg->put<uint16_t>(player->getPlayerInfo(PLAYERINFO_MAXHEALTH));

troque por:


    if (player->getPlayerInfo(PLAYERINFO_MAXHEALTH) > 0)
    {
        msg->put<uint16_t>(uint16_t(player->getHealth() * 100 / player->getPlayerInfo(PLAYERINFO_MAXHEALTH)));
        msg->put<uint16_t>(100);
    }
    else
    {
        msg->put<uint16_t>(0);
        msg->put<uint16_t>(0);  
    }

procure por:


    msg->put<uint16_t>(player->getPlayerInfo(PLAYERINFO_MANA));
    msg->put<uint16_t>(player->getPlayerInfo(PLAYERINFO_MAXMANA));

troque por:


    if (player->getPlayerInfo(PLAYERINFO_MAXMANA) > 0)
    {
        msg->put<uint16_t>(player->getPlayerInfo(PLAYERINFO_MANA) * 100 / player->getPlayerInfo(PLAYERINFO_MAXMANA));
        msg->put<uint16_t>(100);
    }
    else
    {
        msg->put<uint16_t>(0);
        msg->put<uint16_t>(0);
    }
Citar

 

Você tem o código disponível? Se tiver publique-o aqui: 

Spoiler

////////////////////////////////////////////////////////////////////////
// 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 <boost/function.hpp>
#include <iostream>
#include <iomanip>

#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"

#include "resources.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::release()
{
    if(player && player->client) {
        if (!m_spectator) {
            if (player->client->getOwner() == shared_from_this()) {
                player->client->resetOwner();
            }
        } else if(player->client->isBroadcasting()) {
            player->client->removeSpectator(this);
        }

        player->unRef();
        player = nullptr;
    }

    OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this());
    Protocol::release();
}

void ProtocolGame::spectate(const std::string& name, const std::string& password)
{
    PlayerVector players = g_game.getPlayersByName(name);
    Player* _player = NULL;
    if(!players.empty())
        _player = players[random_range(0, (players.size() - 1))];

    if(!_player || _player->isRemoved() || !_player->client->isBroadcasting() || !_player->client->getOwner())
    {
        disconnectClient(0x14, "Stream unavailable.");
        return;
    }

    if(_player->client->banned(getIP()))
    {
        disconnectClient(0x14, "You are banned from this stream.");
        return;
    }

    if(!_player->client->check(password))
    {
        disconnectClient(0x14, "This stream is protected! Invalid password.");
        return;
    }

    m_spectator = true;
    player = _player;
    player->addRef();
    player->client->addSpectator(this);

    player->sendCreatureAppear(player, this);
    player->sendContainers(this);
    if(PrivateChatChannel* channel = g_chat.getPrivateChannel(player))
        chat(channel->getId());

    acceptPackets = true;
    OutputMessagePool::getInstance().addProtocolToAutosend(shared_from_this());
}

void ProtocolGame::spectatorTurn(uint8_t direction) {
    std::vector<Player*> candidates;
    int index = 0;

    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) {
        if (!it->second->client->isBroadcasting()) {
            continue;
        }

        if (it->second->client->getPassword() != "") {
            continue;
        }

        if(it->second->client->banned(getIP())) {
            continue;
        }
        
        if (it->second == player) {
            index = candidates.size();
        }

        candidates.push_back(it->second);
    }

    if (candidates.size() < 2) {
        return;
    }

    if (direction == 0 || direction == 1) {
        direction = uint8_t (1);
    }

    if (direction == 2 || direction == 3) {
        direction = uint8_t (-1);
    }
    
    if (index == 0 && direction == -1) {
        direction = uint8_t (0);
    }
    
    Player* _player = candidates[(index + direction) % candidates.size()];
    if (!_player || player == _player) {
        return;
    }

    if(!_player || _player->isRemoved() || !_player->client->getOwner()) {
        return;
    }
    
    if((time(NULL) - this->m_lastSwitch) < 1) {
        return;
    }

    this->m_lastSwitch = time(NULL);
    player->client->removeSpectator(this);
    player->unRef();

    player = _player;
    player->addRef();

    knownCreatureSet.clear();
    player->sendCreatureAppear(player, this);
    player->sendContainers(this);
    if(PrivateChatChannel* channel = g_chat.getPrivateChannel(player))
        chat(channel->getId());

    player->client->addSpectator(this);
    
    //acceptPackets = true;
}

void ProtocolGame::login(const std::string& name, uint32_t id, const std::string&,
    OperatingSystem_t operatingSystem, uint16_t version, bool gamemaster)
{
    //dispatcher thread
    PlayerVector players = g_game.getPlayersByName(name);
    Player* foundPlayer = NULL;
    if(!players.empty())
        foundPlayer = players[random_range(0, (players.size() - 1))];

    bool accountManager = g_config.getBool(ConfigManager::ACCOUNT_MANAGER);
    if(!foundPlayer || g_config.getNumber(ConfigManager::ALLOW_CLONES) ||
        (accountManager && name == "Account Manager"))
    {
        player = new Player(name, getThis());
        player->addRef();

        player->setID();
        if(!IOLoginData::getInstance()->loadPlayer(player, name, true))
        {
            disconnectClient(0x14, "Your character could not be loaded.");
            return;
        }

        Ban ban;
        ban.value = player->getGUID();
        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);

            std::stringstream stream;
            stream << "Your account has been " << (deletion ? "deleted" : "banished") << " at:\n" << formatDateEx(ban.added, "%d %b %Y").c_str() << " by: " << name_.c_str()
                << "\nReason:\n" << getReason(ban.reason).c_str() << ".\nComment:\n" << ban.comment.c_str() << ".\nYour " << (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n")
                << (deletion ? "" : formatDateEx(ban.expires).c_str());
            disconnectClient(0x14, stream.str().c_str());
            return;
        }

        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;
            }
        }
        else if(player->getName() == "Account Manager")
        {
            if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
            {
                disconnectClient(0x14, "Account Manager is disabled.");
                return;
            }

            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;
        }

        if(!player->hasFlag(PlayerFlag_CanAlwaysLogin))
        {
            if(g_game.getGameState() == GAMESTATE_CLOSING)
            {
                disconnectClient(0x14, "Gameworld is just going down, please come back later.");
                return;
            }

            if(g_game.getGameState() == GAMESTATE_CLOSED)
            {
                disconnectClient(0x14, "Gameworld is currently closed, please come back later.");
                return;
            }
        }

        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;
            }
        }

        if(!WaitingList::getInstance()->login(player))
        {
            auto output = OutputMessagePool::getOutputMessage();

            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));
            send(output);
            disconnect();
            return;
        }

        if(!IOLoginData::getInstance()->loadPlayer(player, name))
        {
            disconnectClient(0x14, "Your character could not be loaded.");
            return;
        }

        player->setClientVersion(version);
        player->setOperatingSystem(operatingSystem);

        if(player->isUsingOtclient())
        {
            player->registerCreatureEvent("ExtendedOpcode");
        }

        player->lastIP = player->getIP();
        player->lastLoad = OTSYS_TIME();
        player->lastLogin = std::max(time(NULL), player->lastLogin + 1);

        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;
        }

        acceptPackets = true;
    } else {
        if(eventConnect != 0 || !g_config.getBool(ConfigManager::REPLACE_KICK_ON_LOGIN))
        {
            // task has already been scheduled just bail out (should not be overriden)
            disconnectClient(0x14, "You are already logged in.");
            return;
        }

        if (foundPlayer->client) {
            foundPlayer->client->disconnect();
            foundPlayer->isConnecting = true;
            foundPlayer->setClientVersion(version);
            eventConnect = Scheduler::getInstance().addEvent(createSchedulerTask(
                1000, boost::bind(&ProtocolGame::connect, getThis(), foundPlayer->getID(), operatingSystem, version)));
        } else {
            connect(foundPlayer->getID(), operatingSystem, version);
        }
    }
    OutputMessagePool::getInstance().addProtocolToAutosend(shared_from_this());
}

bool ProtocolGame::logout(bool displayEffect, bool forceLogout)
{
    //dispatcher thread
    if(!player)
        return false;

    if(player->hasCondition(CONDITION_EXHAUST, 1))
    {
        player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
        return false;
    }

    if(!player->isRemoved())
    {
        if(!forceLogout)
        {
            if(!IOLoginData::getInstance()->hasCustomFlag(player->getAccount(), PlayerCustomFlag_CanLogoutAnytime))
            {
                if(player->getTile()->hasFlag(TILESTATE_NOLOGOUT))
                {
                    if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 500, 0, false, 1))
                        player->addCondition(condition);

                    player->sendCancelMessage(RET_YOUCANNOTLOGOUTHERE);
                    return false;
                }

                if(player->getZone() != ZONE_PROTECTION && player->hasCondition(CONDITION_INFIGHT))
                {
                    if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 500, 0, false, 1))
                        player->addCondition(condition);

                    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, true);
        }
        else if(!g_creatureEvents->playerLogout(player, true))
            return false;

        if(displayEffect && !player->isGhost())
            g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
    }

    player->client->clear(true);
    disconnect();
    if(player->isRemoved())
        return true;

    return g_game.removeCreature(player);
}

void ProtocolGame::chat(uint16_t channelId)
{
    PrivateChatChannel* tmp = g_chat.getPrivateChannel(player);
    if(!tmp)
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    if(channelId)
    {
        msg->addByte(0xB2);
        msg->add<uint16_t>(tmp->getId());
        msg->addString(tmp->getName());
    }
    else
    {
        msg->addByte(0xAB);
        msg->addByte(1);
        msg->add<uint16_t>(tmp->getId());
        msg->addString("Live Channel");
    }
}

bool ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem, uint16_t version)
{
    eventConnect = 0;

    Player* _player = g_game.getPlayerByID(playerId);
    if(!_player || _player->isRemoved() || _player->hasClient())
    {
        disconnectClient(0x14, "You are already logged in.");
        return false;
    }

    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 false;
    }

    player = _player;
    player->addRef();
    player->client->setOwner(getThis());
    player->isConnecting = false;

    player->sendCreatureAppear(player, this);
    player->setOperatingSystem(operatingSystem);
    player->setClientVersion(version);

    player->lastIP = player->getIP();
    player->lastLoad = OTSYS_TIME();

    g_chat.reOpenChannels(player);
    acceptPackets = true;
    return true;
}

void ProtocolGame::disconnectClient(uint8_t error, const char* message)
{
    auto output = OutputMessagePool::getOutputMessage();
    output->addByte(error);
    output->addString(message);
    send(output);
    disconnect();
}

void ProtocolGame::onConnect()
{
    auto output = OutputMessagePool::getOutputMessage();

    // Skip checksum
    output->skipBytes(sizeof(uint32_t));

    output->add<uint16_t>(0x0006);
    output->addByte(0x1F);
    output->add<uint16_t>(random_range(0, 0xFFFF));
    output->add<uint16_t>(0x00);
    output->addByte(random_range(0, 0xFF));

    // Go back and write checksum
    output->skipBytes(-12);
    output->add<uint32_t>(adlerChecksum(output->getOutputBuffer() + sizeof(uint32_t), 8));

    send(output);
}

void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
{
    if(
#if defined(WINDOWS) && !defined(_CONSOLE)
        !GUI::getInstance()->m_connections ||
#endif
        g_game.getGameState() == GAMESTATE_SHUTDOWN)
    {
        disconnect();
        return;
    }

    OperatingSystem_t operatingSystem = (OperatingSystem_t)msg.get<uint16_t>();
    uint16_t version = msg.get<uint16_t>();

    if(!RSA_decrypt(msg))
    {
        disconnect();
        return;
    }

    uint32_t key[4] = {msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>()};
    enableXTEAEncryption();
    setXTEAKey(key);
    if(operatingSystem >= CLIENTOS_OTCLIENT_LINUX)
        sendExtendedOpcode(0x00, std::string());

    bool gamemaster = (msg.get<char>() != (char)0);
    std::string name = msg.getString(), character = msg.getString(), password = msg.getString();

    msg.skipBytes(6);
    if(!g_config.getBool(ConfigManager::MANUAL_ADVANCED_CONFIG))
    {
        if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
        {
            disconnectClient(0x14, CLIENT_VERSION_STRING);
            return;
        }
    else
        if(version < g_config.getNumber(ConfigManager::VERSION_MIN) || version > g_config.getNumber(ConfigManager::VERSION_MAX))
        {
            disconnectClient(0x14, g_config.getString(ConfigManager::VERSION_MSG).c_str());
            return;
        }
    }

    if(name.empty())
    {
        name = "10";
    }

    if(g_game.getGameState() < GAMESTATE_NORMAL)
    {
        disconnectClient(0x14, "Gameworld is just starting up, please wait.");
        return;
    }

    if(g_game.getGameState() == GAMESTATE_MAINTAIN)
    {
        disconnectClient(0x14, "Gameworld is under maintenance, please re-connect in a while.");
        return;
    }

    if(IOBan::getInstance()->isIpBanished(getIP()))
    {
        disconnectClient(0x14, "Your IP is banished!");
        return;
    }

    uint32_t id = 1;
    if(!IOLoginData::getInstance()->getAccountId(name, id))
    {
        disconnectClient(0x14, "Invalid account name.");
        return;
    }

    std::string hash, salt;
    if(name != "10" && (!IOLoginData::getInstance()->getPassword(id, hash, salt, character) || !encryptTest(salt + password, hash)))
    {
        disconnectClient(0x14, "Invalid password.");
        return;
    }

    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);

        std::stringstream stream;
        stream << "Your account has been " << (deletion ? "deleted" : "banished") << " at:\n" << formatDateEx(ban.added, "%d %b %Y").c_str() << " by: " << name_.c_str()
               << ".\nThe comment given was:\n" << ban.comment.c_str() << ".\nYour " << (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n")
               << (deletion ? "" : formatDateEx(ban.expires).c_str()) << ".";

        disconnectClient(0x14, stream.str().c_str());
        return;
    }

    if(name == "10")
        Dispatcher::getInstance().addTask(createTask(boost::bind(
            &ProtocolGame::spectate, getThis(), character, password)));
    else
        Dispatcher::getInstance().addTask(createTask(boost::bind(
            &ProtocolGame::login, getThis(), character, id, password, operatingSystem, version, gamemaster)));

}

void ProtocolGame::parsePacket(NetworkMessage &msg)
{
    if(!player || !acceptPackets || g_game.getGameState() == GAMESTATE_SHUTDOWN || msg.getLength() <= 0)
        return;

    uint32_t now = time(NULL);
    if(m_packetTime != now)
    {
        m_packetTime = now;
        m_packetCount = 0;
    }

    ++m_packetCount;
    if(m_packetCount > (uint32_t)g_config.getNumber(ConfigManager::PACKETS_PER_SECOND))
        return;

    uint8_t recvbyte = msg.get<char>();
    if(player->isRemoved() && recvbyte != 0x14) //a dead player cannot performs actions
        return;

    if(m_spectator)
    {
        switch(recvbyte)
        {
            case 0x14: parseLogout(msg); break;
            case 0x96: parseSay(msg); break;
            case 0x1E: parseReceivePing(msg); break;
            case 0x97: parseGetChannels(msg); break;
            case 0x98: parseOpenChannel(msg); break;
            case 0xC9: parseUpdateTile(msg); break;
            case 0xCA: parseUpdateContainer(msg); break;
            case 0xE8: parseDebugAssert(msg); break;
            case 0xA1: parseCancelTarget(msg); break;

            // Ctrl + Arrow
            case 0x6F:
            case 0x70:
            case 0x71:
            case 0x72:
                Dispatcher::getInstance().addTask(
                        createTask(boost::bind(&ProtocolGame::spectatorTurn, this, recvbyte - 0x6F)));
                break;

            default:
                parseCancelWalk(msg);
            break;
        }
    }
    else if(player->isAccountManager())
    {
        switch(recvbyte)
        {
            case 0x14: parseLogout(msg); break;
            case 0x96: parseSay(msg); break;
            case 0x1E: parseReceivePing(msg); break;
            case 0xC9: parseUpdateTile(msg); break;
            case 0xE8: parseDebugAssert(msg); break;
            case 0xA1: parseCancelTarget(msg); break;

            default:
                parseCancelWalk(msg);
            break;
        }
    }
    else
    {
        switch(recvbyte)
        {
            case 0x14: parseLogout(msg); break;
            case 0x1E: parseReceivePing(msg); break;
            case 0x32: parseExtendedOpcode(msg); break;
            case 0x64: parseAutoWalk(msg); break;
            case 0x65:
            case 0x66:
            case 0x67:
            case 0x68: parseMove(msg, (Direction)(recvbyte - 0x65)); break;
            case 0x69: 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:
            case 0x70:
            case 0x71:
            case 0x72: parseTurn(msg, (Direction)(recvbyte - 0x6F)); break;
            case 0x78: parseThrow(msg); break;
            case 0x79: parseLookInShop(msg); break;
            case 0x7A: parsePlayerPurchase(msg); break;
            case 0x7B: parsePlayerSale(msg); break;
            case 0x7C: parseCloseShop(msg); break;
            case 0x7D: parseRequestTrade(msg); break;
            case 0x7E: parseLookInTrade(msg); break;
            case 0x7F: parseAcceptTrade(msg); break;
            case 0x80: parseCloseTrade(); break;
            case 0x82: parseUseItem(msg); break;
            case 0x83: parseUseItemEx(msg); break;
            case 0x84: parseBattleWindow(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 0x8C: parseLookAt(msg); break;
            case 0x8D: parseLookInBattleList(msg); break;
            case 0x96: parseSay(msg); break;
            case 0x97: parseGetChannels(msg); break;
            case 0x98: parseOpenChannel(msg); break;
            case 0x99: parseCloseChannel(msg); break;
            case 0x9A: parseOpenPrivate(msg); break;
            case 0x9E: parseCloseNpc(msg); break;
            case 0x9B: parseProcessRuleViolation(msg); break;
            case 0x9C: parseCloseRuleViolation(msg); break;
            case 0x9D: parseCancelRuleViolation(msg); 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: parseLeaveParty(msg); break;
            case 0xA8: parseSharePartyExperience(msg); break;
            case 0xAA: parseCreatePrivateChannel(msg); break;
            case 0xAB: parseChannelInvite(msg); break;
            case 0xAC: parseChannelExclude(msg); break;
            case 0xBE: parseCancelMove(msg); break;
            case 0xC9: parseUpdateTile(msg); break;
            case 0xCA: parseUpdateContainer(msg); break;
            case 0xD2:
                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:
                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;
            case 0xF2: parseViolationReport(msg); break;

            default:
            {
                std::stringstream s;
                s << "Sent unknown byte: 0x" << std::hex << (int16_t)recvbyte << std::dec;
                Logger::getInstance()->eFile("bots/" + player->getName() + ".log", s.str(), true);
                break;
            }
        }
    }
}

void ProtocolGame::GetTileDescription(const Tile* tile, OutputMessage_ptr msg)
{
    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, OutputMessage_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(OutputMessage_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 if(++skip == 0xFF)
            {
                msg->addByte(0xFF);
                msg->addByte(0xFF);
                skip = -1;
            }
        }
    }
}

void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown)
{
    auto result = knownCreatureSet.insert(id);
    if (!result.second) {
        known = true;
        return;
    }

    known = false;

    if (knownCreatureSet.size() > 250) {
        // Look for a creature to remove
        for (std::unordered_set<uint32_t>::iterator it = knownCreatureSet.begin(); it != knownCreatureSet.end(); ++it) {
            Creature* creature = g_game.getCreatureByID(*it);
            if (!creature || !canSee(creature)) {
                removedKnown = *it;
                knownCreatureSet.erase(it);
                return;
            }
        }

        // Bad situation. Let's just remove anyone.
        std::unordered_set<uint32_t>::iterator it = knownCreatureSet.begin();
        if (*it == id) {
            ++it;
        }

        removedKnown = *it;
        knownCreatureSet.erase(it);
    } else {
        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
{
    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&)
{
    if(m_spectator)
        Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::disconnect, this)));
    else
        Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::logout, this, true, false)));
}

void ProtocolGame::parseCancelWalk(NetworkMessage&)
{
    Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::sendCancelWalk, this)));
}

void ProtocolGame::parseCancelTarget(NetworkMessage&)
{
    Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::sendCancelTarget, this)));
}

void ProtocolGame::parseCreatePrivateChannel(NetworkMessage&)
{
    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&)
{
    if(m_spectator)
        Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::chat, this, 0)));
    else
        addGameTask(&Game::playerRequestChannels, player->getID());
}

void ProtocolGame::parseOpenChannel(NetworkMessage& msg)
{
    uint16_t channelId = msg.get<uint16_t>();
    if(m_spectator)
        Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::chat, this, channelId)));
    else
        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::parseOpenPrivate(NetworkMessage& msg)
{
    const std::string receiver = msg.getString();
    addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver);
}

void ProtocolGame::parseCloseNpc(NetworkMessage&)
{
    addGameTask(&Game::playerCloseNpcChannel, player->getID());
}

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&)
{
    addGameTask(&Game::playerCancelRuleViolation, player->getID());
}

void ProtocolGame::parseViolationWindow(NetworkMessage& msg)
{
    std::string target = msg.getString();
    uint8_t reason = msg.get<char>();
    ViolationAction_t action = (ViolationAction_t)msg.get<char>();
    std::string comment = msg.getString();
    std::string statement = msg.getString();
    uint32_t statementId = (uint32_t)msg.get<uint16_t>();
    bool ipBanishment = (msg.get<char>() == 0x01);
    addGameTask(&Game::playerViolationWindow, player->getID(), target,
        reason, action, comment, statement, statementId, ipBanishment);
}

void ProtocolGame::parseCancelMove(NetworkMessage&)
{
    addGameTask(&Game::playerCancelAttackAndFollow, player->getID());
}

void ProtocolGame::parseReceivePing(NetworkMessage&)
{
    addGameTask(&Game::playerReceivePing, player->getID());
}

void ProtocolGame::parseAutoWalk(NetworkMessage& msg)
{
    uint8_t dirCount = msg.get<char>();
    if(dirCount > 128) //client limit
    {
        for(uint8_t i = 0; i < dirCount; ++i)
            msg.get<char>();

        std::stringstream s;
        s << "Attempt to auto walk for " << (uint16_t)dirCount << " steps - client is limited to 128 steps.";
        Logger::getInstance()->eFile("bots/" + player->getName() + ".log", s.str(), true);
        return;
    }

    std::list<Direction> path;
    for(uint8_t i = 0; i < dirCount; ++i)
    {
        Direction dir = SOUTH;
        switch(msg.get<char>())
        {
            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&, Direction dir)
{
    addGameTask(&Game::playerMove, player->getID(), dir);
}

void ProtocolGame::parseTurn(NetworkMessage&, Direction dir)
{
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), dir);
}

void ProtocolGame::parseRequestOutfit(NetworkMessage&)
{
    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.get<uint16_t>();
    else
        msg.skipBytes(2);

    if(g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS))
    {
        newOutfit.lookHead = msg.get<char>();
        newOutfit.lookBody = msg.get<char>();
        newOutfit.lookLegs = msg.get<char>();
        newOutfit.lookFeet = msg.get<char>();
    }
    else
        msg.skipBytes(4);

    if(g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS))
        newOutfit.lookAddons = msg.get<char>();
    else
        msg.skipBytes(1);

    addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit);
}

void ProtocolGame::parseUseItem(NetworkMessage& msg)
{
    Position pos = msg.getPosition();
    uint16_t spriteId = msg.get<uint16_t>();
    int16_t stackpos = msg.get<char>();
    uint8_t index = msg.get<char>();
    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.get<uint16_t>();
    int16_t fromStackpos = msg.get<char>();
    Position toPos = msg.getPosition();
    uint16_t toSpriteId = msg.get<uint16_t>();
    int16_t toStackpos = msg.get<char>();
    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.get<uint16_t>();
    int16_t fromStackpos = msg.get<char>();
    uint32_t creatureId = msg.get<uint32_t>();
    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.get<char>();
    addGameTask(&Game::playerCloseContainer, player->getID(), cid);
}

void ProtocolGame::parseUpArrowContainer(NetworkMessage& msg)
{
    uint8_t cid = msg.get<char>();
    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.get<char>();
    addGameTask(&Game::playerUpdateContainer, player->getID(), cid);
}

void ProtocolGame::parseThrow(NetworkMessage& msg)
{
    Position fromPos = msg.getPosition();
    uint16_t spriteId = msg.get<uint16_t>();
    int16_t fromStackpos = msg.get<char>();
    Position toPos = msg.getPosition();
    uint8_t count = msg.get<char>();
    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.get<uint16_t>();
    int16_t stackpos = msg.get<char>();
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, spriteId, 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 = 0;

    MessageClasses type = (MessageClasses)msg.get<char>();
    switch(type)
    {
        case MSG_PRIVATE:
        case MSG_GAMEMASTER_PRIVATE:
        case MSG_RVR_ANSWER:
            receiver = msg.getString();
            break;

        case MSG_CHANNEL:
        case MSG_CHANNEL_HIGHLIGHT:
        case MSG_GAMEMASTER_CHANNEL:
        case MSG_GAMEMASTER_ANONYMOUS:
            channelId = msg.get<uint16_t>();
            break;

        default:
            break;
    }

    if(m_spectator)
    {
        Dispatcher::getInstance().addTask(createTask(boost::bind(&Spectators::handle, player->client, this, msg.getString(), channelId)));
        return;
    }

    const std::string text = msg.getString();
    if(text.length() > 255) //client limit
    {
        std::stringstream s;
        s << "Attempt to send message with size " << text.length() << " - client is limited to 255 characters.";
        Logger::getInstance()->eFile("bots/" + player->getName() + ".log", s.str(), true);
        return;
    }

    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSay, player->getID(), channelId, type, receiver, text);
}

void ProtocolGame::parseFightModes(NetworkMessage& msg)
{
    uint8_t rawFightMode = msg.get<char>(); //1 - offensive, 2 - balanced, 3 - defensive
    uint8_t rawChaseMode = msg.get<char>(); //0 - stand while fightning, 1 - chase opponent
    uint8_t rawSecureMode = msg.get<char>(); //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.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.get<char>();
    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.get<char>();
    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.get<char>();
    uint8_t amount = msg.get<char>();
    bool ignoreCap = (msg.get<char>() != (char)0);
    bool inBackpacks = (msg.get<char>() != (char)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.get<char>();
    uint8_t amount = msg.get<char>();
    bool ignoreEquipped = (msg.get<char>() != (char)0);
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount, ignoreEquipped);
}

void ProtocolGame::parseCloseShop(NetworkMessage&)
{
    addGameTask(&Game::playerCloseShop, player->getID());
}

void ProtocolGame::parseRequestTrade(NetworkMessage& msg)
{
    Position pos = msg.getPosition();
    uint16_t spriteId = msg.get<uint16_t>();
    int16_t stackpos = msg.get<char>();
    uint32_t playerId = msg.get<uint32_t>();
    addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId);
}

void ProtocolGame::parseAcceptTrade(NetworkMessage&)
{
    addGameTask(&Game::playerAcceptTrade, player->getID());
}

void ProtocolGame::parseLookInTrade(NetworkMessage& msg)
{
    bool counter = (msg.get<char>() != (char)0);
    int32_t index = msg.get<char>();
    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() > 30)
        return;

    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::parseRotateItem(NetworkMessage& msg)
{
    Position pos = msg.getPosition();
    uint16_t spriteId = msg.get<uint16_t>();
    int16_t stackpos = msg.get<char>();
    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_ASSERTIONS, 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.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::parseLeaveParty(NetworkMessage&)
{
    addGameTask(&Game::playerLeaveParty, player->getID(), false);
}

void ProtocolGame::parseSharePartyExperience(NetworkMessage& msg)
{
    bool activate = (msg.get<char>() != (char)0);
    addGameTask(&Game::playerSharePartyExperience, player->getID(), activate);
}

void ProtocolGame::parseQuests(NetworkMessage&)
{
    addGameTask(&Game::playerQuests, player->getID());
}

void ProtocolGame::parseQuestInfo(NetworkMessage& msg)
{
    uint16_t questId = msg.get<uint16_t>();
    addGameTask(&Game::playerQuestInfo, player->getID(), questId);
}

void ProtocolGame::parseViolationReport(NetworkMessage& msg)
{
    ReportType_t type = (ReportType_t)msg.get<char>();
    uint8_t reason = msg.get<char>();

    std::string name = msg.getString(), comment = msg.getString(), translation = "";
    if(type != REPORT_BOT)
        translation = msg.getString();

    uint32_t statementId = 0;
    if(type == REPORT_STATEMENT)
        statementId = msg.get<uint32_t>();

    addGameTask(&Game::playerReportViolation, player->getID(), type, reason, name, comment, translation, statementId);
}

//********************** Send methods *******************************//
void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xAD);
    msg->addString(receiver);
}

void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x8E);
    msg->add<uint32_t>(creature->getID());
    AddCreatureOutfit(msg, creature, outfit);
}

void ProtocolGame::sendCreatureLight(const Creature* creature)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddCreatureLight(msg, creature);
}

void ProtocolGame::sendWorldLight(const LightInfo& lightInfo)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddWorldLight(msg, lightInfo);
}

void ProtocolGame::sendCreatureWalkthrough(const Creature* creature, bool walkthrough)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x92);
    msg->add<uint32_t>(creature->getID());
    msg->addByte(!walkthrough);
}

void ProtocolGame::sendCreatureShield(const Creature* creature)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x91);
    msg->add<uint32_t>(creature->getID());
    msg->addByte(player->getPartyShield(creature));
}

void ProtocolGame::sendCreatureSkull(const Creature* creature)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x90);
    msg->add<uint32_t>(creature->getID());
    msg->addByte(player->getSkullType(creature));
}

void ProtocolGame::sendCreatureSquare(const Creature* creature, uint8_t color)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x86);
    msg->add<uint32_t>(creature->getID());
    msg->addByte(color);
}

void ProtocolGame::sendTutorial(uint8_t tutorialId)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xDC);
    msg->addByte(tutorialId);
}

void ProtocolGame::sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xDD);
    msg->addPosition(pos);
    msg->addByte(markType);
    msg->addString(desc);
}

void ProtocolGame::sendReLoginWindow()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x28);
}

void ProtocolGame::sendStats()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddPlayerStats(msg);
}

void ProtocolGame::sendTextMessage(MessageClasses mClass, const std::string& message)
{
    AddTextMessage(mClass, message);
}

void ProtocolGame::sendClosePrivate(uint16_t channelId)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    if(channelId == CHANNEL_GUILD || channelId == CHANNEL_PARTY)
        g_chat.removeUserFromChannel(player, channelId);

    msg->addByte(0xB3);
    msg->add<uint16_t>(channelId);
}

void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xB2);
    msg->add<uint16_t>(channelId);
    msg->addString(channelName);
}

void ProtocolGame::sendChannelsDialog(const ChannelsList& channels)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xAB);

    msg->addByte(channels.size());
    for(ChannelsList::const_iterator it = channels.begin(); it != channels.end(); ++it)
    {
        msg->add<uint16_t>(it->first);
        msg->addString(it->second);
    }
}

void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelName)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xAC);

    msg->add<uint16_t>(channelId);
    msg->addString(channelName);
}

void ProtocolGame::sendIcons(int32_t icons)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xA2);
    msg->add<uint16_t>(icons);
}

void ProtocolGame::sendContainer(uint32_t cid, const Container* container, bool hasParent)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x6E);
    msg->addByte(cid);

    msg->addItem(container);
    msg->addString(container->getName());
    msg->addByte(container->capacity());

    msg->addByte(hasParent ? 0x01 : 0x00);
    msg->addByte(std::min(container->size(), 255U));

    ItemList::const_iterator cit = container->getItems();
    for(uint32_t i = 0; cit != container->getEnd() && i < 255; ++cit, ++i)
        msg->addItem(*cit);
}

void ProtocolGame::sendShop(Npc*, const ShopInfoList& shop)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x7A);
    msg->addByte(std::min(shop.size(), (size_t)255));

    ShopInfoList::const_iterator it = shop.begin();
    for(uint16_t i = 0; it != shop.end() && i < 255; ++it, ++i)
        AddShopItem(msg, (*it));
}

void ProtocolGame::sendCloseShop()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x7C);
}

void ProtocolGame::sendGoods(const ShopInfoList& shop)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x7B);
    msg->add<uint32_t>((uint32_t)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;
            const ItemType& it = Item::items[sit->itemId];
            if(sit->subType && it.hasSubType() && !it.stackable)
                subType = sit->subType;

            if(subType != -1)
            {
                uint32_t count = subType;
                if(!it.isFluidContainer() && !it.isSplash())
                    count = player->__getItemTypeCount(sit->itemId, subType);

                if(count > 0)
                    goodsMap[sit->itemId] = count;
                else
                    goodsMap[sit->itemId] = 0;
            }
            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::sendRuleViolationsChannel(uint16_t channelId)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->addByte(0xAE);
        msg->add<uint16_t>(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, MSG_RVR_CHANNEL, rvr.text, channelId, NULL, rvr.time);
        }
    }
}

void ProtocolGame::sendRemoveReport(const std::string& name)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->addByte(0xAF);
        msg->addString(name);
    }
}

void ProtocolGame::sendRuleViolationCancel(const std::string& name)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->addByte(0xB0);
        msg->addString(name);
    }
}

void ProtocolGame::sendLockRuleViolation()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->addByte(0xB1);
    }
}

void ProtocolGame::sendTradeItemRequest(const Player* _player, const Item* item, bool ack)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    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()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x7F);
}

void ProtocolGame::sendCloseContainer(uint32_t cid)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x6F);
    msg->addByte(cid);
}

void ProtocolGame::sendCreatureTurn(const Creature* creature, int16_t stackpos)
{
    if(stackpos >= 10 || !canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(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());
}

void ProtocolGame::sendCreatureSay(const Creature* creature, MessageClasses type, const std::string& text, Position* pos, uint32_t statementId)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddCreatureSpeak(msg, creature, type, text, 0, pos, statementId);
}

void ProtocolGame::sendCreatureChannelSay(const Creature* creature, MessageClasses type, const std::string& text, uint16_t channelId, uint32_t statementId)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddCreatureSpeak(msg, creature, type, text, channelId, NULL, statementId);
}

void ProtocolGame::sendStatsMessage(MessageClasses type, const std::string& message,
    Position pos, MessageDetails* details/* = NULL*/)
{
    AddTextMessage(type, message, &pos, details);
}

void ProtocolGame::sendCancel(const std::string& message)
{
    AddTextMessage(MSG_STATUS_SMALL, message);
}

void ProtocolGame::sendCancelTarget()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xA3);
    msg->add<uint32_t>(0);
}

void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x8F);
    msg->add<uint32_t>(creature->getID());
    msg->add<uint16_t>(speed);
}

void ProtocolGame::sendCancelWalk()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xB5);
    msg->addByte(player->getDirection());
}

void ProtocolGame::sendSkills()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddPlayerSkills(msg);
}

void ProtocolGame::sendPing()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    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;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    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;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddMagicEffect(msg, pos, type);
}

void ProtocolGame::sendAnimatedText(const Position& pos, uint8_t color, std::string text)
{
    if(!canSee(pos))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddAnimatedText(msg, pos, color, text);
}

void ProtocolGame::sendCreatureHealth(const Creature* creature)
{
    if(!canSee(creature))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    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::clog << "[Warning - ProtocolGame::sendFYIBox] Trying to send an empty or too huge message." << std::endl;
        return;
    }

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x15);
    msg->addString(message);
}

//tile
void ProtocolGame::sendAddTileItem(const Tile*, const Position& pos, uint32_t stackpos, const Item* item)
{
    if(stackpos >= 10 || !canSee(pos))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddTileItem(msg, pos, stackpos, item);
}

void ProtocolGame::sendUpdateTileItem(const Tile*, const Position& pos, uint32_t stackpos, const Item* item)
{
    if(stackpos >= 10 || !canSee(pos))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    UpdateTileItem(msg, pos, stackpos, item);
}

void ProtocolGame::sendRemoveTileItem(const Tile*, const Position& pos, uint32_t stackpos)
{
    if(stackpos >= 10 || !canSee(pos))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    RemoveTileItem(msg, pos, stackpos);
}

void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos)
{
    if(!canSee(pos))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    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;

    if(creature != player)
    {
        if (stackpos >= 10) {
            return;
        }

        OutputMessage_ptr msgg = getOutputBuffer();
        if(!msgg)
            return;

        TRACK_MESSAGE(msgg);
        AddTileCreature(msgg, pos, stackpos, creature);
        return;
    }

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x0A);
    msg->add<uint32_t>(player->getID());
    msg->add<uint16_t>(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(0);
            }
        }
    }

    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);

    LightInfo lightInfo;
    g_game.getWorldLightInfo(lightInfo);

    AddWorldLight(msg, lightInfo);
    AddCreatureLight(msg, creature);

    player->sendIcons();
    if(m_spectator)
        return;

    for(VIPSet::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*, const Position& pos, uint32_t stackpos)
{
    if(stackpos >= 10 || !canSee(pos))
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    RemoveTileItem(msg, pos, stackpos);
}

void ProtocolGame::sendMoveCreature(const Creature* creature, const Tile*, const Position& newPos,
    uint32_t newStackpos, const Tile*, const Position& oldPos, uint32_t oldStackpos, bool teleport)
{
    if(creature == player)
    {
        if(teleport || oldStackpos >= 10)
        {
            OutputMessage_ptr msg = getOutputBuffer();
            if(!msg)
                return;

            TRACK_MESSAGE(msg);
            if (oldStackpos < 10)
                RemoveTileItem(msg, oldPos, oldStackpos);
            AddMapDescription(msg, newPos);
        }
        else
        {
            if(oldPos.z != 7 || newPos.z < ?
            {
                OutputMessage_ptr msg = getOutputBuffer();
                if(!msg)
                    return;

                TRACK_MESSAGE(msg);
                msg->addByte(0x6D);
                msg->addPosition(oldPos);
                msg->addByte(oldStackpos);
                msg->addPosition(newPos);
            }
            else if (oldStackpos < 10) {
                OutputMessage_ptr msg = getOutputBuffer();
                if(!msg)
                    return;

                TRACK_MESSAGE(msg);
                RemoveTileItem(msg, oldPos, oldStackpos);
            }

            if(newPos.z > oldPos.z) {
                MoveDownCreature(creature, newPos, oldPos, oldStackpos);
            } else if(newPos.z < oldPos.z) {
                MoveUpCreature(creature, newPos, oldPos, oldStackpos);
            }

            if(oldPos.y > newPos.y) // north, for old x
            {
                OutputMessage_ptr msg = getOutputBuffer();
                if(!msg)
                    return;

                TRACK_MESSAGE(msg);
                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
            {
                OutputMessage_ptr msg = getOutputBuffer();
                if(!msg)
                    return;

                TRACK_MESSAGE(msg);
                msg->addByte(0x67);
                GetMapDescription(oldPos.x - 8, newPos.y + 7, newPos.z, 18, 1, msg);
            }

            if(oldPos.x < newPos.x) // east, [with new y]
            {
                OutputMessage_ptr msg = getOutputBuffer();
                if(!msg)
                    return;

                TRACK_MESSAGE(msg);
                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]
            {
                OutputMessage_ptr msg = getOutputBuffer();
                if(!msg)
                    return;

                TRACK_MESSAGE(msg);
                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;

        if(!teleport && (oldPos.z != 7 || newPos.z < ? && oldStackpos < 10)
        {
            OutputMessage_ptr msg = getOutputBuffer();
            if(!msg)
                return;

            TRACK_MESSAGE(msg);
            msg->addByte(0x6D);
            msg->addPosition(oldPos);
            msg->addByte(oldStackpos);
            msg->addPosition(newPos);
        }
        else
        {
            if (oldStackpos < 10 || newStackpos < 10) {
                OutputMessage_ptr msg = getOutputBuffer();
                if(!msg)
                    return;

                TRACK_MESSAGE(msg);
                if (oldStackpos < 10)
                RemoveTileItem(msg, oldPos, oldStackpos);

                if (newStackpos < 10) {
                    AddTileCreature(msg, newPos, newStackpos, creature);
                }
            }
        }
    }
    else if(canSee(oldPos))
    {
        if(oldStackpos >= 10 || !player->canSeeCreature(creature))
            return;

        OutputMessage_ptr msg = getOutputBuffer();
        if(!msg)
            return;

        TRACK_MESSAGE(msg);
        RemoveTileItem(msg, oldPos, oldStackpos);
    }
    else if(newStackpos < 10 && canSee(newPos) && player->canSeeCreature(creature))
    {
        OutputMessage_ptr msg = getOutputBuffer();
        if(!msg)
            return;

        TRACK_MESSAGE(msg);
        AddTileCreature(msg, newPos, newStackpos, creature);
    }
}

//inventory
void ProtocolGame::sendAddInventoryItem(slots_t slot, const Item* item)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddInventoryItem(msg, slot, item);
}

void ProtocolGame::sendUpdateInventoryItem(slots_t slot, const Item* item)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    UpdateInventoryItem(msg, slot, item);
}

void ProtocolGame::sendRemoveInventoryItem(slots_t slot)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    RemoveInventoryItem(msg, slot);
}

//containers
void ProtocolGame::sendAddContainerItem(uint8_t cid, const Item* item)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    AddContainerItem(msg, cid, item);
}

void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint8_t slot, const Item* item)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    UpdateContainerItem(msg, cid, slot, item);
}

void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint8_t slot)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    RemoveContainerItem(msg, cid, slot);
}

void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxLen, bool canWrite)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x96);
    msg->add<uint32_t>(windowTextId);
    msg->addItem(item);
    if(canWrite)
    {
        msg->add<uint16_t>(maxLen);
        msg->addString(item->getText());
    }
    else
    {
        msg->add<uint16_t>(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::sendHouseWindow(uint32_t windowTextId, House*,
    uint32_t, const std::string& text)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0x97);
    msg->addByte(0x00);
    msg->add<uint32_t>(windowTextId);
    msg->addString(text);
}

void ProtocolGame::sendOutfitWindow()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    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->add<uint16_t>(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->add<uint16_t>(player->getDefaultOutfit().lookType);
        msg->addString("Your outfit");
        msg->addByte(player->getDefaultOutfit().lookAddons);
    }

    player->hasRequestedOutfit(true);
}

void ProtocolGame::sendQuests()
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xF0);

    msg->add<uint16_t>(Quests::getInstance()->getQuestCount(player));
    for(QuestList::const_iterator it = Quests::getInstance()->getFirstQuest(); it != Quests::getInstance()->getLastQuest(); ++it)
    {
        if(!(*it)->isStarted(player))
            continue;

        msg->add<uint16_t>((*it)->getId());
        msg->addString((*it)->getName());
        msg->addByte((*it)->isCompleted(player));
    }
}

void ProtocolGame::sendQuestInfo(Quest* quest)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xF1);
    msg->add<uint16_t>(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)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xD3);
    msg->add<uint32_t>(guid);
}

void ProtocolGame::sendVIPLogOut(uint32_t guid)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xD4);
    msg->add<uint32_t>(guid);
}

void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, bool online)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xD2);
    msg->add<uint32_t>(guid);
    msg->addString(name);
    msg->addByte(online ? 1 : 0);
}

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;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    if(knownCreatureSet.find(creature->getID()) != knownCreatureSet.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::AddMapDescription(OutputMessage_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(MessageClasses mClass, const std::string& message,
    Position* pos/* = NULL*/, MessageDetails* details/* = NULL*/)
{
    if(mClass >= MSG_STATUS_CONSOLE_RED)
    {
        if(mClass <= MSG_STATUS_CONSOLE_BLUE)
        {
            OutputMessage_ptr msg = getOutputBuffer();
            if(!msg)
                return;

            msg->addByte(0xB4);
            msg->addByte(mClass);
            msg->addString(message);
        }

        if(details)
        {
            OutputMessage_ptr msg = getOutputBuffer();
            if(!msg)
                return;

            AddAnimatedText(msg, *pos, details->color, asString(details->value));
            if(details->sub)
                AddAnimatedText(msg, *pos, details->sub->color, asString(details->sub->value));
        }
    }
}

void ProtocolGame::AddAnimatedText(OutputMessage_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(OutputMessage_ptr msg, const Position& pos, uint8_t type)
{
    msg->addByte(0x83);
    msg->addPosition(pos);
    msg->addByte(type + 1);
}

void ProtocolGame::AddDistanceShoot(OutputMessage_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(OutputMessage_ptr msg, const Creature* creature, bool known, uint32_t remove)
{
    if(!known)
    {
        msg->add<uint16_t>(0x61);
        msg->add<uint32_t>(remove);
        msg->add<uint32_t>(creature->getID());
        msg->addString(creature->getHideName() ? "" : creature->getName());
    }
    else
    {
        msg->add<uint16_t>(0x62);
        msg->add<uint32_t>(creature->getID());
    }

    if(!creature->getHideHealth())
        msg->addByte((uint8_t)std::ceil(creature->getHealth() * 100. / std::max(creature->getMaxHealth(), 1)));
    else
        msg->addByte(0x00);

    msg->addByte((uint8_t)creature->getDirection());
    AddCreatureOutfit(msg, creature, creature->getCurrentOutfit());

    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);

    msg->addByte(lightInfo.level);
    msg->addByte(lightInfo.color);

    msg->add<uint16_t>(creature->getStepSpeed());
    msg->addByte(player->getSkullType(creature));
    msg->addByte(player->getPartyShield(creature));
    if(!known)
        msg->addByte(player->getGuildEmblem(creature));

    msg->addByte(!player->canWalkthrough(creature));
}

void ProtocolGame::AddPlayerStats(OutputMessage_ptr msg)
{
    msg->addByte(0xA0);
    msg->add<uint16_t>(player->getHealth());
    msg->add<uint16_t>(player->getPlayerInfo(PLAYERINFO_MAXHEALTH));
    msg->add<uint32_t>(uint32_t(player->getFreeCapacity() * 100));
    uint64_t experience = player->getExperience();
    if(experience > 0x7FFFFFFF)
        msg->add<uint32_t>(0x7FFFFFFF);
    else
        msg->add<uint32_t>(experience);

    msg->add<uint16_t>(player->getPlayerInfo(PLAYERINFO_LEVEL));
    msg->addByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT));
    msg->add<uint16_t>(player->getPlayerInfo(PLAYERINFO_MANA));
    msg->add<uint16_t>(player->getPlayerInfo(PLAYERINFO_MAXMANA));
    msg->addByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVEL));
    msg->addByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT));
    msg->addByte(player->getPlayerInfo(PLAYERINFO_SOUL));
    msg->add<uint16_t>(player->getStaminaMinutes());
}

void ProtocolGame::AddPlayerSkills(OutputMessage_ptr msg)
{
    msg->addByte(0xA1);
    for(uint8_t i = 0; i <= SKILL_LAST; ++i)
    {
        msg->addByte(player->getSkill((skills_t)i, SKILL_LEVEL));
        msg->addByte(player->getSkill((skills_t)i, SKILL_PERCENT));
    }
}

void ProtocolGame::AddCreatureSpeak(OutputMessage_ptr msg, const Creature* creature, MessageClasses type,
    std::string text, uint16_t channelId, Position* pos, uint32_t statementId)
{
    if(type > MSG_SPEAK_MONSTER_LAST) {
        type = MSG_SPEAK_SAY;
    }

    msg->addByte(0xAA);
    if(creature)
    {
        msg->add<uint32_t>(statementId);
        if(creature->getSpeakType() != MSG_NONE)
            type = creature->getSpeakType();

        switch(type)
        {
            case MSG_GAMEMASTER_ANONYMOUS:
                msg->addString("");
                break;
            case MSG_RVR_ANSWER:
                msg->addString("Gamemaster");
                break;
            default:
                msg->addString(!creature->getHideName() ? creature->getName() : "");
                break;
        }

        const Player* speaker = creature->getPlayer();
        if(speaker && !speaker->isAccountManager() && !speaker->hasCustomFlag(PlayerCustomFlag_HideLevel))
            msg->add<uint16_t>(speaker->getPlayerInfo(PLAYERINFO_LEVEL));
        else
            msg->add<uint16_t>(0x00);
    }
    else
    {
        msg->add<uint32_t>(0x00);
        msg->addString("");
        msg->add<uint16_t>(0x00);
    }

    msg->addByte(type);
    switch(type)
    {
        case MSG_SPEAK_SAY:
        case MSG_SPEAK_WHISPER:
        case MSG_SPEAK_YELL:
        case MSG_SPEAK_MONSTER_SAY:
        case MSG_SPEAK_MONSTER_YELL:
        case MSG_NPC_FROM:
        {
            if(pos)
                msg->addPosition(*pos);
            else if(creature)
                msg->addPosition(creature->getPosition());
            else
                msg->addPosition(Position(0,0,7));

            break;
        }

        case MSG_CHANNEL:
        case MSG_CHANNEL_HIGHLIGHT:
        case MSG_GAMEMASTER_CHANNEL:
        case MSG_GAMEMASTER_ANONYMOUS:
            msg->add<uint16_t>(channelId);
            break;

        case MSG_RVR_CHANNEL:
        {
            msg->add<uint32_t>(uint32_t(OTSYS_TIME() / 1000 & 0xFFFFFFFF) - statementId/*use it as time:)*/);
            break;
        }

        default:
            break;
    }

    msg->addString(text);
}

void ProtocolGame::AddCreatureHealth(OutputMessage_ptr msg,const Creature* creature)
{
    msg->addByte(0x8C);
    msg->add<uint32_t>(creature->getID());
    if(!creature->getHideHealth())
        msg->addByte((uint8_t)std::ceil(creature->getHealth() * 100. / std::max(creature->getMaxHealth(), (int32_t)1)));
    else
        msg->addByte(0x00);
}

void ProtocolGame::AddCreatureOutfit(OutputMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow/* = false*/)
{
    if(outfitWindow || (!creature->isInvisible() && (!creature->isGhost()
        || !g_config.getBool(ConfigManager::GHOST_INVISIBLE_EFFECT))))
    {
        msg->add<uint16_t>(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->add<uint16_t>(outfit.lookTypeEx);
    }
    else
        msg->add<uint32_t>(0x00);
}

void ProtocolGame::AddWorldLight(OutputMessage_ptr msg, const LightInfo& lightInfo)
{
    msg->addByte(0x82);
    msg->addByte(lightInfo.level);
    msg->addByte(lightInfo.color);
}

void ProtocolGame::AddCreatureLight(OutputMessage_ptr msg, const Creature* creature)
{
    msg->addByte(0x8D);
    msg->add<uint32_t>(creature->getID());

    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);

    msg->addByte(lightInfo.level);
    msg->addByte(lightInfo.color);
}

//tile
void ProtocolGame::AddTileItem(OutputMessage_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(OutputMessage_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(OutputMessage_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(OutputMessage_ptr msg, const Position& pos, uint32_t stackpos)
{
    if (stackpos >= 10) return;

    msg->addByte(0x6C);
    msg->addPosition(pos);
    msg->addByte(stackpos);
}

void ProtocolGame::MoveUpCreature(const Creature* creature,
    const Position& newPos, const Position& oldPos, uint32_t)
{
    if(creature != player)
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);

    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(const Creature* creature,
    const Position& newPos, const Position& oldPos, uint32_t)
{
    if(creature != player)
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        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(OutputMessage_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(OutputMessage_ptr msg, slots_t slot)
{
    msg->addByte(0x79);
    msg->addByte(slot);
}

void ProtocolGame::UpdateInventoryItem(OutputMessage_ptr msg, slots_t slot, const Item* item)
{
    AddInventoryItem(msg, slot, item);
}

//containers
void ProtocolGame::AddContainerItem(OutputMessage_ptr msg, uint8_t cid, const Item* item)
{
    msg->addByte(0x70);
    msg->addByte(cid);
    msg->addItem(item);
}

void ProtocolGame::UpdateContainerItem(OutputMessage_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(OutputMessage_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, MessageClasses type, uint16_t channel)
{
    OutputMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    msg->addByte(0xAA);
    msg->add<uint32_t>(0x00);
    msg->addString(author);
    msg->add<uint16_t>(0x00);
    msg->addByte(type);
    msg->add<uint16_t>(channel);
    msg->addString(text);
}

void ProtocolGame::AddShopItem(OutputMessage_ptr 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 if(it.stackable || it.charges)
        msg->addByte(item.subType);
    else
        msg->addByte(0x00);

    msg->addString(item.itemName);
    msg->add<uint32_t>(uint32_t(it.weight * 100));
    msg->add<uint32_t>(item.buyPrice);
    msg->add<uint32_t>(item.sellPrice);
}

void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg)
{
    uint8_t opcode = msg.get<char>();
    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
    if(player && !player->isUsingOtclient())
        return;

    OutputMessage_ptr msg = getOutputBuffer();
    msg->addByte(0x32);
    msg->addByte(opcode);
    msg->addString(buffer);
}

Você tem alguma imagem que possa auxiliar no problema? Se sim, coloque-a aqui. 

 

Link para o post
Compartilhar em outros sites

Cade os erros?

 

 

 

Nós somos aquilo que fazemos repetidamente. Excelência, não é um modo de agir, mas um hábito.

                                                                                                                                                                                                                                        Aristóteles 

Link para o post
Compartilhar em outros sites
9 horas atrás, Wesleyt10 disse:

ja resolvi, muito obrigado ! podem fechar!

 

Por favor, poste a solução para ajudar outros com o mesmo problema.

 

 

 

Nós somos aquilo que fazemos repetidamente. Excelência, não é um modo de agir, mas um hábito.

                                                                                                                                                                                                                                        Aristóteles 

Link para o post
Compartilhar em outros sites

nao serpa possivel , pois eu possuo uma otx diferente dessa e nao usei mais essa para adicionar o sistema, a que possuo ganhei do meu primo que é desnvolvedor, nao posso divulgar, e tambem oque usei é baseado no tfs 1.2 nao funcionaria para otx

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 cloudrun2023
      CloudRun - Sua Melhor Escolha para Hospedagem de OTServer!
      Você está procurando a solução definitiva para hospedar seu OTServer com desempenho imbatível e segurança inigualável? Não procure mais! Apresentamos a CloudRun, sua parceira confiável em serviços de hospedagem na nuvem.
       
      Recursos Exclusivos - Proteção DDoS Avançada:
      Mantenha seu OTServer online e seguro com nossa robusta proteção DDoS, garantindo uma experiência de jogo ininterrupta para seus jogadores.
       
      Servidores Ryzen 7 Poderosos: Desfrute do poder de processamento superior dos servidores Ryzen 7 para garantir um desempenho excepcional do seu OTServer. Velocidade e estabilidade garantidas!
       
      Armazenamento NVMe de Alta Velocidade:
      Reduza o tempo de carregamento do jogo com nosso armazenamento NVMe ultrarrápido. Seus jogadores vão adorar a rapidez com que podem explorar o mundo do seu OTServer.
       
      Uplink de até 1GB:
      Oferecemos uma conexão de alta velocidade com até 1GB de largura de banda, garantindo uma experiência de jogo suave e livre de lag para todos os seus jogadores, mesmo nos momentos de pico.
       
      Suporte 24 Horas:
      Estamos sempre aqui para você! Nossa equipe de suporte está disponível 24 horas por dia, 7 dias por semana, para resolver qualquer problema ou responder a qualquer pergunta que você possa ter. Sua satisfação é a nossa prioridade.
       
      Fácil e Rápido de Começar:
      Configurar seu OTServer na CloudRun é simples e rápido. Concentre-se no desenvolvimento do seu jogo enquanto cuidamos da hospedagem.
       
      Entre em Contato Agora!
      Website: https://central.cloudrun.com.br/index.php?rp=/store/cloud-ryzen-brasil
      Email: [email protected]
      Telefone: (47) 99902-5147

      Não comprometa a qualidade da hospedagem do seu OTServer. Escolha a CloudRun e ofereça aos seus jogadores a melhor experiência de jogo possível. Visite nosso site hoje mesmo para conhecer nossos planos e começar!
       
      https://central.cloudrun.com.br/index.php?rp=/store/cloud-ryzen-brasil
       
      CloudRun - Onde a Velocidade Encontra a Confiabilidade!
       

    • Por FeeTads
      SALVE rapaziada do TK, esses dias vim pensando em novos scripts pro meu OT, e em um deles eu precisava que determinada area não contasse frag pro player que matasse outros, PORÉM eu precisava que os players que morressem nessa area ainda assim tivessem as penalidades da sua morte, procurei por ai, achei alguns scripts que apenas tiravam o SKULL e não realmente o FRAG do player.

      **script atualizado 22/10/2023** - melhorado e otimizado, levei o script pra puxar as infos por .lua / creatureScripts

      vou disponibilizar o code aqui, e o que fazer pra determinada area não contar frag.

      SOURCE OTX 2 / TFS 0.x, Funciona em TFS 1.x mudando as tags e ajeitando as sintaxes.

      vá em creatureevent.cpp

      procure por:
      else if(type == "preparedeath") _type = CREATURE_EVENT_PREPAREDEATH;
      Adiciona abaixo:
      else if(type == "nocountfrag") _type = CREATURE_EVENT_NOCOUNTFRAG;

      procure por:
      case CREATURE_EVENT_PREPAREDEATH: return "onPrepareDeath";  
      Adicione abaixo: 
      case CREATURE_EVENT_NOCOUNTFRAG: return "noCountFragArea";

      procure por:
      case CREATURE_EVENT_PREPAREDEATH: return "cid, deathList";
      Adicione abaixo:
      case CREATURE_EVENT_NOCOUNTFRAG: return "cid, target";

      agora no mesmo arquivo, vá até o final do arquivo e adicione essa função:
      uint32_t CreatureEvent::executeNoCountFragArea(Creature* creature, Creature* target) { //noCountFragArea(cid, target) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(creature->getPosition()); std::ostringstream scriptstream; scriptstream << "local cid = " << env->addThing(creature) << std::endl; scriptstream << "local target = " << env->addThing(target) << std::endl; if(m_scriptData) 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::ostringstream 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)); lua_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::clog << "[Error - CreatureEvent::noCountFragArea] Call stack overflow." << std::endl; return 0; } }

      agora vá em creatureevent.h

      procure por:
      CREATURE_EVENT_PREPAREDEATH
      adicione abaixo:
      CREATURE_EVENT_NOCOUNTFRAG

      procure por:
      uint32_t executePrepareDeath(Creature* creature, DeathList deathList);
      Adicione abaixo:
      uint32_t executeNoCountFragArea(Creature* creature, Creature* target);

      agora vá em player.cpp

      procure por:
      bool Player::onKilledCreature(Creature* target, DeathEntry& entry)
      abaixo de:
      War_t enemy; if(targetPlayer->getEnemy(this, enemy)) { if(entry.isLast()) IOGuild::getInstance()->updateWar(enemy); entry.setWar(enemy); }
      Adicione o seguinte código:
      if (targetPlayer){ CreatureEventList killEvents = getCreatureEvents(CREATURE_EVENT_NOCOUNTFRAG); for (const auto &event : killEvents) { if (!event->executeNoCountFragArea(this, target)) { return true; } } }

      //

      Feito isso, tudo completo na sua source, agora é necessário adicionar o creaturescript dentro do servidor

      vá até creaturescripts/scripts
      crie um arquivo chamado, "noCountFragInArea.lua"
      e dentro dele cole o código:
       
      --[[ script feito por feetads / TibiaKing ]]-- --[[ discord: feetads / FeeTads#0246 ]]-- -- Add positions here for which you do not want to count frags local areas = { [1] = {from = {x = 91, y = 122, z = 7}, to = {x = 98, y = 127, z = 7}}, -- from = area superior esquerda / to = area inferior direita (formando um quadrado) } local onlyKillerInArea = false -- only killer need to be in area? function noCountFragArea(cid, target) if not isCreature(cid) or not isCreature(target) then return true end local posKiller = getPlayerPosition(cid) local posTarget = getPlayerPosition(target) for i = 1, #areas do local area = areas[i] if isInArea(posKiller, area.from, area.to) then if onlyKillerInArea then return false elseif isInArea(posTarget, area.from, area.to) then return false end end end return true end
      agora em creaturescripts.xml
      <event type="nocountfrag" name="fragarea" event="script" value="noCountFragInArea.lua"/>
      agora em creaturescripts/scripts/login.lua
       procure por OU semelhante a esse:
      registerCreatureEvent(cid, "AdvanceSave")
      e abaixo adicione:
      registerCreatureEvent(cid, "fragarea")

      //


      Agora tudo certo, quando quiser adiciona uma area que não pega frag, vá até o script e apenas coloque a area, igual o demonstrado no script

      Exemplo:
      local areas = { [1] = {from = {x = 91, y = 122, z = 7}, to = {x = 98, y = 127, z = 7}}, [2] = {from = {x = 1000, y = 1000, z = 7}, to = {x = 1100, y = 1100, z = 7}}, }
      assim somente colocando a area no script e abrindo o server ou dando /reload, já funcionará a area como não pegar frag.
      Esse sistema pode ser bom pra areas de pvp ativo, onde você ainda quer que o player que morrer perca os atributos, como se fosse uma morte normal, porém não conta frag pra quem matar.
      Bom pra sistemas tipo castle 48h (guild war), onde há diversas mortes e risco de pegar red, atrapalhando a war.

      Façam bom proveito dos scripts, e deixem os créditos no script rsrs

      **Eu fiz as alterações e o simples código por isso vim disponibilizar, créditos meus**
    • Por Muvuka
      Abri canal a força creaturescript acho que funcione no creaturescript cria script creaturescript
       
      <channel id="9" name="HELP" logged="yes"/>
      <channel id="12" name="Report Bugs" logged="yes"/>
      <channel id="13" name="Loot" logged="yes"/>
      <channel id="14" name="Report Character Rules Tibia Rules" logged="yes"/>
      <channel id="15" name="Death Channel"/>
      <channel id="6548" name="DexSoft" level="1"/>
      <channel id="7" name="Reports" logged="yes"/>
       
      antes de 
              if(lastLogin > 0) then adicione isso:
                      doPlayerOpenChannel(cid, CHANNEL_HELP) doPlayerOpenChannel(cid, 1,  2, 3) = 1,2 ,3 Channels, entendeu? NÃO FUNCIONA EU QUERO UM MEIO DE ABRI SEM USA A SOURCE
       
      EU NÃO CONSEGUI ABRI EU NÃO TENHO SOURCE
       
       
    • Por bolachapancao
      Rapaziada seguinte preciso de um script que ao utilizar uma alavanca para até 4 jogadores.
      Os jogadores serão teleportados para hunt durante uma hora e depois de uma hora os jogadores serão teleportados de volta para o templo.
       
      Observação: caso o jogador morra ou saia da hunt o evento hunt é cancelado.

      Estou a base canary
      GitHub - opentibiabr/canary: Canary Server 13.x for OpenTibia community.
       
    • Por RAJADAO
      .Qual servidor ou website você utiliza como base? 
      Sabrehaven 8.0
      Qual o motivo deste tópico? 
      Ajuda com novos efeitos
       
      Olá amigos, gostaria de ajuda para introduzir os seguintes efeitos no meu servidor (usando o Sabrehaven 8.0 como base), adicionei algumas runas novas (avalanche, icicle, míssil sagrado, stoneshower & Thunderstorm) e alguns novos feitiços (exevo mas san, exori san, exori tera, exori frigo, exevo gran mas frigo, exevo gran mas tera, exevo tera hur, exevo frigo hur) mas nenhum dos efeitos dessas magias parece existir no servidor, alguém tem um link para um tutorial ou algo assim para que eu possa fazer isso funcionar?
      Desculpe pelo mau inglês, sou brasileiro.

      Obrigado!


      AVALANCHE RUNE id:3161 \/
      (COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_ICEAREA)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ICE)

      STONESHOWER RUNE id:3175 \/
      (COMBAT_PARAM_TYPE, COMBAT_EARTHDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_STONES)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_EARTH)

      THUNDERSTORM RUNE id:3202 \/
      (COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_E NERGYHIT)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ENERGYBALL)

      ICICLE RUNE id:3158 \/
      COMBAT_ICEDAMAGE
      CONST_ME_ICEAREA
      CONST_ANI_ICE

      SANTO MÍSSIL RUNA id:3182 \/
      (COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_HOLYDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_HOLY)

      CONST_ME_PLANTATTACK (exevo gran mas tera)
      CONST_ME_ICETORNADO (exevo gran mas frigo)
      CONST_ME_SMALLPLANTS (exevo tera hur)
      CONST_ME_ICEAREA (exevo frigo hur)
      CONST_ME_ICEATTACK (exori frigo)
      CONST_ME_CARNIPHILA (exori tera)

      EXORI SAN \/
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_SMALLHOLY)
      CONST_ME_HOLYDAM IDADE

      EXEVO MAS SAN \/
      CONST_ME_HOLYAREA
×
×
  • Criar Novo...

Informação Importante

Confirmação de Termo