Jump to content

SoD: Thrix' Game. Adding mod NPCs in a random fashion? (*spoilers*)


jastey

Recommended Posts

In SoD, the demon Thrix plays a game with the PC for one of the joined NPCs' soul. For the original game this is done by random transactions that call 4 different state triggers where the order of the possible (original) NPCs is switched, so the NPC that gets picked will not be the same for every load/playthrough.

Example:

Thrix stated his game. The player gets one out of four different reply options:

Spoiler

IF ~~ THEN BEGIN 19 // from: 15.6 15.7 15.8 15.9 15.10
  SAY #38891 /* ~Thrix is glad to hear it, though you should have let Thrix finish telling you the terms before agreeing. For if you lose the bet, you will also lose one of your friends to Thrix's service.~ */
  IF ~  RandomNum(4,1)
~ THEN REPLY #38892 /* ~What? No, no, I can't accept that. The bet is off.~ */ GOTO 21
  IF ~  RandomNum(4,2)
~ THEN REPLY #38892 /* ~What? No, no, I can't accept that. The bet is off.~ */ GOTO 22
  IF ~  RandomNum(4,3)
~ THEN REPLY #38892 /* ~What? No, no, I can't accept that. The bet is off.~ */ GOTO 23
  IF ~  RandomNum(4,4)
~ THEN REPLY #38892 /* ~What? No, no, I can't accept that. The bet is off.~ */ GOTO 24

Looking at states 21-24 we see that it's supposed to be the same reaction from Thrix, the only difference is the order of the following call of joined NPCs:

Spoiler

IF ~~ THEN BEGIN 21 // from: 19.0 19.5
  SAY #38895 /* ~Aha. Thrix does not know how this sort of thing works in the Prime Material Plane. But in Avernus, a contract is a contract. The wager is made. Win and one of these items will be yours. Lose and Thrix takes one of your friends.~ [BD38895] */
  IF ~~ THEN GOTO 10
  IF ~  Global("BD_Saved_Rasaad","bd4500",0)
IsValidForPartyDialogue("RASAAD")
~ THEN GOTO 103
  IF ~  Global("BD_Saved_Safana","bd4500",0)
IsValidForPartyDialogue("SAFANA")
~ THEN GOTO 104
  IF ~  Global("BD_Saved_Edwin","bd4500",0)
IsValidForPartyDialogue("EDWIN")
~ THEN GOTO 105
  IF ~  Global("BD_Saved_Baeloth","bd4500",0)
IsValidForPartyDialogue("BAELOTH")
~ THEN GOTO 106
  IF ~  Global("BD_Saved_Mkhiin","bd4500",0)
IsValidForPartyDialogue("MKHIIN")
~ THEN GOTO 107
  IF ~  Global("BD_Saved_Glint","bd4500",0)
IsValidForPartyDialogue("GLINT")
~ THEN GOTO 108
  IF ~  Global("BD_Saved_Dorn","bd4500",0)
IsValidForPartyDialogue("DORN")
~ THEN GOTO 109
  IF ~  Global("BD_Saved_Neera","bd4500",0)
IsValidForPartyDialogue("NEERA")
~ THEN GOTO 110
  IF ~  Global("BD_Saved_Viconia","bd4500",0)
IsValidForPartyDialogue("VICONIA")
~ THEN GOTO 111
  IF ~  Global("BD_Saved_Voghiln","bd4500",0)
IsValidForPartyDialogue("VOGHILN")
~ THEN GOTO 112
  IF ~  Global("BD_Saved_Dynaheir","bd4500",0)
IsValidForPartyDialogue("DYNAHEIR")
~ THEN GOTO 95
  IF ~  Global("BD_Saved_Minsc","bd4500",0)
IsValidForPartyDialogue("MINSC")
~ THEN GOTO 101
  IF ~  Global("BD_Saved_Khalid","bd4500",0)
IsValidForPartyDialogue("KHALID")
~ THEN GOTO 97
  IF ~  Global("BD_Saved_Jaheira","bd4500",0)
IsValidForPartyDialogue("JAHEIRA")
~ THEN GOTO 99
  IF ~  Global("BD_Saved_Corwin","bd4500",0)
IsValidForPartyDialogue("CORWIN")
~ THEN GOTO 94
END

IF ~~ THEN BEGIN 22 // from: 19.1 19.6
  SAY #38895 /* ~Aha. Thrix does not know how this sort of thing works in the Prime Material Plane. But in Avernus, a contract is a contract. The wager is made. Win and one of these items will be yours. Lose and Thrix takes one of your friends.~ [BD38895] */
  IF ~~ THEN GOTO 10
  IF ~  Global("BD_Saved_Neera","bd4500",0)
