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

Drawing a looktype on a creature based on currently equipped headgear.

Slime

Active Member
Joined
Jan 25, 2014
Messages
115
Reaction score
32
I need some tips on how to draw an additional overlay based on the item a character is wearing in the head slot. I've been looking for solution inside mapview.cpp and creature.cpp, but nothing comes to my mind. My guess would be that I should send additional data from server about ids of helmets people on the screen are wearing, then make a table with item id - looktype to draw - position offset for every outfit, but it's not that easy to bring to reality. I'm trying to understand how functions like Creature::internalDrawOutfit or Creature::drawOutfit work, but I cant figure out where do they get the tibia.dat id of looktype to draw.
34503
 
You would need sprite sheet with every item that will be "moving" with player animations (if you have any).
eg. Player is moving, his hand is animating using 3 frames so you have to make items that are placed on hand move with it by drawing sprite sheet with 3 frames. Then you just have to code it and make it draw just like addons, because that's what addons are (so pretty much copy & paste with little modifications).
 
C++:
if(m_outfit.getHat() != 0) {
            auto datType = g_things.rawGetThingType(m_outfit.getHat(), ThingCategoryCreature);
            datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
        }
Something like this?
 
C++:
if(m_outfit.getHat() != 0) {
            auto datType = g_things.rawGetThingType(m_outfit.getHat(), ThingCategoryCreature);
            datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
        }
Something like this?
Can't tell, wasn't working with that yet, don't know what method rawGetThingType is, what does it return etc. I'll be working on that in a week or so.
 
C++:
    ThingType* rawGetThingType(uint16 id, ThingCategory category) { return m_thingTypes[category][id].get(); }
As far as I understand it returns id and category (missile, looktype, effect, etc) from tibia.dat.
 
I can't help you with the code right now. Don't have proper resources to test it. You will have to try it yourself, sorry. Maybe someone else can help you but I don't think that anyone will do it for free.
 
34509
Getting there. I managed to glue outfit no.10 to all outfits on the screen.
 
34517

