• 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!

Solved NPC with more than 255 (limit) items on list [OTVclientv8 + TFS 1.5 Nekiro 8.6]

VitoxMaster

Member
Joined
Feb 6, 2023
Messages
38
Reaction score
16
Hi everyone.
I couldn't find similar topic so I've decided to post it. Perhaps someone will be able to guide me or provide some tips / reasonable solution.
On my server I wanted to have just 1 NPC who buys all the creature products. Everything was fine when list of items was smaller than 255 items. When it extended number 255 list became empty:
1704649480575.png
Lowering list to 254 brings back items in list, but it's not solution for me. I've checked what's going on in OTClient's terminal and that's the result:1704649696078.png
I assume that somewhere in code there is uint8_t instead of uint16_t and that's the source of problems but I cannot tell how many places should be changed. In protocolgame.cpp there was a function "sendSaleItemList" and I rewrote uint8_t there to uint16_t but nothing happens. Are client codes also necessary to adjust?

C++:
    uint16_t itemsToSend = std::min<size_t>(saleMap.size(), std::numeric_limits<uint16_t>::max());
    msg.addByte(itemsToSend);
Additionally info: last week I extended my .dat and .spr files but If I remember correctly problem was occuring even before that.
I'm working on TFS 1.5 Nekiro downgrade 8.6 and latest, available OTVClient version
Thanks in advance for any help!

NPC Definition:
Lua:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Elred" script="default.lua" walkinterval="2000" floorchange="0">
    <health now="150" max="150"/>
    <look type="128" head="0" body="107" legs="76" feet="126" addons="3" corpse="2212"/>
    <parameters>
        <parameter key="module_shop" value="1"/>
        <parameter key="message_greet" value="Hello |PLAYERNAME|. I buy all addons in good price."/>
        <parameter key="shop_sellable" value="
