void ProtocolGame::parseContainerUpdateItem(InputMessage& msg)
{
    int containerId = msg.getU8();
    int slot = msg.getU8();
    ItemPtr item = internalGetItem(msg);
    g_lua.callGlobalField("Game", "onContainerUpdateItem", containerId, slot, item);
}
Outfit ProtocolGame::internalGetOutfit(InputMessage& msg)
{
    Outfit outfit;

    int id = msg.getU16();
    if(id != 0) {
        outfit.setCategory(ThingsType::Creature);
        int head = msg.getU8();
        int body = msg.getU8();
        int legs = msg.getU8();
        int feet = msg.getU8();
        int addons = msg.getU8();

        outfit.setId(id);
        outfit.setHead(head);
        outfit.setBody(body);
        outfit.setLegs(legs);
        outfit.setFeet(feet);
        outfit.setAddons(addons);
    }
    else {
        int id = msg.getU16();
        if(id == 0) {
            outfit.setCategory(ThingsType::Effect);
            outfit.setId(13);
        }
        else {
            outfit.setCategory(ThingsType::Item);
            outfit.setId(id);
        }
    }

    return outfit;
}
void ProtocolGame::parseWorldLight(InputMessage& msg)
{
    Light light;
    light.intensity = msg.getU8();
    light.color = msg.getU8();

    g_map.setLight(light);
}
void ProtocolGame::parsePlayerCash(InputMessage& msg)
{
    msg.getU32();
    int size = msg.getU8();

    for(int i = 0; i < size; i++) {
        msg.getU16(); // itemid
        msg.getU8(); // runecharges
    }
}
void ProtocolGame::parseOpenShopWindow(InputMessage& msg)
{
    int listCount = msg.getU8();
    for(int i = 0; i < listCount; ++i) {
        msg.getU16(); // item id
        msg.getU8(); // runecharges
        msg.getString(); // item name
        msg.getU32(); // weight
        msg.getU32(); // buy price
        msg.getU32(); // sell price
    }
}
void ProtocolGame::parseCreatureLight(InputMessage& msg)
{
    uint id = msg.getU32();

    Light light;
    light.intensity = msg.getU8();
    light.color = msg.getU8();

    CreaturePtr creature = g_map.getCreatureById(id);
    if(creature)
        creature->setLight(light);
}
void ProtocolGame::parseTileRemoveThing(InputMessage& msg)
{
    Position pos = parsePosition(msg);
    int stackPos = msg.getU8();

    g_map.removeThingByPos(pos, stackPos);
}
void ProtocolGame::parseDeath(InputMessage& msg)
{
#if PROTOCOL==862
    msg.getU8(); // 100 is a fair death. < 100 is a unfair death.
#endif
    g_game.processDeath();
}
void ProtocolLogin::onRecv(InputMessage& inputMessage)
{
    try {
        while(!inputMessage.eof()) {
            int opt = inputMessage.getU8();
            switch(opt) {
            case Proto::LoginServerError:
                parseError(inputMessage);
                break;
            case Proto::LoginServerMotd:
                parseMOTD(inputMessage);
                break;
            case Proto::LoginServerUpdateNeeded:
                callLuaField("onError", "Client needs update.");
                break;
            case Proto::LoginServerCharacterList:
                parseCharacterList(inputMessage);
                break;
            default:
                Fw::throwException("unknown opt byte ", opt);
                break;
            }
        }
    } catch(Exception& e) {
        logTraceError(e.what());
    }
    disconnect();
}
void ProtocolGame::parseTileAddThing(InputMessage& msg)
{
    Position pos = parsePosition(msg);
    int stackPos = msg.getU8();

    ThingPtr thing = internalGetThing(msg);
    g_map.addThing(thing, pos, stackPos);
}
void ProtocolGame::parseVipState(InputMessage& msg)
{
    uint id = msg.getU32();
    std::string name = msg.getString();
    bool online = msg.getU8() != 0;

    g_lua.callGlobalField("Game", "onAddVip", id, name, online);
}
Position ProtocolGame::parsePosition(InputMessage& msg)
{
    uint16 x = msg.getU16();
    uint16 y = msg.getU16();
    uint8  z = msg.getU8();

    return Position(x, y, z);
}
void ProtocolGame::parseSafeTradeRequest(InputMessage& msg)
{
    msg.getString(); // name
    int count = msg.getU8();

    for(int i = 0; i < count; i++)
        internalGetItem(msg);
}
void ProtocolGame::parseCreatureSkulls(InputMessage& msg)
{
    uint id = msg.getU32();
    int skull = msg.getU8();

    CreaturePtr creature = g_map.getCreatureById(id);
    if(creature)
        creature->setSkull(skull);
}
void ProtocolGame::parseOpenContainer(InputMessage& msg)
{
    int containerId = msg.getU8();
    int itemId = msg.getU16();
    std::string name = msg.getString();
    int capacity = msg.getU8();
    bool hasParent = (msg.getU8() != 0);
    int itemCount = msg.getU8();

    std::vector<ItemPtr> items;
    items.reserve(itemCount);
    for(int i = 0; i < itemCount; i++) {
        ItemPtr item = internalGetItem(msg);
        items.push_back(item);
    }

    g_lua.callGlobalField("Game", "onContainerOpen", containerId, itemId, name, capacity, hasParent, items);
}
void ProtocolGame::parseQuestPartList(InputMessage& msg)
{
    msg.getU16(); // quest id
    int missionCount = msg.getU8();
    for(int i = 0; i < missionCount; i++) {
        msg.getString(); // quest name
        msg.getString(); // quest description
    }
}
void ProtocolGame::parseTextMessage(InputMessage& msg)
{
    int type = msg.getU8();

    std::string typeDesc = Proto::translateTextMessageType(type);
    std::string message = msg.getString();

    g_game.processTextMessage(typeDesc, message);
}
void ProtocolGame::parseQuestList(InputMessage& msg)
{
    int questsCount = msg.getU16();
    for(int i = 0; i < questsCount; i++) {
        msg.getU16(); // quest id
        msg.getString(); // quest name
        msg.getU8(); // quest state
    }
}
void ProtocolGame::parseCreatureShields(InputMessage& msg)
{
    uint id = msg.getU32();
    int shield = msg.getU8();

    CreaturePtr creature = g_map.getCreatureById(id);
    if(creature)
        creature->setShield(shield);
}
void ProtocolGame::parseCreatureTurn(InputMessage& msg)
{
    uint id = msg.getU32();
    Otc::Direction direction = (Otc::Direction)msg.getU8();

    CreaturePtr creature = g_map.getCreatureById(id);
    if(creature)
        creature->turn(direction);
}
void ProtocolGame::parseCreatureHealth(InputMessage& msg)
{
    uint id = msg.getU32();
    int healthPercent = msg.getU8();

    CreaturePtr creature = g_map.getCreatureById(id);
    if(creature)
        creature->setHealthPercent(healthPercent);
}
void ProtocolGame::parseCreatureSquare(InputMessage& msg)
{
    uint id = msg.getU32();
    int color = msg.getU8();

    CreaturePtr creature = g_map.getCreatureById(id);
    if(creature)
        creature->addVolatileSquare(color);
}
void ProtocolGame::parseMagicEffect(InputMessage& msg)
{
    Position pos = parsePosition(msg);
    int effectId = msg.getU8();

    EffectPtr effect = EffectPtr(new Effect());
    effect->setId(effectId);

    g_map.addThing(effect, pos);
}
void ProtocolGame::parseDistanceMissile(InputMessage& msg)
{
    Position fromPos = parsePosition(msg);
    Position toPos = parsePosition(msg);
    int shotId = msg.getU8();

    MissilePtr shot = MissilePtr(new Missile());
    shot->setId(shotId);
    shot->setPath(fromPos, toPos);
    g_map.addThing(shot, fromPos);
}
void ProtocolGame::parsePlayerLogin(InputMessage& msg)
{
    uint playerId = msg.getU32();
    int serverBeat = msg.getU16();
    int playerCanReportBugs = msg.getU8();

    m_localPlayer = LocalPlayerPtr(new LocalPlayer);
    m_localPlayer->setId(playerId);
    m_localPlayer->setCanReportBugs(playerCanReportBugs);
    g_game.processLogin(m_localPlayer, serverBeat);
}
ItemPtr ProtocolGame::internalGetItem(InputMessage& msg, int id)
{
    if(id == 0)
        id = msg.getU16();

    ItemPtr item = Item::create(id);
    if(item->isStackable() || item->isFluidContainer() || item->isFluid())
        item->setData(msg.getU8());

    return item;
}
void ProtocolGame::parseChannelList(InputMessage& msg)
{
    int count = msg.getU8();
    std::vector<std::tuple<int, std::string> > channelList(count);
    for(int i = 0; i < count; i++) {
        int id = msg.getU16();
        std::string name = msg.getString();
        channelList.push_back(std::make_tuple(id, name));
    }

    g_lua.callGlobalField("Game", "onChannelList", channelList);
}
void ProtocolGame::parsePlayerSkills(InputMessage& msg)
{
    for(int skill = 0; skill < Otc::LastSkill; skill++) {
        int values[Otc::LastSkillType];
        for(int skillType = 0; skillType < Otc::LastSkillType; skillType++) {
            values[skillType] = msg.getU8();
            m_localPlayer->setSkill((Otc::Skill)skill, (Otc::SkillType)skillType, values[skillType]);
        }

        g_lua.callGlobalField("Game", "onSkillChange", skill, values[Otc::SkillLevel], values[Otc::SkillPercent]);
    }
}
void ProtocolGame::parseAnimatedText(InputMessage& msg)
{
    Position position = parsePosition(msg);
    int color = msg.getU8();
    std::string text = msg.getString();

    AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
    animatedText->setColor(color);
    animatedText->setText(text);

    g_map.addThing(animatedText, position);
}
void ProtocolGame::parseOutfitWindow(InputMessage& msg)
{
    Outfit outfit = internalGetOutfit(msg);

    typedef std::tuple<int, std::string, int> OutfitInfo;
    std::vector<OutfitInfo> outfitList;

    uint8 outfitCount = msg.getU8();
    for(int i = 0; i < outfitCount; i++) {
        uint16 outfitId = msg.getU16();
        std::string outfitName = msg.getString();
        uint8 outfitAddons = msg.getU8();

        outfitList.push_back(OutfitInfo(outfitId, outfitName, outfitAddons));
    }

    CreaturePtr creature = CreaturePtr(new Creature);
    creature->setXPattern(2);
    creature->setOutfit(outfit);

    g_lua.callGlobalField("Game", "onOpenOutfitWindow", creature, outfitList);
}