Jump to content


Photo

Area Modding Tool & Tutorial by Qwinn


  • Please log in to reply
164 replies to this topic

#1 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 25 April 2008 - 12:47 PM

Just spent a lot of time writing these macros to help my own coding for the upcoming PS:T Fixpack and Unfinished Business, and I figured I'd share. I have modified several files with them.

One macro provides a lot of the offsets and stuff you generally need to look up in NI or IESDP and provides their values for you in consistently named variables for your use.

Another two macros will redo all the offsets and counters for you when adding any combination of new sections to a .ARE file with very very little work on your part.

Feel free to cut and paste this entire file and use it as an include in your programs. The comments within the file explain what it does and how it works.

Keep an eye here, because I hope to be adding a couple of macros that will allow you to edit the vertexes in an existing door, container or trigger, or add items to an existing container, hopefully within a day or two after I've worked the kinks out.

Enjoy!

EDIT: 05/28/09. Significant update. Now updated to work with any IE game, hopefully... only tested for PS:T, but now takes into account fields used by other IE games like Map Notes and Projectile Traps (exclusive to BG2). If you're using it for a game other than PS:T, make sure to adjust the value of the variable "Q_Game" set in the first macro, Q_AREInitVars.

Also note, these macros will not work with IWD2, the area file is significantly different.

EDIT 2: 05/30/09: Attached a downloadable version of these macros at the end of this post, to save the trouble of cutting and pasting.

EDIT 3: 06/01/09: Tweaked to account for adding to empty sections sharing the same offset with a non-empty section.

EDIT 4: 06/11/09: Added Sasha's GAME_IS logic to replace manual SET Q_Game, thanks to Sasha.

// ======================= BEGIN Q_ARE_InitVars Macro Definition =========================

DEFINE_PATCH_MACRO ~Q_ARE_InitVars~ BEGIN

PATCH_IF (GAME_IS ~PST~) BEGIN //only pst games
SET Q_Game = 1
END
PATCH_IF (GAME_IS ~soa tob bgt tutu tutu_totsc~) BEGIN //all bg2 engine games
SET Q_Game = 2
END
PATCH_IF !(GAME_IS ~PST soa tob bgt tutu tutu_totsc IWD2~) BEGIN //any other ie game but pst, bg2 variants and iwd2
SET Q_Game = 3
END

// WEIDU AREA MAPPING TOOL #1, by Qwinn

// This macro initializes variables to be used by the other WAMT macros.  They are also highly useful
// for the coder him/herself to use, and even if none of the other macros are installed or used,
// inserting the include in order to use this macro can save a lot of referring back and forth
// to NI and IESDP.

// OVERVIEW/TUTORIAL ON THE AREA FILE

// An Area file is comprised of 1 main section and 15 subsections. The main section contains
// basic information about the area, and also stores information about each of the 15 subsections.
// Each of the subsections can hold a varying number of records, and thus the main section stores
// offsets and counts which are used to map the rest of file.
//
// The 15 subsections are referred to in these tools with the following 5 letter codes:
//
// "Actor"  =  Actors
// "Trigg"  =  Info Triggers
// "Spawn"  =  Spawn Points
// "Entra"  =  Entrances
// "Conta"  =  Containers
// "Items"  =  Items
// "Ambie"  =  Ambients
// "Varia"  =  Variables - not used in PS:T
// "Doors"  =  Doors
// "Tiled"  =  Tiled Objects - not used in PS:T
// "Vertx"  =  Vertexes
// "Explo"  =  Explored Bitmap - not used in PS:T.  no count, offset only
// "Anima"  =  Animations
// "Songs"  =  Songs - no count, offset only
// "RestS"  =  Rest Spawns - no count, offset only
// "MapNo"  =  Map Notes - not used in PS:T
// "ProTr"  =  Projectile Traps - BG2 only

// This macro sets up variables pointing to all the useful information about each subsection.
// To use those variables, use these variable names, replacing the XXXXX with the code above
// for the section you want to work with:

// SHORT DESCRIPTION OF STATIC VARIABLES:

// Q_Siz_XXXXX = Size of the description of XXXXX in any area file.  Constant.
// Q_Num_XXXXX = Count of XXXXX records in current area file.  Varies.
// Q_SoL_XXXXX = Whether the Q_Num_XXXXX field is a Short or Long.  2 = short, 4 = long.   Needed for the WRITE.
// Q_OoN_XXXXX = Offset where value in Q_Num_XXXXX is stored in any area file.  Constant.
// Q_Off_XXXXX = Offset where records of type XXXXX start in current area file.  Varies.
// Q_OoO_XXXXX = Offset of the offset - where value in Q_Off_XXXXX is stored in any area file.  Constant.

// LONG DESCRIPTION OF STATIC VARIABLES:

// Q_Siz_XXXXX = the size, in bytes, of one instance of section XXXXX in any area file.
// For example, Q_Siz_Items has the value 0x14, which is hexidecimal for 20 bytes, the
// size of one Item record.  I got these values from referring to both Near Infinity and
// IESDP.  These values are constant for any area file.

// Q_Num_XXXXX = the count of how many XXXXX records are in this area.  For example, Q_Num_Doors
// is the number of Doors set up in this area.  These values depend on the .ARE you're editing.

// Q_SoL_XXXXX = whether the Count field of a given section is a short or long.  It varies.  Unfortunately.
// 2 = short, 4 = long.

// Q_OoN_XXXXX = the offset where the previous value, Q_Num_XXXXX, is stored in the main section
// of any area file. (OoN = Offset Of Number).  For example, if you do READ_SHORT "Q_OoN_Conta"
// "NumOfContainers", your NumOfContainers variable will get the same value as Q_Num_Conta.  Why
// store the offsets if I already have the values stored in variables?   So I know where to
// write back to when I need to at the end of my editing.  These values are the same for any
// area file.

// Q_Off_XXXXX = the offset, from the beginning of the file, where records of the subsection in
// question start being stored in this particular area file.  These values depend on the area
// you're editing.

// Q_OoO_XXXXX = the offset where the previous value, Q_Off_XXXXX, is stored in the main section
// of any area file. (OoO = Offset Of Offset).  For example, if you do READ_LONG "Q_OoO_Conta"
// "FirstContainerDescriptionInTheFileStartsHere", that variable will get the same value as
// Q_OffConta.  Why store the offsets of the offset?  Because I may have to write to that offset,
// as adding to sections earlier in the file will require a change to the position/offset of
// subsections deeper into the file.  These values are constant for any area file.

// If you want instructions on how to use the tool to have it remap an area file for you,
// see the other macro sections.

// ============================== STATIC VARIABLES  ===========================

// Size of one instance of each type of record

SET "Q_Siz_Actor" = 0x110  // Size of Actor Section
SET "Q_Siz_Trigg" = 0xc4   // Size of Trigger Section
SET "Q_Siz_Spawn" = 0xc8   // Size of Spawn Points Section
SET "Q_Siz_Entra" = 0x68   // Size of Entrances Section
SET "Q_Siz_Conta" = 0xc0   // Size of Containers Section
SET "Q_Siz_Items" = 0x14   // Size of Items Section
SET "Q_Siz_Ambie" = 0xd4   // Size of Ambients Section
SET "Q_Siz_Varia" = 0x54   // Size of Variables Section - not used in PS:T
SET "Q_Siz_Doors" = 0xc8   // Size of Doors Section
SET "Q_Siz_Tiled" = 0x6c   // Size of Tiled Objects Section 0 - not used in PS:T
SET "Q_Siz_Vertx" = 0x4	// Size of Vertexes Section - size of one set of X, Y coordinates
SET "Q_Siz_Explo" = 0x0	// Size of Explored Bitmap Section - not applicable
SET "Q_Siz_Anima" = 0x4c   // Size of Animations Section
SET "Q_Siz_Songs" = 0x90   // Size of Songs Section
SET "Q_Siz_RestS" = 0xe4   // Size of Rest Spawn Section
SET "Q_Siz_MapNo" = 0x34  // Size of Map Notes Section - not used in PS:T
SET "Q_Siz_ProTr" = 0x1A  // Size of Projectile Traps Section - only used in BG2?

// Sets the offsets where count of each type of record is stored in any area file

SET "Q_OoN_Actor" = 0x58 // Offset of Number Of Actors
SET "Q_OoN_Trigg" = 0x5a // Offset of Number Of Trigger
SET "Q_OoN_Spawn" = 0x64 // Offset of Number Of Spawn Points
SET "Q_OoN_Entra" = 0x6c // Offset of Number Of Entrances
SET "Q_OoN_Conta" = 0x74 // Offset of Number Of Containers
SET "Q_OoN_Items" = 0x76 // Offset of Number Of Items
SET "Q_OoN_Ambie" = 0x82 // Offset of Number Of Ambients
SET "Q_OoN_Varia" = 0x8c // Offset of Number Of Variables
SET "Q_OoN_Doors" = 0xa4 // Offset of Number Of Doors
SET "Q_OoN_Tiled" = 0xb4 // Offset of Number Of Tiled Objects
SET "Q_OoN_Vertx" = 0x80 // Offset of Number Of Vertexes
SET "Q_OoN_Explo" = 0x0 // Offset of Number Of Explored Bitmap - not applicable
SET "Q_OoN_Anima" = 0xac // Offset of Number Of Animations
SET "Q_OoN_Songs" = 0x0 // Offset of Number Of Songs - not applicable
SET "Q_OoN_RestS" = 0x0 // Offset of Number Of Rest Spawn - not applicable
PATCH_IF "Q_Game" = 1 THEN BEGIN SET "Q_OoN_MapNo" = 0xcc // Offset of Number of Map Notes in PS:T
			  END ELSE BEGIN SET "Q_OoN_MapNo" = 0xc8 // Offset of Number of Map Notes in all other IE games
END
PATCH_IF "Q_Game" = 2 THEN BEGIN SET "Q_OoN_ProTr" = 0xcc  // Offset of Number of Projectile Traps in BG2
			  END ELSE BEGIN SET "Q_OoN_ProTr" = 0	  //  Not Applicable
END

// Using those offsets, load the actual count of each type
// of record from the area file currently loaded.

READ_SHORT "Q_OoN_Actor" "Q_Num_Actor"  // Number of Actors
READ_SHORT "Q_OoN_Trigg" "Q_Num_Trigg"  // Number of Triggers
READ_LONG  "Q_OoN_Spawn" "Q_Num_Spawn"  // Number of Spawn Points
READ_LONG  "Q_OoN_Entra" "Q_Num_Entra"  // Number of Entrances
READ_SHORT "Q_OoN_Conta" "Q_Num_Conta"  // Number of Containers
READ_SHORT "Q_OoN_Items" "Q_Num_Items"  // Number of Items
READ_SHORT "Q_OoN_Ambie" "Q_Num_Ambie"  // Number of Ambients
READ_LONG  "Q_OoN_Varia" "Q_Num_Varia"  // Number of Variables
READ_LONG  "Q_OoN_Doors" "Q_Num_Doors"  // Number of Doors
READ_LONG  "Q_OoN_Tiled" "Q_Num_Tiled"  // Number of Tiled Objects
READ_SHORT "Q_OoN_Vertx" "Q_Num_Vertx"  // Number of Vertexes
SET "Q_Num_Explo" = 1  // Only 1 Explored Bitmap section per area.  This isn't really needed.
READ_LONG  "Q_OoN_Anima" "Q_Num_Anima"  // Number of Animations
SET "Q_Num_Songs" = 1  // Only 1 song section per area.  This isn't really needed.
SET "Q_Num_RestS" = 1 // Only 1 rest section per area.  This isn't really needed.
READ_LONG  "Q_OoN_MapNo" "Q_Num_MapNo"  // Number of Mapnotes
PATCH_IF "Q_Game" = 2 THEN BEGIN READ_LONG "Q_OoN_ProTr" "Q_Num_ProTr"  // Number of Projectile Traps in BG2
			  END ELSE BEGIN SET "Q_Num_ProTr" = 0	  //  Not Applicable
END


// Whether the "Number of" field is a long or a short field.  Long = 4, Short = 2
SET "Q_SoL_Actor" = 2
SET "Q_SoL_Trigg" = 2
SET "Q_SoL_Spawn" = 4
SET "Q_SoL_Entra" = 4
SET "Q_SoL_Conta" = 2
SET "Q_SoL_Items" = 2
SET "Q_SoL_Ambie" = 2
SET "Q_SoL_Varia" = 4
SET "Q_SoL_Doors" = 4
SET "Q_SoL_Tiled" = 4
SET "Q_SoL_Vertx" = 2
SET "Q_SoL_Explo" = 0	// Not applicable
SET "Q_SoL_Anima" = 4
SET "Q_SoL_Songs" = 0   //  Not applicable
SET "Q_SoL_RestS" = 0   // Not applicable
SET "Q_SoL_MapNo" = 4
SET "Q_SoL_ProTr" = 4

// The offsets at which each subsection's offset in any .ARE file is stored