Acorn,11213,10;
Antlers,11214,150;
ancient stone,10549,200;
Ape Fur,5883,1050;
hydra egg,4850,500;
Badger Fur,11216,125;
Banana Sash,12467,155;
Bat Decoration,6492,3000;
Bat Wing,5894,250;
Battle stone,12403,290;
Bear Paw,5896,600;
Behemoth Claw,5930,4000;
Scarab Coin,2159,100;
Black Hood,10562,390;
Black Wool,12404,400;
Blood Preservation,12405,420;
Bloody Pincers,10550,200;
Blue Piece of Cloth,5912,500;
Boggy Dreads,10584,400;
Bone Shoulderplate,11321,250;
Bonelord Eye,5898,1080;
Bony Tail,11194,310;
Book of Necromantic Rituals,11237,380;
Book of Prayers,10563,220;
Brimstone Fangs,12658,480;
Brimstone Shell,12659,310;
Broken Crossbow,12407,70;
Broken Draken Mail,12616,440;
Broken Gladiator Shield,10573,205;
Broken Halberd,11335,200;
Broken Helmet,12409,80;
Broken Key Ring,12608,8000;
Broken Shamanic Staff,12408,105;
Broken Slicer,12617,220;
Brown Piece of Cloth,5913,300;
Bunch of Troll Hair,10606,70;
Bundle of Cursed Straw,10605,900;
Carniphila Seeds,11217,250;
Carrion Worm Fang,11192,75;
Cat's Paw,5480,3000;
Centipede Leg,11218,128;
Chicken Feather,5890,430;
Cobra Tongue,10551,55;
Colourful Feather,12470,110;
Compass,11219,145;
Corrupted Flag,11326,900;
Countess Sorrow's Frozen Tear,6536,60000;
Crab Pincers,11189,135;
Cultish Mask,10555,380;
Cultish Robe,10556,250;
Cultish Symbol,12411,600;
Cyclops Toe,10574,255;
Dark Rosary,11220,148;
Demon Dust,5906,1500;
Demon Horn,5954,1200;
Demonic Skeletal Hand,10564,140;
Demonic Essence,6500,800;
Dirty Turban,12412,140;
Downy Feather,12640,120;
Dracola's Eye,6546,60000;
Dracoyle Statue,9948,5000;
Dragon Claw,10020,25000;
Dragon Priest's Wandtip,11361,275;
Dragon's Tail,12413,200;
Draken Sulphur,12614,650;
Draken Wristbands,12615,530;
Egg of the Many,10523,800;
Elder Bonelord Tentacle,11193,250;
Elven Astral Observer,12421,120;
Elven Scouting Glass,12420,100;
Elvish Talisman,10552,105;
Enchanted Chicken Wing,5891,20000;
Essence of a Bad Dream,11223,370;
Eye Patch,6098,200;
Eye of Corruption,12627,390;
Fiery Heart,10553,575;
Fish Fin,5895,450;
Flask of Embalming Fluid,12422,180;
Flask of Warrior's Sweat,5885,12000;
Frost Giant Pelt,10575,260;
Frosty Ear of a Troll,10565,130;
Frosty Heart,10578,480;
Gauze Bandage,10566,190;
Geomancer's Robe,12414,280;
Geomancer's Staff,12419,320;
Ghastly Dragon Head,11366,800;
Ghostly Tissue,10607,120;
Ghoul Snack,12423,100;
Giant Eye,11197,480;
Girlish Hair Decoration,12399,80;
Gland,8971,600;
Glob of Acid Slime,9967,35;
Glob of Mercury,9966,40;
Glob of Tar,9968,50;
Goblin Ear,12495,40;
Green Dragon Leather,5877,225;
Green Dragon Scale,5920,280;
Green Piece of Cloth,5910,600;
Hair of a Banshee,12402,450;
Half-Digested Piece of Meat,11200,85;
Half-Eaten Brain,10576,105;
Hardened Bone,5925,300;
Haunted Piece of Wood,10600,215;
Heaven Blossom,2743,200;
Hellhound Slobber,10554,500;
Hellspawn Tail,11221,575;
High Guard Flag,11332,650;
High Guard Shoulderplates,11333,230;
Holy Orchid,5922,1500;
Hook,6097,225;
Heaven Blossom,5921,250;
Honeycomb,5902,800;
Hunter's Quiver,12425,580;
Hydra Head,11199,800;
Iron Ore,5880,500;
Jewelled Belt,12426,280;
Kongra's Shoulderpad,12427,300;
Lancer Beetle Shell,11372,240;
Legionnaire Flags,11334,500;
Lion's Mane,10608,180;
Lizard Essence,12636,300;
Lizard Leather,5876,250;
Lizard Scale,5881,320;
Luminous Orb,12410,800;
Lump of Dirt,10609,40;
Lump of Earth,11222,230;
Magic Sulphur,5904,8000;
Mammoth Tusk,11238,300;
Mantassin Tail,12445,380;
Minotaur Horn,12428,155;
Minotaur Leather,5878,180;
Mr. Punish's Handcuffs,6537,60000;
Mutated Bat Ear,10579,520;
Mutated Flesh,11225,150;
Mutated Rat Tail,10585,250;
Mystical Hourglass,10577,700;
Necromantic Robe,12431,350;
Nettle Blossom,11231,175;
Nettle Spit,12432,125;
Neutral Matter,8310,750;
Noble Turban,12442,430;
Nose Ring,5804,10000;
Orc Leather,12435,80;
Orc Tooth,11113,225;
Orcish Gear,12433,150;
Peg Leg,6126,200;
Pelvis Bone,12437,130;
Perfect Behemoth Fang,5893,2250;
Petrified Scream,11337,350;
Piece of Archer Armor,12439,120;
Piece of Crocodile Leather,11196,115;
Piece of Dead Brain,10580,820;
Piece of Massacre's Shell,6540,60000;
Piece of Scarab Shell,10558,145;
Piece of Warrior Armor,12438,150;
Pig Foot,10610,210;
Pile of Grave Earth,12440,125;
Poison Spider Shell,12441,80;
Poisonous Slime,10557,80;
Polar Bear Paw,10567,230;
Protective Charm,12400,750;
Purple Robe,12429,210;
Quara Bone,12447,600;
Quara Eye,12444,450;
Quara Pincers,12446,510;
Quara Tentacle,12443,340;
Red Dragon Leather,5948,500;
Red Dragon Scale,5882,600;
gear crystal,10572,200;
gear wheel,9690,500;
Red Piece of Cloth,5911,2000;
Yellow Piece of Cloth,5914,225;
metal spike,11215,320;
piece of draconian steel,5889,3000;
war crystal,10571,460;
piece of hell steel,5888,500;
piece of hellfire armor,10581,550;
piece of royal steel,5887,10000;
Rope Belt,12448,360;
shiny stone,11227,500;
Rotten Piece of Cloth,11208,130;
Sabretooth,11228,500;
Safety Pin,12449,220;
Sandcrawler Shell,11373,220;
Scale of Corruption,12629,680;
Scarab Pincers,10548,280;
Scorpion Tail,10568,85;
Scroll of Heroic Deeds,12466,300;
Scythe Leg,11229,450;
Sea Serpent Scale,10583,520;
Seeds,7732,150;
Shaggy Tail,11324,25;
Shamanic Hood,12434,105;
Silky Fur,11209,105;
Skeleton Decoration,6526,3500;
Skull Belt,12436,150;
Skunk Tail,11191,100;
Small Flask of Eyedrops,12468,195;
Small Notebook,12406,480;
Small Oil Lamp,2063,250;
Small Pitchfork,12469,170;
Snake Skin,10611,600;
Sniper Gloves,5875,5000;
Soul Stone,5809,10000;
Spider Fangs,8859,100;
Spider Silk,5879,3000;
Spiked Iron Ball,11325,200;
Spirit Container,5884,40000;
Spooky Blue Eye,10559,295;
Star Herb,2800,115;
Stone Herb,2799,120;
Stone Wing,11195,220;
Strand of Medusa Hair,11226,600;
Strange Symbol,2174,300;
Striped Fur,11210,150;
Swamp Grass,10603,120;
Tail of Corruption,12628,440;
Tarantula Egg,11198,200;
Tattered Piece of Robe,10601,150;
Tentacle Piece,12622,8000;
Terramite Eggs,11370,100;
Terramite Legs,11371,100;
Terramite Shell,11369,120;
Terrorbird Beak,11190,195;
The Handmaiden's Protector,6539,60000;
The Imperor's Trident,6534,60000;
The Plasmother's Remains,6535,60000;
Thick Fur,11224,250;
Troll Green,2805,125;
Trollroot,12471,150;
Turtle Shell,5899,900;
Tusk,3956,800;
Undead Heart,11367,400;
Unholy Bone,11233,680;
Vampire Dust,5905,1000;
Vampire Teeth,10602,475;
Warmaster's Wristguards,11322,280;
Warwolf Fur,11235,130;
Weaver's Wandtip,11314,250;
Werewolf Fur,11234,580;
White Piece of Cloth,5909,1000;
Widow's Mandibles,11328,310;
Winged Tail,11230,800;
Winter Wolf Fur,11212,220;
Witch Broom,10569,160;
Wolf Paw,5897,270;
Wood,5901,95;
Wool,11236,105;
Wyrm Scale,10582,500;
Wyvern Talisman,10561,385;
Crawler Head Plating,15482,160;
Compound Eye,15486,180;
Kollos Shell,15480,440;
Gooey Mass,15572,5000;
Swarmer Antenna,15479,170;
Waspoid Claw,15483,330
        "/>
    </parameters>
