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

OTClient Mod problem redemption 4.0

norol

Member
Joined
Mar 19, 2026
Messages
17
Solutions
2
Reaction score
5
Location
Poland
Hello, I have a problem, I don't know why the text above the player's name isn't displayed, no errors
my cod tfs revscripts
LUA:
local RANK_STORAGE = 80000

local function getRank(player)
    local v = player:getStorageValue(RANK_STORAGE)
    if v < 0 then v = 0 end
    return v
end

local function sendRank(toPlayer, target)
    if not toPlayer or not target then return end

    local rank = getRank(target)

    print("[RANK] send:", target:getName(), "-> do:", toPlayer:getName(), "rank:", rank)

    toPlayer:sendExtendedOpcode(50, target:getId() .. "|" .. rank)
end

local function broadcastRank(player)
    print("[RANK] broadcast for:", player:getName())

    local spectators = Game.getSpectators(player:getPosition(), false, true, 7, 7, 5, 5)

    for _, spec in ipairs(spectators) do
        if spec:isPlayer() then

            if spec ~= player then
                sendRank(spec, player)
            end

            sendRank(player, spec)
        end
    end
end

local loginEvent = CreatureEvent("RankLogin")

function loginEvent.onLogin(player)
    if player:getStorageValue(RANK_STORAGE) == -1 then
        player:setStorageValue(RANK_STORAGE, 0)
    end

    addEvent(function()
        if player then
            broadcastRank(player)
        end
    end, 500)

    return true
end

loginEvent:register()
LUA:
local ranks = {}

function init()
    connect(g_game, {
        onGameStart = onGameStart,
        onGameEnd = onGameEnd
    })

    print("[RANK] init ok")
end

function terminate()
    disconnect(g_game, {
        onGameStart = onGameStart,
        onGameEnd = onGameEnd
    })
end

function onGameStart()
    print("[RANK] game start")

    g_game.enableFeature(GameExtendedOpcode)
    ProtocolGame.registerExtendedOpcode(50, onOpcode)
end

function onGameEnd()
    ProtocolGame.unregisterExtendedOpcode(50)
end

function onOpcode(protocol, opcode, buffer)
    print("[RANK] take:", buffer)

    local id, rank = buffer:match("(%d+)|(%d+)")
    id = tonumber(id)
    rank = tonumber(rank)

    if not id then return end

    ranks[id] = rank

    local creature = getCreatureById(id)
    if creature then
        setRank(creature, rank)
    end
end

function setRank(creature, rank)
    if creature.rankLabel then
        creature.rankLabel:destroy()
    end

    local label = g_ui.createWidget('RankLabel', modules.game_interface.getMapPanel())
    label:setText(getRankName(rank))
    label:attachToCreature(creature)

    creature.rankLabel = label

    print("[RANK] label:", creature:getName(), getRankName(rank))
end

function getRankName(rank)
    if rank == 1 then return "Man"
    elseif rank == 2 then return "Mantwo"
    elseif rank == 3 then return "Girl"
    elseif rank == 4 then return "Girltwo"
    else return "Nobody"
    end
end
otui
Code:
RankLabel < Label
  font: verdana-11px-rounded
  color: white
  text-align: center
  anchors.horizontalCenter: parent.horizontalCenter
  anchors.bottom: parent.top
  margin-bottom: 15
otmod
Code:
Module
  name: game_rank
  description: Rank system
  author: lose
  version: 1.0

  autoload: true

  scripts: [ rank.lua ]
  otuis: [ rank.otui ]
please help me solve the problem
 
his does not exist in any OTC client
LUA:
label:attachToCreature(creature)
Try with:
Code:
g_game.getLocalPlayer():attachWidget(label)


prefer to use SetTile

Diff:
---
 src/client/creature.cpp             | 19 ++++++++++++++++++-
 src/client/creature.h               |  6 ++++++
 src/client/luafunctions.cpp         |  4 ++++
 src/framework/graphics/cachedtext.h |  1 +
 4 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/src/client/creature.cpp b/src/client/creature.cpp
index cddf7b123..fcc6c3bbd 100644
--- a/src/client/creature.cpp
+++ b/src/client/creature.cpp
@@ -32,6 +32,7 @@
 #include <framework/core/clock.h>
 #include <framework/core/eventdispatcher.h>
 #include <framework/core/graphicalapplication.h>
+#include <framework/graphics/fontmanager.h>
 #include <framework/graphics/drawpoolmanager.h>
 #include <framework/graphics/shadermanager.h>
 #include <framework/graphics/texturemanager.h>
