jastey Posted August 21, 2020 Share Posted August 21, 2020 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)? Quote Link to comment
argent77 Posted August 21, 2020 Share Posted August 21, 2020 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. Quote Link to comment
jastey Posted August 21, 2020 Author Share Posted August 21, 2020 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. Quote Link to comment
Magus Posted August 21, 2020 Share Posted August 21, 2020 STATE_WHICH_SAYS #43058, I think Quote Link to comment
argent77 Posted August 21, 2020 Share Posted August 21, 2020 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 Quote Link to comment
jastey Posted August 21, 2020 Author Share Posted August 21, 2020 @argent77 thank you very much for the help. Unfortunately, I need also example code for what would I put into the // patch response trigger %idx% Quote Link to comment
argent77 Posted August 21, 2020 Share Posted August 21, 2020 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. Quote Link to comment
jastey Posted August 21, 2020 Author Share Posted August 21, 2020 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. Quote Link to comment
argent77 Posted August 21, 2020 Share Posted August 21, 2020 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%~. Quote Link to comment
jastey Posted August 21, 2020 Author Share Posted August 21, 2020 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. Quote Link to comment
argent77 Posted August 21, 2020 Share Posted August 21, 2020 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. Quote Link to comment
jastey Posted August 22, 2020 Author Share Posted August 22, 2020 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. Quote Link to comment
argent77 Posted August 22, 2020 Share Posted August 22, 2020 (edited) 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 August 22, 2020 by argent77 Quote Link to comment
jastey Posted August 24, 2020 Author Share Posted August 24, 2020 Thank you very much for your help. I haven't implemented it yet but will so soon. Quote Link to comment
jastey Posted September 3, 2020 Author Share Posted September 3, 2020 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 Quote Link to comment
Recommended Posts
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.