SET "Q_OoO_Actor" = 0x54 // Offset of Actors Offset
SET "Q_OoO_Trigg" = 0x5c // Offset of Trigger Offset
SET "Q_OoO_Spawn" = 0x60 // Offset of Spawn Points Offset
SET "Q_OoO_Entra" = 0x68 // Offset of Entrances Offset
SET "Q_OoO_Conta" = 0x70 // Offset of Containers Offset
SET "Q_OoO_Items" = 0x78 // Offset of Items Offset
SET "Q_OoO_Ambie" = 0x84 // Offset of Ambients Offset
SET "Q_OoO_Varia" = 0x88 // Offset of Variables Offset
SET "Q_OoO_Doors" = 0xa8 // Offset of Doors Offset
SET "Q_OoO_Tiled" = 0xb8 // Offset of Tiled Objects Offset
SET "Q_OoO_Vertx" = 0x7c // Offset of Vertexes Offset
SET "Q_OoO_Explo" = 0xa0 // Offset of Explored Bitmap Offset
SET "Q_OoO_Anima" = 0xb0 // Offset of Animations Offset
SET "Q_OoO_Songs" = 0xbc // Offset of Songs Offset
SET "Q_OoO_RestS" = 0xc0 // Offset of Rest Spawn Offset
PATCH_IF "Q_Game" = 1 THEN BEGIN SET "Q_OoO_MapNo" = 0xc8 // Offset of Map Notes Offset in PS:T
				  END ELSE BEGIN SET "Q_OoO_MapNo" = 0xc4 // Offset of Map Notes Offset in all other IE games
END
PATCH_IF "Q_Game" = 2 THEN BEGIN SET "Q_OoO_ProTr" = 0xcc  // Offset of Projectile Traps section in BG2
		  END ELSE BEGIN SET "Q_OoO_ProTr" = 0 //  Not Applicable
END

// Using those offsets, load the actual offsets as they exist in this specific area file

READ_LONG "Q_OoO_Actor" "Q_Off_Actor"  // Actors Offset
READ_LONG "Q_OoO_Trigg" "Q_Off_Trigg"  // Trigger Offset
READ_LONG "Q_OoO_Spawn" "Q_Off_Spawn"  // Spawn Points Offset
READ_LONG "Q_OoO_Entra" "Q_Off_Entra"  // Entrances Offset
READ_LONG "Q_OoO_Conta" "Q_Off_Conta"  // Containers Offset
READ_LONG "Q_OoO_Items" "Q_Off_Items"  // Items Offset
READ_LONG "Q_OoO_Ambie" "Q_Off_Ambie"  // Ambients Offset
READ_LONG "Q_OoO_Varia" "Q_Off_Varia"  // Variables Offset
READ_LONG "Q_OoO_Doors" "Q_Off_Doors"  // Doors Offset
READ_LONG "Q_OoO_Tiled" "Q_Off_Tiled"  // Tiled Objects Offset
READ_LONG "Q_OoO_Vertx" "Q_Off_Vertx"  // Vertexes Offset
READ_LONG "Q_OoO_Explo" "Q_Off_Explo"  // Explored Bitmap Offset
READ_LONG "Q_OoO_Anima" "Q_Off_Anima"  // Animations Offset
READ_LONG "Q_OoO_Songs" "Q_Off_Songs"  // Songs Offset
READ_LONG "Q_OoO_RestS" "Q_Off_RestS"  // Rest Spawn Offset
READ_LONG "Q_OoO_MapNo" "Q_Off_MapNo" // Map Notes Offset
PATCH_IF "Q_Game" = 2 THEN BEGIN READ_LONG "Q_OoO_ProTr" "Q_Off_ProTr" // Projectile Trap Offset in BG2
		  END ELSE BEGIN SET "Q_Off_ProTr" = 0 //  Not Applicable.  Value of 0 will keep it from ever updating in inner S2 loop of Process macro.
END

END

// ====================== BEGIN Q_AREAdd_InitVars Macro Definition ========================

DEFINE_PATCH_MACRO ~Q_AREAdd_InitVars~
BEGIN

// Use this macro in conjunction with macro ~Q_AREAdd_Process~ if you are adding entirely
// new records to any of the subsections.  This macro will reset all of the offsets, indexes
// and counts in your .ARE record to match your additions with very little work on your
// part, as well as supply you with variables storing the offsets where you should start
// writing your new records.

// Best of all, it does so in a dynamic manner which should not interfere with any other
// mods that come before or after yours, always assuming they take similar care to be
// compatible with other mods, of course.

// Do NOT use this macro if you need to modify the vertexes in an existing trigger, door
// or container, or adding items to an existing container.  You CAN use it to add room for
// both new triggers/doors/containers and the new vertexes that go along with them.

// Another two macros, named Q_AREVertex_InitVars and Q_AREVertex_Process will be provided
// in the case that you need to modify the vertexes in an existing door/trigger/container.
// Another two macros, Q_AREItem_InitVars and Q_AREItem_Process will be provided if you need
// to add items to an existing container.

// INSTRUCTIONS FOR USE:

// All you need to do is include these macro definitions somewhere in your .tp2 (near the top,
// preferably.)  Then when ready to use them, use your COPY or COPY_EXISTING statement to grab the
// .ARE file you're working with, run -this- macro, like this:

// LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~

// ... then set your Q_New_XXXXX variables... what do you set your Q_NewXXXXX variable to?
// Just how many records of each type you want to add.  Say you need to add 3 actors,
// 2 containers (each containing 5 vertexes and 2 items), and two triggers (each containing
// 10 vertexes).  Here's all you need to do:

// SET Q_NewActor = 3
// SET Q_NewConta = 2
// SET Q_NewItems = 4
// SET Q_NewVertx = 30

// ... and then run the Q_AREAdd_Process macro, like this:

// LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

// That macro will insert bytes into each subsection in the file to accomodate the new records
// you want to add, and all offsets and counts will be updated for you.


// So, putting it all together, and assuming you included this file somewhere in your tp2,
// the whole process for prepping your file for the addition of 3 actors,
// 2 containers (each containing 5 vertexes and 2 items), and two triggers (each containing
// 10 vertexes), is this:

// LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
// SET Q_NewActor = 3
// SET Q_NewConta = 2
// SET Q_NewItems = 4
// SET Q_NewVertx = 30
// LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~


// That's it.  The right amount of bytes needed to write in your actors, containers,
// items and vertexes is now available in the file, with all the various offsets
// and counts updated to match.

// But how do you know where to actually write your records?  You can find the offset
// at which the new space was inserted at the variables Q_NewOffset_XXXXX, which the
// tool has filled in for you.

// It is recommended that you immediately start writing to the fields you want to write
// to.  In this example, you would start writing your new actors at Q_NewOffset_Actor,
// your new containers at Q_NewOffset_Conta, your new items at Q_NewOffset_Items
// and your new vertexes at Q_NewOffset_Vertx.

// If you plan to use this or any of the other macros included with the WAMT tool more,
// than once in your tp2, you should always rerun the _InitVars macro associated with
// the _Process macro you intend to use to clear any old values.  That's why I recommend
// immediately doing your writes, so that you don't forget and rerun this tool somewhere
// else, does wiping out all your NewOffset values telling you where you can write your
// new subsections.

// This macro will initialize all of the Q_New_XXXXX variables and the output variables
// (i.e. Q_NewOffset_XXXXX).

SET "Q_New_Actor" = 0 // Number of New Actors
SET "Q_New_Trigg" = 0 // Number of New Triggers
SET "Q_New_Spawn" = 0 // Number of New Spawn Points
SET "Q_New_Entra" = 0 // Number of New Entrances
SET "Q_New_Conta" = 0 // Number of New Containers
SET "Q_New_Items" = 0 // Number of New Items
SET "Q_New_Ambie" = 0 // Number of New Ambients
SET "Q_New_Varia" = 0 // Number of New Variables
SET "Q_New_Doors" = 0 // Number of New Doors
SET "Q_New_Tiled" = 0 // Number of New Tiled Objects
SET "Q_New_Vertx" = 0 // Number of New Vertexes
SET "Q_New_Anima" = 0 // Number of New Animations
SET "Q_New_MapNo" = 0 // Number of Map Notes
SET "Q_New_ProTr" = 0 // Number of Projectile Traps


// Initializing the variables that return the offset where the new areas have been created

SET "Q_NewOffset_Actor" = 0 // Begin writing your new actors here.
SET "Q_NewOffset_Trigg" = 0 // Begin writing your new triggers here.
SET "Q_NewOffset_Spawn" = 0 // Etc.
SET "Q_NewOffset_Entra" = 0
SET "Q_NewOffset_Conta" = 0
SET "Q_NewOffset_Items" = 0
SET "Q_NewOffset_Ambie" = 0
SET "Q_NewOffset_Varia" = 0
SET "Q_NewOffset_Doors" = 0
SET "Q_NewOffset_Tiled" = 0
SET "Q_NewOffset_Vertx" = 0
SET "Q_NewOffset_Anima" = 0
SET "Q_NewOffset_MapNo" = 0
SET "Q_NewOffset_ProTr" = 0

SET "Q_NewOffset_Explo" = 0  // These 3 cannot have new records created, but need variables to compile
SET "Q_NewOffset_Songs" = 0
SET "Q_NewOffset_RestS" = 0


SET "Q_ManualInsert" = 0  // If you want to handle the INSERT_BYTES (or DELETE_BYTES, potentially)
						  // by yourself, set this flag to 1

END

// ====================== END Q_AREAdd_InitVars Macro Definition ========================


// ===================== BEGIN Q_AREAdd_Process Macro Definition ========================

DEFINE_PATCH_MACRO ~Q_AREAdd_Process~
BEGIN

// DO NOT use this macro without first running Q_AREAdd_InitVars.
// Documentation for the use of this macro is contained within that macro definition.

PATCH_FOR_EACH "S1" IN
  ~Actor~ ~Trigg~ ~Spawn~ ~Entra~ ~Conta~ ~Items~ ~Ambie~ ~Varia~ ~Doors~
  ~Tiled~ ~Vertx~ ~Anima~ ~MapNo~ ~ProTr~
BEGIN
  SET "Q_NewSect" = $Q_New("%S1%") // How many new sections user has asked for
  PATCH_IF !("Q_NewSect" = 0) THEN
  BEGIN
	// WRITE_ASCII 0x33c ~%S1%~ #32 // DEBUG
	SET "Q_OoNSect" = $Q_OoN("%S1%") // Offset where count of each section is stored
	SET "Q_NumSect" = $Q_Num("%S1%") // Original count for that section
	SET "Q_SoLSect" = $Q_SoL("%S1%")  // Whether original count is stored as long or short
	SET "Q_OoOSect1" = $Q_OoO("%S1%") // Offset of offset for the section
	SET "Q_Offset1" = $Q_Off("%S1%") // Offset of the section being added to
	SET "Q_SizSect" = $Q_Siz("%S1%") // The size of one new section

	PATCH_FOR_EACH "S2" IN
	  ~Actor~ ~Trigg~ ~Spawn~ ~Entra~ ~Conta~ ~Items~ ~Ambie~ ~Varia~ ~Doors~
	  ~Tiled~ ~Vertx~ ~Explo~ ~Anima~ ~Songs~ ~RestS~ ~MapNo~ ~ProTr~
	BEGIN
	  // WRITE_ASCII 0x33c ~%S1% %S2%~ #32 // DEBUG
	  SET "Q_Offset2" = $Q_Off("%S2%") // Offset of each other section
	  SET "Q_OoOSect2" = $Q_OoO("%S2%") // Offset of that offset
	  SET "Q_OldInsert" = $Q_NewOffset("%S2%") // Previous insert offsets need to be updated too
	  PATCH_IF ("Q_Offset2" >= "Q_Offset1") AND NOT ("%S1%" STRING_EQUAL "%S2%") THEN
	  BEGIN
		WRITE_LONG "Q_OoOSect2" ("Q_Offset2" + ("Q_NewSect" * "Q_SizSect"))
	  END
	  PATCH_IF ("Q_OldInsert" >= "Q_Offset1") AND NOT ("%S1%" STRING_EQUAL "%S2%") THEN
	  BEGIN
		SET $Q_NewOffset("%S2%") = $Q_NewOffset("%S2%") + ("Q_NewSect" * "Q_SizSect")
	  END
	END
	SET $Q_NewOffset("%S1%") = "Q_Offset1" + ("Q_NumSect" * "Q_SizSect")
	SET "Q_InsertOffset" = $Q_NewOffset("%S1%")
	PATCH_IF "Q_ManualInsert" = 0 THEN
	BEGIN
	  INSERT_BYTES "Q_InsertOffset" ("Q_NewSect" * "Q_SizSect")
	END
		PATCH_IF "Q_SoLSect" = 2 THEN BEGIN WRITE_SHORT "Q_OoNSect" ("Q_NumSect" + "Q_NewSect") END
								 ELSE BEGIN WRITE_LONG  "Q_OoNSect" ("Q_NumSect" + "Q_NewSect") END
	LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~  // Reset all our variables to their new values
  END
END

END

// ====================== END Q_AREAdd_Process Macro Definition ========================




// ==================== BEGIN Q_AREVertex_InitVars Macro Definition ====================

DEFINE_PATCH_MACRO ~Q_AREVertex_InitVars~
BEGIN

// This macro initializes some constant variables for use by the Q_AREVertex_Process macro,
// and also the variables that the user will set to make the macro work.

