Custom Tokens transferred from Module to Module

Hi all,

I have this bug since years, and I was thinking of releasing my work and noting it down as a know bug until an epiphany comes to me and I solve it. To my good luck, (or bad) this happened today. I pinpointed the bug but I need help solving it. Here it goes.

Years ago Tchos gave me a flawless system to track kills in a quest. I won’t go into details, but he used some custom tokens in the journal entry and let’s say we needed 10 creatures killed to complete the quest. That’s the flavor of the system with many more details which are irrelevant here.

The difference between Tchos’ Scoure of Candle Cove where he used this, and my work is that he only had one module. I got 15. And the information about the creatures killed does not get carried when a world travel happens, i.e changing modules.

My journal entry should says something like Creature 1 killed: 0/1.
After I kill it, it should say Creature 1 killed 1/1.
This happens fine, but then I change module and the journal reports 0/1 again.

There are 7 creatures across 7 modules. And now for the technicalities.

When the quest is initialized, we call
SetCustomTokenEx(5050, "0");

The function definition

// Sets the custom token identified by the number in iToken to the 
// string value specified in sValue. Also duplicates the value as a 
// local string stored on the module object so the GetCustomTokenEx 
// function can retrieve it at any time.
void SetCustomTokenEx(int iToken, string sValue) 
{ 
	if(iToken <= 0) { return; } 
 
	// Change the custom token variable and duplicate it.
	SetCustomToken(iToken, sValue);
	SetGlobalString("CUSTOM" + IntToString(iToken), sValue); 
}

There is a getter too

// Retrieves the current value of the custom token identified by the 
// number in iToken by reading the local string variable containing 
// the duplicated token value which was stored on the module object 
// by the SetCustomTokenEx function. If the custom token was set using 
// the default SetCustomToken function instead of SetCustomTokenEx, 
// this function may return an incorrect or blank string.
string GetCustomTokenEx(int iToken)
{ 
 	if(iToken <= 0) { return ""; }
 
	// Return the content of the module variable being used to duplicate 
	// the token variable.
	    return GetGlobalString("CUSTOM" +IntToString(iToken));
}

I tried putting the getter with my token identifier on my module load scripts but to no avail. As soon as I go in a different module the journal reports 0/1 on all previously set tokens. So that’s the facts. I don’t know why it refuses to work.

tl;dr Above functions set a token and work fine, but on changing module the token doesn’t get carried with.

I don’t know… Try one of these instead.

Option 1
// Sets the custom token identified by the number in iToken to the
// string value specified in sValue. Also duplicates the value as a
// local string stored on the module object so the GetCustomTokenEx
// function can retrieve it at any time.
void SetCustomTokenEx(int iToken, string sValue)
{
	if (iToken <= 0) { return; }

	// Change the custom token variable and duplicate it.
	SetCustomToken(iToken, sValue);
	SetLocalString(GetFirstPC(), "CUSTOM" + IntToString(iToken), sValue);
}

// Retrieves the current value of the custom token identified by the
// number in iToken by reading the local string variable containing
// the duplicated token value which was stored on the module object
// by the SetCustomTokenEx function. If the custom token was set using
// the default SetCustomToken function instead of SetCustomTokenEx,
// this function may return an incorrect or blank string.
string GetCustomTokenEx(int iToken)
{
 	if (iToken <= 0) { return ""; }

	// Return the content of the module variable being used to duplicate
	// the token variable.
	return GetLocalString(GetFirstPC(), "CUSTOM" + IntToString(iToken));
}
Option 2
// Sets the custom token identified by the number in iToken to the
// string value specified in sValue. Also duplicates the value as a
// local string stored on the module object so the GetCustomTokenEx
// function can retrieve it at any time.
void SetCustomTokenIntEx(int iToken, int iValue)
{
	if (iToken <= 0) { return; }

	// Change the custom token variable and duplicate it.
	SetCustomToken(iToken, IntToString(iValue));
	SetGlobalInt("CUSTOM" + IntToString(iToken), iValue);
}

// Retrieves the current value of the custom token identified by the
// number in iToken by reading the local string variable containing
// the duplicated token value which was stored on the module object
// by the SetCustomTokenEx function. If the custom token was set using
// the default SetCustomToken function instead of SetCustomTokenEx,
// this function may return an incorrect or blank string.
string GetCustomTokenIntEx(int iToken)
{
 	if (iToken <= 0) { return ""; }

	// Return the content of the module variable being used to duplicate
	// the token variable.
	return IntToString(GetGlobalInt("CUSTOM" + IntToString(iToken)));
}
Option 3
// Sets the custom token identified by the number in iToken to the
// string value specified in sValue. Also duplicates the value as a
// local string stored on the module object so the GetCustomTokenEx
// function can retrieve it at any time.
void SetCustomTokenEx(int iToken, string sValue)
{
	if (iToken <= 0) { return; }

	// Change the custom token variable and duplicate it.
	SetCustomToken(iToken, sValue);
	SetCampaignString("CustomTokens", "CUSTOM" + IntToString(iToken), sValue, GetFirstPC());
}

// Retrieves the current value of the custom token identified by the
// number in iToken by reading the local string variable containing
// the duplicated token value which was stored on the module object
// by the SetCustomTokenEx function. If the custom token was set using
// the default SetCustomToken function instead of SetCustomTokenEx,
// this function may return an incorrect or blank string.
string GetCustomTokenEx(int iToken)
{
 	if (iToken <= 0) { return ""; }

	// Return the content of the module variable being used to duplicate
	// the token variable.
	return GetCampaignString("CustomTokens", "CUSTOM" + IntToString(iToken), GetFirstPC());
}

Hmm, none works. Interesting. I do have a workaround but it doesn’t look pretty. Whereas I now have 1 quest for all 7 creatures, I can just create 7 quests. Sometimes aesthetics have to take a hit I guess.

string GetCustomTokenEx(int iToken, int bRefreshModuleToken = FALSE)
{ 
    if (iToken <= 0) { return ""; }
 
    string sToken = GetGlobalString("CUSTOM" + IntToString(iToken));

    if (bRefreshModuleToken)
        SetCustomToken(iToken, sToken);

    // Return the content of the module variable being used to duplicate 
    // the token variable.
    return sToken;
}

?

Still not. Some more info perhaps might help. When the quest starts I get

Creature name: 0/1
Creature name: 0/1

I kill first creature and journal now writes

Creature name: 1/1
Creature name: 0/1

I switch modules via world map travel, and journal becomes

Creature name: /1
Creature name: /1

Even the 0s are gone, which were set at token initialization.

that’s what I just got in a test

// 'add_tokens_and_quest'

const string JOURNAL = "jt_testtoken";


void SetCustomTokenEx(int iToken, string sValue);

//
void main()
{
    SetCustomTokenEx(3000, "1");
    SetCustomTokenEx(3001, "2");
    SetCustomTokenEx(3002, "3");
    SetCustomTokenEx(3003, "4");
    SetCustomTokenEx(3004, "5");

    AddJournalQuestEntry(JOURNAL, 1, GetLastOpenedBy());
}


//
void SetCustomTokenEx(int iToken, string sValue)
{
    SetCustomToken(iToken, sValue);
    SetGlobalString("CUSTOM" + IntToString(iToken), sValue);
}

but by setting the tokens in the 2nd module’s OnModuleLoad event …

// 'mod_load'

const int iTOKENS_START = 3000;
const int iTOKENS_COUNT = 5;

void main()
{
    string sToken;

    int iToken = iTOKENS_START;
    for (; iToken != iTOKENS_START + iTOKENS_COUNT; ++iToken)
    {
        sToken = GetGlobalString("CUSTOM" + IntToString(iToken));
        SetCustomToken(iToken, sToken);
    }
}

eet works (fer me).

I noticed that the module in which the tokens were initially set held onto the values. They simply had to be transfered to the 2nd (3rd, 4th, …) modules. But if they change in subsequent modules, the values would likely have to be transfered back to other modules in their OnModuleLoad scripts.

In other words, if this works for ya Andy, a system of handling tokens from module to module to module should be set up.

( using a struct to contain all of the custom tokens that are used could be convenient if you like structs – or it may be simpler to simply iterate through your token-range as i did above )

So from what I understand… if I travel back to the module where I initially set the tokens to 0 I should see 0/1 again?

In any case, this problem shouldn’t hold back a whole release. I will break the creatures to individual quests and keep working on it for an update. Thanks for the help though, very informative again :slight_smile:

i believe so

/cheers

1 Like

You could just store local ints on an item and recall them in the module.

However, to ensure the item stores the integers, you make sure that the item with the variables travels between modules within a container. This is how I got around transferring variables between modules without using campaign variables. i.e. They travel with the player on an item stored within a container.

You would then require the supporting code to pull the variables off the item and put them back into the custom tokens.

First raised on my blog here: https://worldofalthea.blogspot.com/2019/01/the-adventure-continues-16-deeper.html (Third point.)

1 Like