IsValidForPartyDialogue("NEERA")
~ THEN GOTO 110
  IF ~  Global("BD_Saved_Viconia","bd4500",0)
IsValidForPartyDialogue("VICONIA")
~ THEN GOTO 111
  IF ~  Global("BD_Saved_Voghiln","bd4500",0)
IsValidForPartyDialogue("VOGHILN")
~ THEN GOTO 112
  IF ~  Global("BD_Saved_Dynaheir","bd4500",0)
IsValidForPartyDialogue("DYNAHEIR")
~ THEN GOTO 95
  IF ~  Global("BD_Saved_Minsc","bd4500",0)
IsValidForPartyDialogue("MINSC")
~ THEN GOTO 101
  IF ~  Global("BD_Saved_Khalid","bd4500",0)
IsValidForPartyDialogue("KHALID")
~ THEN GOTO 97
  IF ~  Global("BD_Saved_Jaheira","bd4500",0)
IsValidForPartyDialogue("JAHEIRA")
~ THEN GOTO 99
  IF ~  Global("BD_Saved_Corwin","bd4500",0)
IsValidForPartyDialogue("CORWIN")
~ THEN GOTO 94
  IF ~  Global("BD_Saved_Rasaad","bd4500",0)
IsValidForPartyDialogue("RASAAD")
~ THEN GOTO 103
  IF ~  Global("BD_Saved_Safana","bd4500",0)
IsValidForPartyDialogue("SAFANA")
~ THEN GOTO 104
  IF ~  Global("BD_Saved_Edwin","bd4500",0)
IsValidForPartyDialogue("EDWIN")
~ THEN GOTO 105
  IF ~  Global("BD_Saved_Baeloth","bd4500",0)
IsValidForPartyDialogue("BAELOTH")
~ THEN GOTO 106
  IF ~  Global("BD_Saved_Mkhiin","bd4500",0)
IsValidForPartyDialogue("MKHIIN")
~ THEN GOTO 107
  IF ~  Global("BD_Saved_Glint","bd4500",0)
IsValidForPartyDialogue("GLINT")
~ THEN GOTO 108
  IF ~  Global("BD_Saved_Dorn","bd4500",0)
IsValidForPartyDialogue("DORN")
~ THEN GOTO 109
END

IF ~~ THEN BEGIN 23 // from: 19.2 19.7
  SAY #38895 /* ~Aha. Thrix does not know how this sort of thing works in the Prime Material Plane. But in Avernus, a contract is a contract. The wager is made. Win and one of these items will be yours. Lose and Thrix takes one of your friends.~ [BD38895] */
  IF ~~ THEN GOTO 10
  IF ~  Global("BD_Saved_Glint","bd4500",0)
IsValidForPartyDialogue("GLINT")
~ THEN GOTO 108
  IF ~  Global("BD_Saved_Dorn","bd4500",0)
IsValidForPartyDialogue("DORN")
~ THEN GOTO 109
  IF ~  Global("BD_Saved_Minsc","bd4500",0)
IsValidForPartyDialogue("MINSC")
~ THEN GOTO 101
  IF ~  Global("BD_Saved_Khalid","bd4500",0)
IsValidForPartyDialogue("KHALID")
~ THEN GOTO 97
  IF ~  Global("BD_Saved_Neera","bd4500",0)
IsValidForPartyDialogue("NEERA")
~ THEN GOTO 110
  IF ~  Global("BD_Saved_Viconia","bd4500",0)
IsValidForPartyDialogue("VICONIA")
~ THEN GOTO 111
  IF ~  Global("BD_Saved_Voghiln","bd4500",0)
IsValidForPartyDialogue("VOGHILN")
~ THEN GOTO 112
  IF ~  Global("BD_Saved_Dynaheir","bd4500",0)
IsValidForPartyDialogue("DYNAHEIR")
~ THEN GOTO 95
  IF ~  Global("BD_Saved_Jaheira","bd4500",0)
IsValidForPartyDialogue("JAHEIRA")
~ THEN GOTO 99
  IF ~  Global("BD_Saved_Corwin","bd4500",0)
IsValidForPartyDialogue("CORWIN")
~ THEN GOTO 94
  IF ~  Global("BD_Saved_Rasaad","bd4500",0)
IsValidForPartyDialogue("RASAAD")
~ THEN GOTO 103
  IF ~  Global("BD_Saved_Safana","bd4500",0)
IsValidForPartyDialogue("SAFANA")
~ THEN GOTO 104
  IF ~  Global("BD_Saved_Edwin","bd4500",0)
IsValidForPartyDialogue("EDWIN")
~ THEN GOTO 105
  IF ~  Global("BD_Saved_Baeloth","bd4500",0)
IsValidForPartyDialogue("BAELOTH")
~ THEN GOTO 106
  IF ~  Global("BD_Saved_Mkhiin","bd4500",0)
IsValidForPartyDialogue("MKHIIN")
~ THEN GOTO 107
END

IF ~~ THEN BEGIN 24 // from: 19.3 19.8
  SAY #38895 /* ~Aha. Thrix does not know how this sort of thing works in the Prime Material Plane. But in Avernus, a contract is a contract. The wager is made. Win and one of these items will be yours. Lose and Thrix takes one of your friends.~ [BD38895] */
  IF ~~ THEN GOTO 10
  IF ~  Global("BD_Saved_Mkhiin","bd4500",0)
IsValidForPartyDialogue("MKHIIN")
~ THEN GOTO 107
  IF ~  Global("BD_Saved_Edwin","bd4500",0)
IsValidForPartyDialogue("EDWIN")
~ THEN GOTO 105
  IF ~  Global("BD_Saved_Baeloth","bd4500",0)
IsValidForPartyDialogue("BAELOTH")
~ THEN GOTO 106
  IF ~  Global("BD_Saved_Jaheira","bd4500",0)
IsValidForPartyDialogue("JAHEIRA")
~ THEN GOTO 99
  IF ~  Global("BD_Saved_Corwin","bd4500",0)
IsValidForPartyDialogue("CORWIN")
~ THEN GOTO 94
  IF ~  Global("BD_Saved_Rasaad","bd4500",0)
IsValidForPartyDialogue("RASAAD")
~ THEN GOTO 103
  IF ~  Global("BD_Saved_Viconia","bd4500",0)
IsValidForPartyDialogue("VICONIA")
~ THEN GOTO 111
  IF ~  Global("BD_Saved_Voghiln","bd4500",0)
IsValidForPartyDialogue("VOGHILN")
~ THEN GOTO 112
  IF ~  Global("BD_Saved_Minsc","bd4500",0)
IsValidForPartyDialogue("MINSC")
~ THEN GOTO 101
  IF ~  Global("BD_Saved_Khalid","bd4500",0)
IsValidForPartyDialogue("KHALID")
~ THEN GOTO 97
  IF ~  Global("BD_Saved_Glint","bd4500",0)
IsValidForPartyDialogue("GLINT")
~ THEN GOTO 108
  IF ~  Global("BD_Saved_Dorn","bd4500",0)
IsValidForPartyDialogue("DORN")
~ THEN GOTO 109
  IF ~  Global("BD_Saved_Neera","bd4500",0)
IsValidForPartyDialogue("NEERA")
~ THEN GOTO 110
  IF ~  Global("BD_Saved_Dynaheir","bd4500",0)
IsValidForPartyDialogue("DYNAHEIR")
~ THEN GOTO 95
  IF ~  Global("BD_Saved_Safana","bd4500",0)
IsValidForPartyDialogue("SAFANA")
~ THEN GOTO 104
END

My question is: how would I add a mod NPC to these trees so that it is a. also random enough and b. compatible with other mods?

Possibility 1:

The mod NPC gets assigned not at the bottom of the transaction list but also via EXTEND_TOP #X at other places, for example after the same original NPC for all four states. Disadvantage: the count number of the transaction shifts which is bad if a mod tries to add actions or transtrigger for certain original NPCs.

Possibility 2:

Add the mod NPC to the end of the list but add a RandomNum(X,Y) trigger which lets the mod NPC be skipped randomly. Disadvantage: it's possible that the mod NPC is not chosen even though they are the only joined NPC in the group.

Possibility 3 which I am trying to avoid:

Add the mod NPC to teh bottom always. Great disadvantage: the last installed mod NPC will be the one that it chosen always.

Any suggestions?

Link to comment

I would read the number of transitions in each state, divide it by 4, and insert mod transitions at (trans_num / 4) * (state_ind - 21) points.

EDIT So basically, what you suggest in 1, it seems. As for compatibility... You might have a point, but imo it's the least evil nonetheless - because in order to break something it requires another mod to 1) try to edit vanilla transitions and 2) do it without reading data first.

PPS ...and also 3) be willing to poke the awful mess that is Thrix dialog file with a ten foot pole. This dialog was the worst in the entire SoD by a huge margin, because writers wanted to have random element added. In retrospect, may we should've added small cutscene effect and move all the rng calculations in there🤔

Edited by Ardanis
Link to comment

The original dialog is already twice, if not thrice, as messy, so... I'd be cautious about making it even worse.

Looking at it again, I recall you can refuse Thrix his choice of a party member and have him choose again. So technically you can go with 3rd idea and append NPC at the bottom - even if two mods will conflict there, you can still write "nope, choose someone else" option to stay in line with the original, and get the previous NPC mod as a next choice.

