• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

How do you hide this icon?

mackerel

Well-Known Member
Joined
Apr 26, 2017
Messages
398
Solutions
18
Reaction score
74
When someone summons a creature, they are given special icons;

green shield to the one who is in charge
red shield to other players to indicate this is other player summon

like this:

7EXBGY2.png


Is there any way to hide it for specific monsters?
If not, is there a way to hide it completely?
If not, is there a way to remove it completely?

Tfs 1.0
 
Solution
TFS 1.0? You'll have to compile it yourself though.

game.cpp, find void Game::updateCreatureType(Creature* creature) method and replace it with:

The following code is not 100% correct, see How do you hide this icon?
C++:
void Game::updateCreatureType(Creature* creature)
{
    const Player* masterPlayer = nullptr;

    uint32_t creatureId = creature->getID();
    CreatureType_t creatureType = creature->getType();
    if (creatureType == CREATURETYPE_MONSTER) {
        const Creature* master = creature->getMaster();
        if (master) {
            masterPlayer = master->getPlayer();
            if (masterPlayer) {
                creatureType = CREATURETYPE_SUMMON_OTHERS;
            }
        }
    }

    //send to clients...
TFS 1.0? You'll have to compile it yourself though.

game.cpp, find void Game::updateCreatureType(Creature* creature) method and replace it with:

The following code is not 100% correct, see How do you hide this icon?
C++:
void Game::updateCreatureType(Creature* creature)
{
    const Player* masterPlayer = nullptr;

    uint32_t creatureId = creature->getID();
    CreatureType_t creatureType = creature->getType();
    if (creatureType == CREATURETYPE_MONSTER) {
        const Creature* master = creature->getMaster();
        if (master) {
            masterPlayer = master->getPlayer();
            if (masterPlayer) {
                creatureType = CREATURETYPE_SUMMON_OTHERS;
            }
        }
    }

    //send to clients
    SpectatorHashSet spectators;
    map.getSpectators(spectators, creature->getPosition(), true, true);

    if (creatureType == CREATURETYPE_SUMMON_OTHERS) {
        for (Creature* spectator : spectators) {
            Player* player = spectator->getPlayer();
            if (masterPlayer == player) {
                player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
            }
        }
    } else {
        for (Creature* spectator : spectators) {
            spectator->getPlayer()->sendCreatureType(creatureId, creatureType);
        }
    }
}

And ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove) in protocolgame.cpp, replace it with this:

C++:
void ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove)
{
    CreatureType_t creatureType = creature->getType();

    const Player* otherPlayer = creature->getPlayer();

    if (known) {
        msg.add<uint16_t>(0x62);
        msg.add<uint32_t>(creature->getID());
    } else {
        msg.add<uint16_t>(0x61);
        msg.add<uint32_t>(remove);
        msg.add<uint32_t>(creature->getID());
        msg.addByte(creatureType);
        msg.addString(creature->getName());
    }

    if (creature->isHealthHidden()) {
        msg.addByte(0x00);
    } else {
        msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100));
    }

    msg.addByte(creature->getDirection());

    if (!creature->isInGhostMode() && !creature->isInvisible()) {
        AddOutfit(msg, creature->getCurrentOutfit());
    } else {
        static Outfit_t outfit;
        AddOutfit(msg, outfit);
    }

    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);
    msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level);
    msg.addByte(lightInfo.color);

    msg.add<uint16_t>(creature->getStepSpeed() / 2);

    msg.addByte(player->getSkullClient(creature));
    msg.addByte(player->getPartyShield(otherPlayer));

    if (!known) {
        msg.addByte(player->getGuildEmblem(otherPlayer));
    }

    if (creatureType == CREATURETYPE_MONSTER) {
        const Creature* master = creature->getMaster();
        if (master) {
            const Player* masterPlayer = master->getPlayer();
            if (masterPlayer) {
                if (masterPlayer == player) {
                    creatureType = CREATURETYPE_SUMMON_OWN;
                }
            }
        }
    }

    msg.addByte(creatureType); // Type (for summons)
    msg.addByte(creature->getSpeechBubble());
    msg.addByte(0xFF); // MARK_UNMARKED

    if (otherPlayer) {
        msg.add<uint16_t>(otherPlayer->getHelpers());
    } else {
        msg.add<uint16_t>(0x00);
    }

    msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01);
}