C++:
    m_outfit.setHat(14);
        if (m_outfit.getHat() != 0 && isPlayer()) {
            Point hatDest = dest;
            hatDest.y -= 4 * scaleFactor;
            auto datType = g_things.rawGetThingType(m_outfit.getHat(), ThingCategoryCreature);
            datType->draw(hatDest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
        }
Kind of works for one type of hat (looktype no. 14). Now I need to grab hat types of all creatures on the screen, any ideas? Should I just write a new function to send it from server or is there a way to grab those already?
 
View attachment 34517

C++:
    m_outfit.setHat(14);
        if (m_outfit.getHat() != 0 && isPlayer()) {
            Point hatDest = dest;
            hatDest.y -= 4 * scaleFactor;
            auto datType = g_things.rawGetThingType(m_outfit.getHat(), ThingCategoryCreature);
            datType->draw(hatDest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
        }
Kind of works for one type of hat (looktype no. 14). Now I need to grab hat types of all creatures on the screen, any ideas? Should I just write a new function to send it from server or is there a way to grab those already?
You will have to get it from server. Client doen't know what is someone wearing, by default. OnCreatureAppear, ask server for data about what do they wear.
 
View attachment 34509
Getting there. I managed to glue outfit no.10 to all outfits on the screen.
trying to figure out what each sprite is representing. xD
So the player is some wizard outfit.
Brown thing is a rotworm?
Blue * dark grey.. umm energy elemental?
and the fire fox thing.. I guess fire elemental?

Looks cool anyway.
Good luck with the equipped item stuff.
 
34518
So the player is some wizard outfit. - correct
Brown thing is a rotworm? - nope, sort of an alive tree stump demon thing
Blue * dark grey.. umm energy elemental? - nope, it's an aleslug, a slug with a keg of beer on the back34519
and the fire fox thing.. I guess fire elemental? - correct, it's Ifra, female fire djinn-elemental kind of thing
That white bat isn't really a bat. It's a Snat, a snail with bat wings instead of a shell. Oh boy, creating my own autistic world is fun!
 
I'm almost there but I need some more advice. Hat data is sent inside ProtocolGame::sendAddCreature (TFS 0.3.6) and read by OTC inside ProtocolGame::getCreature. It needs some kind of refresh like relog or teleport before sprite appears. Will sending all data from ProtocolGame::sendAddCreature 4-5 times a second to keep updating headgears slow the server too much? Should I make separate functions for updating headgears alone?
 
I'm almost there but I need some more advice. Hat data is sent inside ProtocolGame::sendAddCreature (TFS 0.3.6) and read by OTC inside ProtocolGame::getCreature. It needs some kind of refresh like relog or teleport before sprite appears. Will sending all data from ProtocolGame::sendAddCreature 4-5 times a second to keep updating headgears slow the server too much? Should I make separate functions for updating headgears alone?
If sendAddCreature is used to send stuff about outfit, name etc. when player/creature appears on player screen the yes, this is the proper way. Why it takes some to time appear? No idea, I don't see the code. Maybe it's related to client and not the server. You should add few more information to the message, containing items ids so there won't be any visible change in lag.
 
That sounds like an odd choice, why aren't you sending the necessary data through either sendInventoryItem or sendOutfit? :p
 
I think 0.3.6 doesn't have sendInventoryItem, I tried to do it through sendOutfit, but it didn't work.
@oen432
It starts to be visible because I teleported using /a command. Requesting that info mainly when somebody appears on the screen is not a good idea, what if someone changes headgear while being on screen already? I'd probably have to send sendAddCreature() every time somebody on screen equips something.
 
I think 0.3.6 doesn't have sendInventoryItem, I tried to do it through sendOutfit, but it didn't work.
@oen432
It starts to be visible because I teleported using /a command. Requesting that info mainly when somebody appears on the screen is not a good idea, what if someone changes headgear while being on screen already? I'd probably have to send sendAddCreature() every time somebody on screen equips something.
Why? You are not sending that much of a data. How many items can player have? 5? This isn't enough to create server lag. Even if someone will be walking in and out of the screen. As for if someone changes equipment while on player screen, just create separated function for that and send update to players near the player who just equipped something else.
 
As for if someone changes equipment while on player screen, just create separated function for that and send update to players near the player who just equipped something else.
Actually I'm asking how to do that now. sendAddCreature is already sending everything when somebody is entering the screen.
 
I'm not sure, but shouldn't it be the same as when a player changes outfit? You probably just need to send the same information when player equip/remove items to all spectators.
Check how it's done to trigger the outfit change for you and your spectators, and how the ot client handles it, if the player changes his outfit, the otclient is triggered, so you need to check how it's done and do the same.. If someone from your screen change his hat, all spectators from that player should receive a packet informing that with his new hat looktype


Edit: actually you could do something on sources(server side) to change the player outfit when he equip or remove some item, and change what the packet containing the outfit sends to the client (add 1 more information, like "addon3" but called "hat"), and also parse this information where the outfit from creatures are set on otclient




On server side, you may need to change this method:
void ProtocolGame::AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow/* = false*/)
 
Last edited:
protocolgame.cpp (server)
C++:
void ProtocolGame::AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow/* = false*/)
{   //16bit headgear id at the beginning
    if(creature->getPlayer() && creature->getPlayer()->getInventoryItem(SLOT_HEAD) != NULL)
    msg->AddItemId(creature->getPlayer()->getInventoryItem(SLOT_HEAD));
    else
    msg->AddU16(0x00);
 
    if(outfitWindow || !creature->getPlayer() || (!creature->isInvisible() && (!creature->isGhost()
        || !g_config.getBool(ConfigManager::GHOST_INVISIBLE_EFFECT))))
    {

        msg->AddU16(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->AddU16(outfit.lookTypeEx);
    }
    else
        msg->AddU32(0x00);
}

protocolgameparse.cpp (client)
C++:
void ProtocolGame::parseCreatureOutfit(const InputMessagePtr& msg)
{
 
    uint id = msg->getU32();
    uint hat = msg->getU16();
    Outfit outfit = getOutfit(msg);
 
 

    CreaturePtr creature = g_map.getCreatureById(id);
    if (creature)
    {
        creature->setOutfit(outfit);
        outfit.setHatId(hat);

    }
   
 

    else
        g_logger.traceError("could not get creature");
}

C++:
Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
{
    Outfit outfit;
   uint16 hat = msg->getU16();
    int lookType;
    if(g_game.getFeature(Otc::GameLooktypeU16))
        lookType = msg->getU16();
    else
        lookType = msg->getU8();

    if(lookType != 0) {
        outfit.setCategory(ThingCategoryCreature);
        int head = msg->getU8();
        int body = msg->getU8();
        int legs = msg->getU8();
        int feet = msg->getU8();
        int addons = 0;
        if(g_game.getFeature(Otc::GamePlayerAddons))
            addons = msg->getU8();

        if(!g_things.isValidDatId(lookType, ThingCategoryCreature)) {
            g_logger.traceError(stdext::format("invalid outfit looktype %d", lookType));
            lookType = 0;
        }

        outfit.setId(lookType);
        outfit.setHead(head);
        outfit.setBody(body);
        outfit.setLegs(legs);
        outfit.setFeet(feet);
        outfit.setAddons(addons);
        outfit.setHatId(hat);

    }
    else {
        int lookTypeEx = msg->getU16();
        if(lookTypeEx == 0) {
            outfit.setCategory(ThingCategoryEffect);
            outfit.setAuxId(13); // invisible effect id
        }
        else {
            if(!g_things.isValidDatId(lookTypeEx, ThingCategoryItem)) {
                g_logger.traceError(stdext::format("invalid outfit looktypeex %d", lookTypeEx));
                lookTypeEx = 0;
            }
            outfit.setCategory(ThingCategoryItem);
            outfit.setAuxId(lookTypeEx);
        }
    }
I moved everything to outfit related functions, but it still needs some kind of refresh to work. I tried adding
C++:
client->sendCreatureOutfit(getCreature(), getCurrentOutfit());
inside server's player.cpp, void Player::eek:nThink(uint32_t interval) but it started showing random stuff on the map and crashing the game.
 
I'm without my laptop, but looking on tfs 0.3.6 via github, I think what sends the outfit update to the client is this function inside game.cpp

internalCreatureChangeOutfit

Maybe, instead of adding a "hat uint16" on addCreatureOutfit, you could find on sources words like "lookLegs" and add "lookHat" (probably you will need to create a uint16 instead of 8, since you are parsing an helmet id). After doing that, you'll need to know when the helmet is changed, so you can check how tfs does "onEquip and onDeEquip" events (i didn't check, but should be something on game, or movements, or items)

On client, I think you shouldn't modify parseCreatureOutfit, but instead you can modify "get Outfit" and copy/paste "outfit.setLegs" to outfit.setHat..

I don't know if it would work, but I think this is more or less the route to follow
 
Back
Top