Jump to content

Toss your semi-useful WeiDU macros here


Recommended Posts

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 by subtledoctor
Link to comment
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.

Link to comment

@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 by Luke
Link to comment
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).

Link to comment

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 by K4thos
Link to comment

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

 

 

Link to comment

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~

 

 

 

Link to comment

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

 

 

Link to comment

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

 

Link to comment
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

 

 

Link to comment

@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~

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