It should work by not informing users that this is a summon (so the red shield should not appear). I don't know what other implications this may have, feel free to test it :) If you want to remove the green shield as well then use this version of functions (removes both green and red):

C++:
void Game::updateCreatureType(Creature* creature)
{
    const Player* masterPlayer = nullptr;

    uint32_t creatureId = creature->getID();
    CreatureType_t creatureType = creature->getType();

    //send to clients
    SpectatorHashSet spectators;
    map.getSpectators(spectators, creature->getPosition(), true, true);

    for (Creature* spectator : spectators) {
        spectator->getPlayer()->sendCreatureType(creatureId, creatureType);
    }
}


C++:
void ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove)
{
    CreatureType_t creatureType = creature->getType();

    const Player* otherPlayer = creature->getPlayer();

    if (known) {
        msg.add<uint16_t>(0x62);
        msg.add<uint32_t>(creature->getID());
    } else {
        msg.add<uint16_t>(0x61);
        msg.add<uint32_t>(remove);
        msg.add<uint32_t>(creature->getID());
        msg.addByte(creatureType);
        msg.addString(creature->getName());
    }

    if (creature->isHealthHidden()) {
        msg.addByte(0x00);
    } else {
        msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100));
    }

    msg.addByte(creature->getDirection());

    if (!creature->isInGhostMode() && !creature->isInvisible()) {
        AddOutfit(msg, creature->getCurrentOutfit());
    } else {
        static Outfit_t outfit;
        AddOutfit(msg, outfit);
    }

    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);
    msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level);
    msg.addByte(lightInfo.color);

    msg.add<uint16_t>(creature->getStepSpeed() / 2);

    msg.addByte(player->getSkullClient(creature));
    msg.addByte(player->getPartyShield(otherPlayer));

    if (!known) {
        msg.addByte(player->getGuildEmblem(otherPlayer));
    }

    msg.addByte(creatureType); // Type (for summons)
    msg.addByte(creature->getSpeechBubble());
    msg.addByte(0xFF); // MARK_UNMARKED

    if (otherPlayer) {
        msg.add<uint16_t>(otherPlayer->getHelpers());
    } else {
        msg.add<uint16_t>(0x00);
    }

    msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01);
}

Again, this has not been tested, but it should do what you're asking for. I'm not aware of any side-effects this may have, so check carefully.
 
Last edited:
Solution
TFS 1.0? You'll have to compile it yourself though.

game.cpp, find void Game::updateCreatureType(Creature* creature) method and replace it with:

C++:
void Game::updateCreatureType(Creature* creature)
{
    const Player* masterPlayer = nullptr;

    uint32_t creatureId = creature->getID();
    CreatureType_t creatureType = creature->getType();
    if (creatureType == CREATURETYPE_MONSTER) {
        const Creature* master = creature->getMaster();
        if (master) {
            masterPlayer = master->getPlayer();
            if (masterPlayer) {
                creatureType = CREATURETYPE_SUMMON_OTHERS;
            }
        }
    }

    //send to clients
    SpectatorHashSet spectators;
    map.getSpectators(spectators, creature->getPosition(), true, true);

    if (creatureType == CREATURETYPE_SUMMON_OTHERS) {
        for (Creature* spectator : spectators) {
            Player* player = spectator->getPlayer();
            if (masterPlayer == player) {
                player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
            }
        }
    } else {
        for (Creature* spectator : spectators) {
            spectator->getPlayer()->sendCreatureType(creatureId, creatureType);
        }
    }
}

And ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove) in protocolgame.cpp, replace it with this:

C++:
void ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove)
{
    CreatureType_t creatureType = creature->getType();

    const Player* otherPlayer = creature->getPlayer();

    if (known) {
        msg.add<uint16_t>(0x62);
        msg.add<uint32_t>(creature->getID());
    } else {
        msg.add<uint16_t>(0x61);
        msg.add<uint32_t>(remove);
        msg.add<uint32_t>(creature->getID());
        msg.addByte(creatureType);
        msg.addString(creature->getName());
    }

    if (creature->isHealthHidden()) {
        msg.addByte(0x00);
    } else {
        msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100));
    }

    msg.addByte(creature->getDirection());

    if (!creature->isInGhostMode() && !creature->isInvisible()) {
        AddOutfit(msg, creature->getCurrentOutfit());
    } else {
        static Outfit_t outfit;
        AddOutfit(msg, outfit);
    }

    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);
    msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level);
    msg.addByte(lightInfo.color);

    msg.add<uint16_t>(creature->getStepSpeed() / 2);

    msg.addByte(player->getSkullClient(creature));
    msg.addByte(player->getPartyShield(otherPlayer));

    if (!known) {
        msg.addByte(player->getGuildEmblem(otherPlayer));
    }

    if (creatureType == CREATURETYPE_MONSTER) {
        const Creature* master = creature->getMaster();
        if (master) {
            const Player* masterPlayer = master->getPlayer();
            if (masterPlayer) {
                if (masterPlayer == player) {
                    creatureType = CREATURETYPE_SUMMON_OWN;
                }
            }
        }
    }

    msg.addByte(creatureType); // Type (for summons)
    msg.addByte(creature->getSpeechBubble());
    msg.addByte(0xFF); // MARK_UNMARKED

    if (otherPlayer) {
        msg.add<uint16_t>(otherPlayer->getHelpers());
    } else {
        msg.add<uint16_t>(0x00);
    }

    msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01);
}

It should work by not informing users that this is a summon (so the red shield should not appear). I don't know what other implications this may have, feel free to test it :) If you want to remove the green shield as well then use this version of functions (removes both green and red):

C++:
void Game::updateCreatureType(Creature* creature)
{
    const Player* masterPlayer = nullptr;

    uint32_t creatureId = creature->getID();
    CreatureType_t creatureType = creature->getType();

    //send to clients
    SpectatorHashSet spectators;
    map.getSpectators(spectators, creature->getPosition(), true, true);

    for (Creature* spectator : spectators) {
        spectator->getPlayer()->sendCreatureType(creatureId, creatureType);
    }
}


C++:
void ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove)
{
    CreatureType_t creatureType = creature->getType();

    const Player* otherPlayer = creature->getPlayer();

    if (known) {
        msg.add<uint16_t>(0x62);
        msg.add<uint32_t>(creature->getID());
    } else {
        msg.add<uint16_t>(0x61);
        msg.add<uint32_t>(remove);
        msg.add<uint32_t>(creature->getID());
        msg.addByte(creatureType);
        msg.addString(creature->getName());
    }

    if (creature->isHealthHidden()) {
        msg.addByte(0x00);
    } else {
        msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100));
    }

    msg.addByte(creature->getDirection());

    if (!creature->isInGhostMode() && !creature->isInvisible()) {
        AddOutfit(msg, creature->getCurrentOutfit());
    } else {
        static Outfit_t outfit;
        AddOutfit(msg, outfit);
    }

    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);
    msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level);
    msg.addByte(lightInfo.color);

    msg.add<uint16_t>(creature->getStepSpeed() / 2);

    msg.addByte(player->getSkullClient(creature));
    msg.addByte(player->getPartyShield(otherPlayer));

    if (!known) {
        msg.addByte(player->getGuildEmblem(otherPlayer));
    }

    msg.addByte(creatureType); // Type (for summons)
    msg.addByte(creature->getSpeechBubble());
    msg.addByte(0xFF); // MARK_UNMARKED

    if (otherPlayer) {
        msg.add<uint16_t>(otherPlayer->getHelpers());
    } else {
        msg.add<uint16_t>(0x00);
    }

    msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01);
}

Again, this has not been tested, but it should do what you're asking for. I'm not aware of any side-effects this may have, so check carefully.

It's better to just remove else statement from each file than replacing everything, I've noticed there are words that are different when compared to yours

It does work, thanks for that. I just hope there are no side effects of using this, but in reality i'd rather do something like

C++:
           if (masterPlayer == player) {
               player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
           } else {
               player->sendCreatureType(creatureId, creatureType_NONE);
           }

instead of that:

C++:
           if (masterPlayer == player) {
               player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
           }
 
It's better to just remove else statement from each file than replacing everything, I've noticed there are words that are different when compared to yours

It does work, thanks for that. I just hope there are no side effects of using this, but in reality i'd rather do something like

C++:
           if (masterPlayer == player) {
               player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
           } else {
               player->sendCreatureType(creatureId, creatureType_NONE);
           }

instead of that:

C++:
           if (masterPlayer == player) {
               player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
           }

Yes, I agree that removing parts of the function is better if you know what you're doing :) but for someone who just wants to copy&paste code, it is better to replace whole function definition, because identifying function block seems easier.