// First, the variables the tool will use.  This basically sets the variables defining
// the "First Vertex Index" and count fields within doors, trigger and containers in much
// the same way the Q_AREInitVars does it for the offsets in the main section of the .ARE
// file.  These offsets are from the beginning of a door/trigger/container definition, btw,
// not the beginning of the .ARE file.  You can ignore this part.  Instructions continue below.

// The key to the fields in this file, by the way, are:

// "Trigg"  - Vertex list for triggers
// "Conta"  - Vertex list for containers
// "DoorO"  - Vertex list for door in Open position
// "DoorC"  - Vertex list for door in Closed position
// "DoorOI" - Vertex list for door in Open, Impeded position
// "DoorCI" - Vertex list for door in Closed, Impeded position

// Note:  The IESDP and Near Infinity disagree on these offsets.  IESDP has definite errors
// in theirs though, so I'm going with the values in NI.  If someone finds out NI is wrong
// too, please let me know.

SET "QV_OffFVI_Trigg"  = 0x2c
SET "QV_OffFVI_Conta"  = 0x50
SET "QV_OffFVI_DoorO"  = 0x2c
SET "QV_OffFVI_DoorC"  = 0x34
SET "QV_OffFVI_DoorOI" = 0x50
SET "QV_OffFVI_DoorCI" = 0x48

SET "QV_OffNumV_Trigg"  = 0x2a
SET "QV_OffNumV_Conta"  = 0x54
SET "QV_OffNumV_DoorO"  = 0x30
SET "QV_OffNumV_DoorC"  = 0x32
SET "QV_OffNumV_DoorOI" = 0x4e
SET "QV_OffNumV_DoorCI" = 0x4c

// INSTRUCTIONS FOR USE:

// To remap the vertexes of an existing trigger, door or container, you must supply 3
// different values - the type of record you're changing, the offset to the definition of that
// record, and the new number of vertexes attached to that record.

// The three variables the user must fill in are:
// QV_Offset -  The offset of the Item, Door or Container definition whose vertexes are being remapped
// QV_Count  -  The new number of vertexes attached to this item, door or container
// QV_Type   -  This must be an integer value from 1 to 6:

// 1 - Trigger
// 2 - Container
// 3 - Door, Open
// 4 - Door, Closed
// 5 - Door, Open Impeded
// 6 - Door, Closed Impeded

// Initializing those variables now:

SET "QV_Type" = 0
SET "QV_Offset" = 0
SET "QV_VCount" = 0

// COMPATIBILITY NOTE:  I strongly suggest NOT hardcoding the value of QV_Offset.  Doing so will
// likely make your mod incompatible with other mods.  If you want to modify the vertexes of the
// third trigger in your area, set the value of QV_Offset dynamically like this:
// "QV_Offset" = "Q_Off_Trigg" + ("Q_Siz_Trigg" * 2)

// You should have run the macro Q_ARE_InitVars prior to even thinking about using these macros
// anyway, so those two Q_ variables will already be filled in for you at this point.

// Also be aware that, when I say "third trigger", I don't mean the third trigger listed in NI,
// which lists them alphabetically by assigned name.  I mean the third one sequentially in the
// file.  Look at the starting offset of each trigger to get the actual order they are sequenced
// in in the file.

// Here's an example of how to use this macro.  Say you want to change the "Open" vertex of
// the fifth door in your file.  It originally had 6 vertexes, and your new map has 9 vertexes.

// INCLUDE Q_AREMacros.tph

// ...

// COPY_EXISTING ~AR0400.ARE~ ~override~
// LAUNCH_PATCH_MACRO Q_ARE_InitVars
// LAUNCH_PATCH_MACRO Q_AREVertex_InitVars  // this macro
// SET "QV_Type" = ~DoorO~
// SET "QV_Offset" = "Q_Off_Doors + (Q_Siz_Doors * 4)
// SET "QV_VCount = 9
// LAUNCH_PATCH_MACRO Q_AREVertex_Process

// That code will first delete the bytes where the vertexes for that door record are mapped, and then
// reinsert bytes to the size you need.  Thus, expect 0's in all the vertexes, you'll need to remap
// them all (which, when it comes to vertex mapping, generally needs to be done anyway).  It will
// also update all the "First Vertex Index" fields in -all- items, doors and containers that need it
// to match their new positions within the vertex pool.

// That's it.  Oh, and you'd get the offset at which you can start writing your new vertexes
// in the variable QV_NewVertexOffset.  Start writing your new vertexes there.  Don't worry
// about pointing your Door file's First Vertex Index to them, that's already done for you.

SET "QV_NewVertexOffset" = 0

END

// ==================== END Q_AREVertex_InitVars Macro Definition ====================

// ==================== BEGIN Q_AREVertex_Process Macro Definition ====================

DEFINE_PATCH_MACRO ~Q_AREVertex_Process~
BEGIN

// DO NOT use this macro without first running Q_AREVertex_InitVars.
// Documentation for the use of this macro is contained within that macro definition.


PATCH_IF "QV_Type" > 0 AND "QV_Type" < 7 THEN
BEGIN
  PATCH_IF "QV_Type" = 1 THEN
  BEGIN
	 SET "QV_OffFVI"  = "QV_OffFVI_Trigg"
	 SET "QV_OffNumV" = "QV_OffNumV_Trigg"
  END
  PATCH_IF "QV_Type" = 2 THEN
  BEGIN
	 SET "QV_OffFVI"  = "QV_OffFVI_Conta"
	 SET "QV_OffNumV" = "QV_OffNumV_Conta"
  END
  PATCH_IF "QV_Type" = 3 THEN
  BEGIN
	 SET "QV_OffFVI"  = "QV_OffFVI_DoorO"
	 SET "QV_OffNumV" = "QV_OffNumV_DoorO"
  END
  PATCH_IF "QV_Type" = 4 THEN
  BEGIN
	 SET "QV_OffFVI"  = "QV_OffFVI_DoorC"
	 SET "QV_OffNumV" = "QV_OffNumV_DoorC"
  END
  PATCH_IF "QV_Type" = 5 THEN
  BEGIN
	 SET "QV_OffFVI"  = "QV_OffFVI_DoorOI"
	 SET "QV_OffNumV" = "QV_OffNumV_DoorOI"
  END
  PATCH_IF "QV_Type" = 6 THEN
  BEGIN
	 SET "QV_OffFVI"  = "QV_OffFVI_DoorCI"
	 SET "QV_OffNumV" = "QV_OffNumV_DoorCI"
  END

  READ_LONG ("QV_Offset" + "QV_OffFVI")  "QV_OldFVI"
  READ_SHORT ("QV_Offset" + "QV_OffNumV") "QV_OldCount"
  SET "QV_Delta" = "QV_VCount" - "QV_OldCount"

  FOR ("i2" = 1; "i2" <= "Q_Num_Trigg"; "i2" += 1)
  BEGIN
	READ_LONG ("Q_Off_Trigg" + ("Q_Siz_Trigg" * ("i2" - 1)) + "QV_OffFVI_Trigg") "QV_EachFVI"
	PATCH_IF "QV_EachFVI" > "QV_OldFVI" THEN
	BEGIN
	  WRITE_LONG ("Q_Off_Trigg" + ("Q_Siz_Trigg" * ("i2" - 1)) + "QV_OffFVI_Trigg")
				  "QV_EachFVI" + "QV_Delta"
	END
  END

  FOR ("i2" = 1; "i2" <= "Q_Num_Conta"; "i2" += 1)
  BEGIN
	READ_LONG ("Q_Off_Conta" + ("Q_Siz_Conta" * ("i2" - 1)) + "QV_OffFVI_Conta") "QV_EachFVI"
	PATCH_IF "QV_EachFVI" > "QV_OldFVI" THEN
	BEGIN
	  WRITE_LONG ("Q_Off_Conta" + ("Q_Siz_Conta" * ("i2" - 1)) + "QV_OffFVI_Conta")
				  "QV_EachFVI" + "QV_Delta"
	END
  END
  FOR ("i2" = 1; "i2" <= "Q_Num_Doors"; "i2" += 1)
  BEGIN
	READ_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorO") "QV_EachFVI"
	PATCH_IF "Q_EachFVI" > "QV_OldFVI" THEN
	BEGIN
	  WRITE_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorO")
				  "QV_EachFVI" + "QV_Delta"
	END
	READ_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorC") "QV_EachFVI"
	PATCH_IF "Q_EachFVI" > "QV_OldFVI" THEN
	BEGIN
	  WRITE_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorC")
				  "QV_EachFVI" + "QV_Delta"
	END
	READ_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorOI") "QV_EachFVI"
	PATCH_IF "Q_EachFVI" > "QV_OldFVI" THEN
	BEGIN
	  WRITE_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorOI")
				  "QV_EachFVI" + "QV_Delta"
	END
	READ_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorOC") "QV_EachFVI"
	PATCH_IF "Q_EachFVI" > "QV_OldFVI" THEN
	BEGIN
	  WRITE_LONG ("Q_Off_Doors" + ("Q_Siz_Doors" * ("i2" - 1)) + "QV_OffFVI_DoorOC")
				  "QV_EachFVI" + "QV_Delta"
	END
  END
  WRITE_SHORT ("QV_Offset" + "QV_OffNumV") "QV_VCount"
  WRITE_SHORT "Q_OoN_Vertx" ("Q_Num_Vertx" + "QV_Delta")
  DELETE_BYTES ("Q_Off_Vertx" + ("QV_OldFVI" * "Q_Siz_Vertx"))
			   ("QV_OldCount" * "Q_Siz_Vertx")
  INSERT_BYTES ("Q_Off_Vertx" + ("QV_OldFVI" * "Q_Siz_Vertx"))
			   ("QV_VCount" * "Q_Siz_Vertx")
  SET "QV_NewVertexOffset" = ("Q_Off_Vertx" + ("QV_OldFVI" * "Q_Siz_Vertx"))
  LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
  SET "Q_ManualInsert" = 1
  SET "Q_New_Vertx" = "QV_Delta"
  LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~
END

END

Attached Files


Edited by Qwinn, 11 June 2009 - 11:44 AM.


#2 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 25 April 2008 - 06:04 PM

I just edited that file to add two of the new macros I promised, that allow you to automatically remap the vertexes on an existing trigger, door or container. I'll add the macros for adding items to a container probably on Monday.

Incidentally, I had the new Q_AREVertex_ vertex modifying macros make a call to the Q_AREAdd_ macros, in order to remap the offsets of all the other files (since the size of the vertex file changes). To do so, I needed to modify the Q_AREAdd_ macros slightly to add a "Q_ManualInsert" flag, and to make the Q_AREAdd macros capable of accepting negative numbers in your "Q_New" variables.

The upshot? You can now use the Q_AREAdd_ macros to reset all the offsets after you manually delete any section. Just set the Q_ManualInsert flag to 1 so that you can handle the actual DELETE_BYTES yourself, tell the tool what sections you deleted by setting the appropriate "Q_New" variable with a negative value (for example, "Q_New_Actor" = -2), and the tool will successfully reset all the offsets for you.

Qwinn

Edited by Qwinn, 25 April 2008 - 07:25 PM.


#3 cmorgan

cmorgan
  • Staff
  • 2301 posts

Posted 25 April 2008 - 09:05 PM

Still reading and catching up, Qwinn - it may take me awhile to follow all of this, but it loosk like once I figure it out it just made dynamic patching of areas much easier.

#4 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 25 April 2008 - 10:54 PM

Hiya cmorgan :)

Well, if it helps, here's a real-world and semi-complex example where I've used it and it's working great. This mods an area file modded for the Restored Candlestick Quest by Platter for Planescape Torment. The only thing missing from this code is the include declaring the macros, but this is all you need to do now. 3 macros with 3 variables telling the tool what to do, and the writes to the new areas, nothing else. Only needed to go to NI to see how to map the areas I was directly writing, didn't have to look up any offsets at all.

// Adding 1 actor (0x110), 2 trigger points (0xc4 each, total 0x188), 10 vertexes (0x4 each, total 0x28)

COPY_EXISTING ~AR0109.ARE~ ~override~
  LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
  LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
  SET "Q_New_Actor" = 1
  SET "Q_New_Trigg" = 2
  SET "Q_New_Vertx" = 10
  LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

// Add Actor

  WRITE_ASCII "Q_NewOffset_Actor"		   ~Ulthera~	  #32 // Name
  WRITE_ASCII "Q_NewOffset_Actor" + 0x80	~ULTHERA~	  #8  // CRE
  WRITE_ASCII "Q_NewOffset_Actor" + 0x48	~DULTHERA~	 #8  // DLG
  WRITE_SHORT "Q_NewOffset_Actor" + 0x20	1554			   // Pos X
  WRITE_SHORT "Q_NewOffset_Actor" + 0x22	2026			   // Pos Y
  WRITE_SHORT "Q_NewOffset_Actor" + 0x24	1554			   // Des X
  WRITE_SHORT "Q_NewOffset_Actor" + 0x26	2026			   // Des Y
  WRITE_SHORT "Q_NewOffset_Actor" + 0x34	9				  // Orientation
  WRITE_LONG  "Q_NewOffset_Actor" + 0x40	0x00ffffff		 // Present
  WRITE_SHORT "Q_NewOffset_Actor" + 0x28	1				  // Visible