Link to comment

Thank you for your suggestions!

11 hours ago, Ardanis said:

This dialog was the worst in the entire SoD by a huge margin

You think? ..

What @DavidW suggested sounds like something I'd do, to be honest. (Not that I'd be smart enough to think of it, though, so thanks!). But the problem is that I will include this into my SoD-NPC tutorial, so maybe making every NPC mod add 10+ more reply options to 72 dialogue states in bdthrix does sound like an unfortunate idea.

11 hours ago, Ardanis said:

I would read the number of transitions in each state, divide it by 4, and insert mod transitions at (trans_num / 4) * (state_ind - 21) points.

I understand the concept but I have no idea how to code that. Suggestions very welcome.

8 hours ago, Ardanis said:

I recall you can refuse Thrix his choice of a party member and have him choose again. So technically you can go with 3rd idea and append NPC at the bottom - even if two mods will conflict there, you can still write "nope, choose someone else" option to stay in line with the original, and get the previous NPC mod as a next choice.

Although it is tempting and would probably be the best compatibility wise, still it restricts the options for mod NPCs quite a bit. Besides, I already wrote "You gambled with my soul?!11!!!!" reactions for 5 NPCs so I want to make this work. 😃

11 hours ago, Ardanis said:

in order to break something it requires another mod to 1) try to edit vanilla transitions and 2) do it without reading data first.

This was not the topic of this post but I'll grab this while it's hot: I do ADD_TRANS_TRIGGER a lot for Imoen4Ever but I have no idea how to read in the correct reply option first so I do it blindly. How would I make sure I add to the correct reply option even if its number count was shifted by another mod?

Link to comment
13 hours ago, jastey said:

You think? ..

Almost the entire dialog consists of "choose party member" states, four initial and then four per each party member if PC refuses to bet them.

 

13 hours ago, jastey said:

I understand the concept but I have no idea how to code that. Suggestions very welcome.

I'm a little rusty to give you an actually working piece, but the logic would be like:

COPY_EXISTING - bdthrix.dlg override
  READ_LONG 0xc states
  x = 0
  FOR (i=21; i<24; ++i) BEGIN
    READ_LONG states + i * 16 + 8 trans_num
    SET insert%i% = ( (trans_num - 1) / 4) * x
    x = (x<3) ? x+1 : 0
  END
  FOR (i=30; i<85; ++i) BEGIN
    READ_LONG states + i * 16 + 8 trans_num
    SET insert%i% = ( (trans_num - 1) / 4) * x
    x = (x<3) ? x+1 : 0
  END

Then in your .d use for each state

EXTEND_BOTTOM bdthrix 21 #%insert21% /* trans list */ END

You'll probably need to EVAL the .d

 

13 hours ago, jastey said:

How would I make sure I add to the correct reply option even if its number count was shifted by another mod?

 I think this may do https://weidu.org/~thebigg/README-WeiDU.html#dActionWhen

Otherwise, you'd have to read the .dlg structure, similar to above.

Edited by Ardanis
Link to comment

Thank you for the suggestions!

13 minutes ago, Ardanis said:

Almost the entire dialog consists of "choose party member" states, four initial and then four per each party member if PC refuses to bet them.

I know, my question was sarcasm. ^^

Link to comment

Reflecting on this, and on the need for something to be iterated across multiple mods, I might be inclined to do something simpler. There are four lots of NPC orderings, yes, with 15 NPCs in each? Insert the new NPC transition at the top of the first one, the bottom of the second, at position 5 of the third, and position 10 of the fourth. That's enough randomness to achieve what you want, I think. The idea isn't to make sure that each NPC is equally likely to be selected, irrespective of party mix (the original script doesn't do that for the original NPCs) - it's just to mix it up a bit so that mod-added NPCs aren't guaranteed to be first or last, and so that the order isn't predictable. I think that suggestion will do it fine, and is (relatively) easy to implement.

Link to comment
On 6/27/2020 at 10:31 PM, DavidW said:

Reflecting on this, and on the need for something to be iterated across multiple mods, I might be inclined to do something simpler. There are four lots of NPC orderings, yes, with 15 NPCs in each? Insert the new NPC transition at the top of the first one, the bottom of the second, at position 5 of the third, and position 10 of the fourth. That's enough randomness to achieve what you want, I think. The idea isn't to make sure that each NPC is equally likely to be selected, irrespective of party mix (the original script doesn't do that for the original NPCs) - it's just to mix it up a bit so that mod-added NPCs aren't guaranteed to be first or last, and so that the order isn't predictable. I think that suggestion will do it fine, and is (relatively) easy to implement.

Late reply: I like this idea very much. Thank you!

Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...