I think you just spotted a mistake! Fixed code:
C++:
void Game::updateCreatureType(Creature* creature)
{
    const Player* masterPlayer = nullptr;
    uint32_t creatureId = creature->getID();
    CreatureType_t creatureType = creature->getType();
    if (creatureType == CREATURETYPE_MONSTER) {
        const Creature* master = creature->getMaster();
        if (master) {
            masterPlayer = master->getPlayer();
            if (masterPlayer) {
                creatureType = CREATURETYPE_SUMMON_OTHERS;
            }
        }
    }
    //send to clients
    SpectatorHashSet spectators;
    map.getSpectators(spectators, creature->getPosition(), true, true);
    if (creatureType == CREATURETYPE_SUMMON_OTHERS) {
        for (Creature* spectator : spectators) {
            Player* player = spectator->getPlayer();
            if (masterPlayer == player) {
                player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
            } else {
                player->sendCreatureType(creatureId, CREATURETYPE_MONSTER);
            }
        }
    } else {
        for (Creature* spectator : spectators) {
            spectator->getPlayer()->sendCreatureType(creatureId, creatureType);
        }
    }
}

I don't agree sending CREATURETYPE_NONE would be correct here, CREATURETYPE_MONSTER is correct type for monsters (both hostile and summoned).
 
Last edited:
Yes, I agree that removing parts of the function is better if you know what you're doing :) but for someone who just wants to copy&paste code, it is better to replace whole function definition, because identifying function block seems easier.

I think you just spotted a mistake! Fixed code:
C++:
void Game::updateCreatureType(Creature* creature)
{
    const Player* masterPlayer = nullptr;
    uint32_t creatureId = creature->getID();
    CreatureType_t creatureType = creature->getType();
    if (creatureType == CREATURETYPE_MONSTER) {
        const Creature* master = creature->getMaster();
        if (master) {
            masterPlayer = master->getPlayer();
            if (masterPlayer) {
                creatureType = CREATURETYPE_SUMMON_OTHERS;
            }
        }
    }
    //send to clients
    SpectatorHashSet spectators;
    map.getSpectators(spectators, creature->getPosition(), true, true);
    if (creatureType == CREATURETYPE_SUMMON_OTHERS) {
        for (Creature* spectator : spectators) {
            Player* player = spectator->getPlayer();
            if (masterPlayer == player) {
                player->sendCreatureType(creatureId, CREATURETYPE_SUMMON_OWN);
            } else {
                player->sendCreatureType(creatureId, creatureType);
            }
        }
    } else {
        for (Creature* spectator : spectators) {
            spectator->getPlayer()->sendCreatureType(creatureId, creatureType);
        }
    }
}

I don't agree sending CREATURETYPE_NONE would be correct here, CREATURETYPE_MONSTER is correct type for monsters (both hostile and summoned).

this code is the same as original? What do you mean it's fixed O: (but yeah, I've changed to the original one and it is still working). So in this case, only protocolgame.cpp had to be changed.

CREATURETYPE_NONE was just an example (to pass something instead of not having else statement), not sure if there is even a function that define this.
 
this code is the same as original? What do you mean it's fixed O: (but yeah, I've changed to the original one and it is still working). So in this case, only protocolgame.cpp had to be changed.

CREATURETYPE_NONE was just an example (to pass something instead of not having else statement), not sure if there is even a function that define this.
You're right, damn.. my mistake, the CREATURETYPE_MONSTER should be used in "else" clause instead of creatureType variable, updated it there (#4).

I think I should post it in Resources subforum and link here, instead of having all these changes spead over the thread.
 
Last edited:
You're right, damn.. my mistake, the CREATURETYPE_MONSTER should be used in "else" clause instead of creatureType variable, updated it there (#4).

all in all, I see no difference between creatureType and CREATURETYPE_MONSTER

I think both will work, but I haven't tested CREATURETYPE_MONSTER
 
all in all, I see no difference between creatureType and CREATURETYPE_MONSTER

I think both will work, but I haven't tested CREATURETYPE_MONSTER

creatureType will be CREATURETYPE_SUMMON_OTHERS, thus showing the red shield icon. CREATURETYPE_MONSTER on the other hand will let client application treat it as a regular monster - no shield icon.

So you should use void Game::updateCreatureType(Creature* creature) implementation from #4. I'm not sure where this method is called, but may eventually lead to some small glitches if not changed.
 
Back
Top