// Add 2 Triggers

  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0)		 ~candle1~	   #32 // Name
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x20  2				   // Travel Trigger Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x22  695				 // Left
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x24  686				 // Top
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x26  804				 // Right
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x28  839				 // Bottom
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x2a  5				   // Num of Vertexes
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x2c  "Q_Num_Vertx" - 10  // First Vertex Index
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x34  48				  // Cursor Frame
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x38  ~AR0207~		 #8 // Destination Area
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x40  ~fr0109~		#32 // Entrance name
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x60  0x0002			  // Party Required Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x70  749				 // Trap Loc X
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x72  762				 // Trap Loc Y
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x7c  ~~			  #32 // Script Name (BCS)

  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1)		 ~cantrig1~	  #32 // Name
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x20  0				   // Proximity Trigger Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x22  572				 // Left
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x24  697				 // Top
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x26  876				 // Right
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x28  918				 // Bottom
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x2a  5				   // Num of Vertexes
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x2c  "Q_Num_Vertx" - 5   // First Vertex Index
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x34  0				   // Cursor Frame
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x38  ~~			   #8 // Destination Area
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x40  ~~			  #32 // Entrance name
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x60  0x0001			  // Reset Trap Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x70  749				 // Trap Loc X
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x72  762				 // Trap Loc Y
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x7c  ~CANTRIG1~	  #32 // Script Name (BCS)

// Add 10 Vertexes

  WRITE_SHORT "Q_NewOffset_Vertx" + 0   804
  WRITE_SHORT "Q_NewOffset_Vertx" + 2   779
  WRITE_SHORT "Q_NewOffset_Vertx" + 4   784
  WRITE_SHORT "Q_NewOffset_Vertx" + 6   686
  WRITE_SHORT "Q_NewOffset_Vertx" + 8   698
  WRITE_SHORT "Q_NewOffset_Vertx" + 10  736
  WRITE_SHORT "Q_NewOffset_Vertx" + 12  695
  WRITE_SHORT "Q_NewOffset_Vertx" + 14  839
  WRITE_SHORT "Q_NewOffset_Vertx" + 16  804
  WRITE_SHORT "Q_NewOffset_Vertx" + 18  779
  WRITE_SHORT "Q_NewOffset_Vertx" + 20  721
  WRITE_SHORT "Q_NewOffset_Vertx" + 22  918
  WRITE_SHORT "Q_NewOffset_Vertx" + 24  572
  WRITE_SHORT "Q_NewOffset_Vertx" + 26  865
  WRITE_SHORT "Q_NewOffset_Vertx" + 28  794
  WRITE_SHORT "Q_NewOffset_Vertx" + 30  697
  WRITE_SHORT "Q_NewOffset_Vertx" + 32  876
  WRITE_SHORT "Q_NewOffset_Vertx" + 34  809
  WRITE_SHORT "Q_NewOffset_Vertx" + 36  721
  WRITE_SHORT "Q_NewOffset_Vertx" + 38  918

 BUT_ONLY_IF_IT_CHANGES



On the other hand, don't try the thing I suggested with using the AREAdd_ macros to help -delete- records by giving it negative numbers just yet... I'm trying to get that working myself and it's -sorta- working but I've got unused bytes left over, so let me get back to you on that.

But using it do add works like a charm.

Qwinn

Edited by Qwinn, 28 May 2009 - 04:24 PM.


#5 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 25 April 2008 - 11:50 PM

Okay, with the delete thing, here's the thing: If you're trying to delete a trigger with vertexes, first use the vertex modding macros - the Q_AREVertex_ ones, to delete the vertexes. -Then-, you can use the AREAdd_ macros to get rid of the trigger itself. That'll work great.

Here's another example of my using it, from the same Candlestick mod. In this one, to mimick what the original mod did, I needed to delete a trigger, then add 2.

COPY_EXISTING ~AR0207.ARE~ ~override~
LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~

// This block remaps the vertexes of Trigger 4 down to zero, deleting them properly.
LAUNCH_PATCH_MACRO ~Q_AREVertex_InitVars~
SET "QV_Type" = 1
SET "QV_VCount" = 0
SET "QV_Offset" = ("Q_Off_Trigg" + ("Q_Siz_Trigg" * 3))
LAUNCH_PATCH_MACRO ~Q_AREVertex_Process~

// Now that the trigger doesn't have any vertexes attached anymore, using the AREAdd macros to get rid of it works
// great. Note how I'm physically deleting the trigger myself, setting the Q_ManualInsert flag so the AREAdd macro
// doesn't execute the normal INSERT_BYTES statement, and then setting Q_New_Trigg to negative 1 to subtract
// the length of 1 trigger record from all the offsets that follow it.
LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
DELETE_BYTES ("Q_Off_Trigg" + ("Q_Siz_Trigg" * 3)) "Q_Siz_Trigg"
SET "Q_New_Trigg" = 0 - 1
SET "Q_ManualInsert" = 1
LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

// Now we add two triggers with 7 vertexes attached to the first one and no vertexes on the second.

LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
SET "Q_New_Trigg" = 2
SET "Q_New_Vertx" = 7
LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) ~cantrig2~ #32 // Name
WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x20 0 // Proximity Trigger
WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x22 496 // Left
WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x24 428 // Top
WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x26 631 // Right
// Etc. etc. etc.

WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) ~candle2~ #32 // Name
WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x20 2 // Travel Trigger
WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x22 540 // Left
// Etc. etc.

WRITE_SHORT "Q_NewOffset_Vertx" + 0 534
WRITE_SHORT "Q_NewOffset_Vertx" + 2 430
WRITE_SHORT "Q_NewOffset_Vertx" + 4 496
// Etc. Etc.

// The Etc.'s are just where I snipped the rest of the WRITE's to the new records, nothing useful to be learned from
// those beyond the first few lines of each.

Qwinn

Edited by Qwinn, 26 April 2008 - 12:02 AM.


#6 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 03 May 2008 - 09:25 AM

Bleah... added code tags to the first post, should be a lot more readable now, sorry bout that.

Qwinn

#7 Kaeloree

Kaeloree

    Head Molder

  • Administrator
  • 9198 posts

Posted 23 May 2009 - 04:18 PM

I actually think I'm going to move this to IE Tutorials, so it's more visible--it's a great resource, and it deserves a little more love. ;)

#8 Icendoan

Icendoan

    "An Infinite Deal of Nothing"

  • Member
  • 1723 posts

Posted 23 May 2009 - 04:46 PM

I don't actually think it is in the Comprehensive List™ yet. :)

Icen
Proud member of the 'I HATE Elminster!' Club!

Mods in development: Keeping Yoshimo

#9 Kaeloree

Kaeloree

    Head Molder

  • Administrator
  • 9198 posts

Posted 23 May 2009 - 04:53 PM

Nope, the list hasn't been updated in a few months--I'll give SC a poke.

#10 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 24 May 2009 - 04:25 AM

My concerns, questions, and other things....

For me personally, your portion that changes the offset number to a variable name is pointless. I always have to refer to the IESDP because I forget whether it is _BYTE _SHORT _LONG or _ASCII. So for me, the offset number might as well be there too.

My goal is to shorten the amount of code needed. The macro information actually seems to extend the amount of code needed inside the tp2 (perhaps it is the spaces and instructions that make it seem larger). It just changes where it is located. Instead of being in the actual patch it's in the header. Wouldn't it be better served as a tph file that could be included via PATCH_INCLUDE?

I'd be more apt to add code I don't understand but works if it was a called up file rather than pasting it into my tp2 file.

