If you're going to go this route, it's probably easiest if you do it when you first write the code. It can be added later, but since this is an example, let's start out with the timer variables in place. For the purposes of this example, we'll assume you're writing a romance, that ## is your personal prefix, that ##NPCJ is the name of your NPC's joined dialogue file, that ##NPCS is your NPC's override script, that ##NPC is your NPC's DV, and that your NPC's name is NPC. Not original, but it avoids confusion later.
So we've got
/* Name: NPC DV: ##NPC J dialogue: ##NPCJ Override: ##NPCS */
If you were writing a mod without variables, you would need a romance match. Many people would put that in the NPC's override script, so let's do that. This NPC likes females, but doesn't have any other romance requirements.
// ##npcs.baf - NPC's override script starts here
/* Romance Match - in ##npcs.baf */
IF
InParty(Myself)
Global("##NPCMatch","GLOBAL",0)
Gender(Player1,FEMALE)
THEN
RESPONSE #100
SetGlobal("##NPCRomanceActive","GLOBAL",1)
SetGlobal("##NPCLovetalk","GLOBAL",1)
RealSetGlobalTimer("##NPCTime","GLOBAL",3600)
SetGlobal("##NPCMatch","GLOBAL",1)
END
/* Exclude males if the PC should stumble across a Girdle of Masculinity/Femininity later */
IF
InParty(Myself)
Global("##NPCMatch","GLOBAL",0)
!Gender(Player1,FEMALE)
THEN
RESPONSE #100
SetGlobal("##NPCMatch","GLOBAL",2)
END
And that's it. Pretty straightforward, even with the additional script block for gender-bender belts.
Now we'll do it if the way we would if we were going to use variable timers. Most of the time, your prefix will contain characters that can go in an IDS table with no problem, but if your personal prefix contains unusual characters like !, you might just have to omit your prefix.
// ##npcs.baf - NPC's override script starts here
/* Romance Match - in ##npcs.baf */
IF
InParty(Myself)
Global("##NPCMatch","GLOBAL",0)
Gender(Player1,FEMALE)
THEN
RESPONSE #100
SetGlobal("##NPCRomanceActive","GLOBAL",1)
SetGlobal("##NPCLovetalk","GLOBAL",1)
RealSetGlobalTimer("##NPCTime","GLOBAL",##NPC_TIMER)
SetGlobal("##NPCMatch","GLOBAL",1)
END
/* Exclude males if the PC should stumble across a Girdle of Masculinity/Femininity later */
IF
InParty(Myself)
Global("##NPCMatch","GLOBAL",0)
!Gender(Player1,FEMALE)
THEN
RESPONSE #100
SetGlobal("##NPCMatch","GLOBAL",2)
END
Yes, I know, timers need integers. We'll get to that later, when we make up the tp2. For now, on to the block where you cue the first talk.
/* Cues lovetalks - in ##npcs.baf */
IF
InParty(Myself)
RealGlobalTimerExpired("##NPCTime","GLOBAL")
Global("##NPCRomanceActive","GLOBAL",1)
CombatCounter(0)
See(Player1)
!StateCheck(Player1,CD_STATE_NOTVALID)
!StateCheck(Myself,CD_STATE_NOTVALID)
Global("##NPCLovetalk","GLOBAL",1) // Yes, this will be an OR() block, but for this example, we're only using one
THEN
RESPONSE #100
IncrementGlobal("##NPCLovetalk","GLOBAL",1)
END
/* Starts lovetalks - in ##npcs.baf */
IF
InParty(Myself)
RealGlobalTimerExpired("##NPCTime","GLOBAL")
Global("##NPCRomanceActive","GLOBAL",1)
CombatCounter(0)
See(Player1)
!StateCheck(Player1,CD_STATE_NOTVALID)
!StateCheck(Myself,CD_STATE_NOTVALID)
Global("##NPCLovetalk","GLOBAL",2) // Yes, this will be an OR() block, but for this example, we're only using one
THEN
RESPONSE #100
PlaySong(0)
PlaySound("NPCsong")
StartDialogueNoSet(Player1)
END
You don't see the variable ##NPC_TIMER anywhere, so we don't need to do anything special to this block.
Now, let's look at the dialogue itself. We'll just show the first state. This is where you close the global and set the timer for the next talk. Please note the order. Closing the variable before setting the timer works fine, but setting the timer and then attempting to close the variable will result in the variable not getting set.
This is how you would do it if you weren't using variable timers.
// from ##NPCJ.d
IF ~Global("##NPCLovetalk","GLOBAL",2)~ THEN BEGIN T1
SAY ~If you aren't busy, I'd like to talk to you for a while.~
++ ~What's on your mind?~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",3600)~ + T1.1
++ ~I'm never too busy for you!~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",3600)~ + T1.2
+ ~InParty("Anomen")
InMyArea("Anomen")
!StateCheck("Anomen",CD_STATE_NOTVALID)
Global("AnomenRomanceActive","GLOBAL",1)~ + ~Not now, NPC, I'm trying to get Anomen's attention.~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",3600)~ + T1.3
++ ~I'm in the middle of something.~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",3600)~ + T1.4
END
And this is how you would do it if you wanted to use variable timers. Note that the only difference is the substitution of ##NPC_TIMER for 3600.
// from ##NPCJ.d
IF ~Global("##NPCLovetalk","GLOBAL",2)~ THEN BEGIN T1
SAY ~If you aren't busy, I'd like to talk to you for a while.~
++ ~What's on your mind?~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",##NPC_TIMER)~ + T1.1
++ ~I'm never too busy for you!~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",##NPC_TIMER)~ + T1.2
+ ~InParty("Anomen")
InMyArea("Anomen")
!StateCheck("Anomen",CD_STATE_NOTVALID)
Global("AnomenRomanceActive","GLOBAL",1)~ + ~Not now, NPC, I'm trying to get Anomen's attention.~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",##NPC_TIMER)~ + T1.3
++ ~I'm in the middle of something.~ DO ~SetGlobal("##NPCLovetalk","GLOBAL",3) RealSetGlobalTimer("##NPCTime","GLOBAL",##NPC_TIMER)~ + T1.4
END
So far, so good. No rocket science. Now we're going to have to do the tp2 stuff to make it all come together. This is a little tricky, so I'll
First, we have to define our variables.
// from setup-npc.tp2
PRINT ~Select NPC's dialogue timer:~
PRINT ~Please choose one of the following:
[1] 15 minutes real time minimum between dialogues
[2] 30 minutes real time minimum between dialogues
[3] 45 minutes real time minimum between dialogues
[4] 1 hour real time minimum between dialogues (recommended)
[5] 1 hour 30 minutes real time minimum between dialogues
[6] 2 hours real time minimum between dialogues~
OUTER_SPRINT ~npctimer~ ~placeholder_value~
OUTER_WHILE (!(IS_AN_INT ~npctimer~) OR (~npctimer~ > 0x6) OR (~npctimer~ < 0x1)) BEGIN
PRINT ~Please select 1, 2, 3, 4, 5 or 6 and press enter.~
ACTION_READLN ~npctimer~
END
ACTION_IF ("npctimer" = 1) THEN BEGIN
APPEND ~gtimes.ids~ ~900 ##NPC_TIMER~
PRINT ~Speed: minimum 15 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 2) THEN BEGIN
APPEND ~gtimes.ids~ ~1800 ##NPC_TIMER~
PRINT ~Speed: minimum 30 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 3) THEN BEGIN
APPEND ~gtimes.ids~ ~2700 ##NPC_TIMER~
PRINT ~Speed: minimum 45 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 4) THEN BEGIN
APPEND ~gtimes.ids~ ~3600 ##NPC_TIMER~
PRINT ~Speed: minimum 1 hour real time between dialogues~
END
ACTION_IF ("npctimer" = 5) THEN BEGIN
APPEND ~gtimes.ids~ ~5400 ##NPC_TIMER~
PRINT ~Speed: minimum 1 hour 30 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 6) THEN BEGIN
APPEND ~gtimes.ids~ ~7200 ##NPC_TIMER~
PRINT ~Speed: minimum 2 hours real time between dialogues~
END
It isn't as bad as it looks. The first block is merely defining a temporary variable and saying what the acceptable range of values can be. The ACTION_IF lines that follow are associating the number the player enters with that temporary variable. Let's try it with comments.
// from setup-npc.tp2
/* This isn't a separate component. It's part of the mod. Since this is the case, we're going to have to tell the player what we're doing using PRINT */
PRINT ~Select NPC's dialogue timer:~
/* Now we have to tell the player what his options are. */
PRINT ~Please choose one of the following:
[1] 15 minutes real time minimum between dialogues
[2] 30 minutes real time minimum between dialogues
[3] 45 minutes real time minimum between dialogues
[4] 1 hour real time minimum between dialogues (recommended)
[5] 1 hour 30 minutes real time minimum between dialogues
[6] 2 hours real time minimum between dialogues~
/* This first line defines the variable. It means, paraphrased
IN_THE_NEXT_CHUNK_OF_CODE_THAT_FOLLOWS ~npctimer~ is a ~placeholder_value~ */
/* OK, the actual explanation is more complicated than that, but this is essential what it does. */
OUTER_SPRINT ~npctimer~ ~placeholder_value~
/* This section says, paraphrased
IF_PLAYER_INPUTS_SOMETHING_THAT (is NOT an INTEGER) OR (is > 6) OR (is < 1) THEN
PRINT ~Please select 1, 2, 3, 4, 5, or 6 and press enter.~
OTHERWISE READ ~npctimer~ and substitute the number the player enters*/
OUTER_WHILE (!(IS_AN_INT ~npctimer~) OR (~npctimer~ > 0x6) OR (~npctimer~ < 0x1)) BEGIN
PRINT ~Please select 1, 2, 3, 4, 5 or 6 and press enter.~
ACTION_READLN ~npctimer~
END
/* This is where the timer variable you put in your script and dialogue gets defined */
/* Paraphrased, the first ACTION_IF block says
IF_PLAYER_ENTERS 1,
APPEND ~gtimes.ids~ with ~900 ##NPC_TIMER~
and then PRINT ~Speed: minimum 15 minutes real time between dialogues~ */
/* gtimes.ids is the IDS table where all those handy shortcuts like ONE_DAY and FIVE_ROUNDS are stored */
ACTION_IF ("npctimer" = 1) THEN BEGIN
APPEND ~gtimes.ids~ ~900 ##NPC_TIMER~
PRINT ~Speed: minimum 15 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 2) THEN BEGIN
APPEND ~gtimes.ids~ ~1800 ##NPC_TIMER~
PRINT ~Speed: minimum 30 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 3) THEN BEGIN
APPEND ~gtimes.ids~ ~2700 ##NPC_TIMER~
PRINT ~Speed: minimum 45 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 4) THEN BEGIN
APPEND ~gtimes.ids~ ~3600 ##NPC_TIMER~
PRINT ~Speed: minimum 1 hour real time between dialogues~
END
ACTION_IF ("npctimer" = 5) THEN BEGIN
APPEND ~gtimes.ids~ ~5400 ##NPC_TIMER~
PRINT ~Speed: minimum 1 hour 30 minutes real time between dialogues~
END
ACTION_IF ("npctimer" = 6) THEN BEGIN
APPEND ~gtimes.ids~ ~7200 ##NPC_TIMER~
PRINT ~Speed: minimum 2 hours real time between dialogues~
END
We're almost done. We've coded our scripts and dialogues to accept variable timers and we've defined those variable timers in the tp2. Now we have to compile the dialogues and scripts. Note that you have to define the variable timers in the tp2 before you attempt to compile anything using them. Doing it the other way around will result in errors.
Ordinarily, if you wanted to compile a dialogue or a script, you would just use this
// from setup-npc.tp2 COMPILE ~npc/dialogue/##npcj.d~ COMPILE ~npc/script/##npcs.baf~
Since you are using variable timers, you can't do that. Instead, you have to use something a little different. It's still easy.
COMPILE EVALUATE_BUFFER ~npc/dialogue/##npcj.d~ COMPILE EVALUATE_BUFFER ~npc/script/##npcs.baf~
And that's all there is to it.
Fine print: According to the WeiDU docs, OUTER_SPRINT will break --traify, but I just installed an untraified testing mod using OUTER_SPRINT in an untraified tp2, uninstalled the mod, traified the tp2, and then installed the mod again, and everything worked fine. If in doubt, use OUTER_TEXT_SPRINT with %'s around the variable instead. Check the WeiDU docs for more info.