@@ -260,7 +261,14 @@ void Creature::drawInformation(const MapPosInfo& mapRect, const Point& dest, con
 
     if (drawFlags & Otc::DrawNames) {
         m_name.draw(textRect, fillColor);
-
+        if (m_titleCache.hasText()) {
+            Size titleSize = m_titleCache.getTextSize();
+            Point textCenter = textRect.topCenter();
+            textRect.setWidth(titleSize.width());
+            textRect.setHeight(titleSize.height());
+            textRect.moveBottomCenter(textCenter);
+            m_titleCache.draw(textRect, m_titleColor);
+        }
         if (m_text) {
             auto extraTextSize = m_text->getTextSize();
             Rect extraTextRect = Rect(p.x - extraTextSize.width() / 2.0, p.y + 15, extraTextSize);
@@ -1297,4 +1305,13 @@ std::string Creature::getText()
 bool Creature::canShoot(int distance)
 {
     return getTile() ? getTile()->canShoot(distance) : false;
+}
+
+void Creature::setTitle(const std::string & title, const std::string & font, const Color & color)
+{
+    m_titleCache.setText(title);
+    if (!font.empty()) {
+        m_titleCache.setFont(g_fonts.getFont(font));
+    }
+    m_titleColor = color;
 }
\ No newline at end of file
diff --git a/src/client/creature.h b/src/client/creature.h
index 179c1cc6c..4f4de1c9a 100644
--- a/src/client/creature.h
+++ b/src/client/creature.h
@@ -189,6 +189,10 @@ minHeight,
     void clearText() { setText("", Color::white); }
     bool canShoot(int distance);
 
+    void setTitle(const std::string& title, const std::string& font, const Color& color);
+    void clearTitle() { setTitle("", "", Color::white); }
+    std::string getTitle() { return m_titleCache.getText(); }
+
     const auto& getIcons() {
         static std::vector<std::tuple<uint8_t, uint8_t, uint16_t>> vec;
         return m_icons ? m_icons->iconEntries : vec;
@@ -280,6 +284,8 @@ private:
 
     EventPtr m_disappearEvent;
 
+    CachedText m_titleCache;
+    Color m_titleColor;
     CachedText m_name;
     CachedStep m_stepCache;
 
diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp
index 6e0c39e2f..42d24685c 100644
--- a/src/client/luafunctions.cpp
+++ b/src/client/luafunctions.cpp
@@ -628,6 +628,10 @@ void Client::registerLuaFunctions()
     g_lua.bindClassMemberFunction<Creature>("setVocation", &Creature::setVocation);
     g_lua.bindClassMemberFunction<Creature>("getVocation", &Creature::getVocation);
 
+    g_lua.bindClassMemberFunction<Creature>("setTitle", &Creature::setTitle);
+    g_lua.bindClassMemberFunction<Creature>("clearTitle", &Creature::clearTitle);
+    g_lua.bindClassMemberFunction<Creature>("getTitle", &Creature::getTitle);
+
 #ifdef FRAMEWORK_EDITOR
     g_lua.registerClass<ItemType>();
     g_lua.bindClassMemberFunction<ItemType>("getServerId", &ItemType::getServerId);
diff --git a/src/framework/graphics/cachedtext.h b/src/framework/graphics/cachedtext.h
index 0268621d5..ca2029925 100644
--- a/src/framework/graphics/cachedtext.h
+++ b/src/framework/graphics/cachedtext.h
@@ -41,6 +41,7 @@ public:
     bool hasText() const { return !m_text.empty(); }
     BitmapFontPtr getFont() const { return m_font; }
     Fw::AlignmentFlag getAlign() const { return m_align; }
+    bool hasText() { return !m_text.empty(); }
 
 private:
     void update();
 
Last edited:
LUA:
    addEvent(function()
        if player then
            broadcastRank(player)
        end
    end, 500)
IDK about OTC problem, but this code can easily crash OTS on TFS 1.x.
If players logout or die within 0.5 sec after login, player will point to address in RAM that does not exist anymore - it's not 100% crash, you can logout few times in 0.1 sec and it won't crash, but finally it will crash.

It should be:
LUA:
    addEvent(function(playerId)
        local player = Player(playerId)
        if player then
            broadcastRank(player)
        end
    end, 500, player:getId())
You have to 'restore' player variable using player ID (number( to safely test if player then.
 
his does not exist in any OTC client
LUA:
label:attachToCreature(creature)
Try with:
Code:
g_game.getLocalPlayer():attachWidget(label)


prefer to use SetTile

Diff:
---
 src/client/creature.cpp             | 19 ++++++++++++++++++-
 src/client/creature.h               |  6 ++++++
 src/client/luafunctions.cpp         |  4 ++++
 src/framework/graphics/cachedtext.h |  1 +
 4 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/src/client/creature.cpp b/src/client/creature.cpp
index cddf7b123..fcc6c3bbd 100644
--- a/src/client/creature.cpp
+++ b/src/client/creature.cpp
@@ -32,6 +32,7 @@
 #include <framework/core/clock.h>
 #include <framework/core/eventdispatcher.h>
 #include <framework/core/graphicalapplication.h>
+#include <framework/graphics/fontmanager.h>
 #include <framework/graphics/drawpoolmanager.h>
 #include <framework/graphics/shadermanager.h>
 #include <framework/graphics/texturemanager.h>
@@ -260,7 +261,14 @@ void Creature::drawInformation(const MapPosInfo& mapRect, const Point& dest, con
 
     if (drawFlags & Otc::DrawNames) {
         m_name.draw(textRect, fillColor);
-
+        if (m_titleCache.hasText()) {
+            Size titleSize = m_titleCache.getTextSize();
+            Point textCenter = textRect.topCenter();
+            textRect.setWidth(titleSize.width());
+            textRect.setHeight(titleSize.height());
+            textRect.moveBottomCenter(textCenter);
+            m_titleCache.draw(textRect, m_titleColor);
+        }
         if (m_text) {
             auto extraTextSize = m_text->getTextSize();
             Rect extraTextRect = Rect(p.x - extraTextSize.width() / 2.0, p.y + 15, extraTextSize);
@@ -1297,4 +1305,13 @@ std::string Creature::getText()
 bool Creature::canShoot(int distance)
 {
     return getTile() ? getTile()->canShoot(distance) : false;
+}
+
+void Creature::setTitle(const std::string & title, const std::string & font, const Color & color)
+{
+    m_titleCache.setText(title);
+    if (!font.empty()) {
+        m_titleCache.setFont(g_fonts.getFont(font));
+    }
+    m_titleColor = color;
 }
\ No newline at end of file
diff --git a/src/client/creature.h b/src/client/creature.h
index 179c1cc6c..4f4de1c9a 100644
--- a/src/client/creature.h
+++ b/src/client/creature.h
@@ -189,6 +189,10 @@ minHeight,
     void clearText() { setText("", Color::white); }
     bool canShoot(int distance);
 
+    void setTitle(const std::string& title, const std::string& font, const Color& color);
+    void clearTitle() { setTitle("", "", Color::white); }
+    std::string getTitle() { return m_titleCache.getText(); }
+
     const auto& getIcons() {
         static std::vector<std::tuple<uint8_t, uint8_t, uint16_t>> vec;
         return m_icons ? m_icons->iconEntries : vec;
@@ -280,6 +284,8 @@ private:
 
     EventPtr m_disappearEvent;
 
+    CachedText m_titleCache;
+    Color m_titleColor;
     CachedText m_name;
     CachedStep m_stepCache;
 
diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp
index 6e0c39e2f..42d24685c 100644
--- a/src/client/luafunctions.cpp
+++ b/src/client/luafunctions.cpp
@@ -628,6 +628,10 @@ void Client::registerLuaFunctions()
     g_lua.bindClassMemberFunction<Creature>("setVocation", &Creature::setVocation);
     g_lua.bindClassMemberFunction<Creature>("getVocation", &Creature::getVocation);
 
+    g_lua.bindClassMemberFunction<Creature>("setTitle", &Creature::setTitle);
+    g_lua.bindClassMemberFunction<Creature>("clearTitle", &Creature::clearTitle);
+    g_lua.bindClassMemberFunction<Creature>("getTitle", &Creature::getTitle);
+
 #ifdef FRAMEWORK_EDITOR
     g_lua.registerClass<ItemType>();
     g_lua.bindClassMemberFunction<ItemType>("getServerId", &ItemType::getServerId);
diff --git a/src/framework/graphics/cachedtext.h b/src/framework/graphics/cachedtext.h
index 0268621d5..ca2029925 100644
--- a/src/framework/graphics/cachedtext.h
+++ b/src/framework/graphics/cachedtext.h
@@ -41,6 +41,7 @@ public:
     bool hasText() const { return !m_text.empty(); }
     BitmapFontPtr getFont() const { return m_font; }
     Fw::AlignmentFlag getAlign() const { return m_align; }
+    bool hasText() { return !m_text.empty(); }
 
 private:
     void update();
it doesn't give anything, as if the customer didn't receive an answerBez tytułu.webp
Post automatically merged:

IDK about OTC problem, but this code can easily crash OTS on TFS 1.x.
If players logout or die within 0.5 sec after login, player will point to address in RAM that does not exist anymore - it's not 100% crash, you can logout few times in 0.1 sec and it won't crash, but finally it will crash.

It should be:
LUA:
    addEvent(function(playerId)
        local player = Player(playerId)
        if player then
            broadcastRank(player)
        end
    end, 500, player:getId())
You have to 'restore' player variable using player ID (number( to safely test if player then.
you're right, thank you
 
Back
Top