subtledoctor Posted August 14, 2020 Share Posted August 14, 2020 (edited) This is not complicated, but maybe useful for kit mods: I've made a drop-in-ready .tpa file containing two functions which will check whether the next kit to be installed will overlap with the IDS value of the Abjurer, Conjurer, or Diviner mage specialists. (They are 0x0040, 0x0080, and 0x0100.) If you add enough kits into your game, three of the mod-added kits might be assigned IDS values of 0x4040, 0x4080, and 0x4100 by Weidu's ADD_KIT function. (My current install has about 300 kits; all three of those overlaps occur.) When this happens, especially if the mod-added kit is an arcane spellcaster, some aspects of it will be overridden by characteristics of the vanilla mage kits. The linked code will 1) check whether the next kit to be installed will overlap with one of those three; and 2) if so, it will insert a dummy kit first to take the problematic spot, and then continue on to allow the next real kit to be installed after. Using this is simple: drop that .tpa file into a mod (or replicate it, whatever); then INCLUDE ~%MOD_FOLDER%/lib/extra_kits.tpa~ LAF check_kit_conflict END ...then add your kit as usual. In my mods, the INCLUDE line goes in my ALWAYS block, and I simply inserted "LAF check_kit_conflict END" ahead of each time I saw the ADD_KIT command. Even in mods that add dozens of kits, this was fairly pain-free. Edited February 12, 2021 by subtledoctor Quote Link to comment
Caedwyr Posted August 14, 2020 Share Posted August 14, 2020 Thanks, adding this to my sorcerer kit mod since I seem to recall that sorcerer kits could run into this issue as well. Quote Link to comment
subtledoctor Posted August 15, 2020 Share Posted August 15, 2020 On 8/14/2020 at 12:09 AM, Caedwyr said: Thanks, adding this to my sorcerer kit mod since I seem to recall that sorcerer kits could run into this issue as well. Definitely can affect sorcerers - the game will happily apply a mage kit to a sorcerer. (I once played with Dynaheir as a sorcerer, but let her keep the Invoker kit.) This issue can really affect any kit; you may end up with a cleric that imposes a -2 save bonus against conjuration spells upon targets. I don't think the record screen will say anything with a cleric kit, but cleric spells do have schools and this might (slightly) affect gameplay even if you don't realize it. Quote Link to comment
Luke Posted August 28, 2020 Share Posted August 28, 2020 @Ardanis ADD_SPELL_HEADER: this should be WRITE_SHORT instead of WRITE_BYTE. Quote Link to comment
ptifab Posted August 28, 2020 Share Posted August 28, 2020 @Luke @Ardanis 12 hours ago, Luke said: @Ardanis ADD_SPELL_HEADER: this should be WRITE_SHORT instead of WRITE_BYTE. and in the same code: ADD_SPELL_HEADER: this should be WRITE_SHORT instead of WRITE_LONG ? Quote Link to comment
Luke Posted August 29, 2020 Share Posted August 29, 2020 11 hours ago, ptifab said: @Luke @Ardanis and in the same code: ADD_SPELL_HEADER: this should be WRITE_SHORT instead of WRITE_LONG ? Yep, correct. Quote Link to comment
Luke Posted August 31, 2020 Share Posted August 31, 2020 (edited) @ptifab OK, technically speaking some of them are not really bugs (e.g., offsets 0x2, 0x10). For instance, let's consider offset 0x2 ("Location"). Since legal values for these fields never fall outside the byte range, then writing WRITE_BYTE is not that bad (even if the "Location" field of SPL files is 2 bytes long...) Edited August 31, 2020 by Luke Quote Link to comment
kjeron Posted August 31, 2020 Share Posted August 31, 2020 1 hour ago, Luke said: @ptifab OK, technically speaking some of them are not really bugs (e.g., offsets 0x2, 0x10). For instance, let's consider offset 0x2 ("Location"). Since legal values for these fields never fall outside the byte range, then writing WRITE_BYTE is not that bad (even if the "Location" field of SPL files is 2 bytes long...) 0x10 (Minimum level) does have a full two-byte range. Standard spellcasting only utilizes the first byte (0-255), but opcodes that specify casting level (146*2/326*EFF/333) have access to the entire range (0 - 65535). Quote Link to comment
K4thos Posted June 30, 2021 Share Posted June 30, 2021 (edited) Action function for generating associative array listing all files inside specified path and all its subdirectories. https://github.com/K4thos/IE-code-repository/blob/master/generate_filelist_array.tpa Example usage: LAF GENERATE_FILELIST_ARRAY STR_VAR path = EVAL ~%MOD_FOLDER%~ RET_ARRAY filelist_array = filelist END ACTION_PHP_EACH filelist_array AS filepath => extension BEGIN PRINT ~%filepath% => %extension%~ END Edited June 30, 2021 by K4thos Quote Link to comment
tipun Posted July 20, 2021 Share Posted July 20, 2021 Three functions: FC_EDIT_AREA_DOOR FC_EDIT_AREA_REGION FC_EDIT_AREA_CONTAINER They generally correspond to the standard weidu functions: ALTER_AREA_REGION ALTER_AREA_CONTAINER ALTER_AREA_DOOR but allow polygons to be modified. And the search for the desired structure occurs using a large number of parameters. Spoiler //BLOCK FC_UPDETE_AREA_OFFSETS DEFINE_PATCH_FUNCTION FC_UPDETE_AREA_OFFSETS INT_VAR num = 1 STR_VAR type = actor //actor 0x110, trigger 0x0c4, spawn 0x0c8, entrance 0x068, container 0x0c0, item 0x014, vertex 0x004, ambient 0x0d4, variable 0x050, door 0x0c8, animation 0x04c, automap 0x034, projectile 0x01c RET done BEGIN //BLOCK SET done = 0 READ_LONG 0x054 aco //actor_off READ_LONG 0x05c tro //trigger_off READ_LONG 0x060 spo //spawn_off READ_LONG 0x068 eno //entrance_off READ_LONG 0x070 coo //container_off READ_LONG 0x078 ito //item_off READ_LONG 0x07c veo //vertex_off READ_LONG 0x084 amo //ambient_off READ_LONG 0x088 vao //variable_off READ_SHORT 0x090 ofo //object_flag_off READ_LONG 0x0a0 exo //explored_off READ_LONG 0x0a8 doo //door_off READ_LONG 0x0b0 ano //animation_off READ_LONG 0x0b8 too //tiled_off READ_LONG 0x0bc soo //song_off READ_LONG 0x0c0 reo //rest_off READ_LONG 0x0c4 auo //automap_off READ_LONG 0x0cc pro //projectile_off PATCH_MATCH ~%type%~ WITH ~actor~ BEGIN SET size = num * 0x110 SET off = aco END ~trigger~ BEGIN SET size = num * 0x0c4 SET off = tro END ~spawn~ BEGIN SET size = num * 0x0c8 SET off = spo END ~entrance~ BEGIN SET size = num * 0x068 SET off = eno END ~container~ BEGIN SET size = num * 0x0c0 SET off = coo END ~item~ BEGIN SET size = num * 0x014 SET off = ito END ~vertex~ BEGIN SET size = num * 0x004 SET off = veo END ~ambient~ BEGIN SET size = num * 0x0d4 SET off = amo END ~variable~ BEGIN SET size = num * 0x050 SET off = vao END ~door~ BEGIN SET size = num * 0x0c8 SET off = doo END ~animation~ BEGIN SET size = num * 0x04c SET off = ano END ~automap~ BEGIN SET size = num * 0x034 SET off = auo END ~projectile~ BEGIN SET size = num * 0x01c SET off = pro END DEFAULT SET size = 0 SET off = 0 END PATCH_IF ( size != 0 ) AND ( off != 0 ) BEGIN PATCH_IF ( ~%type%~ STR_CMP ~actor~ ) AND ( aco >= off ) BEGIN WRITE_LONG 0x054 aco + size END PATCH_IF ( ~%type%~ STR_CMP ~trigger~ ) AND ( tro >= off ) BEGIN WRITE_LONG 0x05c tro + size END PATCH_IF ( ~%type%~ STR_CMP ~spawn~ ) AND ( spo >= off ) BEGIN WRITE_LONG 0x060 spo + size END PATCH_IF ( ~%type%~ STR_CMP ~entrance~ ) AND ( eno >= off ) BEGIN WRITE_LONG 0x068 eno + size END PATCH_IF ( ~%type%~ STR_CMP ~container~ ) AND ( coo >= off ) BEGIN WRITE_LONG 0x070 coo + size END PATCH_IF ( ~%type%~ STR_CMP ~item~ ) AND ( ito >= off ) BEGIN WRITE_LONG 0x078 ito + size END PATCH_IF ( ~%type%~ STR_CMP ~vertex~ ) AND ( veo >= off ) BEGIN WRITE_LONG 0x07c veo + size END PATCH_IF ( ~%type%~ STR_CMP ~ambient~ ) AND ( amo >= off ) BEGIN WRITE_LONG 0x084 amo + size END PATCH_IF ( ~%type%~ STR_CMP ~variable~ ) AND ( vao >= off ) BEGIN WRITE_LONG 0x088 vao + size END PATCH_IF ( ofo >= off ) BEGIN WRITE_SHORT 0x090 ofo + size END PATCH_IF ( exo >= off ) BEGIN WRITE_LONG 0x0a0 exo + size END PATCH_IF ( ~%type%~ STR_CMP ~door~ ) AND ( doo >= off ) BEGIN WRITE_LONG 0x0a8 doo + size END PATCH_IF ( ~%type%~ STR_CMP ~animation~ ) AND ( ano >= off ) BEGIN WRITE_LONG 0x0b0 ano + size END PATCH_IF ( too >= off ) BEGIN WRITE_LONG 0x0b8 too + size END PATCH_IF ( soo >= off ) BEGIN WRITE_LONG 0x0bc soo + size END PATCH_IF ( reo >= off ) BEGIN WRITE_LONG 0x0c0 reo + size END PATCH_IF ( ~%type%~ STR_CMP ~automap~ ) AND ( auo >= off ) BEGIN WRITE_LONG 0x0c4 auo + size END PATCH_IF ( ~%type%~ STR_CMP ~projectile~ ) AND ( pro >= off ) BEGIN WRITE_LONG 0x0cc pro + size END SET done = 1 END //BLOCKEND END //BLOCKEND //BLOCK FC_GET_XY_COORDINATE DEFINE_PATCH_FUNCTION FC_GET_XY_COORDINATE INT_VAR num = 0 RET x1 y1 BEGIN y1 = ( num >> 16 ) x1 = num - ( y1 << 16 ) END //BLOCKEND //BLOCK FC_UPDATE_VERTEX_INDEX DEFINE_PATCH_FUNCTION FC_UPDATE_VERTEX_INDEX INT_VAR skip = 0 numx = 100000 adds = 100000 STR_VAR type = trigger //trigger, container, door BEGIN READ_SHORT 0x5a type_cnt READ_LONG 0x5c type_off PATCH_IF ( type_cnt > 0 ) BEGIN FOR ( i = 0 ; i < type_cnt ; ++i ) BEGIN PATCH_IF ( ~%type%~ STR_EQ ~trigger~ ) AND ( i = skip ) BEGIN END ELSE BEGIN READ_LONG type_off + i * 0x0c4 + 0x2c f_vert PATCH_IF ( f_vert >= numx ) BEGIN WRITE_LONG type_off + i * 0x0c4 + 0x2c f_vert + adds END END END END READ_SHORT 0x74 type_cnt READ_LONG 0x70 type_off PATCH_IF ( type_cnt > 0 ) BEGIN FOR ( i = 0 ; i < type_cnt ; ++i ) BEGIN PATCH_IF ( ~%type%~ STR_EQ ~container~ ) AND ( i = skip ) BEGIN END ELSE BEGIN READ_LONG type_off + i * 0x0c0 + 0x50 f_vert PATCH_IF ( f_vert >= numx ) BEGIN WRITE_LONG type_off + i * 0x0c0 + 0x50 f_vert + adds END END END END READ_LONG 0xa4 type_cnt READ_LONG 0xa8 type_off PATCH_IF ( type_cnt > 0 ) BEGIN FOR ( i = 0 ; i < type_cnt ; ++i ) BEGIN PATCH_IF ( ~%type%~ STR_EQ ~door~ ) AND ( i = skip ) BEGIN END ELSE BEGIN READ_LONG type_off + i * 0x0c8 + 0x2c f_vert PATCH_IF ( f_vert >= numx ) BEGIN WRITE_LONG type_off + i * 0x0c8 + 0x2c f_vert + adds END READ_LONG type_off + i * 0x0c8 + 0x34 f_vert PATCH_IF ( f_vert >= numx ) BEGIN WRITE_LONG type_off + i * 0x0c8 + 0x34 f_vert + adds END READ_LONG type_off + i * 0x0c8 + 0x48 f_vert PATCH_IF ( f_vert >= numx ) BEGIN WRITE_LONG type_off + i * 0x0c8 + 0x48 f_vert + adds END READ_LONG type_off + i * 0x0c8 + 0x50 f_vert PATCH_IF ( f_vert >= numx ) BEGIN WRITE_LONG type_off + i * 0x0c8 + 0x50 f_vert + adds END END END END END //BLOCKEND //BLOCK FC_EDIT_AREA_DOOR DEFINE_PATCH_FUNCTION FC_EDIT_AREA_DOOR INT_VAR flags = "-1" hp = "-1" ac = "-1" cursor_idx = "-1" trap_detect_dif = "-1" trap_remove_dif = "-1" is_trapped = "-1" is_trap_detect = "-1" launch_x = "-1" launch_y = "-1" detect_diff = "-1" lock_diff = "-1" open_loc_x = "-1" open_loc_y = "-1" close_loc_x = "-1" close_loc_y = "-1" unlock_message = 99999999 speaker_name = 99999999 //vertex_open_X //vertex_closed_X //impeded_open_X //impeded_closed_X vertex_open_0 = "-1" vertex_closed_0 = "-1" impeded_open_0 = "-1" impeded_closed_0 = "-1" // AND ( $vertex(0) >= 0 ) STR_VAR match_name = "same" match_key = "same" match_script = "same" name = "same" doorId = "same" open_sound = "same" close_sound = "same" key = "same" script = "same" travel_trigger = "same" dialogue = "same" RET done BEGIN //BLOCK SET done = 0 SET match = 0 READ_LONG 0x0a4 ~d_cnt~ READ_LONG 0x0a8 ~d_off~ PATCH_IF ( is_trapped > 1 ) BEGIN SET is_trapped = 1 END PATCH_IF ( is_trap_detect > 1 ) BEGIN SET is_trap_detect = 1 END PATCH_IF ( d_cnt > 0 ) BEGIN FOR ( i = 0 ; i < d_cnt ; ++i ) BEGIN SET offset = d_off + i * 0xc8 PATCH_IF ( ~%match_name%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset d_name (32) NULL PATCH_IF ( ~%match_name%~ STR_EQ ~%d_name%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF ( ~%match_key%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset + 0x78 d_key (8) NULL PATCH_IF ( ~%match_key%~ STR_EQ ~%d_key%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF ( ~%match_script%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset + 0x80 d_scr (8) NULL PATCH_IF ( ~%match_script%~ STR_EQ ~%d_scr%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF (match) BEGIN SET door_pos = i SET i = d_cnt SET patch_offset = offset END END END PATCH_IF (match) BEGIN PATCH_IF ( ~%name%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset ~%name%~ (32) END PATCH_IF ( ~%doorId%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x20 ~%doorId%~ (8) END PATCH_IF ( ~%flags%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x28 ~%flags%~ END PATCH_IF ( ~%hp%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x54 ~%hp%~ END PATCH_IF ( ~%ac%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x56 ~%ac%~ END PATCH_IF ( ~%open_sound%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x58 ~%open_sound%~ (8) END PATCH_IF ( ~%close_sound%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x60 ~%close_sound%~ (8) END PATCH_IF ( ~%cursor_idx%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x68 ~%cursor_idx%~ END PATCH_IF ( ~%trap_detect_dif%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x6c ~%trap_detect_dif%~ END PATCH_IF ( ~%trap_remove_dif%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x6e ~%trap_remove_dif%~ END PATCH_IF ( ~%is_trapped%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x70 ~%is_trapped%~ END PATCH_IF ( ~%is_trap_detect%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x72 ~%is_trap_detect%~ END PATCH_IF ( ~%launch_x%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x74 ~%launch_x%~ END PATCH_IF ( ~%launch_y%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x76 ~%launch_y%~ END PATCH_IF ( ~%key%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x78 ~%key%~ (8) END PATCH_IF ( ~%script%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x80 ~%script%~ (8) END PATCH_IF ( ~%detect_diff%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x88 ~%detect_diff%~ END PATCH_IF ( ~%lock_diff%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x8c ~%lock_diff%~ END PATCH_IF ( ~%open_loc_x%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x90 ~%open_loc_x%~ END PATCH_IF ( ~%open_loc_y%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x92 ~%open_loc_y%~ END PATCH_IF ( ~%close_loc_x%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x94 ~%close_loc_x%~ END PATCH_IF ( ~%close_loc_y%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x96 ~%close_loc_y%~ END PATCH_IF ( ~%unlock_message%~ != 99999999 ) BEGIN WRITE_LONG patch_offset + 0x98 ~%unlock_message%~ END PATCH_IF ( ~%travel_trigger%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x9c ~%travel_trigger%~ (24) END PATCH_IF ( ~%speaker_name%~ != 99999999 ) BEGIN WRITE_LONG patch_offset + 0xb4 ~%speaker_name%~ END PATCH_IF ( ~%dialogue%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0xb8 ~%dialogue%~ (8) END //vertex_open_X PATCH_IF ( VARIABLE_IS_SET $vertex_open(0) AND ( $vertex_open(0) >= 0 ) ) BEGIN READ_LONG patch_offset + 0x2c vertex_first READ_SHORT patch_offset + 0x30 vertex_cnt SET deleted_vertex = 0 - vertex_cnt READ_LONG 0x7c all_vertex_off READ_SHORT 0x80 all_vertex_cnt SET v_off = all_vertex_off + vertex_first * 0x004 SET num_v = 0 DELETE_BYTES v_off vertex_cnt * 0x004 SET x_bounding_left = 10000 SET x_bounding_top = 10000 SET x_bounding_right = 0 SET x_bounding_bottom = 0 FOR ( i = 0 ; i < 65535 ; ++i ) BEGIN PATCH_IF ( VARIABLE_IS_SET $vertex_open(~%i%~) ) BEGIN SET v_num = $vertex_open(~%i%~) INSERT_BYTES v_off + i * 0x004 0x004 WRITE_LONG v_off + i * 0x004 v_num LPF FC_GET_XY_COORDINATE INT_VAR num = v_num RET x1 y1 END PATCH_IF ( x_bounding_left > x1 ) BEGIN SET x_bounding_left = x1 END PATCH_IF ( x_bounding_top > y1 ) BEGIN SET x_bounding_top = y1 END PATCH_IF ( x_bounding_right < x1 ) BEGIN SET x_bounding_right = x1 END PATCH_IF ( x_bounding_bottom < y1 ) BEGIN SET x_bounding_bottom = y1 END SET deleted_vertex = deleted_vertex + 1 SET num_v = num_v + 1 END ELSE BEGIN SET i = 65535 END END WRITE_SHORT 0x80 all_vertex_cnt + deleted_vertex WRITE_SHORT patch_offset + 0x30 num_v WRITE_SHORT patch_offset + 0x38 x_bounding_left WRITE_SHORT patch_offset + 0x3a x_bounding_top WRITE_SHORT patch_offset + 0x3c x_bounding_right WRITE_SHORT patch_offset + 0x3e x_bounding_bottom READ_LONG patch_offset + 0x34 upd_vert_1 READ_LONG patch_offset + 0x48 upd_vert_2 READ_LONG patch_offset + 0x50 upd_vert_3 PATCH_IF ( upd_vert_1 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x34 upd_vert_1 + deleted_vertex END PATCH_IF ( upd_vert_2 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x48 upd_vert_2 + deleted_vertex END PATCH_IF ( upd_vert_3 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x50 upd_vert_3 + deleted_vertex END LPF FC_UPDATE_VERTEX_INDEX INT_VAR skip = door_pos numx = vertex_first adds = deleted_vertex STR_VAR type = door END LPF FC_UPDETE_AREA_OFFSETS INT_VAR num = deleted_vertex STR_VAR type = vertex END CLEAR_ARRAY vertex_open END //vertex_closed_X PATCH_IF ( VARIABLE_IS_SET $vertex_closed(0) AND ( $vertex_closed(0) >= 0 ) ) BEGIN READ_LONG patch_offset + 0x34 vertex_first READ_SHORT patch_offset + 0x32 vertex_cnt SET deleted_vertex = 0 - vertex_cnt READ_LONG 0x7c all_vertex_off READ_SHORT 0x80 all_vertex_cnt SET v_off = all_vertex_off + vertex_first * 0x004 SET num_v = 0 DELETE_BYTES v_off vertex_cnt * 0x004 SET x_bounding_left = 10000 SET x_bounding_top = 10000 SET x_bounding_right = 0 SET x_bounding_bottom = 0 FOR ( i = 0 ; i < 65535 ; ++i ) BEGIN PATCH_IF ( VARIABLE_IS_SET $vertex_closed(~%i%~) ) BEGIN SET v_num = $vertex_closed(~%i%~) INSERT_BYTES v_off + i * 0x004 0x004 WRITE_LONG v_off + i * 0x004 v_num LPF FC_GET_XY_COORDINATE INT_VAR num = v_num RET x1 y1 END PATCH_IF ( x_bounding_left > x1 ) BEGIN SET x_bounding_left = x1 END PATCH_IF ( x_bounding_top > y1 ) BEGIN SET x_bounding_top = y1 END PATCH_IF ( x_bounding_right < x1 ) BEGIN SET x_bounding_right = x1 END PATCH_IF ( x_bounding_bottom < y1 ) BEGIN SET x_bounding_bottom = y1 END SET deleted_vertex = deleted_vertex + 1 SET num_v = num_v + 1 END ELSE BEGIN SET i = 65535 END END WRITE_SHORT 0x80 all_vertex_cnt + deleted_vertex WRITE_SHORT patch_offset + 0x32 num_v WRITE_SHORT patch_offset + 0x40 x_bounding_left WRITE_SHORT patch_offset + 0x42 x_bounding_top WRITE_SHORT patch_offset + 0x44 x_bounding_right WRITE_SHORT patch_offset + 0x46 x_bounding_bottom READ_LONG patch_offset + 0x2c upd_vert_1 READ_LONG patch_offset + 0x48 upd_vert_2 READ_LONG patch_offset + 0x50 upd_vert_3 PATCH_IF ( upd_vert_1 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x2c upd_vert_1 + deleted_vertex END PATCH_IF ( upd_vert_2 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x48 upd_vert_2 + deleted_vertex END PATCH_IF ( upd_vert_3 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x50 upd_vert_3 + deleted_vertex END LPF FC_UPDATE_VERTEX_INDEX INT_VAR skip = door_pos numx = vertex_first adds = deleted_vertex STR_VAR type = door END LPF FC_UPDETE_AREA_OFFSETS INT_VAR num = deleted_vertex STR_VAR type = vertex END CLEAR_ARRAY vertex_closed END //impeded_open_X PATCH_IF ( VARIABLE_IS_SET $impeded_open(0) AND ( $impeded_open(0) >= 0 ) ) BEGIN READ_LONG patch_offset + 0x48 vertex_first READ_SHORT patch_offset + 0x4c vertex_cnt SET deleted_vertex = 0 - vertex_cnt READ_LONG 0x7c all_vertex_off READ_SHORT 0x80 all_vertex_cnt SET v_off = all_vertex_off + vertex_first * 0x004 SET num_v = 0 DELETE_BYTES v_off vertex_cnt * 0x004 FOR ( i = 0 ; i < 65535 ; ++i ) BEGIN PATCH_IF ( VARIABLE_IS_SET $impeded_open(~%i%~) ) BEGIN SET v_num = $impeded_open(~%i%~) INSERT_BYTES v_off + i * 0x004 0x004 WRITE_LONG v_off + i * 0x004 v_num SET deleted_vertex = deleted_vertex + 1 SET num_v = num_v + 1 END ELSE BEGIN SET i = 65535 END END WRITE_SHORT 0x80 all_vertex_cnt + deleted_vertex WRITE_SHORT patch_offset + 0x4c num_v READ_LONG patch_offset + 0x2c upd_vert_1 READ_LONG patch_offset + 0x34 upd_vert_2 READ_LONG patch_offset + 0x50 upd_vert_3 PATCH_IF ( upd_vert_1 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x2c upd_vert_1 + deleted_vertex END PATCH_IF ( upd_vert_2 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x34 upd_vert_2 + deleted_vertex END PATCH_IF ( upd_vert_3 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x50 upd_vert_3 + deleted_vertex END LPF FC_UPDATE_VERTEX_INDEX INT_VAR skip = door_pos numx = vertex_first adds = deleted_vertex STR_VAR type = door END LPF FC_UPDETE_AREA_OFFSETS INT_VAR num = deleted_vertex STR_VAR type = vertex END CLEAR_ARRAY impeded_open END //impeded_closed_X PATCH_IF ( VARIABLE_IS_SET $impeded_closed(0) AND ( $impeded_closed(0) >= 0 ) ) BEGIN READ_LONG patch_offset + 0x50 vertex_first READ_SHORT patch_offset + 0x4e vertex_cnt SET deleted_vertex = 0 - vertex_cnt READ_LONG 0x7c all_vertex_off READ_SHORT 0x80 all_vertex_cnt SET v_off = all_vertex_off + vertex_first * 0x004 SET num_v = 0 DELETE_BYTES v_off vertex_cnt * 0x004 FOR ( i = 0 ; i < 65535 ; ++i ) BEGIN PATCH_IF ( VARIABLE_IS_SET $impeded_closed(~%i%~) ) BEGIN SET v_num = $impeded_closed(~%i%~) INSERT_BYTES v_off + i * 0x004 0x004 WRITE_LONG v_off + i * 0x004 v_num SET deleted_vertex = deleted_vertex + 1 SET num_v = num_v + 1 END ELSE BEGIN SET i = 65535 END END WRITE_SHORT 0x80 all_vertex_cnt + deleted_vertex WRITE_SHORT patch_offset + 0x4e num_v READ_LONG patch_offset + 0x2c upd_vert_1 READ_LONG patch_offset + 0x34 upd_vert_2 READ_LONG patch_offset + 0x48 upd_vert_3 PATCH_IF ( upd_vert_1 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x2c upd_vert_1 + deleted_vertex END PATCH_IF ( upd_vert_2 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x34 upd_vert_2 + deleted_vertex END PATCH_IF ( upd_vert_3 >= vertex_first ) BEGIN WRITE_LONG patch_offset + 0x48 upd_vert_3 + deleted_vertex END LPF FC_UPDATE_VERTEX_INDEX INT_VAR skip = door_pos numx = vertex_first adds = deleted_vertex STR_VAR type = door END LPF FC_UPDETE_AREA_OFFSETS INT_VAR num = deleted_vertex STR_VAR type = vertex END CLEAR_ARRAY impeded_closed END SET done = 1 END //BLOCKEND END //BLOCKEND //BLOCK FC_EDIT_AREA_REGION DEFINE_PATCH_FUNCTION FC_EDIT_AREA_REGION INT_VAR region_type = "-1" trigger_value = "-1" cursor_idx = "-1" flags = "-1" info_text = 99999999 trap_detect_dif = "-1" trap_remove_dif = "-1" is_trapped = "-1" is_trap_detect = "-1" launch_x = "-1" launch_y = "-1" alt_point_x = "-1" alt_point_y = "-1" //vertex_X vertex_0 = "-1" STR_VAR match_name = "same" match_key = "same" match_script = "same" name = "same" dest_area = "same" entrance = "same" key = "same" script = "same" RET done BEGIN //BLOCK SET done = 0 SET match = 0 READ_SHORT 0x05a ~d_cnt~ READ_LONG 0x05c ~d_off~ PATCH_IF ( region_type > 2 ) BEGIN SET region_type = 1 END PATCH_IF ( is_trapped > 1 ) BEGIN SET is_trapped = 1 END PATCH_IF ( is_trap_detect > 1 ) BEGIN SET is_trap_detect = 1 END PATCH_IF ( d_cnt > 0 ) BEGIN FOR ( i = 0 ; i < d_cnt ; ++i ) BEGIN SET offset = d_off + i * 0xc4 PATCH_IF ( ~%match_name%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset d_name (32) NULL PATCH_IF ( ~%match_name%~ STR_EQ ~%d_name%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF ( ~%match_key%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset + 0x74 d_key (8) NULL PATCH_IF ( ~%match_key%~ STR_EQ ~%d_key%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF ( ~%match_script%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset + 0x7c d_scr (8) NULL PATCH_IF ( ~%match_script%~ STR_EQ ~%d_scr%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF (match) BEGIN SET door_pos = i SET i = d_cnt SET patch_offset = offset END END END PATCH_IF (match) BEGIN PATCH_IF ( ~%name%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset ~%name%~ (32) END PATCH_IF ( ~%region_type%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x20 ~%region_type%~ END PATCH_IF ( ~%trigger_value%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x30 ~%trigger_value%~ END PATCH_IF ( ~%cursor_idx%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x34 ~%cursor_idx%~ END PATCH_IF ( ~%dest_area%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x38 ~%dest_area%~ (8) END PATCH_IF ( ~%entrance%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x40 ~%entrance%~ (32) END PATCH_IF ( ~%flags%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x60 ~%flags%~ END PATCH_IF ( ~%info_text%~ != 99999999 ) BEGIN WRITE_LONG patch_offset + 0x64 ~%info_text%~ END PATCH_IF ( ~%trap_detect_dif%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x68 ~%trap_detect_dif%~ END PATCH_IF ( ~%trap_remove_dif%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x6a ~%trap_remove_dif%~ END PATCH_IF ( ~%is_trapped%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x6c ~%is_trapped%~ END PATCH_IF ( ~%is_trap_detect%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x6e ~%is_trap_detect%~ END PATCH_IF ( ~%launch_x%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x70 ~%launch_x%~ END PATCH_IF ( ~%launch_y%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x72 ~%launch_y%~ END PATCH_IF ( ~%key%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x74 ~%key%~ (8) END PATCH_IF ( ~%script%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x7c ~%script%~ (8) END PATCH_IF ( ~%alt_point_x%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x84 ~%alt_point_x%~ END PATCH_IF ( ~%alt_point_y%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x86 ~%alt_point_y%~ END PATCH_IF ( VARIABLE_IS_SET $vertex(0) AND ( $vertex(0) >= 0 ) ) BEGIN READ_SHORT patch_offset + 0x2a vertex_cnt READ_LONG patch_offset + 0x2c vertex_first SET deleted_vertex = 0 - vertex_cnt READ_LONG 0x7c all_vertex_off READ_SHORT 0x80 all_vertex_cnt SET v_off = all_vertex_off + vertex_first * 0x004 SET num_v = 0 DELETE_BYTES v_off vertex_cnt * 0x004 SET x_bounding_left = 10000 SET x_bounding_top = 10000 SET x_bounding_right = 0 SET x_bounding_bottom = 0 FOR ( i = 0 ; i < 65535 ; ++i ) BEGIN PATCH_IF ( VARIABLE_IS_SET $vertex(~%i%~) ) BEGIN SET v_num = $vertex(~%i%~) INSERT_BYTES v_off + i * 0x004 0x004 WRITE_LONG v_off + i * 0x004 v_num LPF FC_GET_XY_COORDINATE INT_VAR num = v_num RET x1 y1 END PATCH_IF ( x_bounding_left > x1 ) BEGIN SET x_bounding_left = x1 END PATCH_IF ( x_bounding_top > y1 ) BEGIN SET x_bounding_top = y1 END PATCH_IF ( x_bounding_right < x1 ) BEGIN SET x_bounding_right = x1 END PATCH_IF ( x_bounding_bottom < y1 ) BEGIN SET x_bounding_bottom = y1 END SET deleted_vertex = deleted_vertex + 1 SET num_v = num_v + 1 END ELSE BEGIN SET i = 65535 END END WRITE_SHORT 0x80 all_vertex_cnt + deleted_vertex WRITE_SHORT patch_offset + 0x2a num_v WRITE_SHORT patch_offset + 0x22 x_bounding_left WRITE_SHORT patch_offset + 0x24 x_bounding_top WRITE_SHORT patch_offset + 0x26 x_bounding_right WRITE_SHORT patch_offset + 0x28 x_bounding_bottom LPF FC_UPDATE_VERTEX_INDEX INT_VAR skip = door_pos numx = vertex_first adds = deleted_vertex STR_VAR type = trigger END LPF FC_UPDETE_AREA_OFFSETS INT_VAR num = deleted_vertex STR_VAR type = vertex END CLEAR_ARRAY vertex END SET done = 1 END //BLOCKEND END //BLOCKEND //BLOCK FC_EDIT_AREA_CONTAINER DEFINE_PATCH_FUNCTION FC_EDIT_AREA_CONTAINER INT_VAR loc_x = "-1" loc_y = "-1" type = "-1" lock_diff = "-1" flags = "-1" trap_detect_dif = "-1" trap_remove_dif = "-1" is_trapped = "-1" is_trap_detect = "-1" launch_x = "-1" launch_y = "-1" active_range = "-1" break_diff = "-1" lpick_text = 99999999 //vertex_X vertex_0 = "-1" STR_VAR match_name = "same" match_key = "same" match_script = "same" match_owner = "same" name = "same" script = "same" owner = "same" key = "same" RET done BEGIN //BLOCK SET done = 0 SET match = 0 READ_SHORT 0x074 ~d_cnt~ READ_LONG 0x070 ~d_off~ PATCH_IF ( type > 12 ) BEGIN SET type = 4 END PATCH_IF ( is_trapped > 1 ) BEGIN SET is_trapped = 1 END PATCH_IF ( is_trap_detect > 1 ) BEGIN SET is_trap_detect = 1 END /* */ PATCH_IF ( d_cnt > 0 ) BEGIN FOR ( i = 0 ; i < d_cnt ; ++i ) BEGIN SET offset = d_off + i * 0xc0 PATCH_IF ( ~%match_name%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset d_name (32) NULL PATCH_IF ( ~%match_name%~ STR_EQ ~%d_name%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF ( ~%match_key%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset + 0x78 d_key (8) NULL PATCH_IF ( ~%match_key%~ STR_EQ ~%d_key%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF ( ~%match_script%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset + 0x48 d_scr (8) NULL PATCH_IF ( ~%match_script%~ STR_EQ ~%d_scr%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF ( ~%match_owner%~ STR_CMP ~same~ ) BEGIN READ_ASCII offset + 0x58 d_owner (32) NULL PATCH_IF ( ~%match_owner%~ STR_EQ ~%d_owner%~ ) BEGIN SET match = 1 END ELSE BEGIN SET match = 0 END END PATCH_IF (match) BEGIN SET door_pos = i SET i = d_cnt SET patch_offset = offset END END END PATCH_IF (match) BEGIN PATCH_IF ( ~%name%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset ~%name%~ (32) END PATCH_IF ( ~%loc_x%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x20 ~%loc_x%~ END PATCH_IF ( ~%loc_y%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x22 ~%loc_y%~ END PATCH_IF ( ~%type%~ >= 1 ) BEGIN WRITE_SHORT patch_offset + 0x24 ~%type%~ END PATCH_IF ( ~%lock_diff%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x26 ~%lock_diff%~ END PATCH_IF ( ~%flags%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x28 ~%flags%~ END PATCH_IF ( ~%trap_detect_dif%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x2c ~%trap_detect_dif%~ END PATCH_IF ( ~%trap_remove_dif%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x2e ~%trap_remove_dif%~ END PATCH_IF ( ~%is_trapped%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x30 ~%is_trapped%~ END PATCH_IF ( ~%is_trap_detect%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x32 ~%is_trap_detect%~ END PATCH_IF ( ~%launch_x%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x34 ~%launch_x%~ END PATCH_IF ( ~%launch_y%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x36 ~%launch_y%~ END PATCH_IF ( ~%script%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x48 ~%script%~ (8) END PATCH_IF ( ~%active_range%~ >= 0 ) BEGIN WRITE_SHORT patch_offset + 0x56 ~%active_range%~ END PATCH_IF ( ~%owner%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x58 ~%owner%~ (32) END PATCH_IF ( ~%key%~ STR_CMP ~same~ ) BEGIN WRITE_ASCIIE patch_offset + 0x78 ~%key%~ (8) END PATCH_IF ( ~%break_diff%~ >= 0 ) BEGIN WRITE_LONG patch_offset + 0x80 ~%break_diff%~ END PATCH_IF ( ~%lpick_text%~ != 99999999 ) BEGIN WRITE_LONG patch_offset + 0x84 ~%lpick_text%~ END PATCH_IF ( VARIABLE_IS_SET $vertex(0) AND ( $vertex(0) >= 0 ) ) BEGIN READ_SHORT patch_offset + 0x54 vertex_cnt READ_LONG patch_offset + 0x50 vertex_first SET deleted_vertex = 0 - vertex_cnt READ_LONG 0x7c all_vertex_off READ_SHORT 0x80 all_vertex_cnt SET v_off = all_vertex_off + vertex_first * 0x004 SET num_v = 0 DELETE_BYTES v_off vertex_cnt * 0x004 SET x_bounding_left = 10000 SET x_bounding_top = 10000 SET x_bounding_right = 0 SET x_bounding_bottom = 0 FOR ( i = 0 ; i < 65535 ; ++i ) BEGIN PATCH_IF ( VARIABLE_IS_SET $vertex(~%i%~) ) BEGIN SET v_num = $vertex(~%i%~) INSERT_BYTES v_off + i * 0x004 0x004 WRITE_LONG v_off + i * 0x004 v_num LPF FC_GET_XY_COORDINATE INT_VAR num = v_num RET x1 y1 END PATCH_IF ( x_bounding_left > x1 ) BEGIN SET x_bounding_left = x1 END PATCH_IF ( x_bounding_top > y1 ) BEGIN SET x_bounding_top = y1 END PATCH_IF ( x_bounding_right < x1 ) BEGIN SET x_bounding_right = x1 END PATCH_IF ( x_bounding_bottom < y1 ) BEGIN SET x_bounding_bottom = y1 END SET deleted_vertex = deleted_vertex + 1 SET num_v = num_v + 1 END ELSE BEGIN SET i = 65535 END END WRITE_SHORT 0x80 all_vertex_cnt + deleted_vertex WRITE_SHORT patch_offset + 0x54 num_v WRITE_SHORT patch_offset + 0x38 x_bounding_left WRITE_SHORT patch_offset + 0x3a x_bounding_top WRITE_SHORT patch_offset + 0x3c x_bounding_right WRITE_SHORT patch_offset + 0x3e x_bounding_bottom LPF FC_UPDATE_VERTEX_INDEX INT_VAR skip = door_pos numx = vertex_first adds = deleted_vertex STR_VAR type = container END LPF FC_UPDETE_AREA_OFFSETS INT_VAR num = deleted_vertex STR_VAR type = vertex END CLEAR_ARRAY vertex END SET done = 1 END //BLOCKEND END //BLOCKEND Quote Link to comment
jastey Posted August 7, 2021 Share Posted August 7, 2021 I'll post this here although it's from @argent77. This is for "finding the correct original game reply option number of a certain state number if knowing the stringref number of that reply option". It's interesting if you want to add a trigger to specific reply options but want to prevent patching the wrong one because another mod before yours added reply options via EXTEND_TOP. The output is one number per dialogue state. If several reply options for one dialogue state should be found I think this needs to be expanded or called twice. This is the function, the file is called "get_respone_sstrrefs.tph": // 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 This is how it is used inside the mod. I put this into a tpa that can be INCLUDEd into the tp2. The example searches for two reply options in two different dialogue states (no. 39 and 70) of aran.dlg. It's one reply option per dialogue state, but since it's two different states this can be done in one go. (The example uses it to add a trigger to the reply option, but it could as well be used to add a transaction): Spoiler <<<<<<<< .../inlined/i4e_aran.d /* Aran */ /* #43058 ~Then it is a simple matter of retrieveing Imoen from this place.~ */ ADD_TRANS_TRIGGER ARAN 39 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %responses_39% //0 /* #49175 ~Because of this I lost significantly more. Imoen remains missing.~ */ ADD_TRANS_TRIGGER ARAN 70 ~Global("C#IM_ImoenStays","GLOBAL",0)~ DO %responses_70% //2 >>>>>>>> // List of all potential response strrefs to check ACTION_DEFINE_ASSOCIATIVE_ARRAY response_strrefs BEGIN 43058 => 1 49175 => 1 END COPY_EXISTING ~aran.dlg~ ~override~ // scanning listed dialog states PATCH_FOR_EACH state IN 39 70 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 // prevent adding a trigger if index list is empty PATCH_IF (~%indices%~ STR_EQ ~~) BEGIN TEXT_SPRINT indices "IF ~False()~" 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_70 // are now initialized and can be used in the .d file COMPILE EVAL ~.../inlined/i4e_aran.d~ Quote Link to comment
argent77 Posted August 24, 2021 Share Posted August 24, 2021 Following up on jastey's description of the GET_RESPONSE_STRREFS function above, this is a more powerful version that returns not only response strrefs but also the remaining response elements such as flags, journal entries, triggers, actions and the next dialog state. Definition of patch function GET_DLG_RESPONSES: Spoiler /** * A patch function that returns all responses for a given state as an array. * INT_VAR state The desired dialog state. * RET responses Number of entries in the response array. * RET_ARRAY responses The response array as indexed array. It provides the following * response elements via additional keywords: * flags: Response flags as integer * text: Strref of the response text (-1 if not available) * journal: Strref of the journal text (-1 if not available) * trigger: The response trigger as a string (empty string if not available) * action: The response action as a string (empty string if not available) * next_dlg: The DLG resref containing the next state in the conversation. * next_state: Index of the next dialog state within the DLG resref specified by "next_dlg". * * Example: $response(~0~ ~text~) returns the text strref of the first response */ DEFINE_PATCH_FUNCTION GET_DLG_RESPONSES INT_VAR state = 0 RET responses RET_ARRAY responses BEGIN SET responses = 0 SET $responses(~0~) = 0 // workaround for WeiDU 246 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 0x10 num_responses READ_LONG 0x14 ofs_responses READ_LONG 0x20 ofs_response_triggers READ_LONG 0x24 num_response_triggers READ_LONG 0x28 ofs_actions READ_LONG 0x2c num_actions PATCH_IF (state >= 0 && state < num_states) BEGIN SET ofs_state = ofs_states + (state * 16) READ_LONG (ofs_state + 4) idx_first_response READ_LONG (ofs_state + 8) num_response FOR (response_idx = 0; response_idx < num_response && response_idx < num_responses; ++response_idx) BEGIN SET ofs_response = ofs_responses + (idx_first_response + response_idx) * 32 // response flags READ_LONG ofs_response flags SET $responses(~%responses%~ ~flags~) = flags // response text PATCH_IF (flags & BIT0) BEGIN SET $responses(~%responses%~ ~text~) = LONG_AT (ofs_response + 0x4) END ELSE BEGIN SET $responses(~%responses%~ ~text~) = "-1" END // journal text PATCH_IF (flags & (BIT4 | BIT6 | BIT7 | BIT8)) BEGIN SET $responses(~%responses%~ ~journal~) = LONG_AT (ofs_response + 0x8) END ELSE BEGIN SET $responses(~%responses%~ ~journal~) = "-1" END // trigger READ_LONG (ofs_response + 0xc) idx PATCH_IF ((flags & BIT1) && (idx >= 0 && idx < num_response_triggers)) BEGIN READ_LONG (ofs_response_triggers + idx * 8) ofs_trigger READ_LONG (ofs_response_triggers + idx * 8 + 4) len READ_ASCII ofs_trigger trigger (len) NULL INNER_PATCH_SAVE trigger ~%trigger%~ BEGIN REPLACE_TEXTUALLY ~[%WNL%]+~ ~ ~ END TEXT_SPRINT $responses(~%responses%~ ~trigger~) ~%trigger%~ END ELSE BEGIN TEXT_SPRINT $responses(~%responses%~ ~trigger~) ~~ END // action READ_LONG (ofs_response + 0x10) idx PATCH_IF ((flags & BIT2) && (idx >= 0 && idx < num_actions)) BEGIN READ_LONG (ofs_actions + idx * 8) ofs_action READ_LONG (ofs_actions + idx * 8 + 4) len READ_ASCII ofs_action action (len) NULL INNER_PATCH_SAVE action ~%action%~ BEGIN REPLACE_TEXTUALLY ~[%WNL%]+~ ~ ~ END TEXT_SPRINT $responses(~%responses%~ ~action~) ~%action%~ END ELSE BEGIN TEXT_SPRINT $responses(~%responses%~ ~action~) ~~ END // next state PATCH_IF (flags & BIT3) BEGIN TEXT_SPRINT $responses(~%responses%~ ~next_dlg~) ~~ SET $responses(~%responses%~ ~next_state~) = "-1" END ELSE BEGIN READ_ASCII (ofs_response + 0x14) next_dlg (8) NULL TEXT_SPRINT $responses(~%responses%~ ~next_dlg~) ~%next_dlg%~ SET $responses(~%responses%~ ~next_state~) = LONG_AT (ofs_response + 0x1c) END SET responses += 1 END END END END Example code that prints information of a dialog state to the console (from SoD file BDEDWIN.DLG): Spoiler // Printing all responses of BDEDWIN.DLG, state 46 COPY_EXISTING ~BDEDWIN.DLG~ ~override~ LPF GET_DLG_RESPONSES INT_VAR state = 46 RET responses RET_ARRAY responses END FOR (i = 0; i < responses; ++i) BEGIN TEXT_SPRINT line ~Response: %i%%WNL%~ // Response flags as hex number SPRINTF hex ~%x~ ( $responses(~%i%~ ~flags~) ) TEXT_SPRINT line ~%line% Flags: %hex%%WNL%~ // Response text strref SET value = $responses(~%i%~ ~text~) TEXT_SPRINT line ~%line% Text strref: %value%%WNL%~ // Response journal strref SET value = $responses(~%i%~ ~journal~) TEXT_SPRINT line ~%line% Journal strref: %value%%WNL%~ // Response trigger TEXT_SPRINT text $responses(~%i%~ ~trigger~) TEXT_SPRINT line ~%line% Trigger: %text%%WNL%~ // Response action block TEXT_SPRINT text $responses(~%i%~ ~action~) TEXT_SPRINT line ~%line% Action: %text%%WNL%~ // Reference to next dialog state TEXT_SPRINT text $responses(~%i%~ ~next_dlg~) SET value = $responses(~%i%~ ~next_state~) TEXT_SPRINT line ~%line% Next dialog state: %value% (%text%)%WNL%~ // Output everything to console PATCH_PRINT ~%line%~ END BUT_ONLY Quote Link to comment
jastey Posted August 26, 2021 Share Posted August 26, 2021 @argent77 this looks very powerful, thank you for the expansion of the function. Unfortunately, I do not know how to acually use it. My current problem: I want to patch a mod added reply option. I know how to get the dialogue state (using STATE_WHICH_SAYS), but is it possible with your function to get the transNumber, i.e. the number of the reply option / transaction - could be more than one with the same string - if it's mod added, i.e. the Strref of the reply option as used in the first version of the function is not known (but the mod's string could be called from a tra like it is done for STATE_WHICH_SAYS)? (Or is there a way to determine the stringref-number from mod added strings I'm not aware of?) If yes, I'd need an example for dummies how to do it and thank you in advance for your expetise. Quote Link to comment
argent77 Posted August 26, 2021 Share Posted August 26, 2021 2 hours ago, jastey said: My current problem: I want to patch a mod added reply option. I know how to get the dialogue state (using STATE_WHICH_SAYS), but is it possible with your function to get the transNumber, i.e. the number of the reply option / transaction - could be more than one with the same string - if it's mod added, i.e. the Strref of the reply option as used in the first version of the function is not known (but the mod's string could be called from a tra like it is done for STATE_WHICH_SAYS)? (Or is there a way to determine the stringref-number from mod added strings I'm not aware of?) Usage is exactly like GET_RESPONSE_STRREFS except that you specify a second array parameter ("text") for accessing the response strref. Afaik WeiDU always returns the same strref for identical strings. For example if tra reference @1234 is used to add a new transition to a dialog then RESOLVE_STR_REF(@1234) should return the same strref that can be used to find the response later on. This contrived example adds a response trigger to selected transitions of Jaheira's BG2 dialog. Spoiler // The dialog patching code with variable placeholders <<<<<<<< .../inlined/jaheira_mod.d ADD_TRANS_TRIGGER ~JAHEIRA~ %state% ~True()~ DO %transitions% UNLESS ~True()~ >>>>>>>> // Finding the right state OUTER_SET state = STATE_WHICH_SAYS #1021 FROM ~JAHEIRA~ ACTION_IF (state >= 0) BEGIN OUTER_TEXT_SPRINT transitions ~~ COPY_EXISTING ~jaheira.dlg~ ~override~ // Example responses to patch SET strref1 = 1022 SET strref2 = 1023 // might as well replace with a resolved tra reference LPF GET_DLG_RESPONSES INT_VAR state RET responses RET_ARRAY responses END // Traversing available responses FOR (i = 0; i < responses; ++i) BEGIN PATCH_MATCH $responses(~%i%~ ~text~) WITH strref1 strref2 BEGIN // Match found! TEXT_SPRINT transitions ~%transitions% %i%~ END DEFAULT END END BUT_ONLY // No need to patch if no matching transitions were found ACTION_IF (NOT ~%transitions%~ STR_EQ ~~) BEGIN COMPILE EVAL ~.../inlined/jaheira_mod.d~ END END Quote Link to comment
jastey Posted August 26, 2021 Share Posted August 26, 2021 @argent77 thank you vry much for the example! 10 hours ago, argent77 said: SET strref2 = 1023 // might as well replace with a resolved tra reference Could you or someone else give an example how I would use RESOLVE_STR_REF here, especially if it's supposed to use a line from another mod. Would it be something like this? RESOLVE_STR_REF(@107) USING ~modname/translations/%s/blabla.tra~ 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.