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

TFS 1.X+ How to track how he typed spell with doCreatureSay

Lopaskurwa

Well-Known Member
Joined
Oct 6, 2017
Messages
936
Solutions
2
Reaction score
57
Hi
So i only know the basic script of doCreatureSay so i wondering how to track how he typed that command i mean tracking the caps lock example lets say you type TeST SPELL so doCreatureSay will send that same style and etc... I cant find any information about it.
 
Solution
5zWZxkT.png


I managed to do it :D
I will share my spells functions from spells.cpp that I changed to achieve this results
Code:
TalkActionResult_t Spells::playerSaySpell(Player* player, std::string& words)
{
    std::string str_words = words;

    //strip trailing spaces
    trimString(str_words);

    InstantSpell* instantSpell = getInstantSpell(str_words);
    if (!instantSpell) {
        return TALKACTION_CONTINUE;
    }

    std::string param;
    size_t spellLen = instantSpell->getWords().length();
    size_t paramLen = str_words.length() - spellLen;
    std::string paramText = str_words.substr(spellLen, paramLen);
    if (!paramText.empty() && paramText.front() == ' ') {
        size_t loc1 =...
Hey, I still don't quite understand what you want. You must explain it better with own words ^^

Anyways I managed to accomplish this
U9gZvl7.png


But it's still not perfect yet, for example the spell will always be lowercased letters but I will try fixing it or I can share what I did right now if you are ok with the spell being lowercased letters.
 
Hey, I still don't quite understand what you want. You must explain it better with own words ^^

Anyways I managed to accomplish this
U9gZvl7.png


But it's still not perfect yet, for example the spell will always be lowercased letters but I will try fixing it or I can share what I did right now if you are ok with the spell being lowercased letters.
What i want is to track caps locks and let cast the spell even when you make something like this exevo "blablalbla or ExEvo "sdlftret this is what i mean.
 
5zWZxkT.png


I managed to do it :D
I will share my spells functions from spells.cpp that I changed to achieve this results
Code:
TalkActionResult_t Spells::playerSaySpell(Player* player, std::string& words)
{
    std::string str_words = words;

    //strip trailing spaces
    trimString(str_words);

    InstantSpell* instantSpell = getInstantSpell(str_words);
    if (!instantSpell) {
        return TALKACTION_CONTINUE;
    }

    std::string param;
    size_t spellLen = instantSpell->getWords().length();
    size_t paramLen = str_words.length() - spellLen;
    std::string paramText = str_words.substr(spellLen, paramLen);
    if (!paramText.empty() && paramText.front() == ' ') {
        size_t loc1 = paramText.find('"', 1);
        if (loc1 != std::string::npos) {
            size_t loc2 = paramText.find('"', loc1 + 1);
            if (loc2 == std::string::npos) {
                loc2 = paramText.length();
            } else if (paramText.find_last_not_of(' ') != loc2) {
                return TALKACTION_CONTINUE;
            }

            param = paramText.substr(loc1 + 1, loc2 - loc1 - 1);
        } else {
            trimString(paramText);
            loc1 = paramText.find(' ', 0);
            if (loc1 == std::string::npos) {
                param = paramText;
            } else {
                return TALKACTION_CONTINUE;
            }
        }
    }


    if (instantSpell->playerCastInstant(player, param)) {
        words = str_words.substr(0, spellLen);

        if (!param.empty()) {
            words += " \"" + param.substr(0, 30);
        }

        return TALKACTION_BREAK;
    }

    return TALKACTION_FAILED;
}

in this code you have "param.substr(0, 30);"
this puts a limit to how many letters can be after the spell, I put it as 30 but you can higher it if you want.

and you need change this too
Code:
InstantSpell* Spells::getInstantSpell(const std::string& words)
{
    InstantSpell* result = nullptr;

    for (const auto& it : instants) {
        InstantSpell* instantSpell = it.second;

        const std::string& instantSpellWords = instantSpell->getWords();
        size_t spellLen = instantSpellWords.length();
        if (strncasecmp(instantSpellWords.c_str(), words.c_str(), spellLen) == 0) {
            if (!result || spellLen > result->getWords().length()) {
                result = instantSpell;
                if (words.length() == spellLen) {
                    break;
                }
            }
        }
    }

    if (result) {
        const std::string& resultWords = result->getWords();
        if (words.length() > resultWords.length()) {

            size_t spellLen = resultWords.length();
            size_t paramLen = words.length() - spellLen;
            if (paramLen < 2 || words[spellLen] != ' ') {
                return nullptr;
            }
        }
        return result;
    }
    return nullptr;
}

Just replace ur old functions with the new ones and it should work if your using TFS 1.x
 
Solution
5zWZxkT.png


I managed to do it :D
I will share my spells functions from spells.cpp that I changed to achieve this results
Code:
TalkActionResult_t Spells::playerSaySpell(Player* player, std::string& words)
{
    std::string str_words = words;

    //strip trailing spaces
    trimString(str_words);

    InstantSpell* instantSpell = getInstantSpell(str_words);
    if (!instantSpell) {
        return TALKACTION_CONTINUE;
    }

    std::string param;
    size_t spellLen = instantSpell->getWords().length();
    size_t paramLen = str_words.length() - spellLen;
    std::string paramText = str_words.substr(spellLen, paramLen);
    if (!paramText.empty() && paramText.front() == ' ') {
        size_t loc1 = paramText.find('"', 1);
        if (loc1 != std::string::npos) {
            size_t loc2 = paramText.find('"', loc1 + 1);
            if (loc2 == std::string::npos) {
                loc2 = paramText.length();
            } else if (paramText.find_last_not_of(' ') != loc2) {
                return TALKACTION_CONTINUE;
            }

            param = paramText.substr(loc1 + 1, loc2 - loc1 - 1);
        } else {
            trimString(paramText);
            loc1 = paramText.find(' ', 0);
            if (loc1 == std::string::npos) {
                param = paramText;
            } else {
                return TALKACTION_CONTINUE;
            }
        }
    }


    if (instantSpell->playerCastInstant(player, param)) {
        words = str_words.substr(0, spellLen);

        if (!param.empty()) {
            words += " \"" + param.substr(0, 30);
        }

        return TALKACTION_BREAK;
    }

    return TALKACTION_FAILED;
}

in this code you have "param.substr(0, 30);"
this puts a limit to how many letters can be after the spell, I put it as 30 but you can higher it if you want.

and you need change this too
Code:
InstantSpell* Spells::getInstantSpell(const std::string& words)
{
    InstantSpell* result = nullptr;

    for (const auto& it : instants) {
        InstantSpell* instantSpell = it.second;

        const std::string& instantSpellWords = instantSpell->getWords();
        size_t spellLen = instantSpellWords.length();
        if (strncasecmp(instantSpellWords.c_str(), words.c_str(), spellLen) == 0) {
            if (!result || spellLen > result->getWords().length()) {
                result = instantSpell;
                if (words.length() == spellLen) {
                    break;
                }
            }
        }
    }

    if (result) {
        const std::string& resultWords = result->getWords();
        if (words.length() > resultWords.length()) {

            size_t spellLen = resultWords.length();
            size_t paramLen = words.length() - spellLen;
            if (paramLen < 2 || words[spellLen] != ' ') {
                return nullptr;
            }
        }
        return result;
    }
    return nullptr;
}

Just replace ur old functions with the new ones and it should work if your using TFS 1.x
Yea compiled everything without any errors but damn probably i'm making something wrong with spell .lua because it doesnt show any text for me :D
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_EFFECT, 28)
setCombatParam(combat, COMBAT_PARAM_AGGRESSIVE, 0)

local condition = createConditionObject(CONDITION_HASTE)
setConditionParam(condition, CONDITION_PARAM_TICKS, 42000)
setConditionFormula(condition, 1.0, -56, 1.0, -56)
setCombatCondition(combat, condition)

function onCastSpell(cid, var)
   doCombat(cid, combat, var)
   return false
end
What do you see wrong in this script that can cause not showing the text?
 
Hello sir, I guess best idea would be to go back to your old spells.cpp file and share it with us. Maybe it wasn't the exactly same as I had and it's why it's not working for you. [On my server this is working perfect]
To fix it for youself u should check on the changes I made in the post above and try do adjust ur spells.cpp in the same way. If not just post ur old spells.cpp and i can probably fix it for u when i have time!
 
Hello sir, I guess best idea would be to go back to your old spells.cpp file and share it with us. Maybe it wasn't the exactly same as I had and it's why it's not working for you. [On my server this is working perfect]
To fix it for youself u should check on the changes I made in the post above and try do adjust ur spells.cpp in the same way. If not just post ur old spells.cpp and i can probably fix it for u when i have time!
Sorry it was my bad everything works perfect. I noticed that my config.lua emoteSpells always was false thats why it doesnt worked.
 
5zWZxkT.png


I managed to do it :D
I will share my spells functions from spells.cpp that I changed to achieve this results
Code:
TalkActionResult_t Spells::playerSaySpell(Player* player, std::string& words)
{
    std::string str_words = words;

    //strip trailing spaces
    trimString(str_words);

    InstantSpell* instantSpell = getInstantSpell(str_words);
    if (!instantSpell) {
        return TALKACTION_CONTINUE;
    }

    std::string param;
    size_t spellLen = instantSpell->getWords().length();
    size_t paramLen = str_words.length() - spellLen;
    std::string paramText = str_words.substr(spellLen, paramLen);
    if (!paramText.empty() && paramText.front() == ' ') {
        size_t loc1 = paramText.find('"', 1);
        if (loc1 != std::string::npos) {
            size_t loc2 = paramText.find('"', loc1 + 1);
            if (loc2 == std::string::npos) {
                loc2 = paramText.length();
            } else if (paramText.find_last_not_of(' ') != loc2) {
                return TALKACTION_CONTINUE;
            }

            param = paramText.substr(loc1 + 1, loc2 - loc1 - 1);
        } else {
            trimString(paramText);
            loc1 = paramText.find(' ', 0);
            if (loc1 == std::string::npos) {
                param = paramText;
            } else {
                return TALKACTION_CONTINUE;
            }
        }
    }


    if (instantSpell->playerCastInstant(player, param)) {
        words = str_words.substr(0, spellLen);

        if (!param.empty()) {
            words += " \"" + param.substr(0, 30);
        }

        return TALKACTION_BREAK;
    }

    return TALKACTION_FAILED;
}

in this code you have "param.substr(0, 30);"
this puts a limit to how many letters can be after the spell, I put it as 30 but you can higher it if you want.

and you need change this too
Code:
InstantSpell* Spells::getInstantSpell(const std::string& words)
{
    InstantSpell* result = nullptr;

    for (const auto& it : instants) {
        InstantSpell* instantSpell = it.second;

        const std::string& instantSpellWords = instantSpell->getWords();
        size_t spellLen = instantSpellWords.length();
        if (strncasecmp(instantSpellWords.c_str(), words.c_str(), spellLen) == 0) {
            if (!result || spellLen > result->getWords().length()) {
                result = instantSpell;
                if (words.length() == spellLen) {
                    break;
                }
            }
        }
    }

    if (result) {
        const std::string& resultWords = result->getWords();
        if (words.length() > resultWords.length()) {

            size_t spellLen = resultWords.length();
            size_t paramLen = words.length() - spellLen;
            if (paramLen < 2 || words[spellLen] != ' ') {
                return nullptr;
            }
        }
        return result;
    }
    return nullptr;
}

Just replace ur old functions with the new ones and it should work if your using TFS 1.x
Hello!
Adding quotes when casting a spell with a custom message like it did in tibia 7.6 would be really nice to have.
Example: utamo vita "Fred is here
It looks a little bit different for me in spells.cpp, so if there is anyone out there who could help me achieve this, I would appreciate it extremely much!
I'm using TFS 1.5 Downgraded by Nekiro (GitHub - nekiro/TFS-1.5-Downgrades at 7.72 (https://github.com/nekiro/TFS-1.5-Downgrades/tree/7.72)) and Tibia 7.72 client, no custom client.

Compiling errors:
error C2440: 'initializing': cannot convert from 'const _Ty2' to 'InstantSpell *'
1> with 1> [ 1> _Ty2=InstantSpell 1> ] 1 TFS-1.5-Downgrades-7.72\src\spells.cpp(235,36): message : No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
 
Last edited:
Hello!
Adding quotes when casting a spell with a custom message like it did in tibia 7.6 would be really nice to have.
Example: utamo vita "Fred is here
It looks a little bit different for me in spells.cpp, so if there is anyone out there who could help me achieve this, I would appreciate it extremely much!
I'm using TFS 1.5 Downgraded by Nekiro (GitHub - nekiro/TFS-1.5-Downgrades at 7.72 (https://github.com/nekiro/TFS-1.5-Downgrades/tree/7.72)) and Tibia 7.72 client, no custom client.

Compiling errors:
error C2440: 'initializing': cannot convert from 'const _Ty2' to 'InstantSpell *'
1> with 1> [ 1> _Ty2=InstantSpell 1> ] 1 TFS-1.5-Downgrades-7.72\src\spells.cpp(235,36): message : No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
The original project does not contain const _Ty2.
If your source code is different, you should post the corresponding script or function.

check type _Ty2
like: const auto& _Ty2 = Object;

TFS-1.5-Downgrades-7.72\src\spells.cpp(235,36);
 
The original project does not contain const _Ty2.
If your source code is different, you should post the corresponding script or function.

check type _Ty2
like: const auto& _Ty2 = Object;
I'm not quite sure what you mean with _Ty2 but I don't find anything with that name regardless in my source files.
This is how mine looks like compared to what Evolunia had.
spells.cpp
LUA:
TalkActionResult_t Spells::playerSaySpell(Player* player, std::string& words)
{
    std::string str_words = words;

    //strip trailing spaces
    trimString(str_words);

    InstantSpell* instantSpell = getInstantSpell(str_words);
    if (!instantSpell) {
        return TALKACTION_CONTINUE;
    }

    std::string param;

    if (instantSpell->getHasParam()) {
        size_t spellLen = instantSpell->getWords().length();
        size_t paramLen = str_words.length() - spellLen;
        std::string paramText = str_words.substr(spellLen, paramLen);
        if (!paramText.empty() && paramText.front() == ' ') {
            size_t loc1 = paramText.find('"', 1);
            if (loc1 != std::string::npos) {
                size_t loc2 = paramText.find('"', loc1 + 1);
                if (loc2 == std::string::npos) {
                    loc2 = paramText.length();
                } else if (paramText.find_last_not_of(' ') != loc2) {
                    return TALKACTION_CONTINUE;
                }

                param = paramText.substr(loc1 + 1, loc2 - loc1 - 1);
            } else {
                trimString(paramText);
                loc1 = paramText.find(' ', 0);
                if (loc1 == std::string::npos) {
                    param = paramText;
                } else {
                    return TALKACTION_CONTINUE;
                }
            }
        }
    }

    if (instantSpell->playerCastInstant(player, param)) {
        words = instantSpell->getWords();

        if (instantSpell->getHasParam() && !param.empty()) {
            words += " \"" + param + "\"";
        }

        return TALKACTION_BREAK;
    }

    return TALKACTION_FAILED;
}
And

LUA:
InstantSpell* Spells::getInstantSpell(const std::string& words)
{
    InstantSpell* result = nullptr;

    for (auto& it : instants) {
        const std::string& instantSpellWords = it.second.getWords();
        size_t spellLen = instantSpellWords.length();
        if (strncasecmp(instantSpellWords.c_str(), words.c_str(), spellLen) == 0) {
            if (!result || spellLen > result->getWords().length()) {
                result = &it.second;
                if (words.length() == spellLen) {
                    break;
                }
            }
        }
    }

    if (result) {
        const std::string& resultWords = result->getWords();
        if (words.length() > resultWords.length()) {
            if (!result->getHasParam()) {
                return nullptr;
            }

            size_t spellLen = resultWords.length();
            size_t paramLen = words.length() - spellLen;
            if (paramLen < 2 || words[spellLen] != ' ') {
                return nullptr;
            }
        }
        return result;
    }
    return nullptr;
}
 
Example: utamo vita "Fred is here
It looks a little bit different for me in spells.cpp, so if there is anyone out there who could help me achieve this, I would appreciate it extremely much!
I'm using TFS 1.5 Downgraded by Nekiro (GitHub - nekiro/TFS-1.5-Downgrades at 7.72 (https://github.com/nekiro/TFS-1.5-Downgrades/tree/7.72)) and Tibia 7.72 client, no custom client.
I modified spells to work like on screenshot using Cursor with Gemini 3 Pro AI model. Total cost: 0.41$. Code changes:

1763662439950.webp
 
I modified spells to work like on screenshot using Cursor with Gemini 3 Pro AI model. Total cost: 0.41$. Code changes:

View attachment 96149
Thank you very much, extremely kind!
It works lovely. I really appreciate it! 😭
 
Back
Top