Jump to content

How do I use dActionWhen for ADD_TRANS_TRIGGER?


jastey

Recommended Posts

I want to patch ARAN.dlg state 39 reply option 0 with a variable - but only if this reply option is the original one where you can ask him about Imoen.

This is what I do so far (without failsave):

ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO 0

The reply option has the following text:

Quote

#43058 /* ~Then it is a simple matter of retrieveing Imoen from this place.~ */

I tried the following. There is no error message, but the variable isn't patched to the reply option, either:

ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO 0 IF ~Imoen~

-How would I use the dActionWhen so that it only patches if the reply option really contains a reference to Imoen?

-How would I do this in a way so that I can account for different languages (and, more imprtantly, letters)?

Link to comment

dActionWhen refers to the string the command is about to alter. In the case of ADD_TRANS_TRIGGER it checks the content of an existing trigger block (if available). For example, this check would add the trigger only if it doesn't exist yet:

ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO 0 UNLESS ~"C#IM_ImoenStays"~

I guess you'll have to code your own function if you want to search specific responses for keywords. To simplify the code you could instead check for predefined strrefs, since you want to check vanilla game dialog lines. The strref for the above-mentioned line would be 43058 in BG2/BG2EE.

Link to comment

Ah, I see. Thank you for the clearification.

4 minutes ago, argent77 said:

To simplify the code you could instead check for predefined strrefs, since you want to check vanilla game dialog lines. The strref for the above-mentioned line would be 43058 in BG2/BG2EE.

That would be even better than what I originally anticipated. I'd need coding help to realize this, though, and would be very happy about help.

EDIT: And, while we are at it - would it be possible to scan the existing reply options, and patch the one with #43058 in case it's no longer number "0"?

If yes, I would be very grateful for coding help.

Link to comment
4 minutes ago, qwerty1234567 said:

STATE_WHICH_SAYS #43058, I think

This will only return the state index. I don't think there is a WeiDU command that returns the response index.

 

22 minutes ago, jastey said:

Ah, I see. Thank you for the clearification.

That would be even better than what I originally anticipated. I'd need coding help to realize this, though, and would be very happy about help.

EDIT: And, while we are at it - would it be possible to scan the existing reply options, and patch the one with #43058 in case it's no longer number "0"?

If yes, I would be very grateful for coding help.

Try this:

// Returns all response strrefs for a given state as an array.
DEFINE_PATCH_FUNCTION GET_RESPONSE_STRREFS
INT_VAR
  state = 0
RET
  strrefs  // returns number of array elements
RET_ARRAY
  strrefs  // indexed array with response strrefs
BEGIN
  SET strrefs = 0
  SET $strrefs(~0~) = "-1" // workaround for WeiDU bug

  READ_ASCII 0 sig (8)
  PATCH_IF (~%sig%~ STR_EQ ~DLG V1.0~) BEGIN
    READ_LONG 0x08 num_states
    READ_LONG 0x0c ofs_states
    READ_LONG 0x14 ofs_responses
    PATCH_IF (state >= 0 && state < num_states) BEGIN
      SET ofs = ofs_states + (state * 16)
      READ_LONG (ofs + 4) idx_response
      READ_LONG (ofs + 8) num_response
      FOR (idx = 0; idx < num_response; ++idx) BEGIN
        SET ofs = ofs_responses + (idx_response + idx) * 32
        PATCH_IF ((BYTE_AT ofs) & BIT0) BEGIN   // has text?
          SET $strrefs(~%strrefs%~) = LONG_AT (ofs + 4)
        END ELSE BEGIN
          SET $strrefs(~%strrefs%~) = "-1"
        END
        SET strrefs += 1
      END
    END
  END
END

// Example usage
COPY_EXISTING ~aran.dlg~ ~override~
  LPF GET_RESPONSE_STRREFS
    INT_VAR
      state = 39
    RET
      strrefs
    RET_ARRAY
      strrefs
  END
  FOR (idx = 0; idx < strrefs; ++idx) BEGIN
    PATCH_IF ($strrefs(~%idx%~) = 43058) BEGIN
      // patch response trigger %idx%
    END
  END
BUT_ONLY

 

Link to comment

In that case, change the .d command to this:

ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %idx%

And use this example .tp2 code:

COPY_EXISTING ~aran.dlg~ ~override~
  LPF GET_RESPONSE_STRREFS
    INT_VAR state = 39
    RET strrefs
    RET_ARRAY strrefs
  END
BUT_ONLY

OUTER_FOR (idx = 0; idx < strrefs; ++idx) BEGIN
  ACTION_IF ($strrefs(~%idx%~) = 43058) BEGIN
    // patching response trigger
    COMPILE EVAL ~%MOD_FOLDER%/dialogs/aran.d~
  END
END

I'd recommend to use a more unique variable name in place of "idx" though.

Link to comment

Thank you very much for the example and the help!

