• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

C++ TFS 1.5 7.72 How to send cancel message after choosing locked outfit

dewral

Veteran OT User
Joined
Dec 4, 2019
Messages
343
Solutions
10
Reaction score
351
Hi guys!
Basicaly i wanted that server send cancel message after you choose outfit you don't own.
This part is responsible for displaying all of outfits.
Tfs 1.5 772

C++:
switch (player->getSex()) {
        case PLAYERSEX_FEMALE: {
            msg.add<uint16_t>(351);
            if (player->isPremium()) {
                msg.add<uint16_t>(365);
            } else {
                msg.add<uint16_t>(357);            
            }

            break;
        }

        case PLAYERSEX_MALE: {
            msg.add<uint16_t>(300);
            if (player->isPremium()) {
                msg.add<uint16_t>(316);
            } else {
                msg.add<uint16_t>(306);
            }

            break;
        }

        default: {
            msg.add<uint16_t>(300);
            msg.add<uint16_t>(351);
        }
    }

    writeToOutputBuffer(msg);
}

Could someone help?
 
Last edited:
Solution
You commented somewhere about this as i remember. There was a lot of code to uncomment to make it work right?
You'll break cip client if you do that, unless you dont use it then its fine to use new protocol outfit window and enable this setting in your otclient.
This could be configurable, to make it easier, but I didn't work on downgrades since some time and I don't know if I'll be.
Change also this one
C++:
void ProtocolGame::parseSetOutfit(NetworkMessage& msg)
{
    Outfit_t newOutfit;
    newOutfit.lookType = msg.get<uint16_t>();
    newOutfit.lookHead = msg.getByte();
    newOutfit.lookBody = msg.getByte();
    newOutfit.lookLegs = msg.getByte();
    newOutfit.lookFeet = msg.getByte();
    newOutfit.lookAddons = msg.getByte();
    //newOutfit.lookMount = msg.get<uint16_t>();
    addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit);
}

and protocolgame.cpp

C++:
void ProtocolGame::sendOutfitWindow()
{
    const auto& outfits = Outfits::getInstance().getOutfits(player->getSex());
    if (outfits.size() == 0) {
        return;
    }

    NetworkMessage msg;
    msg.addByte(0xC8);

    Outfit_t currentOutfit = player->getDefaultOutfit();
    if (currentOutfit.lookType == 0) {
        Outfit_t newOutfit;
        newOutfit.lookType = outfits.front().lookType;
        currentOutfit = newOutfit;
    }

    /*Mount* currentMount = g_game.mounts.getMountByID(player->getCurrentMount());
    if (currentMount) {
        currentOutfit.lookMount = currentMount->clientId;
    }*/

    AddOutfit(msg, currentOutfit);

    std::vector<ProtocolOutfit> protocolOutfits;
    if (player->isAccessPlayer()) {
        static const std::string gamemasterOutfitName = "Gamemaster";
        protocolOutfits.emplace_back(gamemasterOutfitName, 75, 0);
    }

    protocolOutfits.reserve(outfits.size());
    for (const Outfit& outfit : outfits) {
        uint8_t addons;
        if (!player->getOutfitAddons(outfit, addons)) {
            continue;
        }

        protocolOutfits.emplace_back(outfit.name, outfit.lookType, addons);
        if (protocolOutfits.size() == 50) { // Game client currently doesn't allow more than 50 outfits
            break;
        }
    }

    msg.addByte(protocolOutfits.size());
    for (const ProtocolOutfit& outfit : protocolOutfits) {
        msg.add<uint16_t>(outfit.lookType);
        msg.addString(outfit.name);
        msg.addByte(outfit.addons);
    }

    /*
    std::vector<const Mount*> mounts;
    for (const Mount& mount : g_game.mounts.getMounts()) {
        if (player->hasMount(&mount)) {
            mounts.push_back(&mount);
        }
    }

    msg.addByte(mounts.size());
    for (const Mount* mount : mounts) {
        msg.add<uint16_t>(mount->clientId);
        msg.addString(mount->name);
    }*/

    writeToOutputBuffer(msg);
}
 
