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

Feature TFS[1.4.2] Questlog/Task counter: Storage tracker in description as string

Klank

Althea ¤ A New World Developer
Joined
Feb 21, 2008
Messages
1,077
Reaction score
631
Location
Norway
Greetings!

I was in need of a task tracker inside the questlog and i did not find anything here on the forum, except for TFS 0.X versions.
So i wanted to share this, as i think many could need it. I am fairly new to C++ so It is made with assistance from ChatGPT and it has 1 flaw, it does not work if ignoreValue = true in the quest.xml file.
If someone wants to improve this code to use it with ignoreValue, feel free to post it here.

Simply change the whole function in quests.cpp (or replace only the whole else statement)
C++:
std::string Mission::getDescription(Player* player) const

with
C++:
std::string Mission::getDescription(Player* player) const
{
    int32_t value;
    player->getStorageValue(storageID, value);

    if (!mainDescription.empty()) {
        std::string desc = mainDescription;
        replaceString(desc, "|STATE|", std::to_string(value));
        replaceString(desc, "\\n", "\n");
        return desc;
    }

    if (ignoreEndValue) {
        for (int32_t current = endValue; current >= startValue; current--) {
            if (value >= current) {
                auto sit = descriptions.find(current);
                if (sit != descriptions.end()) {
                    return sit->second;
                }
            }
        }
    }
    else {
        for (int32_t current = endValue; current >= startValue; current--) {
            if (value == current) {
                auto sit = descriptions.find(current);
                if (sit != descriptions.end()) {
                    std::string desc = sit->second;
                    size_t statePos = desc.find("|STATE|");
                    while (statePos != std::string::npos) {
                        size_t startPos = statePos + 7; // start looking for value after |STATE|.
                        size_t endPos = desc.find("|", startPos); // find the last digit of the storage
                        if (endPos != std::string::npos) {
                            uint32_t storageValueIdentifier = std::stoul(desc.substr(startPos, endPos - startPos));
                            int32_t IdentifiedStorageValue;
                            player->getStorageValue(storageValueIdentifier, IdentifiedStorageValue);
                            desc.replace(statePos, endPos - statePos + 1, std::to_string(IdentifiedStorageValue));
                                                }
                        statePos = desc.find("|STATE|", statePos + 1);
                    }
                    return desc;
                }
            }
        }
    }
    return "An error has occurred, please contact a gamemaster.";
}

Demonstration:
Simply use the |STATE|STORAGEID| inside the quest description (

 is for double new line):

XML:
<mission name="Quest/Task/Mission" storageid="250" startvalue="1" endvalue="3">
            <missionstate id="1" description="Trolls killed: |STATE|249|/200 &#10;&#10;Dragons killed: |STATE|1203| /500 &#10;&#10;Discovered places: |STATE|250|x" />
        </mission>

1699554881457.png1699554899333.png
 
Greetings!

I was in need of a task tracker inside the questlog and i did not find anything here on the forum, except for TFS 0.X versions.
So i wanted to share this, as i think many could need it. I am fairly new to C++ so It is made with assistance from ChatGPT and it has 1 flaw, it does not work if ignoreValue = true in the quest.xml file.
If someone wants to improve this code to use it with ignoreValue, feel free to post it here.

Simply change the whole function in quests.cpp (or replace only the whole else statement)
C++:
std::string Mission::getDescription(Player* player) const

with
C++:
std::string Mission::getDescription(Player* player) const
{
    int32_t value;
    player->getStorageValue(storageID, value);

    if (!mainDescription.empty()) {
        std::string desc = mainDescription;
        replaceString(desc, "|STATE|", std::to_string(value));
        replaceString(desc, "\\n", "\n");
        return desc;
    }

    if (ignoreEndValue) {
        for (int32_t current = endValue; current >= startValue; current--) {
            if (value >= current) {
                auto sit = descriptions.find(current);
                if (sit != descriptions.end()) {
                    return sit->second;
                }
            }
        }
    }
    else {
        for (int32_t current = endValue; current >= startValue; current--) {
            if (value == current) {
                auto sit = descriptions.find(current);
                if (sit != descriptions.end()) {
                    std::string desc = sit->second;
                    size_t statePos = desc.find("|STATE|");
                    while (statePos != std::string::npos) {
                        size_t startPos = statePos + 7; // start looking for value after |STATE|.
                        size_t endPos = desc.find("|", startPos); // find the last digit of the storage
                        if (endPos != std::string::npos) {
                            uint32_t storageValueIdentifier = std::stoul(desc.substr(startPos, endPos - startPos));
                            int32_t IdentifiedStorageValue;
                            player->getStorageValue(storageValueIdentifier, IdentifiedStorageValue);
                            desc.replace(statePos, endPos - statePos + 1, std::to_string(IdentifiedStorageValue));
                                                }
                        statePos = desc.find("|STATE|", statePos + 1);
                    }
                    return desc;
                }
            }
        }
    }
    return "An error has occurred, please contact a gamemaster.";
}

Demonstration:
Simply use the |STATE|STORAGEID| inside the quest description (&#10;&#10; is for double new line):

XML:
<mission name="Quest/Task/Mission" storageid="250" startvalue="1" endvalue="3">
            <missionstate id="1" description="Trolls killed: |STATE|249|/200 &#10;&#10;Dragons killed: |STATE|1203| /500 &#10;&#10;Discovered places: |STATE|250|x" />
        </mission>

View attachment 79883View attachment 79884

Cool thing, deffinitely many people would appreciate that!

There might be an issue of counting starting with -1, if so, just add IdentifiedStorageValue += 1; after player->getStorageValue(storageValueIdentifier, IdentifiedStorageValue); and done :)

Thank you!
 
Cool thing, deffinitely many people would appreciate that!

There might be an issue of counting starting with -1, if so, just add IdentifiedStorageValue += 1; after player->getStorageValue(storageValueIdentifier, IdentifiedStorageValue); and done :)

Thank you!
This did the trick.
----

I am loving this so far!
Can do many things, even though it's just aesthetic, it is a feature that can bring more immersion in the game.
I will be using it to create a statistic page, seen in many RPGs, where you can see how many places you've discovered, creatures you have killed, chickens you have kicked etc.
However in the future I will be using it during quests as well as important moments that require some on-screen explaining of what the character experiences.

29df9dd354e3af23d4bd2c4c535ff970.png

027fe136f44112abb055b93a84388e90.png

----

Thank you for your help as well to get this going!
 
Back
Top