I have several instances in several dlg files. I guess I could use more unique names for the "strrefs" variable, but I do not see a possibility to make the patch process more general. Providing a .d file for each would be ineffective; I guess I'd need to switch to inlined .d for each. In case there is a more efficient way to patch different reply options in different states of different dlgs I'd appreciate a hint, otherwise I'll use your code and use inlined .d files for each instance.

Link to comment

You could do all the variable initializations before compiling the respective .d files. That way the .d may contain as many commands as you want (provided each command references a unique variable name).

Btw, a variable doesn't only have to include a single response index. It can just as well be a string containing multiple indices created by multiple calls of TEXT_SPRINT variable ~%variable% %idx%~.

Link to comment
23 minutes ago, argent77 said:

You could do all the variable initializations before compiling the respective .d files. That way the .d may contain as many commands as you want (provided each command references a unique variable name).

That's what I was thinking off but I wouldn't know how to the syntax would be. Currently, the .d compilation is inside the OUTER_FOR and PATCH_IF to determine whether the strref matches. I can read in several "strrefs" but how would I include the check whether the state has the correct number for the patching.

Hm - I guess it would be possible to determine the correct "idx" reply option index so I could use something like

ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %idx%

inside the d-file (with a more generic variable name than "idx", of course). If you would help me add this to the function that would be super cool.

Link to comment

This is an example how the whole dialog could be processed in one go.

Spoiler

// Assuming this is the .d file with lots of variable replacements
<<<<<<<< .../inlined/aran.d
ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %responses_39%
ADD_TRANS_TRIGGER ARAN 40 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %responses_40%
ADD_TRANS_TRIGGER ARAN 43 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %responses_43%
ADD_TRANS_TRIGGER ARAN 45 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %responses_45%
>>>>>>>>

// List of all potential response strrefs to check
ACTION_DEFINE_ASSOCIATIVE_ARRAY response_strrefs BEGIN
  43058 => 1
  43059 => 1
  43060 => 1
  43061 => 1
  // ...and so on
END
  
COPY_EXISTING ~aran.dlg~ ~override~
  // scanning listed dialog states
  PATCH_FOR_EACH state IN 39 40 43 45 BEGIN
    LPF GET_RESPONSE_STRREFS INT_VAR state RET strrefs RET_ARRAY strrefs END
    TEXT_SPRINT indices ~~  // a temporary variable for building the index list
    FOR (i = 0; i < strrefs; ++i) BEGIN
      SET value = $strrefs(~%i%~)
      // Include index only if strref is listed in the response_strrefs array
      PATCH_IF (VARIABLE_IS_SET $response_strrefs(~%value%~)) BEGIN
        TEXT_SPRINT indices ~%indices% %i%~ // building list of indices
      END
    END
    // initialize variables responses_39, responses_40, ...
    // EVAL is used to create the variable name dynamically
    TEXT_SPRINT EVAL ~responses_%state%~ ~%indices%~
    PATCH_PRINT ~Variable %state%: %indices%~
  END
BUT_ONLY

// Variables response_39, response_40, response_43 and response_45
// are now initialized and can be used in the .d file
COMPILE EVAL ~.../inlined/aran.d~

 

Current implementation requires that all variables contain at least one index or WeiDU will update all available responses of a state. That could be solved by adding a dActionWhen condition that is guaranteed to fail.

Link to comment

Thank you so much for your help and patience.

10 hours ago, argent77 said:

all variables contain at least one index

What exactly does that mean? What are the consequences? If a mod changed the state so much that it no longer contains a reply option with the expected strref, all transactions would be patched (which would be not good)?

10 hours ago, argent77 said:

That could be solved by adding a dActionWhen condition that is guaranteed to fail.

I nearly don't dare to ask. But I have no idea how and where I would put in such a condition.

Link to comment

In case there are no matching response indices found the variable will be empty and the whole expression evaluates to

ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO

This is a valid expression, but results in the script trigger added to all available responses found in state 39 (according to WeiDU docs).

One way to solve it is by adding an IF condition to the ADD_TRANS_TRIGGER that never evaluates to "true". For example:

ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO IF ~a_nonexisting_trigger()~

That can be realized by adding this code right before the line "TEXT_SPRINT EVAL ~responses_%state%~ ~%indices%~" in the example code from my previous comment.

// prevent adding a trigger if index list is empty
PATCH_IF (~%indices%~ STR_EQ ~~) BEGIN
  TEXT_SPRINT indices "IF ~a_nonexisting_trigger()~"
END

 

Edited by argent77
Link to comment

Your suggestions work like a charm. Thank you again for the help.

Unfortunately, I have another problem: in some dialogues, there is multiple reply options in one state with the same string, where the above suggestion fails:

/* AERIE */
/* meeting dialogue */
/* #42158  ~I think you should know, Aerie, that my ultimate goal is to rescue a friend of mine... Imoen... who has been captured by the Cowled Wizards.  It could be dangerous.~ */
ADD_TRANS_TRIGGER AERIE 4 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO 0 3

 

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...