Anyway, here is something I did some time ago and it does indeed work (perhaps extra code involved, but I'm known for my 'needless' code. Extra code is sometimes needed when you want to make sure that things work just right in certain situations, although some will call it needless). It was designed as an inlined file so I could use variables allowing me to make the edits on both totsc and easytutu. How would you have done this in as few code lines as possible?
<<<<<<<< inlined/1803.tph
COPY_EXISTING_REGEXP GLOB ~%file_name%~ ~override~
 PATCH_IF (%SOURCE_SIZE% > 0xd4) BEGIN
//read area script reference
  READ_ASCII 0x94 script_res
//update vertex indices for info points i.e. number of points
  READ_LONG 0x5c info_off
  READ_SHORT 0x5a info_num
  FOR (i= 0; i < "%info_num%"; i += 1) BEGIN
   READ_SHORT ("%info_off%" + (%i% * 0xc4) + 0x2c) info_vertex_first_idx
   PATCH_IF ("%info_vertex_first_idx%" >= 0) BEGIN
	WRITE_SHORT ("%info_off%" + (%i% * 0xc4) + 0x2c) ("%info_vertex_first_idx%" + 10)
   END
  END
//update vertex indices for containers i.e. number of points
  READ_LONG 0x70 container_off
  READ_SHORT 0x74 container_num
  FOR (i = 0; i< "%container_num%"; i += 1) BEGIN
   READ_LONG ("%container_off%" + (%i% * 0xc0) + 0x50) container_vertex_first_idx
   PATCH_IF ("%container_vertex_first_idx%" >= 0) BEGIN
	WRITE_LONG ("%container_off%" + (%i% * 0xc0) + 0x50) ("%container_vertex_first_idx%" + 10)
   END
  END
//update vertex indices for doors i.e. number of points
  READ_LONG 0xa8 door_off
  READ_SHORT 0xa4 door_num
  FOR (i = 0; i < "%door_num%"; i += 1) BEGIN
   READ_LONG ("%door_off%" + (%i% * 0xc8) + 0x2c) door_vertex_open_first_idx
   PATCH_IF ("%door_vertex_open_first_idx%" >= 0) BEGIN
	WRITE_LONG ("%door_off%" + (%i% * 0xc8) + 0x2c) ("%door_vertex_open_first_idx%" + 10)
   END
   READ_LONG ("%door_off%" + (%i% * 0xc8) + 0x34) door_vertex_closed_first_idx
   PATCH_IF ("%door_vertex_closed_first_idx%" >= 0) BEGIN
	WRITE_LONG ("%door_off%" + (%i% * 0xc8) + 0x34) ("%door_vertex_closed_first_idx%" + 10)
   END
   READ_LONG ("%door_off%" + (%i% * 0xc8) + 0x48) door_vertex_impede_closed_first_idx
   PATCH_IF ("%door_vertex_impede_closed_first_idx%" >= 0) BEGIN
	WRITE_LONG ("%door_off%" + (%i% * 0xc8) + 0x48) ("%door_vertex_impede_closed_first_idx%" + 10)
   END
   READ_LONG ("%door_off%" + (%i% * 0xc8) + 0x50) door_vertex_impede_open_first_idx
   PATCH_IF ("%door_vertex_impede_open_first_idx%" >= 0) BEGIN
	WRITE_LONG ("%door_off%" + (%i% * 0xc8) + 0x50) ("%door_vertex_impede_open_first_idx%" + 10)
   END
  END
//insert 2 triggers worth of space
  READ_LONG 0x5c info_off
  READ_SHORT 0x5a info_num
  WRITE_SHORT 0x5a (%info_num% + 2)
  SET new_bytes = (0xc4 * 2)
  SET cmp_loc = %info_off%
  SET check_num = %info_num%
  INSERT_BYTES (%cmp_loc%) (%new_bytes%)
//check other offsets and update as needed
  PATCH_IF (%check_num% > 0) BEGIN
   READ_LONG 0x54 actor_off
   PATCH_IF (%actor_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x54 (%actor_off% + %new_bytes%) //actor_off
   END
   READ_LONG 0x60 spawn_off
   PATCH_IF (%spawn_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x60 (%spawn_off% + %new_bytes%) //spawn_off
   END
   READ_LONG 0x68 entrance_off
   PATCH_IF (%entrance_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x68 (%entrance_off% + %new_bytes%) //entrance_off
   END
   READ_LONG 0x70 container_off
   PATCH_IF (%container_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x70 (%container_off% + %new_bytes%) //container_off
   END
   READ_LONG 0x78 item_off
   PATCH_IF (%item_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x78 (%item_off% + %new_bytes%) //item_off
   END
//no need to update self
//   READ_LONG 0x5c info_off
//   PATCH_IF (%info_off% > %cmp_loc%) BEGIN
//	WRITE_LONG 0x5c (%info_off% + %new_bytes%) //info_off
//   END
   READ_LONG 0x7c vertex_off
   PATCH_IF (%vertex_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x7c (%vertex_off% + %new_bytes%) //vertex_off
   END
   READ_LONG 0x84 ambient_off
   PATCH_IF (%ambient_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x84 (%ambient_off% + %new_bytes%) //ambient_off
   END
   READ_LONG 0x88 variable_off
   PATCH_IF (%variable_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x88 (%variable_off% + %new_bytes%) //variable_off
   END
   READ_LONG 0xa8 door_off
   PATCH_IF (%door_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xa8 (%door_off% + %new_bytes%) //door_off
   END
   READ_LONG 0xa0 explored_off
   PATCH_IF (%explored_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xa0 (%explored_off% + %new_bytes%) //explored_off
   END
   READ_LONG 0xb0 anim_off
   PATCH_IF (%anim_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xb0 (%anim_off% + %new_bytes%) //anim_off
   END
   READ_LONG 0xb8 tiled_off
   PATCH_IF (%tiled_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xb8 (%tiled_off% + %new_bytes%) //tiled_off
   END
   READ_LONG 0xbc song_off
   PATCH_IF (%song_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xbc (%song_off% + %new_bytes%) //song_off
   END
   READ_LONG 0xc0 rest_off
   PATCH_IF (%rest_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xc0 (%rest_off% + %new_bytes%) //rest_off
   END
   READ_LONG 0xc4 automap_off
   PATCH_IF (%automap_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xc4 (%automap_off% + %new_bytes%) //automap_off
   END
   READ_LONG 0xcc pro_traps_off
   PATCH_IF (%pro_traps_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xcc (%pro_traps_off% + %new_bytes%) //automap_off
   END
  END
  ELSE
  PATCH_IF (%check_num% = 0) BEGIN
   READ_LONG 0x54 actor_off
   PATCH_IF (%actor_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x54 (%actor_off% + %new_bytes%) //actor_off
   END
   READ_LONG 0x60 spawn_off
   PATCH_IF (%spawn_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x60 (%spawn_off% + %new_bytes%) //spawn_off
   END
   READ_LONG 0x68 entrance_off
   PATCH_IF (%entrance_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x68 (%entrance_off% + %new_bytes%) //entrance_off
   END
   READ_LONG 0x70 container_off
   PATCH_IF (%container_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x70 (%container_off% + %new_bytes%) //container_off
   END
   READ_LONG 0x78 item_off
   PATCH_IF (%item_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x78 (%item_off% + %new_bytes%) //item_off
   END
//no need to update self
//   READ_LONG 0x5c info_off
//   PATCH_IF (%info_off% >= %cmp_loc%) BEGIN
//	WRITE_LONG 0x5c (%info_off% + %new_bytes%) //info_off
//   END
   READ_LONG 0x7c vertex_off
   PATCH_IF (%vertex_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x7c (%vertex_off% + %new_bytes%) //vertex_off
   END
   READ_LONG 0x84 ambient_off
   PATCH_IF (%ambient_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x84 (%ambient_off% + %new_bytes%) //ambient_off
   END
   READ_LONG 0x88 variable_off
   PATCH_IF (%variable_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x88 (%variable_off% + %new_bytes%) //variable_off
   END
   READ_LONG 0xa8 door_off
   PATCH_IF (%door_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xa8 (%door_off% + %new_bytes%) //door_off
   END
   READ_LONG 0xa0 explored_off
   PATCH_IF (%explored_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xa0 (%explored_off% + %new_bytes%) //explored_off
   END
   READ_LONG 0xb0 anim_off
   PATCH_IF (%anim_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xb0 (%anim_off% + %new_bytes%) //anim_off
   END
   READ_LONG 0xb8 tiled_off
   PATCH_IF (%tiled_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xb8 (%tiled_off% + %new_bytes%) //tiled_off
   END
   READ_LONG 0xbc song_off
   PATCH_IF (%song_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xbc (%song_off% + %new_bytes%) //song_off
   END
   READ_LONG 0xc0 rest_off
   PATCH_IF (%rest_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xc0 (%rest_off% + %new_bytes%) //rest_off
   END
   READ_LONG 0xc4 automap_off
   PATCH_IF (%automap_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xc4 (%automap_off% + %new_bytes%) //automap_off
   END
   READ_LONG 0xcc pro_traps_off
   PATCH_IF (%pro_traps_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xcc (%pro_traps_off% + %new_bytes%) //automap_off
   END
  END
//insert space for vertices for 2 triggers
  READ_LONG 0x7c vertex_off
  READ_SHORT 0x80 vertex_num
  WRITE_SHORT 0x80 (%vertex_num% + 10)
  SET new_bytes = (0x4 * 10)
  SET check_num = %vertex_num%
  SET cmp_loc = %vertex_off%
  INSERT_BYTES (%cmp_loc%) (%new_bytes%)
//check other offsets and update as needed
  PATCH_IF (%check_num% > 0) BEGIN
   READ_LONG 0x54 actor_off
   PATCH_IF (%actor_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x54 (%actor_off% + %new_bytes%) //actor_off
   END
   READ_LONG 0x60 spawn_off
   PATCH_IF (%spawn_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x60 (%spawn_off% + %new_bytes%) //spawn_off
   END
   READ_LONG 0x68 entrance_off
   PATCH_IF (%entrance_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x68 (%entrance_off% + %new_bytes%) //entrance_off
   END
   READ_LONG 0x70 container_off
   PATCH_IF (%container_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x70 (%container_off% + %new_bytes%) //container_off
   END
   READ_LONG 0x78 item_off
   PATCH_IF (%item_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x78 (%item_off% + %new_bytes%) //item_off
   END
   READ_LONG 0x5c info_off
   PATCH_IF (%info_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x5c (%info_off% + %new_bytes%) //info_off
   END
//no need to update self
//   READ_LONG 0x7c vertex_off
//   PATCH_IF (%vertex_off% > %cmp_loc%) BEGIN
//	WRITE_LONG 0x7c (%vertex_off% + %new_bytes%) //vertex_off
//   END
   READ_LONG 0x84 ambient_off
   PATCH_IF (%ambient_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x84 (%ambient_off% + %new_bytes%) //ambient_off
   END
   READ_LONG 0x88 variable_off
   PATCH_IF (%variable_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0x88 (%variable_off% + %new_bytes%) //variable_off
   END
   READ_LONG 0xa8 door_off
   PATCH_IF (%door_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xa8 (%door_off% + %new_bytes%) //door_off
   END
   READ_LONG 0xa0 explored_off
   PATCH_IF (%explored_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xa0 (%explored_off% + %new_bytes%) //explored_off
   END
   READ_LONG 0xb0 anim_off
   PATCH_IF (%anim_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xb0 (%anim_off% + %new_bytes%) //anim_off
   END
   READ_LONG 0xb8 tiled_off
   PATCH_IF (%tiled_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xb8 (%tiled_off% + %new_bytes%) //tiled_off
   END
   READ_LONG 0xbc song_off
   PATCH_IF (%song_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xbc (%song_off% + %new_bytes%) //song_off
   END
   READ_LONG 0xc0 rest_off
   PATCH_IF (%rest_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xc0 (%rest_off% + %new_bytes%) //rest_off
   END
   READ_LONG 0xc4 automap_off
   PATCH_IF (%automap_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xc4 (%automap_off% + %new_bytes%) //automap_off
   END
   READ_LONG 0xcc pro_traps_off
   PATCH_IF (%pro_traps_off% > %cmp_loc%) BEGIN
	WRITE_LONG 0xcc (%pro_traps_off% + %new_bytes%) //automap_off
   END
  END
  ELSE
  PATCH_IF (%check_num% = 0) BEGIN
   READ_LONG 0x54 actor_off
   PATCH_IF (%actor_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x54 (%actor_off% + %new_bytes%) //actor_off
   END
   READ_LONG 0x60 spawn_off
   PATCH_IF (%spawn_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x60 (%spawn_off% + %new_bytes%) //spawn_off
   END
   READ_LONG 0x68 entrance_off
   PATCH_IF (%entrance_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x68 (%entrance_off% + %new_bytes%) //entrance_off
   END
   READ_LONG 0x70 container_off
   PATCH_IF (%container_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x70 (%container_off% + %new_bytes%) //container_off
   END
   READ_LONG 0x78 item_off
   PATCH_IF (%item_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x78 (%item_off% + %new_bytes%) //item_off
   END
   READ_LONG 0x5c info_off
   PATCH_IF (%info_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x5c (%info_off% + %new_bytes%) //info_off
   END
//no need to update self
//   READ_LONG 0x7c vertex_off
//   PATCH_IF (%vertex_off% >= %cmp_loc%) BEGIN
//	WRITE_LONG 0x7c (%vertex_off% + %new_bytes%) //vertex_off
//   END
   READ_LONG 0x84 ambient_off
   PATCH_IF (%ambient_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x84 (%ambient_off% + %new_bytes%) //ambient_off
   END
   READ_LONG 0x88 variable_off
   PATCH_IF (%variable_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0x88 (%variable_off% + %new_bytes%) //variable_off
   END
   READ_LONG 0xa8 door_off
   PATCH_IF (%door_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xa8 (%door_off% + %new_bytes%) //door_off
   END
   READ_LONG 0xa0 explored_off
   PATCH_IF (%explored_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xa0 (%explored_off% + %new_bytes%) //explored_off
   END
   READ_LONG 0xb0 anim_off
   PATCH_IF (%anim_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xb0 (%anim_off% + %new_bytes%) //anim_off
   END
   READ_LONG 0xb8 tiled_off
   PATCH_IF (%tiled_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xb8 (%tiled_off% + %new_bytes%) //tiled_off
   END
   READ_LONG 0xbc song_off
   PATCH_IF (%song_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xbc (%song_off% + %new_bytes%) //song_off
   END
   READ_LONG 0xc0 rest_off
   PATCH_IF (%rest_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xc0 (%rest_off% + %new_bytes%) //rest_off
   END
   READ_LONG 0xc4 automap_off
   PATCH_IF (%automap_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xc4 (%automap_off% + %new_bytes%) //automap_off
   END
   READ_LONG 0xcc pro_traps_off
   PATCH_IF (%pro_traps_off% >= %cmp_loc%) BEGIN
	WRITE_LONG 0xcc (%pro_traps_off% + %new_bytes%) //automap_off
   END
  END
// Write info for Chapter trigger 1
  READ_LONG 0x5c info_off
  WRITE_ASCII (%info_off% + 0) ~Chapter trigger 1~ (32)
  WRITE_SHORT (%info_off% + 0x20) 0
  WRITE_SHORT (%info_off% + 0x22) 380
  WRITE_SHORT (%info_off% + 0x24) 1062
  WRITE_SHORT (%info_off% + 0x26) 541
  WRITE_SHORT (%info_off% + 0x28) 1277
  WRITE_SHORT (%info_off% + 0x2a) 6 //num of vertices
  WRITE_LONG (%info_off% + 0x2c) 0 //index of vertices
  WRITE_LONG (%info_off% + 0x30) 0
  WRITE_LONG (%info_off% + 0x34) 0
  WRITE_ASCII (%info_off% + 0x38) ~~ (8)
  WRITE_ASCII (%info_off% + 0x40) ~~ (32)
  WRITE_LONG (%info_off% + 0x60) 2
  WRITE_LONG (%info_off% + 0x64) 0
  WRITE_SHORT (%info_off% + 0x68) 100
  WRITE_SHORT (%info_off% + 0x6a) 100
  WRITE_SHORT (%info_off% + 0x6c) 1
  WRITE_SHORT (%info_off% + 0x63) 0
  WRITE_SHORT (%info_off% + 0x70) 404
  WRITE_SHORT (%info_off% + 0x72) 1300
  WRITE_BYTE (%info_off% + 0x74) 0
  WRITE_BYTE (%info_off% + 0x75) 0
  WRITE_BYTE (%info_off% + 0x76) 0
  WRITE_BYTE (%info_off% + 0x77) 0
  WRITE_BYTE (%info_off% + 0x78) 0
  WRITE_BYTE (%info_off% + 0x79) 0
  WRITE_BYTE (%info_off% + 0x7a) 0
  WRITE_BYTE (%info_off% + 0x7b) 0
  WRITE_ASCII (%info_off% + 0x7c) ~endch4~ (8)
  WRITE_SHORT (%info_off% + 0x84) 0
  WRITE_SHORT (%info_off% + 0x86) 0
  WRITE_SHORT (%info_off% + 0x88) 0
  WRITE_SHORT (%info_off% + 0x8a) 0
  WRITE_ASCII (%info_off% + 0xbc) ~~ (8)
  FOR (y=0x8c; y<0xbc; y+=1) BEGIN
   WRITE_BYTE (%info_off% + %y%) 0
  END
// Write info for Chapter trigger 2
  WRITE_ASCII (%info_off% + 0xc4 + 0) ~Chapter trigger 2~ (32)
  WRITE_SHORT (%info_off% + 0xc4 + 0x20) 0
  WRITE_SHORT (%info_off% + 0xc4 + 0x22) 1523
  WRITE_SHORT (%info_off% + 0xc4 + 0x24) 272
  WRITE_SHORT (%info_off% + 0xc4 + 0x26) 1629
  WRITE_SHORT (%info_off% + 0xc4 + 0x28) 356
  WRITE_SHORT (%info_off% + 0xc4 + 0x2a) 4 //num of vertices
  WRITE_LONG (%info_off% + 0xc4 + 0x2c) 6 //index of vertices
  WRITE_LONG (%info_off% + 0xc4 + 0x30) 0
  WRITE_LONG (%info_off% + 0xc4 + 0x34) 0
  WRITE_ASCII (%info_off% + 0xc4 + 0x38) ~~ (8)
  WRITE_ASCII (%info_off% + 0xc4 + 0x40) ~~ (32)
  WRITE_LONG (%info_off% + 0xc4 + 0x60) 2
  WRITE_LONG (%info_off% + 0xc4 + 0x64) 0
  WRITE_SHORT (%info_off% + 0xc4 + 0x68) 100
  WRITE_SHORT (%info_off% + 0xc4 + 0x6a) 100
  WRITE_SHORT (%info_off% + 0xc4 + 0x6c) 1
  WRITE_SHORT (%info_off% + 0xc4 + 0x63) 0
  WRITE_SHORT (%info_off% + 0xc4 + 0x70) 1620
  WRITE_SHORT (%info_off% + 0xc4 + 0x72) 340
  WRITE_BYTE (%info_off% + 0xc4 + 0x74) 0
  WRITE_BYTE (%info_off% + 0xc4 + 0x75) 0
  WRITE_BYTE (%info_off% + 0xc4 + 0x76) 0
  WRITE_BYTE (%info_off% + 0xc4 + 0x77) 0
  WRITE_BYTE (%info_off% + 0xc4 + 0x78) 0
  WRITE_BYTE (%info_off% + 0xc4 + 0x79) 0
  WRITE_BYTE (%info_off% + 0xc4 + 0x7a) 0
  WRITE_BYTE (%info_off% + 0xc4 + 0x7b) 0
  WRITE_ASCII (%info_off% + 0xc4 + 0x7c) ~endch4~ (8)
  WRITE_SHORT (%info_off% + 0xc4 + 0x84) 0
  WRITE_SHORT (%info_off% + 0xc4 + 0x86) 0
  WRITE_SHORT (%info_off% + 0xc4 + 0x88) 0
  WRITE_SHORT (%info_off% + 0xc4 + 0x8a) 0
  WRITE_ASCII (%info_off% + 0xc4 + 0xbc) ~~ (8)
  FOR (y=0x8c; y<0xbc; y+=1) BEGIN
   WRITE_BYTE (%info_off% + 0xc4 + %y%) 0
  END
// Chapter trigger 1 -- verticies
  READ_LONG 0x7c vertex_off
  WRITE_SHORT (%vertex_off% + 0) 380
  WRITE_SHORT (%vertex_off% + 2) 1076
  WRITE_SHORT (%vertex_off% + 4) 510
  WRITE_SHORT (%vertex_off% + 6) 1160
  WRITE_SHORT (%vertex_off% + 8) 439
  WRITE_SHORT (%vertex_off% + 10) 1263
  WRITE_SHORT (%vertex_off% + 12) 468
  WRITE_SHORT (%vertex_off% + 14) 1277
  WRITE_SHORT (%vertex_off% + 16) 541
  WRITE_SHORT (%vertex_off% + 18) 1148
  WRITE_SHORT (%vertex_off% + 20) 393
  WRITE_SHORT (%vertex_off% + 22) 1062
// Chapter trigger 2 -- verticies
  WRITE_SHORT (%vertex_off% + 24) 1523
  WRITE_SHORT (%vertex_off% + 26) 292
  WRITE_SHORT (%vertex_off% + 28) 1607
  WRITE_SHORT (%vertex_off% + 30) 356
  WRITE_SHORT (%vertex_off% + 32) 1629
  WRITE_SHORT (%vertex_off% + 34) 334
  WRITE_SHORT (%vertex_off% + 36) 1550
  WRITE_SHORT (%vertex_off% + 38) 272
 END
BUT_ONLY_IF_IT_CHANGES
>>>>>>>>

My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm

#11 Miloch

Miloch

    Barbarian

  • Modder
  • 6553 posts

Posted 24 May 2009 - 09:40 AM

My goal is to shorten the amount of code needed.

Hear, hear. (Wow, I didn't think I'd actually ever hear you say that :P.)

Wouldn't it be better served as a tph file that could be included via PATCH_INCLUDE?

Yep. I think the new convention for patch macros is .tpp and action macros .tpa rather than .tph, though you can put whatever extension on them you want. That one below looks like an action macro (called by INCLUDE rather than PATCH_INCLUDE).

I adapted Ascension64's code to add a container to an area and it seems to work fine. It's at 118 lines for the action macro and another 100 for a patch macro that gets cycled to update offsets. I think it can be shortened/standardised even more though. Of course, I tend to use short variable names and leave things off like percentages and quotes around variables unless they're necessary to keep the byte size of the macro files down too (hey, some mods are bloated enough :P). Also, no real need to write zeros to offsets at inserted bytes, since they should be zero by default.

t-container_add.tpa:
COPY_EXISTING ~%area%.are~ ~override~
  READ_LONG 0x54 actor_off
  READ_LONG 0x5c info_off
  READ_LONG 0x60 spawn_off
  READ_LONG 0x68 entr_off
  READ_LONG 0x70 ctnr_off
  READ_SHORT 0x74 ctnr_num
  READ_LONG 0x78 itm_off
  READ_LONG 0x7c vertex_off
  READ_LONG 0x84 ambient_off
  READ_LONG 0x88 var_off
  READ_LONG 0xa8 door_off
  READ_LONG 0xa0 explored_off
  READ_LONG 0xb0 anim_off
  READ_LONG 0xb8 tiled_off
  READ_LONG 0xbc song_off
  READ_LONG 0xc0 rest_off
  READ_LONG 0xc4 automap_off

  //Add a container
  INSERT_BYTES ctnr_off 0xc0
  WRITE_ASCII ctnr_off ~Container 1~ //Name
  WRITE_SHORT (ctnr_off + 0x20) 4590 // locX
  WRITE_SHORT (ctnr_off + 0x22) 1525 // locY
  WRITE_SHORT (ctnr_off + 0x24) 8 //Type (nonvisible)
  WRITE_SHORT (ctnr_off + 0x26) 100 //Lock difficulty
  WRITE_SHORT (ctnr_off + 0x2e) 100 //Trap removal difficulty
  WRITE_SHORT (ctnr_off + 0x34) 4600 // Trap locX
  WRITE_SHORT (ctnr_off + 0x36) 1535 // Trap locY
  WRITE_SHORT (ctnr_off + 0x38) 4564 // Bound left
  WRITE_SHORT (ctnr_off + 0x3a) 1511 // Bound top
  WRITE_SHORT (ctnr_off + 0x3c) 4580 // Bound right
  WRITE_SHORT (ctnr_off + 0x3e) 1521 // Bound bottom

  //Update offsets and number of containers
  arx_incr = 0xc0
  SPRINT arx_dt ~ctnr~
  PATCH_INCLUDE ~goblins/lib/a6_are_update.tpp~
  WRITE_SHORT 0x74 (ctnr_num + 1)

  //Determine where to insert vertices
  READ_SHORT 0x5a info_num
  PATCH_IF (info_num != 0) BEGIN
	READ_SHORT (info_off + (info_num - 1) * 0xc4 + 0x2a) info_vx_num
	READ_LONG (info_off + (info_num - 1) * 0xc4 + 0x2c) info_vx_idx
	insert_idx = info_vx_num + info_vx_idx
  END ELSE BEGIN
	insert_idx = 0
  END

  //Insert vertices
  READ_SHORT 0x80 vertex_num
  vertex_new_num = 6
  INSERT_BYTES (vertex_off + insert_idx * 0x4) (vertex_new_num * 0x4)
  WRITE_SHORT (vertex_off + insert_idx * 0x4) 4558
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x2) 1519
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x4) 4564
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x6) 1511
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x8) 4576
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0xa) 1509
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0xc) 4588
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0xe) 1511
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x10) 4580
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x12) 1521
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x14) 4564
  WRITE_SHORT (vertex_off + insert_idx * 0x4 + 0x16) 1525

  //Update offsets and number of vertices
  arx_incr = 0x4
  SPRINT arx_dt ~vertex~
  FOR (i = 0; i < vertex_new_num; i += 1) BEGIN
	PATCH_INCLUDE ~goblins/lib/a6_are_update.tpp~
  END
  WRITE_SHORT 0x80 (vertex_num + vertex_new_num)

  //Update vertex information for new container
  WRITE_LONG (ctnr_off + 0x50) insert_idx //First vertex index
  WRITE_LONG (ctnr_off + 0x54) vertex_new_num //Number of vertices

  //Update vertex indices for info points
  READ_SHORT 0x5a info_num
  FOR (i = 0; i < info_num; i += 1) BEGIN
	READ_SHORT (info_off + i * 0xc4 + 0x2c) info_vx_fidx
	PATCH_IF (info_vx_fidx >= insert_idx) BEGIN
	  WRITE_SHORT (info_off + i * 0xc4 + 0x2c) (info_vx_fidx + vertex_new_num)
	END
  END

  //Update vertex indices for other containers
  READ_SHORT 0x74 ctnr_num
  FOR (i = 1; i< ctnr_num; i += 1) BEGIN
	READ_LONG (ctnr_off + i * 0xc0 + 0x50) ctnr_vx_fidx
	PATCH_IF (ctnr_vx_fidx >= insert_idx) BEGIN
	  WRITE_LONG (ctnr_off + i * 0xc0 + 0x50) (ctnr_vx_fidx + vertex_new_num)
	END
  END

  //Update vertex indices for doors
  READ_SHORT 0xa4 door_num
  FOR (i = 0; i < door_num; i += 1) BEGIN
	READ_LONG (door_off + i * 0xc8 + 0x2c) door_vx_open_fidx
	PATCH_IF (door_vx_open_fidx >= insert_idx) BEGIN
	  WRITE_LONG (door_off + i * 0xc8 + 0x2c) (door_vx_open_fidx + vertex_new_num)
	END
	READ_LONG (door_off + i * 0xc8 + 0x34) door_vx_closed_fidx
	PATCH_IF (door_vx_closed_fidx >= insert_idx) BEGIN
	  WRITE_LONG (door_off + i * 0xc8 + 0x34) (door_vx_closed_fidx + vertex_new_num)
	END
	READ_LONG (door_off + i * 0xc8 + 0x48) door_vx_impede_closed_fidx
	PATCH_IF (door_vx_impede_closed_fidx >= insert_idx) BEGIN
	  WRITE_LONG (door_off + i * 0xc8 + 0x48) (door_vx_impede_closed_fidx + vertex_new_num)
	END
	READ_LONG (door_off + i * 0xc8 + 0x50) door_vx_impede_open_fidx
	PATCH_IF (door_vx_impede_open_fidx >= insert_idx) BEGIN
	  WRITE_LONG (door_off + i * 0xc8 + 0x50) (door_vx_impede_open_fidx + vertex_new_num)
	END
  END
BUT_ONLY_IF_IT_CHANGES
a6_are_update.tpp:
SPRINT arx_dt_off ~%arx_dt%_off~
SPRINT arx_dt_num ~%arx_dt%_num~
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~actor~)=0))
		  AND ((actor_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((actor_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x54 (actor_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~info~)=0))   
		  AND ((info_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((info_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x5c (info_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~spawn~)=0))
		  AND ((spawn_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((spawn_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x60 (spawn_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~entrance~)=0))
		  AND ((entr_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((entr_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x68 (entr_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~ctnr~)=0))
		  AND ((ctnr_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((ctnr_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x70 (ctnr_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~itm~)=0))
		  AND ((itm_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((itm_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x78 (itm_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~vertex~)=0))
		  AND ((vertex_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((vertex_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x7c (vertex_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~ambient~)=0))
		  AND ((ambient_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((ambient_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x84 (ambient_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~variable~)=0))
		  AND ((var_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((var_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0x88 (var_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~door~)=0))
		  AND ((door_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((door_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0xa8 (door_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~explored~)=0))
		  AND ((explored_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((explored_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0xa0 (explored_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~anim~)=0))
		  AND ((anim_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((anim_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0xb0 (anim_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~tiled~)=0))
		  AND ((tiled_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((tiled_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0xb8 (tiled_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~song~)=0))
		  AND ((song_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((song_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0xbc (song_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~rest~)=0))
		  AND ((rest_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((rest_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0xc0 (rest_off + arx_incr)
END
PATCH_IF (NOT ((~%arx_dt%~ STRING_COMPARE_CASE ~automap~)=0))
		  AND ((automap_off > EVALUATE_BUFFER ~%%arx_dt_off%%~)
		  OR ((automap_off = EVALUATE_BUFFER ~%%arx_dt_off%%~) AND (EVALUATE_BUFFER ~%%arx_dt_num%%~ = 0))) BEGIN
  WRITE_LONG 0xc4 (automap_off + arx_incr)
END

READ_LONG 0x54 actor_off
READ_LONG 0x5c info_off
READ_LONG 0x60 spawn_off
READ_LONG 0x68 entr_off
READ_LONG 0x70 ctnr_off
READ_SHORT 0x74 ctnr_num
READ_LONG 0x78 itm_off
READ_LONG 0x7c vertex_off
READ_LONG 0x84 ambient_off
READ_LONG 0x88 var_off
READ_LONG 0xa8 door_off
READ_LONG 0xa0 explored_off
READ_LONG 0xb0 anim_off
READ_LONG 0xb8 tiled_off
READ_LONG 0xbc song_off
READ_LONG 0xc0 rest_off
READ_LONG 0xc4 automap_off

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#12 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 24 May 2009 - 01:30 PM

My goal is to shorten the amount of code needed.

Hear, hear. (Wow, I didn't think I'd actually ever hear you say that :P.)

You didn't HEAR me say that. But, maybe you saw me SAY that... :P

APPEND Sasha
IF ~IfValidForPartyDialogue("Miloch")
IfValidForPartyDialogue("Sasha")
Global("ab_code_triple_check","GLOBAL",1)~
THEN BEGIN shorten
SAY ~My goal is to shorten the amount of code needed.~
IF ~~ THEN EXTERN Miloch neverhear
END
END

APPEND Miloch
IF ~~ THEN BEGIN neverhear
SAY ~Hear, hear. (Wow, I didn't think I'd actually ever hear you say that :P.)~
IF ~~ THEN EXTERN Sasha response_to_half_orc
END
END

APPEND Sasha
IF ~~ THEN BEGIN response_to_half_orc
SAY ~You didn't HEAR me say that. But, maybe you saw me SAY that... :P~
THEN DO ~IncrementGlobal("ab_code_triple_check","GLOBAL",1)~ EXIT
END
END

//begin sasha override script file

IF
AreaCheck("shsforums")
HasItem("long_code",Myself)
Detect("Miloch")
!Range("Miloch",4)
GlobalGT("ab_code_triple_check","GLOBAL",1)
THEN
RESPONSE #100
UseItem("long_code","Miloch")
END

//begin item long_code description
This item appears to be a spell scroll, but is not. If the target creature fails a save vs text they will become confused for 15 rounds. Causing the target creature to wander aimlessly attacking whatever moves whether it be friend or foe. Due to the headaches caused by such long code the target creature will loose 5 points in intelligence, 3 points in charisma and suffer 1 hp per round for the duration which is two turns.

fun aside...

I'm toying with the idea of seeing if I can move a portion of my code into a tph rather than doing the macro thing. It is already an inlined file as a whole, but if I can get something that reduces the actual tp2 length, but keeps the data being added in the tp2 that would be good. I'll keep ya updated if you wish...

I would use a macro if it was built into weidu and I could just do something like

ADD_AREA_REGION_TRIGGER ~file_name~  //the add automatically assumes insert bytes and a write for all values at the correct length
//the following would be constants that point to the correct offset location relative to the new region trigger's start point.
  AREA_RT_NAME ~Chapter trigger 1~   //region trigger name
  AREA_RT_TYPE 0					 //0=proximity;1=info;2=travel
  AREA_RT_BBOX_1 380				 //low x value
  AREA_RT_BBOX_2 1062				//low y value
  AREA_RT_BBOX_3 541				 //high x value
  AREA_RT_BBOX_4 1277				//high y value
  AREA_RT_VT_NUM 6				   //number of vertex pairs
  AREA_RT_FLAG 2					 //2=party required
  AREA_RT_TRAP_D 100				 //trap detection difficulty
  AREA_RT_TRAP_R 100				 //trap removal difficulty
  AREA_RT_TRAPPED 1				  //1=yes;0=no
  AREA_RT_LP_X 404				   //x value of launch point
  AREA_RT_LP_Y 1300				  //y value of launch point
  AREA_RT_SCRIPT ~endch4~			//region script

My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm

#13 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 25 May 2009 - 01:17 PM

Wouldn't it be better served as a tph file that could be included via PATCH_INCLUDE?


Of course. That's how I did it. (Well, I just did INCLUDE, not PATCH_INCLUDE). You might want to download my mods and look around and see how it was actually used.

A good reference would be PST-UB/Candlestick/tph/Candlestick.tph.

For me personally, your portion that changes the offset number to a variable name is pointless. I always have to refer to the IESDP because I forget whether it is _BYTE _SHORT _LONG or _ASCII. So for me, the offset number might as well be there too.


I don't generally need to check IESDP for what data types each field is because, when I go to use my macros, I just pull up the last time I used it and edit my writes. Example from candlestick.tph:

COPY_EXISTING ~AR0109.ARE~ ~override~
  LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
  LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
  SET "Q_New_Actor" = 1
  SET "Q_New_Trigg" = 2
  SET "Q_New_Vertx" = 10
  LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

// Add Actor

  WRITE_ASCII "Q_NewOffset_Actor"		   ~Ulthera~	  #32 // Name
  WRITE_ASCII "Q_NewOffset_Actor" + 0x80	~ULTHERA~	  #8  // CRE
  WRITE_ASCII "Q_NewOffset_Actor" + 0x48	~DULTHERA~	 #8  // DLG
  WRITE_LONG  "Q_NewOffset_Actor" + 0x38	0xffffffff		 // Unknown
  WRITE_SHORT "Q_NewOffset_Actor" + 0x20	1554			   // Pos X
  WRITE_SHORT "Q_NewOffset_Actor" + 0x22	2026			   // Pos Y
  WRITE_SHORT "Q_NewOffset_Actor" + 0x24	1554			   // Des X
  WRITE_SHORT "Q_NewOffset_Actor" + 0x26	2026			   // Des Y
  WRITE_SHORT "Q_NewOffset_Actor" + 0x34	9				  // Orientation
  WRITE_LONG  "Q_NewOffset_Actor" + 0x40	0x00ffffff		 // Present
  WRITE_SHORT "Q_NewOffset_Actor" + 0x28	1				  // Visible

// Add 2 Triggers

  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0)		 ~candle1~	   #32 // Name
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x20  2				   // Travel Trigger Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x22  695				 // Left
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x24  686				 // Top
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x26  804				 // Right
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x28  839				 // Bottom
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x2a  5				   // Num of Vertexes
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x2c  "Q_Num_Vertx" - 10  // First Vertex Index
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x34  48				  // Cursor Frame
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x38  ~AR0207~		 #8 // Destination Area
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x40  ~fr0109~		#32 // Entrance name
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x60  0x0004			  // Party Required Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x70  749				 // Trap Loc X
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x72  762				 // Trap Loc Y
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x7c  ~~			  #32 // Script Name (BCS)

  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1)		 ~cantrig1~	  #32 // Name
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x20  0				   // Proximity Trigger Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x22  572				 // Left
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x24  697				 // Top
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x26  876				 // Right
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x28  918				 // Bottom
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x2a  5				   // Num of Vertexes
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x2c  "Q_Num_Vertx" - 5   // First Vertex Index
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x34  0				   // Cursor Frame
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x38  ~~			   #8 // Destination Area
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x40  ~~			  #32 // Entrance name
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x60  0x0002			  // Reset Trap Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x70  724				 // Trap Loc X
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x72  807				 // Trap Loc Y
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 1) + 0x7c  ~CANTRIG1~	  #32 // Script Name (BCS)

// Add 10 Vertexes

  WRITE_SHORT "Q_NewOffset_Vertx" + 0   804
  WRITE_SHORT "Q_NewOffset_Vertx" + 2   779
  WRITE_SHORT "Q_NewOffset_Vertx" + 4   784
  WRITE_SHORT "Q_NewOffset_Vertx" + 6   686
  WRITE_SHORT "Q_NewOffset_Vertx" + 8   698
  WRITE_SHORT "Q_NewOffset_Vertx" + 10  736
  WRITE_SHORT "Q_NewOffset_Vertx" + 12  695
  WRITE_SHORT "Q_NewOffset_Vertx" + 14  839
  WRITE_SHORT "Q_NewOffset_Vertx" + 16  804
  WRITE_SHORT "Q_NewOffset_Vertx" + 18  779

  WRITE_SHORT "Q_NewOffset_Vertx" + 20  721
  WRITE_SHORT "Q_NewOffset_Vertx" + 22  918
  WRITE_SHORT "Q_NewOffset_Vertx" + 24  572
  WRITE_SHORT "Q_NewOffset_Vertx" + 26  865
  WRITE_SHORT "Q_NewOffset_Vertx" + 28  794
  WRITE_SHORT "Q_NewOffset_Vertx" + 30  697
  WRITE_SHORT "Q_NewOffset_Vertx" + 32  876
  WRITE_SHORT "Q_NewOffset_Vertx" + 34  809
  WRITE_SHORT "Q_NewOffset_Vertx" + 36  721
  WRITE_SHORT "Q_NewOffset_Vertx" + 38  918

Next time I need to an actor to an area, I just copy-paste that first Actor section, which already has most of the fields I'd need to touch, along with what data type it is in the WRITE_XXXX, and modify the values being written as necessary. Doing so also saves you a lot of time cause it contains the offsets -within- a particular actor record. I kinda figured copy-pasting your writes would be a given :)

Lastly, if you think my macros contain excessive code, I think that yes, you are counting the comments. If you actually remove the comments, you'll see that the macros are in fact quite short and, I think, pretty darn efficient. Especially Q_AREAdd_Process. That very short macro does pretty much all of the work, everything else is just initializing variables.

Qwinn

Edited by Qwinn, 25 May 2009 - 01:37 PM.


#14 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 26 May 2009 - 03:06 PM

For me personally, your portion that changes the offset number to a variable name is pointless. I always have to refer to the IESDP because I forget whether it is _BYTE _SHORT _LONG or _ASCII. So for me, the offset number might as well be there too.


I don't generally need to check IESDP for what data types each field is because, when I go to use my macros, I just pull up the last time I used it and edit my writes.
....
Next time I need to an actor to an area, I just copy-paste that first Actor section, which already has most of the fields I'd need to touch, along with what data type it is in the WRITE_XXXX, and modify the values being written as necessary. Doing so also saves you a lot of time cause it contains the offsets -within- a particular actor record. I kinda figured copy-pasting your writes would be a given smile.gif

You've probably done a lot more area editing than I have and are more comfortable and sure with what you have previously done. I've only actually made three area edits that I can think of. Two of them are actual edits with existing stuff and I did copy and paste my code between them to a point. The third is what I had posted earlier and that I had actually (with the help of IESDP) extrapolated from a macro and patch that Ascension64 did for me to add the hidden container in the Friendly Arm Inn area of BG to my vanilla game.
It's my preference to have the IESDP open when I do my modding. Even though I copy and paste code sometimes, I still like to make sure that it does point to what it is supposed to be pointing to.

I will see if I can find something you've done and take a look at it...

EDIT: I found the Candlestick tph inside the tweaks package. I recognize what you posted above. Maybe I'm just not ready for something this complex. My eyes are spinning just looking at the code. I had no clue that macros could be inside of an external file, I always thought they had to be in the header of the tp2. I looked at the macros and I can see where you set variable names to the offsets and then read the variable values to get the offset information (to me that's doing the job twice) but after that the macros begin to not make much sense.

They obviously work because you use them. I just have a strong feeling that I won't be able to work it right. I think for now, I need to advance slowly. I'm going to see if I can set/sprint my values inside the tp2 and then use those variables inside a tph where the code I posted above is used but shortened so that I deal with only one trigger at a time.

I guess it'd be like comparing a VW to a Porsche. They both might have the same engine, but they sure do look different...

One question how did you know what value to use in the Flags setting of the region trigger section?
WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x60  0x0004			  // Party Required Flag
The IESDP states that it is in bits and I've always been told that when dealing with bits you've got to use the BAND and BOR stuff to get it set correctly.

Edited by Sasha Al'Therin, 26 May 2009 - 03:36 PM.

My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm

#15 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 27 May 2009 - 09:57 AM

EDIT: I found the Candlestick tph inside the tweaks package.


You mean UB, right?

All 3 of my mods contain all my macro definitions in a directory called utils... as in PST-Fix/utils, PST-UB/utils and PST-Tweak/utils. Candlefix.tph and other components that use those macros then individually INCLUDE those definitions. Yes, I probably could've called it once at the top of the main mod, but I preferred to do so individually in each component that actually uses them, because I dislike having programs that seem to magically call invisible commands, and I prefer my components to be self-contained. The way it's done, when looking at any specific component, it is very clear and obvious where the macros are defined, you don't have to go looking back to the .TP2 to see where vital stuff gets done, and the component is more portable.

I looked at the macros and I can see where you set variable names to the offsets and then read the variable values to get the offset information (to me that's doing the job twice)


I explain why I do that within the comments:

// Why store the offsets if I already have the values stored in variables? So I know where to
// write back to when I need to at the end of my editing.

Once all my edits are done, my macro adjusts the offsets and the counts. I need the offsets for that. I think the macros are also much more readable by giving the offsets variable names indicating what they are instead of just using hardcoded offsets all over the place.

And actually, my PATCH_FOR_EACHes in the Process mod -need- them to all be stored as variables. The PATCH_FOR_EACHes are the crux to how the whole Process macro works. It iterates for each string in the statement, so basically it scans for every kind of section you could possibly want to add. That's how you can say "I want 3 actors, 4 triggers, and 30 vertexes" with one call to the macro, instead of needing to do 3 separate calls for each type of section.

I just have a strong feeling that I won't be able to work it right.


I'm sorry you feel that way. I did try to make it so that you don't actually need to understand how the macros work at all. It's designed to take care of inserting space and adjusting offsets and counts for you, so that all you have to do is write the new records to the offsets which the macros provide you.

Everything my macros do can be done manually by checking IESDP and doing your inserts and stuff one field at a time. Their point is to save you all that overhead which, IMO, is 90% of the time and effort required.

Still, you seem to be doing triggers, which is probably the most complex use of my macros, seeing as how you also have to deal with vertexes and everything. So I can see why that can get confusing. The macros -can- handle those too though.

The IESDP states that it is in bits and I've always been told that when dealing with bits you've got to use the BAND and BOR stuff to get it set correctly.


It is in bits. Explaining this might be a bit complicated. Look at the flag field of a trigger in Near Infinity. Don't even bother continuing to read this until you are looking at it, it will make no sense otherwise.

Each column you see in NI there represents one byte. One byte represents 8 flags. There are 4 columns, therefore 4 bytes, which is why it's a WRITE_LONG. It's backwards, though, and needs to be written right to left. The first column is actually the 4th byte, the second column is the 3rd byte, etc.

One byte is used to correspond to the setting of 8 separate flags. Each flag position has a value - flag 0 = 1, flag 1 = 2, flag 2 = 4, flag 3 = 8, flag 4 = 16, flag 5 = 32, flag 6 = 64 and flag 7 = 128... determine which flags you want "on", and add up their values. You'll always get a number between 0 and 255, which can be stored as a single byte.

Now highlight that flag field in the trigger I mentioned in NI. Underneath identifies what each flag represents. Each column is one byte, reading right to left. In the WRITE you quoted, I only wanted the leftmost column (which actually represents the rightmost byte in the write, as I said it reads right to left) to have a value... I wanted the "Party Required" flag to be checked in that first column and nothing else. So... writing right to left, I wrote 0 (everything in 4th column unchecked) 0 (everything in 3rd column unchecked) 0 (everything in 2nd column unchecked) 4 (only flag 2 in first column checked).

BAND and BOR would I think only be required if you were editing an existing field, to make sure that you were patching over previous mod's changes to those flags rather than overwriting them, but if you're effectively creating the area new, that's not necessary.

Qwinn

Edited by Qwinn, 27 May 2009 - 10:08 AM.


#16 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 27 May 2009 - 02:17 PM

I managed to get something working that will shorten the tp2 code considerably. Miloch should be happy about that 8)
It's not a macro, but all the values are set using the outer forms of SPRINT and SET. Unlike yours it can only handle one trigger at a time. Which is no big deal to me. Most of weidu's built in macros can only add one thing at a time. Example: ADD_CRE_ITEM only adds one item.
My goal was to have something more in the vein of ADD_CRE_ITEM anyway.

You can download a copy of what I did from my website if you'd like to look at it. The page where I've got it listed...

Oh, I managed to use the BOR command for setting the flag value in the new writes.

I like to understand what the code is doing so I could debug my own mods if anyone ever has trouble with something. So if I use code from someone else, I have to take the time to understand what it does. Your code contains things that blow my mind. I know there is a tutorial in the Weidu readme for those array things I think you used, but I got lost in the tutorial. It was like this for me way back when I first started coding with weidu. It's not a lost cause if I currently choose to go another route. I might come back to this eventually, maybe after I've learned more about the stuff inside it though. The patch_for_each was another thing that I didn't get.

I'm a hands on learner. I need to actually do it myself and get it to work. Once I've gotten my own code to work, I can then begin to understand what other people's code is supposed to do. I just have to find a reason within a tp2 component to use an array and patch_for_each.

Couple questions... You needed to set the offsets inside variables for the patch_for_each because patch_for_each only deals in variables is that correct? So since you had set the offsets inside the variables you went ahead and used the variables instead of the offset values themselves in all other instances. You could have used the actual offsets in other locations if you wanted to, correct? Just wanted to know, because if I play around with the patch_for_each thing I don't want to have to use the variables all the time for everything else (even if it does make things easier).

What does patch_for_each do anyway? Weidu readme says that SConrad owes some documentation on that. I'm going to assume (but that gets me in trouble) that based on what I know about adding region triggers to area files and on where I think you are using it in your macros that patch_for_each modifies a list of variables by a set amount defined somewhere... but that's where my understanding ends...
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm

#17 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 06:56 AM

I'll walk you through it. Here is the macro:

PATCH_FOR_EACH "S1" IN
  ~Actor~ ~Trigg~ ~Spawn~ ~Entra~ ~Conta~ ~Items~ ~Ambie~ ~Varia~ ~Doors~
  ~Tiled~ ~Vertx~ ~Explo~ ~Anima~ ~Songs~ ~RestS~
BEGIN
  SET "Q_NewSect" = $Q_New("%S1%") // How many new sections user has asked for
  PATCH_IF !("Q_NewSect" = 0) THEN
  BEGIN
	// WRITE_ASCII 0x33c ~%S1%~ #32 // DEBUG
	SET "Q_OoNSect" = $Q_OoN("%S1%") // Offset where count of each section is stored
	SET "Q_NumSect" = $Q_Num("%S1%") // Original count for that section
	SET "Q_OoOSect1" = $Q_OoO("%S1%") // Offset of offset for the section
	SET "Q_Offset1" = $Q_Off("%S1%") // Offset of the section being added to
	SET "Q_SizSect" = $Q_Siz("%S1%") // The size of one new section
	PATCH_FOR_EACH "S2" IN
	  ~Actor~ ~Trigg~ ~Spawn~ ~Entra~ ~Conta~ ~Items~ ~Ambie~ ~Varia~ ~Doors~
	  ~Tiled~ ~Vertx~ ~Explo~ ~Anima~ ~Songs~ ~RestS~
	BEGIN
	  // WRITE_ASCII 0x33c ~%S1% %S2%~ #32 // DEBUG
	  SET "Q_Offset2" = $Q_Off("%S2%") // Offset of each other section
	  SET "Q_OoOSect2" = $Q_OoO("%S2%") // Offset of that offset
	  SET "Q_OldInsert" = $Q_NewOffset("%S2%") // Previous insert offsets need to be updated too
	  PATCH_IF "Q_Offset2" > "Q_Offset1" THEN
	  BEGIN
		WRITE_LONG "Q_OoOSect2" ("Q_Offset2" + ("Q_NewSect" * "Q_SizSect"))
	  END
	  PATCH_IF "Q_OldInsert" > "Q_Offset1" THEN
	  BEGIN
		SET $Q_NewOffset("%S2%") = $Q_NewOffset("%S2%") + ("Q_NewSect" * "Q_SizSect")
	  END
	END
	SET $Q_NewOffset("%S1%") = "Q_Offset1" + ("Q_NumSect" * "Q_SizSect")
	SET "Q_InsertOffset" = $Q_NewOffset("%S1%")
	PATCH_IF "Q_ManualInsert" = 0 THEN
	BEGIN
	  INSERT_BYTES "Q_InsertOffset" ("Q_NewSect" * "Q_SizSect")
	END
	WRITE_SHORT "Q_OoNSect" ("Q_NumSect" + "Q_NewSect")
	LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~  // Reset all our variables to their new values
  END
END

PATCH_FOR_EACH is just a loop. Just like any other programming language's looping structure. In this case:

PATCH_FOR_EACH "S1" IN
~Actor~ ~Trigg~ ~Spawn~ ~Entra~ ~Conta~ ~Items~ ~Ambie~ ~Varia~ ~Doors~
~Tiled~ ~Vertx~ ~Explo~ ~Anima~ ~Songs~ ~RestS~

...runs 15 times. The first pass through the loop, %S1% equals ~Actor~. The second pass, %S1% equals ~Trigg~. The third time, %S1% equals ~Spawn~. In this way, I have the loop run once for each type of section that can be added to an area. First thing it does:

SET "Q_NewSect" = $Q_New("%S1%")

is check if the user asked for new records of that section type to be created. In the first pass through that loop, when S1 resolves, that statement becomes:

SET "Q_NewSect" = $Q_NewActor

If that value is zero, we don't need to do anything else, skip to the next loop pass (S1 = ~Trigg~).

You'll notice that if it's not zero, then after initializing some more variables, I run through an inner PATCH_FOR_EACH loop almost identical in structure (though in this case, the first pass has S2, rather than S1, set to ~Actor~. Next inner loop pass, S2 = ~Trigg~. Etc. The purpose of this second, inner loop is to run through the offsets of every other section in the area file and, if their offset comes after the one I'm adding records to, I add the size of the new records to those offsets.

So, if I want to add one actor, I set Q_NewActor to 1 in my code, then run my macro. The loop begins with S1 = ~Actor~. Q_NewSect = Q_NewActor, therefore 1. Grab some offsets/values:

SET "Q_OoNSect" = $Q_OoN("%S1%") // Offset where count of each section is stored
	SET "Q_NumSect" = $Q_Num("%S1%") // Original count for that section
	SET "Q_OoOSect1" = $Q_OoO("%S1%") // Offset of offset for the section
	SET "Q_Offset1" = $Q_Off("%S1%") // Offset of the section being added to
	SET "Q_SizSect" = $Q_Siz("%S1%") // The size of one new section

(remember, $Q_OoN("%S1%") during this pass is equivalent to Q_OoNActor. S1 = Actor in all these lines. If this were my second pass through my S1 loop, so that S1 equals "Trigg" on this pass, then it would fetch all the values I initialized for Triggers, such as Q_OoNTrigg, Q_NumTrigg, Q_OoOTrigg, Q_OffTrigg, and Q_SizTrigg.)

... then run through an inner loop where S1 still = ~Actor~, and S2 = ~Actor~. Then S1 still = ~Actor~, but S2 = ~Trigg~. At this point, we add the size of one actor record to the area file's Triggers offset. Then, next S2 loop, add the size of an Actor record to my Spawn offset. Then, next S2 loop, add the size of an Actor record to my Entrances offset. Etc. etc.

I won't drown you by adding any more... hopefully that gets you on the right track though. Let me know if you need further explanation. I'm hoping this will also make clear why I store everything as a variable (so I can use %S1% and %S2% as dynamic parts of my variable names).

Qwinn

Edited by Qwinn, 28 May 2009 - 07:18 AM.


#18 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 28 May 2009 - 07:27 AM

Incidentally, this shows an outstanding flexibility in WeiDU as a programming language. I was, and remain, seriously impressed. I have at least a basic knowledge of quite a few programming languages, and none I can think of allow you to do dynamic compilation of variable names like that.

It took me quite a while to accept the fact that it -could- do something like that, heh. Most programming languages would throw out a mountain of compiler errors the moment it tried to resolve Q_New("%S1%") into an actual usable variable. Dynamically resolve %S1% as a string, sure. As an array element, sure. But as part of a variable name? That's nifty (and powerful) as all hell. Hopefully my macro is a good demonstration of how powerful that can be.

Qwinn

Edited by Qwinn, 28 May 2009 - 07:32 AM.


#19 Miloch

Miloch

    Barbarian

  • Modder
  • 6553 posts

Posted 28 May 2009 - 10:06 AM

Yeah, PATCH_FOR_EACH and ACTION_FOR_EACH are handy, I use them a lot. Not so sure about PHP_EACH and ACTION_PHP_EACH, but I use them a few times, probably without really understanding them well (my orcish brain can only proceed to a certain level of complexity, then gets all wobbly).

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#20 Sasha Al'Therin

Sasha Al'Therin
  • Member
  • 615 posts

Posted 28 May 2009 - 01:15 PM

Had an idea that would make your macros easier for the general populace (like me) to use...

Instead of using this in the tp2:
WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0)		 ~candle1~	   #32 // Name
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x20  2				   // Travel Trigger Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x22  695				 // Left
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x24  686				 // Top
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x26  804				 // Right
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x28  839				 // Bottom
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x2a  5				   // Num of Vertexes
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x2c  "Q_Num_Vertx" - 10  // First Vertex Index
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x34  48				  // Cursor Frame
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x38  ~AR0207~		 #8 // Destination Area
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x40  ~fr0109~		#32 // Entrance name
  WRITE_LONG  "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x60  0x0004			  // Party Required Flag
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x70  749				 // Trap Loc X
  WRITE_SHORT "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x72  762				 // Trap Loc Y
  WRITE_ASCII "Q_NewOffset_Trigg" + ("Q_Siz_Trigg" * 0) + 0x7c  ~~			  #32 // Script Name (BCS)

Have it inside a tph file that you include and just allow the player to SET or SPRINT the variables. I'd be more inclined to use 'unknown but working code' if it would just take a list of variables that I set and use them. With the above, I look at it and go 'Okay where is this going and what is it doing' whereas with a list of sets and sprints I would know that it's being used by the macro launched afterward or by the tph file included afterward. It wouldn't cause any spark of fear about screwing things up. Especially if there was a pre-set list of the variables set at zero/empty named well enough that they can match up with the IESDP or NI entries.

You can look at the code I linked you to in my last post to get an idea of what I'm suggesting. I used ACTION sets and sprints, but PATCH would do the job as well. I would also suggest looking at my new list of writes, because some of them aren't needed for every trigger type and so don't need to be written unless the correct trigger type was specified, but they do need to be included as writes if you do decide to go with my above idea. In the update offset portion, there is code that looks for the presence (or lack thereof) of a certain game engine because some of it's offsets have different values than the other engines that use the same file type.

I noticed some offsets that you don't update which may not have needed updating for your work in PST but in the other engines they need updating (well, I saw that you didn't set them and so you don't update them) You don't update the offsets for automap note nor projectile traps. These are definite musts for BG2. Also saw in your list of sets at the top of the macro file, that you don't set/read certain aspects of the Song Entries and Rest Interruptions sections. Perhaps those aren't used as much in PST, but I've got a feeling that you'll want to include those other sets/reads to be safe with BG and BG2.
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm