Salk 368 Posted February 8, 2020 Hello! Does anyone know how the CUSTOM tokens work in KotOR dialogues? Cheers! Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted February 8, 2020 https://deadlystream.com/topic/7436-gender-check-with-k1s-tlk/ 1 Quote Share this post Link to post Share on other sites
Salk 368 Posted February 8, 2020 Yes, thanks. What I meant was if someone knows whether there is a way to figure out what the next available number used for the CUSTOM is. Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted February 8, 2020 The numbered ones are set dynamically via script, so technically they are all available in a given DLG (aside from whatever ones you are already using). 1 Quote Share this post Link to post Share on other sites
Salk 368 Posted April 1, 2020 Hello again! I was wondering if someone would know how to retrieve the value of custom tokens. The game doesn't unfortunately have a GetCustomToken() function but earlier I found something that gave me hope, although it was short-lived. There is this tutorial from I don't know when and by I don't know who which says: Custom Tokens: The Custom Tokens are slightly different from the Game Tokens. For one thing, to use them them you have to use the format <CUSTOM#>, where "#" is a number between 0 to 2147483647. In practice, however, the game uses 0-9 and the WhereAmI band mod uses 61 and 62, so I'd avoid those in TSL. Also, in K1, the K1R mod uses 1998-2030(or around there) for the Pazaak Tourney, so I'd really avoid those...:) To set a Custom Token: void main() { // Syntax for the function: SetCustomToken(int iTokenToSet, string sMessage) SetCustomToken(2000, "Hi, I'm token 2000!"); } Though there is no GetCustomToken function, you can still check the value in a script: void main() { string sToken = "<CUSTOM2000>"; if(sToken == "Hi, I'm token 2000") { SendMessageToPC(GetFirstPC(), "Yep, this is it."); } else { SendMessageToPC(GetFirstPC(), "No, it's not it."); } } Unfortunately it seems that string sToken returns "<CUSTOM2000>" rather than the content of the token. The NWN Lexicon here under "Token Duplication" speaks of another method using two other functions that are not present in KotOR (SetLocalString() and GetLocalString()). The game uses <CUSTOM17> and <CUSTOM 26> to store the time for the latest swoop race and I need to retrieve those values. Any idea? Thanks a lot! Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted April 1, 2020 Add new lines to the TLK that are just the <CUSTOMxx> identifiers. Then use GetStringByStrRef(nStrRef) to pull the value as a string. You can use GetStringLeft/GetStringRight and StringToInt if you need to break it up into its mins/secs/milliseconds components. Quote Share this post Link to post Share on other sites
AmanoJyaku 183 Posted April 1, 2020 I think you use the following to set up a token: Spoiler // c_parts_spikes /* Checks to see if the player has a specified number of repair parts or spikes, optionally modified by skill iNum The number of parts or spikes iSpikes 0 = repair parts, 1 = spikes iSkillMod 0 = skill not factored in, 1 = skill is factored in Use c_token_setup to setup tokens beforehand */ // Created By: Tony Evans 8/9/04 #include "k_inc_debug" #include "k_inc_utility" int StartingConditional() { int iNum = GetScriptParameter(1); int iSpikes = GetScriptParameter(2); int iSkillMod = GetScriptParameter(3); int iType; int iCost; if (iSpikes) iType = SKILL_COMPUTER_USE; else iType = SKILL_REPAIR; if (iSkillMod) iCost = UT_DeterminesItemCost(iNum, iType); else (iCost = iNum); AurPostString("Spikes = " + IntToString(UT_ReturnSpikePartAmount(iType)) + " Cost = " + IntToString(iCost), 5, 5, 5.0); if(UT_ReturnSpikePartAmount(iType) >= iCost) { return TRUE; } return FALSE; } Then, you use the following to retrieve a token: Spoiler // c_parts_spikes /* Checks to see if the player has a specified number of repair parts or spikes, optionally modified by skill iNum The number of parts or spikes iSpikes 0 = repair parts, 1 = spikes iSkillMod 0 = skill not factored in, 1 = skill is factored in Use c_token_setup to setup tokens beforehand */ // Created By: Tony Evans 8/9/04 #include "k_inc_debug" #include "k_inc_utility" int StartingConditional() { int iNum = GetScriptParameter(1); int iSpikes = GetScriptParameter(2); int iSkillMod = GetScriptParameter(3); int iType; int iCost; if (iSpikes) iType = SKILL_COMPUTER_USE; else iType = SKILL_REPAIR; if (iSkillMod) iCost = UT_DeterminesItemCost(iNum, iType); else (iCost = iNum); AurPostString("Spikes = " + IntToString(UT_ReturnSpikePartAmount(iType)) + " Cost = " + IntToString(iCost), 5, 5, 5.0); if(UT_ReturnSpikePartAmount(iType) >= iCost) { return TRUE; } return FALSE; } tl;dr GetScriptParameter(int) Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted April 1, 2020 GetScriptParameter is a TSL function. Salk is talking about K1. Quote Share this post Link to post Share on other sites
AmanoJyaku 183 Posted April 1, 2020 Need. More. Coffee. Quote Share this post Link to post Share on other sites
Salk 368 Posted April 1, 2020 1 hour ago, DarthParametric said: Add new lines to the TLK that are just the <CUSTOMxx> identifiers. Then use GetStringByStrRef(nStrRef) to pull the value as a string. You can use GetStringLeft/GetStringRight and StringToInt if you need to break it up into its mins/secs/milliseconds components. That's exactly what I did but GetStringByStrRef() returns <CUSTOMxx>, not its value. My STR 49415 is <CUSTOM17> (this should be the token used to store the time for the player's latest race on Manaan). and this is my code: int Result (int nResult) { SetGlobalBoolean("MAN_JUST_RACED", FALSE); return nResult; } int StartingConditional() { if (GetGlobalBoolean("MAN_JUST_RACED") == TRUE) { string sLastTimeManaan = GetStringByStrRef(49415); string sLastTimeManaanMinutes = GetSubString(sLastTimeManaan, 0, 1); string sLastTimeManaanSeconds = GetSubString(sLastTimeManaan, 2, 2); string sLastTimeManaanFractions = GetSubString(sLastTimeManaan, 5, 2); //string sOpponentTimeManaan; if (GetGlobalNumber("CRI_SWP_RESULT") == 1) { //sOpponentTimeManaan = "0:30:12"; if (StringToInt(sLastTimeManaanMinutes) > 0) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 30) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 12) { return Result(1); } else { return 0; } } else if (GetGlobalNumber("CRI_SWP_RESULT") == 2) { //sOpponentTimeManaan = "0:26:16"; if (StringToInt(sLastTimeManaanMinutes) > 0) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 26) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 16) { return Result(1); } else { return 0; } } else if (GetGlobalNumber("CRI_SWP_RESULT") == 3) { //sOpponentTimeManaan = "0:23:63"; if (StringToInt(sLastTimeManaanMinutes) > 0) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 23) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 63) { return Result(1); } else { return 0; } } else { //sOpponentTimeManaan = "0:22:98"; if (StringToInt(sLastTimeManaanMinutes) > 0) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 22) { return Result(1); } else if (StringToInt(sLastTimeManaanSeconds) > 98) { return Result(1); } else { return 0; } } } else { return 0; } } Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted April 1, 2020 What happens if you call it as a BarkString? I assume the same thing, which would presumably mean it only works in a DLG. Quote Share this post Link to post Share on other sites
Salk 368 Posted April 1, 2020 (edited) Weird... The BarkString DOES return the token's value instead... Either I need more coffee (which I don't drink) like our friend above or the April's fool is on me today. void main { string sLastTimeManaan = GetStringByStrRef(49415); BarkString(OBJECT_SELF, 49415); SendMessageToPC(GetFirstPC(), sLastTimeManaan); } The BarkString() correctly retrieves the value of the token while the message feedback reports <CUSTOM17>. More ideas? Cheers! Edited April 1, 2020 by Salk Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted April 1, 2020 Depends on how exactly the BarkString function works. Since, results-wise, it performs exactly the same as calling a DLG with a single node, it's probably just passing the StrRef to the engine's conversation system in the same manner as when it parses a DLG. Quote Share this post Link to post Share on other sites
Salk 368 Posted April 1, 2020 I suppose there is no solution then. It's really quite frustrating that Bioware didn't bother writing a simple GetCustomToken function to retrieve the value and it's even more frustrating to find a "tutorial" whose author didn't even bother to test the veracity of their own code. If someone else has any other idea however, I'd be overjoyed. Thanks! Quote Share this post Link to post Share on other sites
AmanoJyaku 183 Posted April 1, 2020 Got it to work. There is no GetCustomToken because you don't need it: //SetToken.nss void main() { SetCustomToken(2000, "Hi, I'm token 2000!"); } The DLG file: Line 1 - "I am ugly." //Execute SetToken.ncs here, just as an example Line 2 - "Yes, you are very ugly." Line 3 - "I knew it. <CUSTOM2000>" The printed text: NPC - "I am ugly." //SetToken.ncs fires and sets 2000 PC - "Yes, you are very ugly." NPC - "I knew it. Hi, I'm token 2000!" Quote Share this post Link to post Share on other sites
Salk 368 Posted April 2, 2020 It does work in the dialogue file. It's when assigned to a string that doesn't work. Quote Share this post Link to post Share on other sites
AmanoJyaku 183 Posted April 2, 2020 Are you trying to record the times in a journal entry, and then retrieve them later? Quote Share this post Link to post Share on other sites
Salk 368 Posted April 2, 2020 I'm trying to change the record times to beat for the different tiers in the swoop races on Manaan and Tatooine. Quote Share this post Link to post Share on other sites
AmanoJyaku 183 Posted April 2, 2020 Did you try modifying k_inc_man.nss? int QUEEDLE_TIME = 3012; int CASSANDRA_TIME = 2702; int JAX_TIME = 2548; int CHAMP_TIME = 2348; Quote Share this post Link to post Share on other sites
Salk 368 Posted April 2, 2020 I modified the necessary files so that the game shows the desired times in dialogues creating this following new file, called on heartbeat in the area: void SetTokenRaceTime(int nToken, int nRacerTime) { // calculate the time components int nMinutes = nRacerTime/6000; int nSeconds = (nRacerTime - (nMinutes * 6000)) / 100; int nFractions = nRacerTime - ((nMinutes * 6000) + (nSeconds * 100)); //building the time string string sTime = IntToString(nMinutes) + ":"; if (nSeconds < 10) { sTime = sTime + "0"; } sTime = sTime + IntToString(nSeconds) + ":"; if(nFractions < 10) { sTime = sTime + "0"; } sTime = sTime + IntToString(nFractions); SetCustomToken(nToken,sTime); } void main() { int QUEEDLE_TIME = 3012; int CASSANDRA_TIME = 2616; int JAX_TIME = 2363; int CHAMP_TIME = 2298; SetTokenRaceTime(18, QUEEDLE_TIME); SetTokenRaceTime(19, CASSANDRA_TIME); SetTokenRaceTime(20, JAX_TIME); SetTokenRaceTime(21, CHAMP_TIME); } This code changes the custom tokens (I have a similar one for Tatooine) in the dialogues so that the times displayed in dialogues are the ones I want. But at the end of each race the game uses a global variable to check whether the player has won or lost and that variable is set using the original racing times. That's why I tried to create a new WON/LOST conditional script that no longer depends on checking that variable but rather compares the Player's time in the last race (which is stored in CUSTOM17 for Manaan) and the opponent's record time. The problem is that there is no way, it seems, to retrieve that CUSTOM17 value from script. And that goes against what that person that wrote the tutorial said. The reason I cannot try and change things directly in the original script is, of course, that it doesn't decompile. Cheers! Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted April 2, 2020 Thanks to AmanoJyaku's input, there's now a hacky workaround for decompiling most of the problematic Tatooine and Manaan scripts. Some still won't decompile, but these should be all of the relevant ones that fail specifically due to one of the globals in the Tatooine/Manaan includes. Tatooine_Swoop_Registration_(tat_m17ae)_Scripts_Using_Include.7z Manaan_Ahto_East_(manm26ab)_Scripts_Using_Include.7z 1 Quote Share this post Link to post Share on other sites
Salk 368 Posted April 2, 2020 Well, I am truly delighted. Thanks, AmanoJyaku! And DP too, of course. I cannot even begin to count how many headaches having these means one year ago would have spared. Quote Share this post Link to post Share on other sites
DarthParametric 3,777 Posted April 2, 2020 Indeed, but better late than never. Hopefully most/all of the remaining ones will be able to be decompiled eventually as well. Quote Share this post Link to post Share on other sites
JCarter426 1,214 Posted April 2, 2020 I might not be remembering this clearly since it's been a while since I took a look at custom tokens, but as I recall they are limited to the dialogue that's currently active. If you want to keep track of a value for longer than that, you need to use local or global variables. And if I'm remembering correctly, that would also mean it should be safe to use whatever number you want. The game uses some consistently, like 30s for computer spikes and 40s for repair parts, and it would be safe to avoid the ones used by the combat system, but apart from that it probably doesn't matter. Quote Share this post Link to post Share on other sites
Salk 368 Posted April 4, 2020 Do you happen to have also decompiled k_ptat_17ae_area.ncs, @DarthParametric? I'd need to check how the game handles a few globals that are there. Cheers! Quote Share this post Link to post Share on other sites