Oh powerful deities of NWScript, I summon thee!
Here's the thing. I have the random quest system in place and it comes with journal entries, too. As such, these entries need to be dynamic, so custom tokens need to be put in place.
I have created a function SetQuestTokens(object oPC), which gets quest data from a PC-specific database and sets tokens used in journal entries accordingly. My thinking is as follows: if I use the SetQuestTokens function just before adding a quest entry to the PC's journal, it will correctly display PC's quest data and will support multiple players with quests with varying data, because a moment before adding each PC's journal entry, tokens will be set for that specific PC.
And while it does work flawlessly for a single player, I've noticed display bugs in the journal when more people play - stuff like reward being different than what it should, missing quest objective NPC's name, etc. I have no idea what the reason for these bugs are, since I thought journal entries are baked and won't change once they're in the PC's journal even if new tokens are set.
Here's my SetQuestTokens function (it's supposed to work in Polish and English, hence two tokens for each piece of data):
void SetQuestTokens(object oPC)
{
string sDB = CharacterDB(oPC); //PC-specific database
string sRegion = GetCampaignString(sDB, "QUEST_REGION");
int nTavern = GetCampaignInt(sDB, "QUEST_TAVERN");
string sExtra = GetCampaignString(sDB, "QUEST_EXTRA");
string sExtra2 = GetCampaignString(sDB, "QUEST_EXTRA2");
string sNpcName = GetCampaignString(sDB, "QUEST_NPC_NAME");
string sNpcLastName = GetCampaignString(sDB, "QUEST_NPC_LASTNAME");
SetCustomToken(10001, GetCampaignString(sDB, "QUEST_CLI_NAME"));
SetCustomToken(10002, GetCampaignString(sDB, "QUEST_CLI_LASTNAME"));
SetCustomToken(10003, sNpcName);
SetCustomToken(10004, sNpcLastName);
SetCustomToken(10015, GetCampaignString(sDB, "QUEST_NP2_NAME"));
SetCustomToken(10016, GetCampaignString(sDB, "QUEST_NP2_LASTNAME"));
SetCustomToken(10020, IntToString(GetCampaignInt(sDB, "QUEST_INTELCOST")));
if (GetCampaignString(sDB, "QUEST_TEMPLATE") == "ransom" && (GetCampaignInt(sDB, "QUEST_BACKGROUND") == 1 || GetCampaignInt(sDB, "QUEST_BACKGROUND") == 2))
{
SetCustomToken(10018, "kompletny");
SetCustomToken(10019, "a complete");
}
if (GetCampaignString(sDB, "QUEST_TEMPLATE") == "ransom" && (GetCampaignInt(sDB, "QUEST_BACKGROUND") == 3 || GetCampaignInt(sDB, "QUEST_BACKGROUND") == 4))
{
SetCustomToken(10018, "niekompletny");
SetCustomToken(10019, "an incomplete");
}
if (sRegion == "greencoast")
{
SetCustomToken(10005, "Zielone Wybrzeze");
SetCustomToken(10006, "Green Coast");
}
SetCustomToken(10007, IntToString(GetCampaignInt(sDB, "QUEST_REWARD")));
if (nTavern == 1)
{
SetCustomToken(10008, "Alverton");
SetCustomToken(10009, "Alverton");
}
SetCustomToken(10010, IntToString(11*GetCampaignInt(sDB, "QUEST_REWARD")/10));
if (sExtra == "sister")
{
SetCustomToken(10011, "Moja ukochana siostra");
SetCustomToken(10012, "My beloved sister");
}
if (sExtra == "brother")
{
SetCustomToken(10011, "Moj brat");
SetCustomToken(10012, "My brother");
}
if (sExtra == "kid")
{
SetCustomToken(10011, "Moje biedne dziecko");
SetCustomToken(10012, "My poor child");
}
if (sExtra == "all")
{
SetCustomToken(10011, "Moja rodzina");
SetCustomToken(10012, "My whole family");
}
if (sExtra == "murderer")
{
SetCustomToken(10011, "winnym wielokrotnego morderstwa");
SetCustomToken(10012, "who is guilty of numerous murders");
}
if (sExtra == "bandit")
{
SetCustomToken(10011, "przewodzi zorganizowanej gildii bandytow");
SetCustomToken(10012, "who is the leader of an organized bandit guild");
}
if (sExtra == "fugitive")
{
SetCustomToken(10011, "niedawno uciekl z pilnie strzezonego garnizonu");
SetCustomToken(10012, "who has recently escaped from a guarded garrison");
}
if (sExtra == "male")
{
SetCustomToken(10011, "mojego drogiego przyjaciela");
SetCustomToken(10012, "him");
}
if (sExtra == "female")
{
SetCustomToken(10011, "moja droga przyjaciolke");
SetCustomToken(10012, "her");
}
if (sExtra == "cards")
{
SetCustomToken(10011, "karty");
SetCustomToken(10012, "cards");
}
if (sExtra == "dice")
{
SetCustomToken(10011, "kosci");
SetCustomToken(10012, "dice");
}
if (sExtra2 == "cankill")
{
SetCustomToken(10013, "Moge zabic swoj cel.");
SetCustomToken(10014, "I can also kill my target.");
}
if (sExtra2 == "mustkill")
{
SetCustomToken(10013, "Po wykonaniu tego zadania musze zabic moj cel.");
SetCustomToken(10014, "I have to kill my target once I complete this task.");
}
if (sExtra2 == "cantkill")
{
SetCustomToken(10013, "Nie moge zabic swojego celu.");
SetCustomToken(10014, "I must not kill my target.");
}
if (sExtra2 == "cantnotice")
{
SetCustomToken(10013, "Moj cel nie moze zginac, ani nawet zauwazyc, ze zostal okradziony.");
SetCustomToken(10014, "My target must not die or even notice they've been robbed.");
}
if (sExtra2 == "1000" || sExtra2 == "700" || sExtra2 == "1500" || sExtra2 == "2000")
{
SetCustomToken(10017, sExtra2);
}
if (sExtra == "stealring")
{
SetCustomToken(10011, "pierscien");
SetCustomToken(10012, "ring");
}
if (sExtra == "stealamulet")
{
SetCustomToken(10011, "amulet");
SetCustomToken(10012, "amulet");
}
if (sExtra == "stealsphere")
{
SetCustomToken(10011, "przedmiot przypominajacy kule energii");
SetCustomToken(10012, "item resembling a sphere of energy");
}
if (sExtra == "stealhand")
{
SetCustomToken(10011, "przedmiot przypominajacy martwa dlon");
SetCustomToken(10012, "item resembling a dead hand");
}
if (sExtra == "stealdisc")
{
SetCustomToken(10011, "przedmiot przypominajacy kamienny dysk");
SetCustomToken(10012, "item resembling a stone disc");
}
if (sExtra == "lostbrother")
{
SetCustomToken(10011, "moim drogim bracie");
SetCustomToken(10012, "my dear brother");
}
if (sExtra == "lostsister")
{
SetCustomToken(10011, "mojej drogiej siostrze");
SetCustomToken(10012, "my dear sister");
}
if (sExtra == "lostmale")
{
SetCustomToken(10011, "moj dobry przyjaciel");
SetCustomToken(10012, "he");
}
if (sExtra == "lostfemale")
{
SetCustomToken(10011, "moja dobra przyjaciolka");
SetCustomToken(10012, "she");
}
if (sExtra == "husband")
{
SetCustomToken(10011, "moj ukochany maz");
SetCustomToken(10012, "my beloved husband");
}
if (sExtra == "wife")
{
SetCustomToken(10011, "moja ukochana zona");
SetCustomToken(10012, "my beloved wife");
}
if (sExtra == "escortmale")
{
SetCustomToken(10011, "Moj przyjaciel");
SetCustomToken(10012, "he");
}
if (sExtra == "escortfemale")
{
SetCustomToken(10011, "Moja przyjaciolka");
SetCustomToken(10012, "she");
}
if (sExtra == "kidnbrother")
{
SetCustomToken(10011, "moj brat");
SetCustomToken(10012, "my brother");
}
if (sExtra == "kidnsister")
{
SetCustomToken(10011, "moja siostra");
SetCustomToken(10012, "my sister");
}
if (sExtra == "kidnhusband")
{
SetCustomToken(10011, "mojego drogiego meza");
SetCustomToken(10012, "my dear husband");
}
if (sExtra == "kidnwife")
{
SetCustomToken(10011, "moja droga zone");
SetCustomToken(10012, "my dear wife");
}
if (sExtra == "rescuewife")
{
SetCustomToken(10011, "Moja zona zostala porwana");
SetCustomToken(10012, "My wife has been kidnapped");
}
if (sExtra == "rescuehusband")
{
SetCustomToken(10011, "Moj maz zostal porwany");
SetCustomToken(10012, "My husband has been kidnapped");
}
if (sExtra == "rescuebrother")
{
SetCustomToken(10011, "Moj brat zostal porwany");
SetCustomToken(10012, "My brother has been kidnapped");
}
if (sExtra == "rescuesister")
{
SetCustomToken(10011, "Moja siostra zostala porwana");
SetCustomToken(10012, "My sister has been kidnapped");
}
if (sExtra == "rescuemfriend")
{
SetCustomToken(10011, "Moj przyjaciel zostal porwany");
SetCustomToken(10012, "My friend has been kidnapped");
}
if (sExtra == "rescueffriend")
{
SetCustomToken(10011, "Moja przyjaciolka zostala porwana");
SetCustomToken(10012, "My friend has been kidnapped");
}
if (sExtra2 == "forc")
{
SetCustomToken(10013, "orkow");
SetCustomToken(10014, "orcs");
}
if (sExtra2 == "fhobgoblin")
{
SetCustomToken(10013, "orkliny");
SetCustomToken(10014, "bugbears");
}
if (sExtra2 == "freptilian")
{
SetCustomToken(10013, "jaszczuroludzi");
SetCustomToken(10014, "reptilians");
}
if (sExtra2 == "fdrow")
{
SetCustomToken(10013, "drowy");
SetCustomToken(10014, "drows");
}
if (sExtra2 == "fduergar")
{
SetCustomToken(10013, "duergarow");
SetCustomToken(10014, "duergars");
}
if (sExtra == "drow")
{
SetCustomToken(10011, "drowy");
SetCustomToken(10012, "drows");
}
if (sExtra == "duergar")
{
SetCustomToken(10011, "duergary");
SetCustomToken(10012, "duergars");
}
if (sExtra == "human")
{
SetCustomToken(10011, "ludzie");
SetCustomToken(10012, "humans");
}
if (sExtra == "elf")
{
SetCustomToken(10011, "elfy");
SetCustomToken(10012, "elves");
}
if (sExtra == "dwarf")
{
SetCustomToken(10011, "krasnoludy");
SetCustomToken(10012, "dwarves");
}
if (sExtra2 == "drow")
{
SetCustomToken(10013, "drowy");
SetCustomToken(10014, "drows");
}
if (sExtra2 == "duergar")
{
SetCustomToken(10013, "duergary");
SetCustomToken(10014, "duergars");
}
if (sExtra2 == "human")
{
SetCustomToken(10013, "ludzie");
SetCustomToken(10014, "humans");
}
if (sExtra2 == "elf")
{
SetCustomToken(10013, "elfy");
SetCustomToken(10014, "elves");
}
if (sExtra2 == "dwarf")
{
SetCustomToken(10013, "krasnoludy");
SetCustomToken(10014, "dwarves");
}
if (sExtra2 == "orc")
{
SetCustomToken(10013, "orkowie");
SetCustomToken(10014, "orcs");
}
if (sExtra2 == "hobgoblin")
{
SetCustomToken(10013, "orkliny");
SetCustomToken(10014, "bugbears");
}
if (sExtra2 == "reptilian")
{
SetCustomToken(10013, "jaszczuroludzie");
SetCustomToken(10014, "reptilians");
}
}
This function is called on several occassions: when the quest is first taken by the PC, when the quest entry is updated to reflect on the PC's success or failure and in OnClientEnter event if the PC's database has quest data.
Here's the example taken from the OnClientEnter script:
//Add random quest journal entry the PC should have
string sCharDB = CharacterDB(oPC);
int nQuestEntry = GetCampaignInt(sCharDB, "QUEST_JOURNAL");
if (nQuestEntry != 0)
{
SetQuestTokens(oPC);
AddJournalQuestEntry("random_quest", nQuestEntry, oPC, FALSE, FALSE, TRUE);
}
else RemoveAllItems(oPC, "quest_proof");
If you need me to send more code, just give me the word.
Big thanks in advance.