</npc>
 
Last edited:
Changing network message structure needs to be aligned for both parties, client & server.
Client needs to be aware what portion of message to parse and interpret as itemsCount:


C++:
const uint8_t size = msg->getU8();
 
@lursky Thanks for your reply, I've tried your solution but I'm not sure if it's enough. Debugging otclient showed me that the function responsible for the window opening is:
C++:
void ProtocolGame::parseOpenNpcTrade(const InputMessagePtr& msg)
{
    std::vector<std::tuple<ItemPtr, std::string, int, int64_t, int64_t>> items;
    std::string npcName;

    if (g_game.getFeature(Otc::GameNameOnNpcTrade))
        npcName = msg->getString();
    if (g_game.getFeature(Otc::GameTibia12Protocol)) {
        if(g_game.getProtocolVersion() >= 1220)
            msg->getU16(); // shop item id
        if (g_game.getProtocolVersion() >= 1240)
            msg->getString();
    }

    int listCount;

    if (g_game.getProtocolVersion() >= 986) // tbh not sure from what version
        listCount = msg->getU16();
    else
        listCount = msg->getU8();

I caught what's inside listCount = msg->getU8() and in case when I rewrote it as a msg->getU16(). Unfortunately both cases: 0 value (when I send 255 items in parse list). Applying change in parsePlayerGoods function doesn't solve issue:

C++:
void ProtocolGame::parsePlayerGoods(const InputMessagePtr& msg)
{
    std::vector<std::tuple<ItemPtr, int>> goods;

    uint64_t money;
    if (g_game.getFeature(Otc::GameDoublePlayerGoodsMoney))
        money = msg->getU64();
    else
        money = msg->getU32();

    int size = msg->getU8();
    for (int i = 0; i < size; i++) {
        int itemId = msg->getU16();
        int amount;

        if (g_game.getFeature(Otc::GameDoubleShopSellAmount))
            amount = msg->getU16();
        else
            amount = msg->getU8();

        goods.push_back(std::make_tuple(Item::create(itemId), amount));
    }

    g_game.processPlayerGoods(money, goods);
}


Perhaps my server changes are incompatible.
 
As Otclient is written the way it's compatible with many versions you'd need to change this condition to expect it U16 for 8.60 version:
C++:
if (g_game.getProtocolVersion() >= 986) // tbh not sure from what version
to
C++:
if (g_game.getProtocolVersion() >= 860) // tbh not sure from what version

Reminder: Your server changes (extension of that size from U8 to U16) would crash official client & other OTClients.
 
@lursky helped me in an application of correct changes.

For now changes look as follow:
  • Server side (Nekiro TFS 1.5 8.6):
    • src/protocolgame.cpp
      1705435700740.png
      C++:
      msg.add<uint16_t>(itemsToSend);
      1705435722039.png

    • C++:
          uint16_t itemsToSend = std::min<size_t>(saleMap.size(), std::numeric_limits<uint16_t>::max());
          msg.add<uint16_t>(itemsToSend);
      
          uint16_t i = 0;
          for (std::map<uint16_t, uint32_t>::const_iterator it = saleMap.begin(); i < itemsToSend; ++it, ++i) {
              msg.addItemId(it->first);
              msg.addByte(std::min<uint32_t>(it->second, std::numeric_limits<uint16_t>::max()));
          }
  • Client side (OtClientv8);
    • src/client/protocolgameparse.cpp
      1705435767652.png
      C++:
      int listCount = msg->getU16();
      1705435784079.png
      C++:
      int size = msg->getU16();
 
Back
Top