Change also this one
C++:
void ProtocolGame::parseSetOutfit(NetworkMessage& msg)
{
    Outfit_t newOutfit;
    newOutfit.lookType = msg.get<uint16_t>();
    newOutfit.lookHead = msg.getByte();
    newOutfit.lookBody = msg.getByte();
    newOutfit.lookLegs = msg.getByte();
    newOutfit.lookFeet = msg.getByte();
    newOutfit.lookAddons = msg.getByte();
    //newOutfit.lookMount = msg.get<uint16_t>();
    addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit);
}

and protocolgame.cpp

C++:
void ProtocolGame::sendOutfitWindow()
{
    const auto& outfits = Outfits::getInstance().getOutfits(player->getSex());
    if (outfits.size() == 0) {
        return;
    }

    NetworkMessage msg;
    msg.addByte(0xC8);

    Outfit_t currentOutfit = player->getDefaultOutfit();
    if (currentOutfit.lookType == 0) {
        Outfit_t newOutfit;
        newOutfit.lookType = outfits.front().lookType;
        currentOutfit = newOutfit;
    }

    /*Mount* currentMount = g_game.mounts.getMountByID(player->getCurrentMount());
    if (currentMount) {
        currentOutfit.lookMount = currentMount->clientId;
    }*/

    AddOutfit(msg, currentOutfit);

    std::vector<ProtocolOutfit> protocolOutfits;
    if (player->isAccessPlayer()) {
        static const std::string gamemasterOutfitName = "Gamemaster";
        protocolOutfits.emplace_back(gamemasterOutfitName, 75, 0);
    }

    protocolOutfits.reserve(outfits.size());
    for (const Outfit& outfit : outfits) {
        uint8_t addons;
        if (!player->getOutfitAddons(outfit, addons)) {
            continue;
        }

        protocolOutfits.emplace_back(outfit.name, outfit.lookType, addons);
        if (protocolOutfits.size() == 50) { // Game client currently doesn't allow more than 50 outfits
            break;
        }
    }

    msg.addByte(protocolOutfits.size());
    for (const ProtocolOutfit& outfit : protocolOutfits) {
        msg.add<uint16_t>(outfit.lookType);
        msg.addString(outfit.name);
        msg.addByte(outfit.addons);
    }

    /*
    std::vector<const Mount*> mounts;
    for (const Mount& mount : g_game.mounts.getMounts()) {
        if (player->hasMount(&mount)) {
            mounts.push_back(&mount);
        }
    }

    msg.addByte(mounts.size());
    for (const Mount* mount : mounts) {
        msg.add<uint16_t>(mount->clientId);
        msg.addString(mount->name);
    }*/

    writeToOutputBuffer(msg);
}
parseSetOutfit() was already like that. Tried the sendOutfitWindow() but same glitching issue.
 
How did you register features?
Lua:
if(version >= 770) then
        g_game.enableFeature(GamePlayerAddons)
        g_game.enableFeature(GameLooktypeU16)
        g_game.enableFeature(GameMessageStatements)
        g_game.enableFeature(GameLoginPacketEncryption)
        g_game.enableFeature(GameNewOutfitProtocol)

    end
 
Lua:
if(version >= 770) then
        g_game.enableFeature(GamePlayerAddons)
        g_game.enableFeature(GameLooktypeU16)
        g_game.enableFeature(GameMessageStatements)
        g_game.enableFeature(GameLoginPacketEncryption)
        g_game.enableFeature(GameNewOutfitProtocol)

    end
Did you install this? OTCv8 detection, custom features packet, bigget packet size and bug f… · OTCv8/forgottenserver@2839d4d (https://github.com/OTCv8/forgottenserver/commit/2839d4d7a8ad3597eff6c786f4ceb9b1b4b4456b)
 
I did not at that time, but i tried it and i wasnt able to login after that, instantly connection error in client. i'll try to look into it more at the weekend.
Make a thread on support i'll help you, i remember i had this issue when i first time to install this :)
 
Back
Top