Jump to content


Photo

Area Modding Tool & Tutorial by Qwinn


  • Please log in to reply
164 replies to this topic

#121 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 09 June 2009 - 11:54 AM

I've got generic default values assigned inside the definition in case the user doesn't need or want to set something. Things like 100 for probability1; 2 for timing mode; 1 for target; 0-1 for opcode; everything else is 0 or ~~

Eh, but this is what the WeiDU macros do, so why not save yourself (and your users/downloaders) code and use them instead? Unless you need to do other things a little more complex (which is what the Free Action macros were for, to change something surgically inside an existing item effect etc.).

What is included with weidu are MACROs and as such all values need to be set whether or not they are used. Because the item effects use the spell effect coding there is the additional variable for headers which when wanting to add a new global/equipping effect to an item makes no sense and causes confusion as to what it should be set as. I therefore took your code (because it was more readily available) and defined it as a function where I could list pre-defined values as defaults within the function definition. Now instead of needing to SET or SPRINT every variable, the user can just set what they need/want and be done with it...

Maybe it's your long variable names, though they're not as long as some people's biggrin.gif.

Yeah, yeah, yeah... and some people like to know what they are doing, when they are doing it....


General query on macros and functions...
If there are multiple components which could use the same macros and/or functions within a mod, should the macro/function definitions be loaded for each component or just once for the whole mod? I'm concerned with the possibility of someone installing part of the components, installing a different mod and then installing the rest of my mod...

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


#122 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 09 June 2009 - 01:48 PM

How is this different from my macros as they exist, other than your somehow avoiding the need to run the two InitVars macros?

The idea is to wrap yours into a FUNCTION shell, along with the writes. Thus leaving the end-modder only having to define desired values.

Retired from modding.


#123 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 09 June 2009 - 02:47 PM

To the best of my ability.

//////////
//ACTORS//
//////////

// Note: adding actors via script is usually a better solution, as it allows them to appear even if the area was already visited

SET ag_q_number = 1							 // the number of actor you've just added and are setting values for

SET ag_q = (Q_NewOffset_Actor+Q_Siz_Actor*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~ActorName~ #32	  // how it shall appear when opened in editor
WRITE_SHORT (ag_q + 0x20)  0					// position, X
WRITE_SHORT (ag_q + 0x22)  0					// position, Y
WRITE_SHORT (ag_q + 0x24)  0					// destination, Y
WRITE_SHORT (ag_q + 0x26)  0					// destination, Y
WRITE_LONG  (ag_q + 0x34)  0					// orientation, 0-15, starting south and incrementing clockwise
WRITE_LONG  (ag_q + 0x40)  0xffffffff		   // schedule, ffffffff means it's always present
WRITE_ASCII (ag_q + 0x80)  ~crefile~   #8	   // CRE file

// Note: the following generally aren't changed
WRITE_LONG  (ag_q + 0x28)  1					// unknown
WRITE_LONG  (ag_q + 0x2c)  0					// spawned flag
WRITE_LONG  (ag_q + 0x30)  0					// animation
WRITE_LONG  (ag_q + 0x38)  0xffffffff		   // unknown
WRITE_LONG  (ag_q + 0x3c)  0					// unknown
WRITE_LONG  (ag_q + 0x44)  0					// NumTimesTalkedTo(x)
WRITE_ASCII (ag_q + 0x48)  ~~		  #8	   // dialog
WRITE_ASCII (ag_q + 0x50)  ~~		  #8	   // script (override)
WRITE_ASCII (ag_q + 0x58)  ~~		  #8	   // script (class)
WRITE_ASCII (ag_q + 0x60)  ~~		  #8	   // script (race)
WRITE_ASCII (ag_q + 0x68)  ~~		  #8	   // script (general)
WRITE_ASCII (ag_q + 0x70)  ~~		  #8	   // script (default)
WRITE_ASCII (ag_q + 0x78)  ~~		  #8	   // script (specific)


////////////
//TRIGGERS//
////////////

SET ag_q_number = 1							 // the number of infotrigger you've just added and are setting values for

SET ag_q = (Q_NewOffset_Trigg+Q_Siz_Trigg*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~TriggerName~  #32   // trigger's name
WRITE_SHORT (ag_q + 0x20)  0					// type
WRITE_SHORT (ag_q + 0x22)  0					// bounding box, left
WRITE_SHORT (ag_q + 0x24)  0					// bounding box, top
WRITE_SHORT (ag_q + 0x26)  0					// bounding box, right
WRITE_SHORT (ag_q + 0x28)  0					// bounding box, down
WRITE_SHORT (ag_q + 0x2a)  0					// vertex count
WRITE_LONG  (ag_q + 0x2c)  0					// vertex index
WRITE_LONG  (ag_q + 0x30)  0					// unknown
WRITE_LONG  (ag_q + 0x34)  0					// cursor
WRITE_ASCII (ag_q + 0x38)  ~~			 #8	// exit ARE resref
WRITE_ASCII (ag_q + 0x40)  ~EntranceName~ #32   // destination entrance
WRITE_SHORT (ag_q + 0x60)  0					// flags
WRITE_SHORT (ag_q + 0x62)  0					// more flags, none seems to be ever used
WRITE_LONG  (ag_q + 0x64)  0					// dialog.tlk string for info points (type = 1)
WRITE_SHORT (ag_q + 0x68)  0					// trap detection difficulty
WRITE_SHORT (ag_q + 0x6a)  0					// trap removal difficulty
WRITE_SHORT (ag_q + 0x6c)  0					// is 'trap' trapped?
WRITE_SHORT (ag_q + 0x6e)  0					// is trap detected?
WRITE_SHORT (ag_q + 0x70)  0					// trap position, X
WRITE_SHORT (ag_q + 0x72)  0					// trap position, Y
WRITE_ASCII (ag_q + 0x74)  ~~			 #8	// unknown
WRITE_ASCII (ag_q + 0x7c)  ~~			 #8	// BCS resref for triggers (type = 0)


//////////
//SPAWNS//
//////////

// Note: contains some unknowns, it might be better to use scripts instead, as BG2 often does


/////////////
//ENTRANCES//
/////////////

SET ag_q_number = 1							 // the number of entrance you've just added and are setting values for

SET ag_q = (Q_NewOffset_Entra+Q_Siz_Entra*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~EntranceName~ #32   // how it shall appear when opened in editor
WRITE_SHORT (ag_q + 0x20)  0					// position, X
WRITE_SHORT (ag_q + 0x22)  0					// position, Y
WRITE_SHORT (ag_q + 0x24)  0					// orientation, 0-15, starting south and incrementing clockwise


//////////////
//CONTAINERS//
//////////////

SET ag_q_number = 1							 // the number of container you've just added and are setting values for

SET ag_q = (Q_NewOffset_Conta+Q_Siz_Conta*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~ContainerName~ #32  // container's name
WRITE_SHORT (ag_q + 0x20)  0					// position to use, X
WRITE_SHORT (ag_q + 0x22)  0					// position to use, Y
WRITE_SHORT (ag_q + 0x24)  0					// type
WRITE_SHORT (ag_q + 0x26)  0					// lock difficulty
WRITE_LONG  (ag_q + 0x28)  0					// flags
WRITE_SHORT (ag_q + 0x2c)  0					// trap detection difficulty
WRITE_SHORT (ag_q + 0x2e)  0					// trap removal difficulty
WRITE_SHORT (ag_q + 0x30)  0					// is container trapped?
WRITE_SHORT (ag_q + 0x32)  0					// is trap detected?
WRITE_SHORT (ag_q + 0x34)  0					// trap position, X
WRITE_SHORT (ag_q + 0x36)  0					// trap position, Y
WRITE_SHORT (ag_q + 0x38)  0					// bounding box, left
WRITE_SHORT (ag_q + 0x3a)  0					// bounding box, top
WRITE_SHORT (ag_q + 0x3c)  0					// bounding box, right
WRITE_SHORT (ag_q + 0x3e)  0					// bounding box, down
WRITE_LONG  (ag_q + 0x40)  0					// item index
WRITE_LONG  (ag_q + 0x44)  0					// item count
WRITE_ASCII (ag_q + 0x48)  ~~			 #8	// trap BCS resref
WRITE_LONG  (ag_q + 0x50)  0					// vertex index
WRITE_LONG  (ag_q + 0x54)  0					// vertex count

// 0x58 #32 unknown

WRITE_ASCII (ag_q + 0x78)  ~~			#8	 // key ITM resref
WRITE_LONG  (ag_q + 0x80)  0					// unknown
WRITE_LONG  (ag_q + 0x84)  0					// dialog.tlk string when picking an unpickable container


/////////
//ITEMS//
/////////

SET ag_q_number = 1							 // the number of item you've just added and are setting values for

SET ag_q = (Q_NewOffset_Items+Q_Siz_Items*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~~			#8	 // ITM resref
WRITE_SHORT (ag_q + 0x08)  0					// expiration time
WRITE_SHORT (ag_q + 0x0a)  0					// charges 1
WRITE_SHORT (ag_q + 0x0c)  0					// charges 2
WRITE_SHORT (ag_q + 0x0e)  0					// charges 3
WRITE_LONG  (ag_q + 0x10)  0					// flags


////////////
//AMBIENTS//
////////////

SET ag_q_number = 1							 // the number of ambient you've just added and are setting values for

SET ag_q = (Q_NewOffset_Ambie+Q_Siz_Ambie*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~AmbientName~   #32  // ambient's name
WRITE_SHORT (ag_q + 0x20)  0					// position, X
WRITE_SHORT (ag_q + 0x22)  0					// position, Y
WRITE_SHORT (ag_q + 0x24)  0					// radius
WRITE_SHORT (ag_q + 0x26)  0					// height

WRITE_SHORT (ag_q + 0x28)  0					// unknown
WRITE_SHORT (ag_q + 0x2a)  0					// unknown
WRITE_SHORT (ag_q + 0x2c)  0					// unknown

WRITE_SHORT (ag_q + 0x2e)  0					// sound volume, percentage
WRITE_ASCII (ag_q + 0x30)  ~~			   #8  // 1st WAV resref
WRITE_ASCII (ag_q + 0x38)  ~~			   #8  // 2nd WAV resref
WRITE_ASCII (ag_q + 0x40)  ~~			   #8  // 3rd WAV resref
WRITE_ASCII (ag_q + 0x48)  ~~			   #8  // 4th WAV resref
WRITE_ASCII (ag_q + 0x50)  ~~			   #8  // 5th WAV resref
WRITE_ASCII (ag_q + 0x58)  ~~			   #8  // 6th WAV resref
WRITE_ASCII (ag_q + 0x60)  ~~			   #8  // 7th WAV resref
WRITE_ASCII (ag_q + 0x68)  ~~			   #8  // 8th WAV resref
WRITE_ASCII (ag_q + 0x70)  ~~			   #8  // 9th WAV resref
WRITE_ASCII (ag_q + 0x78)  ~~			   #8  // 10th WAV resref
WRITE_SHORT (ag_q + 0x80)  0					// total number of sounds
WRITE_SHORT (ag_q + 0x82)  0					// unknown
WRITE_LONG  (ag_q + 0x84)  0					// base time intervals between sounds
WRITE_LONG  (ag_q + 0x88)  0					// base time deviation
WRITE_LONG  (ag_q + 0x8c)  0xffffffff		   // time of day when active
WRITE_LONG  (ag_q + 0x00)  1					// flags


/////////////
//VARIABLES//
/////////////

// Note: you want to set variables from within a script, not like this


/////////
//DOORS//
/////////

SET ag_q_number = 1							 // the number of door you've just added and are setting values for

SET ag_q = (Q_NewOffset_Doors+Q_Siz_Doors*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~DoorName~	 #32   // A long name for this door. Could be used by scripts.
WRITE_ASCII (ag_q + 0x20)  ~~			 #8	// door's ID, used in conjunction with WED
WRITE_LONG  (ag_q + 0x28)  0					// flags

WRITE_LONG  (ag_q + 0x2c)  0					// vertex index for open state
WRITE_SHORT (ag_q + 0x30)  0					// vertex number for open state
WRITE_SHORT (ag_q + 0x32)  0					// vertex number for closed state
WRITE_LONG  (ag_q + 0x34)  0					// vertex index for closed state
WRITE_SHORT (ag_q + 0x38)  0					// bounding box for open state, left
WRITE_SHORT (ag_q + 0x3a)  0					// bounding box for open state, top
WRITE_SHORT (ag_q + 0x3c)  0					// bounding box for open state, right
WRITE_SHORT (ag_q + 0x3e)  0					// bounding box for open state, down
WRITE_SHORT (ag_q + 0x40)  0					// bounding box for closed state, left
WRITE_SHORT (ag_q + 0x42)  0					// bounding box for closed state, top
WRITE_SHORT (ag_q + 0x44)  0					// bounding box for closed state, right
WRITE_SHORT (ag_q + 0x46)  0					// bounding box for closed state, down
WRITE_LONG  (ag_q + 0x48)  0					// vertex index for closed state, impeded
WRITE_SHORT (ag_q + 0x4c)  0					// vertex number for closed state, impeded
WRITE_SHORT (ag_q + 0x4e)  0					// vertex number for open state, impeded
WRITE_LONG  (ag_q + 0x50)  0					// vertex index for open state, impeded

WRITE_SHORT (ag_q + 0x54)  0					// unknown
WRITE_SHORT (ag_q + 0x56)  0					// unknown

WRITE_ASCII (ag_q + 0x58)  ~~			  #8   // sound resref for opening
WRITE_ASCII (ag_q + 0x60)  ~~			  #8   // sound resref for closing
WRITE_LONG  (ag_q + 0x68)  30				   // cursor type
WRITE_SHORT (ag_q + 0x6c)  0					// trap detection difficulty
WRITE_SHORT (ag_q + 0x6e)  0					// trap removal difficulty
WRITE_SHORT (ag_q + 0x70)  0					// is door trapped?
WRITE_SHORT (ag_q + 0x72)  0					// is trap detected?
WRITE_SHORT (ag_q + 0x74)  0					// trap position, X
WRITE_SHORT (ag_q + 0x76)  0					// trap position, Y
WRITE_ASCII (ag_q + 0x78)  ~~			  #8   // key strref
WRITE_ASCII (ag_q + 0x80)  ~~			  #8   // script strref
WRITE_LONG  (ag_q + 0x88)  0					// detection difficulty (for secret doors)
WRITE_LONG  (ag_q + 0x8c)  0					// lock difficulty
WRITE_SHORT (ag_q + 0x90)  0					// open position, X
WRITE_SHORT (ag_q + 0x92)  0					// open position, Y
WRITE_SHORT (ag_q + 0x94)  0					// close position, X
WRITE_SHORT (ag_q + 0x96)  0					// close position, Y
WRITE_LONG  (ag_q + 0x98)  0					// message when attempting to picklock an unpickable
WRITE_ASCII (ag_q + 0x9c)  ~TrigName~	 #32   // transition infotrigger, the one that activates when the door is opened

// 0xac #8 - unknown

// Note: the following are from NI, IESDP gives different offsets
WRITE_LONG  (ag_q + 0xb4)  0					// door's name when initiating a dialog, string from dialog.tlk
WRITE_ASCII (ag_q + 0xb8)  ~~			  #8   // DLG strref


/////////////////
//TILED OBJECTS//
/////////////////

// Note: no information about this type of objects


////////////
//VERTICES//
////////////

// Note: you really want to use the alternative version instead

SET ag_q_number = 1							 // the number of vertex you've just added and are setting values for

SET ag_q = (Q_NewOffset_Vertx+Q_Siz_Vertx*(ag_q_number - 1)) // do NOT touch this line

WRITE_SHORT (ag_q + 0x00)  0					// position, X
WRITE_SHORT (ag_q + 0x02)  0					// position, Y


////////////////////////
//VERTICES ALTERNATIVE//
////////////////////////

// Note: nobody wants to handle each vertex separatedly, therefore follow this pattern,
//	   increasing the numbers inside of brackets by 4 for every additional vertex 

// 1st vertex
WRITE_SHORT (Q_NewOffset_Vertx + 0)  0		  // position, X
WRITE_SHORT (Q_NewOffset_Vertx + 2)  0		  // position, Y

// 2nd vertex
WRITE_SHORT (Q_NewOffset_Vertx + 4)  0		  // position, X
WRITE_SHORT (Q_NewOffset_Vertx + 6)  0		  // position, Y

// 3rd vertex
WRITE_SHORT (Q_NewOffset_Vertx + 8)  0		  // position, X
WRITE_SHORT (Q_NewOffset_Vertx + 10) 0		  // position, Y

// 4th vertex
WRITE_SHORT (Q_NewOffset_Vertx + 12) 0		  // position, X
WRITE_SHORT (Q_NewOffset_Vertx + 14) 0		  // position, Y

// etc.


//////////////
//ANIMATIONS//
//////////////

SET ag_q_number = 1							 // the number of animation you've just added and are setting values for

SET ag_q = (Q_NewOffset_Anima+Q_Siz_Anima*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCII (ag_q + 0x00)  ~AnimationName~ #32  // animation's name
WRITE_SHORT (ag_q + 0x20)  0					// position, X
WRITE_SHORT (ag_q + 0x22)  0					// position, Y
WRITE_ASCII (ag_q + 0x28)  ~~			  #8   // BAM resref
WRITE_LONG  (ag_q + 0x34)  0b00000000 00000000 00010000 00000101   // flags

// Note: the following generally aren't changed
WRITE_LONG  (ag_q + 0x24)  0xffffffff		   // schedule, ffffffff means it's always present
WRITE_SHORT (ag_q + 0x30)  0					// sequence number
WRITE_SHORT (ag_q + 0x32)  0					// frame number
WRITE_SHORT (ag_q + 0x38)  0					// height
WRITE_SHORT (ag_q + 0x3a)  0					// transparency, 255 is invisible
WRITE_SHORT (ag_q + 0x3c)  0					// starting frame
WRITE_BYTE  (ag_q + 0x3e)  0					// looping chance, 0 equals 100%
WRITE_BYTE  (ag_q + 0x3f)  0					// starting delay
WRITE_ASCII (ag_q + 0x40)  ~~			  #8   // palette


/////////////
//MAP NOTES//
/////////////

// Note: Qwinn says it's unused in PST

SET ag_q_number = 1							 // the number of map note you've just added and are setting values for

SET ag_q = (Q_NewOffset_MapNo+Q_Siz_MapNo*(ag_q_number - 1)) // do NOT touch this line

WRITE_SHORT (ag_q + 0x00)  0					// position, X
WRITE_SHORT (ag_q + 0x02)  0					// position, Y
WRITE_LONG  (ag_q + 0x04)  0					// strref to dialog.tlk or TOH/TOT files
WRITE_SHORT (ag_q + 0x08)  1					// Strref location (0=extenal (tot/toh), 1=internal (tlk)
WRITE_SHORT (ag_q + 0x0a)  0					// colour of the note, 0-7


///////////////
//PROJECTILES//
///////////////

// Note: adding projectiles via script is usually a better solution, as it allows them to appear even if the area was already visited
// Note: needs to be tested first, NI is of no use here

Edited by GeN1e, 09 June 2009 - 02:50 PM.

Retired from modding.


#124 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 09 June 2009 - 03:10 PM

How is this different from my macros as they exist, other than your somehow avoiding the need to run the two InitVars macros?

The idea is to wrap yours into a FUNCTION shell, along with the writes. Thus leaving the end-modder only having to define desired values.

Do you think we ought to have the discussion about making it easier for a user to use the macros into a different thread? Since the macros themselves won't be changed...

I have attempted what you've suggested. It is a difficult task to say the least. I have created functions & macros to work with Qwinn's macros when adding region triggers and the associated vertex points. But they don't wrap around Qwinn's they actually require Qwinn's macros to be run first... If you'd like to see it, just ask. I don't want to spam the thread with too much code...

@Qwinn -- I ran the aforementioned functions & macros with yours and was able to successfully add two triggers and the associated vertex points to an area in BG1. I did however forget to add the game_is checks. DLTCEP, Infinity Explorer, and Near Infinity gave no errors when opening the file. Q_Game had been pre-set to 1 which is for PST. I didn't think that there would be too much of an issue because BG is older than PST and doesn't use the sections where the Q_Game value is used. However, I will ensure that the the game_is checks are there prior to the next fixpack update....

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


#125 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 09 June 2009 - 03:34 PM

If there are multiple components which could use the same macros and/or functions within a mod, should the macro/function definitions be loaded for each component or just once for the whole mod? I'm concerned with the possibility of someone installing part of the components, installing a different mod and then installing the rest of my mod...

You can probably put it in an ALWAYS at the beginning of the mod, but that's cludgy because there are doubtless some components that do not need it, so it just bogs the runtime to load it for each one. That's another reason I prefer using .tpp/.tpa files to .tph and PATCH_INCLUDE/INCLUDE to LAUNCH_PATCH_MACRO commands.

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


#126 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 09 June 2009 - 05:28 PM

If there are multiple components which could use the same macros and/or functions within a mod, should the macro/function definitions be loaded for each component or just once for the whole mod? I'm concerned with the possibility of someone installing part of the components, installing a different mod and then installing the rest of my mod...

You can probably put it in an ALWAYS at the beginning of the mod, but that's cludgy because there are doubtless some components that do not need it, so it just bogs the runtime to load it for each one. That's another reason I prefer using .tpp/.tpa files to .tph and PATCH_INCLUDE/INCLUDE to LAUNCH_PATCH_MACRO commands.

Other than the letter, what is the difference between .tpp/.tpa and .tph files? .tph was the first extra file type that the bigg introduced with the commands INCLUDE/PATCH_INCLUDE. Where did .tpp and .tpa come from? I don't think the file extension really matters so long as it is .tpX where X is some other letter. Everything you've done in a .tpp can be done in a .tph and accessed in the very same manner.

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


#127 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 09 June 2009 - 06:16 PM

Other than the letter, what is the difference between .tpp/.tpa and .tph files? .tph was the first extra file type that the bigg introduced with the commands INCLUDE/PATCH_INCLUDE. Where did .tpp and .tpa come from? I don't think the file extension really matters so long as it is .tpX where X is some other letter.

TPA is for an action, TPP for a patch. It doesn't matter what you call the extensions, the difference is so you can easily tell what they are without digging into them. And the big difference is the method of accessing them.

Everything you've done in a .tpp can be done in a .tph and accessed in the very same manner.

Well that is where you're wrong, at least with the type of .tph files you're used to (including this one), which are laundry list includes of bunches of macros, some of which may not be necessary for any given mod or component. If you define them in separate files, you don't need a separate LAUNCH_x_MACRO, you just [PATCH_]INCLUDE your code when and only when you need it without having to do a separate LAUNCH. Moreover, you don't even have to bother INCLUDing it at the start of your code, in an ALWAYS or for each component. It's better, but don't take my word for it, there's (relatively dated at this point) threads either here, G3, PPG where the bigg, Nythrun and others concurred. I myself did not see the merits of this approach until I started using it myself, and now that I think about it, you were also party to these discussions and I thought you understood too (at the time :P).

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


#128 Mike1072

Mike1072
  • Modder
  • 539 posts

Posted 09 June 2009 - 07:18 PM

General query on macros and functions...
If there are multiple components which could use the same macros and/or functions within a mod, should the macro/function definitions be loaded for each component or just once for the whole mod? I'm concerned with the possibility of someone installing part of the components, installing a different mod and then installing the rest of my mod...

Yes, for each component be sure to INCLUDE all external files that define the macros/functions you are using so it won't ever fail to install. You'll have trouble enough keeping track of everything they require if you end up using multiple files and moving your definitions between them, so don't intentionally not include something that's needed.

You can probably put it in an ALWAYS at the beginning of the mod, but that's cludgy because there are doubtless some components that do not need it, so it just bogs the runtime to load it for each one. That's another reason I prefer using .tpp/.tpa files to .tph and PATCH_INCLUDE/INCLUDE to LAUNCH_PATCH_MACRO commands.

I'm not convinced that runtime would be noticeably affected when reading a few extra macro definitions, but sticking definitions in a separate file lets you reuse functions, which IMO automatically makes it better.

By the way, yay for coding discussions.


Thanks for the list GeN1e, I'll throw up an example function stealing shamelessly from your actor block here if you don't mind, as I'm somewhat familiar with them (but not so much the other .are structures).

Function Declaration
//////////
//ACTORS//
//////////

// Note: adding actors via script is usually a better solution, as it allows them to appear even if the area was already visited

DEFINE_PATCH_FUNCTION ~WRITE_ARE_ACTOR~
  INT_VAR
	prefix_actor_offset = 0	   // required.  offset to write actor information to
	prefix_xpos = 0			   // required.  position, x
	prefix_ypos = 0			   // required.  position, y
	prefix_xdest = (0 - 1)		// optional.  destination, x (default: xpos, no movement)
	prefix_ydest = (0 - 1)		// optional.  destination, y (default: ypos, no movement)
	prefix_anim = 0			   // required?  should be equal to the value at 0x28 in the .cre
	prefix_orientation = 0		// optional.  from 0-15 for the different compass directions, starting at 0 south and going clockwise until 15 sse (default: south)
	prefix_schedule = 0xffffff	// optional.  24-bit bit field, see .are structure (default: show up at all times of day)
  STR_VAR					 
	prefix_name = ~Default Actor~ // optional.  creature's name/desc for the .are when opened in editor
	prefix_crefile = ~~		   // required.  resource name of the .cre
BEGIN
  PATCH_IF (prefix_orientation < 0 || prefix_orientation > 15) BEGIN
	PATCH_PRINT ~WRITE_ARE_ACTOR: Invalid orientation specified, defaulting to orientation 0 (south).~
	SET prefix_orientation = 0
  END
  PATCH_IF (prefix_xdest < 0) BEGIN // no destination x coordinate specified
	SET prefix_xdest = prefix_xpos
  END
  PATCH_IF (prefix_ydest < 0) BEGIN // no destination y coordinate specified.  if neither were specified, creature will stay where spawned unless scripted
	SET prefix_ydest = prefix_ypos
  END
  
  WRITE_ASCIIE (prefix_actor_offset + 0x00) ~%prefix_name%~ #32 // how it shall appear when opened in editor
  WRITE_SHORT  (prefix_actor_offset + 0x20) prefix_xpos
  WRITE_SHORT  (prefix_actor_offset + 0x22) prefix_ypos
  WRITE_SHORT  (prefix_actor_offset + 0x24) prefix_xdest
  WRITE_SHORT  (prefix_actor_offset + 0x26) prefix_ydest
  WRITE_LONG   (prefix_actor_offset + 0x28) 0b0001 // cre not attached
  WRITE_LONG   (prefix_actor_offset + 0x2c) 0 // hasn't been spawned
  WRITE_LONG   (prefix_actor_offset + 0x30) prefix_anim
  WRITE_LONG   (prefix_actor_offset + 0x34) prefix_orientation // orientation, 0-15, starting south and incrementing clockwise
  WRITE_LONG   (prefix_actor_offset + 0x38) 0xffffffff // 'visible' flag that needs to be -1
  WRITE_LONG   (prefix_actor_offset + 0x40) prefix_schedule // schedule, 0xffffffff means it's always present
  WRITE_LONG   (prefix_actor_offset + 0x44) 0 // NumTimesTalkedTo(x)
  WRITE_ASCIIE (prefix_actor_offset + 0x48) ~~ #8 // dialog
  WRITE_ASCIIE (prefix_actor_offset + 0x50) ~~ #8 // script (override)
  WRITE_ASCIIE (prefix_actor_offset + 0x58) ~~ #8 // script (class)
  WRITE_ASCIIE (prefix_actor_offset + 0x60) ~~ #8 // script (race)
  WRITE_ASCIIE (prefix_actor_offset + 0x68) ~~ #8 // script (general)
  WRITE_ASCIIE (prefix_actor_offset + 0x70) ~~ #8 // script (default)
  WRITE_ASCIIE (prefix_actor_offset + 0x78) ~~ #8 // script (specific)
  WRITE_ASCIIE (prefix_actor_offset + 0x80) ~%prefix_crefile%~ #8
END

And here's what you'd do if you wanted to add an actor or two, after copy/pasting the above definition somewhere. GeN1e's offset-grabbing ag_q stuff is one of the ways you can go through each actor one at a time.

Function Usage
// call Qwinn's macros, adding room for say, 2 actors, then...

SET ag_q_number = 1 // the number of actor you've just added and are setting values for
SET ag_q = (Q_NewOffset_Actor+0x110*(ag_q_number - 1)) // do NOT touch this line

LAUNCH_PATCH_FUNCTION ~WRITE_ARE_ACTOR~
  INT_VAR
	prefix_actor_offset = ag_q
	prefix_xpos = 400
	prefix_ypos = 200
	prefix_anim = 0x6100 // male human fighter
  STR_VAR					 
	prefix_name = ~Mean-Looking Fighter Dude~
	prefix_crefile = ~meanfgtr~
END

SET ag_q_number = 2 // the number of actor you've just added and are setting values for
SET ag_q = (Q_NewOffset_Actor+0x110*(ag_q_number - 1)) // do NOT touch this line

LAUNCH_PATCH_FUNCTION ~WRITE_ARE_ACTOR~
  INT_VAR
	prefix_actor_offset = ag_q
	prefix_xpos = 440
	prefix_ypos = 240
	prefix_anim = 0x6210 // female human mage
	prefix_orientation = 5 // nnw
  STR_VAR					 
	prefix_name = ~Sultry Sorceress~
	prefix_crefile = ~hawtmage~
END
The point of this is to show how a user would only have to deal with the LAUNCH_PATCH_FUNCTION ~WRITE_ARE_ACTOR~ stuff, leaving some of the repetitive and confusing stuff behind.

#129 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 09 June 2009 - 07:47 PM

I'm not convinced that runtime would be noticeably affected when reading a few extra macro definitions, but sticking definitions in a separate file lets you reuse functions, which IMO automatically makes it better.

"Not convinced" does not suggest you tested it and can say with any degree of certainty or even likelihood. In any case, why [re]include 5 or 50 macros you don't need for every component? Perhaps you overlooked my second post where I explained the advantages:
  • .tph files... are [usually] laundry list includes of bunches of macros, some of which may not be necessary for any given mod or component. (aka "why include 5 or 50 macros you don't need for every component")
  • you don't need a separate LAUNCH_x_MACRO, you just [PATCH_]INCLUDE your code when and only when you need it without having to do a separate LAUNCH
  • you don't even have to bother INCLUDing it at the start of your code, in an ALWAYS or for each component

I'll throw up an example function stealing shamelessly from your actor block here if you don't mind, as I'm somewhat familiar with them

But why even bother with that when:

Note: adding actors via script is usually a better solution, as it allows them to appear even if the area was already visited

Also, I don't understand why functions are any better than macros, apart from variables, which I've never had a problem with in any macros I've used. Though perhaps local variable use in functions keeps runtime down, but somehow I doubt that. Also why do we need STR_VAR in addition to SPRINT or INT_VAR in addition to [SET]?

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


#130 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 09 June 2009 - 08:49 PM

Also, I don't understand why functions are any better than macros, apart from variables, which I've never had a problem with in any macros I've used.

Well, it's fine when you're using your own code exclusively and thus have everything under full control. But when you get to use someone's else library you might run into an incompatibility issue.

But why even bother with that when

Key word is 'usually'. It's easier to set a schedule via inserting actor into ARE, rather than jumping him around. Btw, now that I think of it, it has to do with Aurora.

Also why do we need STR_VAR in addition to SPRINT or INT_VAR in addition to [SET]?

Do you mean this
LAUNCH_PATCH_FUNCTION name
  INT_VAR var1=1	
  STR_VAR var2 = ~idiot~
END
?

Basically, it's just a local SET, unlike global one like this
SET var1=1	
SPRINT var2  ~idiot~
LAUNCH_PATCH_FUNCTION name

Edited by GeN1e, 09 June 2009 - 08:51 PM.

Retired from modding.


#131 Mike1072

Mike1072
  • Modder
  • 539 posts

Posted 09 June 2009 - 08:55 PM

I'm not convinced that runtime would be noticeably affected when reading a few extra macro definitions, but sticking definitions in a separate file lets you reuse functions, which IMO automatically makes it better.

"Not convinced" does not suggest you tested it and can say with any degree of certainty or even likelihood. In any case, why [re]include 5 or 50 macros you don't need for every component? Perhaps you overlooked my second post where I explained the advantages:
  • .tph files... are [usually] laundry list includes of bunches of macros, some of which may not be necessary for any given mod or component. (aka "why include 5 or 50 macros you don't need for every component")
  • you don't need a separate LAUNCH_x_MACRO, you just [PATCH_]INCLUDE your code when and only when you need it without having to do a separate LAUNCH
  • you don't even have to bother INCLUDing it at the start of your code, in an ALWAYS or for each component

No, I haven't done extensive tests, but my experience when including macros and functions in some of my projects has been just fine. If I notice that the unnecessary stuff being included is having a negative effect, I'll definitely look for other solutions, but things are working out fine for the moment, and I like the benefits of this way. Regarding your list, 1) is the only point that could be a serious issue. 3) means one line of extra code and 2) is a re-statement of 3). I probably like my macros to be concentrated so that it's easier to keep track of them and add or test new macros/code blocks, but I am a bit hypocritical because I also like to stick my different components in separate files.

I'll throw up an example function stealing shamelessly from your actor block here if you don't mind, as I'm somewhat familiar with them

But why even bother with that when:

Note: adding actors via script is usually a better solution, as it allows them to appear even if the area was already visited

Well, adding actors to the .are may still be desirable (yay for NPCs who don't apparate in front of you), but more importantly, the idea was to showcase how it could work for any of them, with the example being based on one where I knew which fields were important and might want to be set by the user and which could be ignored.

Also, I don't understand why functions are any better than macros, apart from variables, which I've never had a problem with in any macros I've used. Though perhaps local variable use in functions keeps runtime down, but somehow I doubt that. Also why do we need STR_VAR in addition to SPRINT or INT_VAR in addition to [SET]?

Functions make it cleaner to call specific operations like the WeiDU macros - if implemented with functions, you wouldn't have to specify initial values before calling them in order to prevent them blowing up, plus with a little planning, you can have functions whose parameters get "reset" upon exiting without needing to copy/paste in a huge block of code at the end of your macro setting all values to their defaults. And in general, functions are a better idea in most cases to prevent clashes of variables. If you've ever written macros with FOR loops, and then called one of those macros in the middle of one of your FOR loops and wondered why your variable "i" was completely messed up, you'll get the basic idea.

#132 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 09 June 2009 - 09:44 PM

  • .tph files... are [usually] laundry list includes of bunches of macros, some of which may not be necessary for any given mod or component. (aka "why include 5 or 50 macros you don't need for every component")
  • you don't need a separate LAUNCH_x_MACRO, you just [PATCH_]INCLUDE your code when and only when you need it without having to do a separate LAUNCH
  • you don't even have to bother INCLUDing it at the start of your code, in an ALWAYS or for each component

Regarding your list, 1) is the only point that could be a serious issue.

Actually, 3 is probably the worst of those.

3) means one line of extra code

No it doesn't. It means including however many lines of code are in your .tph when it may not be necessary at all.

and 2) is a re-statement of 3).

No it isn't. In some ways, 3 is more of a restatement of 1. The second point has more to do with precision.

I probably like my macros to be concentrated so that it's easier to keep track of them and add or test new macros/code blocks, but I am a bit hypocritical because I also like to stick my different components in separate files.

Well, you said it yourself :P. But this makes your other objections rather trite. I don't really care that you've coded something your way and are stuck in your ways (that goes for anyone else here). I'm just stating the advantages of the alternative method, which I've come to see as such by those who should know.

yay for NPCs who don't apparate in front of you

I've seen even non-scripted NPCs embedded in .are files "apparate" in front of you.

If you've ever written macros with FOR loops, and then called one of those macros in the middle of one of your FOR loops and wondered why your variable "i" was completely messed up, you'll get the basic idea.

You mean because you used %i% somewhere else in your code for something else? Sounds like sloppy variable declaration :P. I've never seen this problem with FOR loops that wasn't a problem with the code or offsets rather than variables. Maybe I'm "stuck in my ways" too, but I don't offhand see the benefit of recoding my macros as functions when AFAIK they work as is, and work quickly in most cases. The only possible benefit I can see is this:

plus with a little planning, you can have functions whose parameters get "reset" upon exiting without needing to copy/paste in a huge block of code at the end of your macro setting all values to their defaults.

But very few if any of the macros I use require this, though it may be useful for Qwinn's or others. I'd have to see a real example though. It looks like your function is setting a bunch of null variables, and even writing nulls (which really shouldn't be necessary if the default inserted bytes are zero, which they are).

It's easier to set a schedule via inserting actor into ARE, rather than jumping him around. Btw, now that I think of it, it has to do with Aurora.

Well, Aurora is supposed to be scripted to move around at certain times, rather than just appear or disappear at certain hours (supposed to, anyway). In any case, you can quite easily script an NPC to appear and disappear at certain times (using time.ids or timeoday.ids as triggers).

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


#133 Mike1072

Mike1072
  • Modder
  • 539 posts

Posted 09 June 2009 - 11:07 PM

  • .tph files... are [usually] laundry list includes of bunches of macros, some of which may not be necessary for any given mod or component. (aka "why include 5 or 50 macros you don't need for every component")
  • you don't need a separate LAUNCH_x_MACRO, you just [PATCH_]INCLUDE your code when and only when you need it without having to do a separate LAUNCH
  • you don't even have to bother INCLUDing it at the start of your code, in an ALWAYS or for each component

Regarding your list, 1) is the only point that could be a serious issue.

Actually, 3 is probably the worst of those.

3) means one line of extra code

No it doesn't. It means including however many lines of code are in your .tph when it may not be necessary at all.

and 2) is a re-statement of 3).

No it isn't. In some ways, 3 is more of a restatement of 1. The second point has more to do with precision.

I see now that 3 is also important, but I'll try to summarise the differences to see if we're on the same page, since it seems like we're reading that list differently.

Including a file with multiple macros/functions:
  • May spend time reading unnecessary code if not all macros in the file are used in the component - whether practically this time spent would ever be significant has yet to be determined :whistling:
  • Requires you to specify the file in which the macros can be found before calls to execute that code can take place: a bit of extra work; may cause problems for modders with poor memory or who like to copy/paste
  • Can use functions
  • Can have more than one piece of code in the same file
Including files containing "instant" code, no macros/functions:
  • All code read is executed, so no chance of overhead
  • No prerequisites before the code can be called
  • No way to use functions
  • Each piece of code requires its own file

I probably like my macros to be concentrated so that it's easier to keep track of them and add or test new macros/code blocks, but I am a bit hypocritical because I also like to stick my different components in separate files.

Well, you said it yourself :P. But this makes your other objections rather trite. I don't really care that you've coded something your way and are stuck in your ways (that goes for anyone else here). I'm just stating the advantages of the alternative method, which I've come to see as such by those who should know.

It's good to hear an argument for doing something differently - I probably wouldn't have thought of point #2 in my list otherwise, and it is something to think about. I don't think there's really a practical need to stick with one or the other except for the sake of consistency.

If you've ever written macros with FOR loops, and then called one of those macros in the middle of one of your FOR loops and wondered why your variable "i" was completely messed up, you'll get the basic idea.

You mean because you used %i% somewhere else in your code for something else? Sounds like sloppy variable declaration :P. I've never seen this problem with FOR loops that wasn't a problem with the code or offsets rather than variables.

Yes, it is a result of coding something without thinking things all the way through. But still, wouldn't it be nice to be able to write macros without having to come up with an inventive name for each [loop, other] variable you use in the off case someone else (even you at a later time) might pick that name for one of their variables? The reason why I've encountered problems with "i" is likely due to my absent-minded mentality of code scope, which was missing in WeiDU before functions.

Maybe I'm "stuck in my ways" too, but I don't offhand see the benefit of recoding my macros as functions when AFAIK they work as is, and work quickly in most cases. The only possible benefit I can see is this:

plus with a little planning, you can have functions whose parameters get "reset" upon exiting without needing to copy/paste in a huge block of code at the end of your macro setting all values to their defaults.

But very few if any of the macros I use require this, though it may be useful for Qwinn's or others. I'd have to see a real example though. It looks like your function is setting a bunch of null variables, and even writing nulls (which really shouldn't be necessary if the default inserted bytes are zero, which they are).

You probably don't have to recode all your macros, but it should be high on your list to consider when designing new ones. (I had thought of redoing my IR macros, but I decided it would be safer if I left that nasty old code alone, since it appears that it's behaving the way it's supposed to.) The function I posted above *is* a real example (I even tested it to make sure it worked). The null and zero writes probably don't do anything, but they're in there so you know what's what, and if you wanted to add something later (ie. the script section), it wouldn't be difficult. They could be left there commented out if you were really concerned. Anyway, here's the equivalent non-function-using code to my 'Usage' example above, if you want to see the difference (and I left out the zero/null parts). :)

Same Example as Before, Minus the Function
// call Qwinn's macros, adding room for say, 2 actors, then...

SET ag_q_number = 1 // the number of actor you've just added and are setting values for
SET ag_q = (Q_NewOffset_Actor+0x110*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCIIE (ag_q + 0x00) ~Mean-Looking Fighter Dude~ #32 // how it shall appear when opened in editor
WRITE_SHORT  (ag_q + 0x20) 400
WRITE_SHORT  (ag_q + 0x22) 200
WRITE_SHORT  (ag_q + 0x24) 400
WRITE_SHORT  (ag_q + 0x26) 200
WRITE_LONG   (ag_q + 0x28) 0b0001 // cre not attached
WRITE_LONG   (ag_q + 0x30) 0x6100
//WRITE_LONG   (ag_q + 0x34) 0 // orientation, 0-15, starting south and incrementing clockwise
WRITE_LONG   (ag_q + 0x38) 0xffffffff // 'visible' flag that needs to be -1
WRITE_LONG   (ag_q + 0x40) 0xffffff // schedule, 0xffffff means it's always present
WRITE_ASCIIE (ag_q + 0x80) ~meanfgtr~ #8

SET ag_q_number = 2 // the number of actor you've just added and are setting values for
SET ag_q = (Q_NewOffset_Actor+0x110*(ag_q_number - 1)) // do NOT touch this line

WRITE_ASCIIE (ag_q + 0x00) ~Sultry Sorceress~ #32 // how it shall appear when opened in editor
WRITE_SHORT  (ag_q + 0x20) 440
WRITE_SHORT  (ag_q + 0x22) 240
WRITE_SHORT  (ag_q + 0x24) 440
WRITE_SHORT  (ag_q + 0x26) 240
WRITE_LONG   (ag_q + 0x28) 0b0001 // cre not attached
WRITE_LONG   (ag_q + 0x30) 0x6210
WRITE_LONG   (ag_q + 0x34) 5 // orientation, 0-15, starting south and incrementing clockwise
WRITE_LONG   (ag_q + 0x38) 0xffffffff // 'visible' flag that needs to be -1
WRITE_LONG   (ag_q + 0x40) 0xffffff // schedule, 0xffffff means it's always present
WRITE_ASCIIE (ag_q + 0x80) ~hawtmage~ #8
Notice the need to duplicate coordinates when you want the creature to stay in a spot, the writing of seemingly random things that never change (cre not attached, visible flag, schedule). The more of these annoyances that exist, the more functions make things easier.

#134 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 10 June 2009 - 05:42 AM

Including a file with multiple macros/functions:

  • May spend time reading unnecessary code if not all macros in the file are used in the component - whether practically this time spent would ever be significant has yet to be determined :whistling:
  • Requires you to specify the file in which the macros can be found before calls to execute that code can take place: a bit of extra work; may cause problems for modders with poor memory or who like to copy/paste
  • Can use functions
  • Can have more than one piece of code in the same file
Including files containing "instant" code, no macros/functions:
  • All code read is executed, so no chance of overhead
    > (a good thing)
  • No prerequisites before the code can be called
    > (would also be a good thing if true, but if your .tpa/.tpp files are done as macros (or functions) you still need to declare variables and specify which macro/file you're invoking)
  • No way to use functions
    > (I don't see why not - at worst you'd have to do a separate LAUNCH after the INCLUDE)
  • Each piece of code requires its own file
    > (not necessarily [see above point] but would kind of defeat the purpose otherwise)

See italics.

The function I posted above *is* a real example (I even tested it to make sure it worked).

What I meant was a real example of this:

plus with a little planning, you can have functions whose parameters get "reset" upon exiting without needing to copy/paste in a huge block of code at the end of your macro setting all values to their defaults.

You are calling Qwinn's macros (the whole business), including the "huge block of code at the end... setting all values to their defaults" which you said should not be necessary "with a little planning."

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


#135 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 10 June 2009 - 06:40 AM

If I may ask, what "huge block of code" at the end of my macros are we referring to? The entire Process macro is 38 lines long, and that's if you count most BEGINs and ENDs as separate lines.

If we're talking about InitVars being rerun, that's roughly 108 lines of code, virtually all of which are either just SETs or READs. If you guys are -really- worried about it, you could break out the true constants (such as the Size and Offset of Offset variables) from the actual count and offset values, which are the only ones that really need to be reset at the end. That would reduce the InitVars that gets rerun at the end down to only about 36 READ's. Of course, this would add a single LAUNCH_PATCH_MACRO, which I realize is tragic.

But I still think it's seriously ridiculous to worry about it, considering the statistics for the UB installation I've already repeated twice that should really settle any even mild lingering doubt about runtime issues. There are none. Zero. You can use the -crap- out of them and the installation is still virtually instantaneous. I'd appreciate it if, before we continued making a big deal about it, someone actually tried installing PST:UB which uses the hell out of 'em and then say with a straight face that they really have installation time issues.

Qwinn

Edited by Qwinn, 10 June 2009 - 06:50 AM.


#136 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 10 June 2009 - 01:23 PM

If we're talking about InitVars being rerun, that's roughly 108 lines of code, virtually all of which are either just SETs or READs. If you guys are -really- worried about it, you could break out the true constants (such as the Size and Offset of Offset variables) from the actual count and offset values, which are the only ones that really need to be reset at the end.

Mike is suggesting even that isn't necessary in a function (as opposed to a macro). I'm skeptical too, though I'll concede it's a possibility. Why don't you let him prove it? Can't do any harm.

There is no code over a few lines that can't be improved. No one is saying there's issues with your macros, but that doesn't mean they can't be optimised further. That is what this thread is for, I thought. No need to get defensive. But as for this:

But I still think it's seriously ridiculous to worry about it, considering the statistics for the UB installation I've already repeated twice that should really settle any even mild lingering doubt about runtime issues. There are none. Zero. You can use the -crap- out of them and the installation is still virtually instantaneous.

No, I would not several seconds of runtime to add a single container with 6 vertices "virtually instantaneous." And like I said, if there's code that performs this identical task in half the time, it suggests there is room for optimisation - again, no need to get defensive. This is probably true for most of my code too, and for that matter, the code that does it in half the time (not my code).

I'd appreciate it if, before we continued making a big deal about it, someone actually tried installing PST:UB which uses the hell out of 'em and then say with a straight face that they really have installation time issues.

It took 20 seconds on my machine. Is that a problem? No. Does that mean it can't be done in 10 or 5 seconds, with perhaps half the code? No. Why not explore the possibilities at least?

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


#137 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 10 June 2009 - 01:23 PM

@Mike1072 -- I saw in your example that you set the used values inside the launch. Do you think that that would solve the issue I brought up over at PPG concerning FUNCTIONS and variables? If so, I'll give that a try and see how it works...

@Miloch -- When I said that anything you did in a tpp or tpa file, I could do in a tph file. I meant it. I don't consider tph files to be just a big long list of functions and macros. ANY external file that I use and contains code to be called up, whether it be function, macro or immediate patch/action code is assigned as a tph file (although I prefer the later as inlined files if I know I'm going to use it more than once in the same component). I use descriptive names to tell me what the contents are. I know you like things short and sweet, but I've not seen any REAL time differences in using longer names verses shorter names. By real, I mean a mod taking 45 minutes to install verses 2 hours, not this nanosecond stuff...

Qwinns macros are FASTER because now I don't have to do as much work when working with area files. So what if it adds .012345 seconds per use. I don't care! It saved me at least over 30 minutes in coding if not more...

And I'm going to avoid the discussion on whether this or that is faster and better because discussing it is not conducive to a good attitude on my part. Suffice it to say, that install time is not an issue with me so long as the code works properly and gets the job done correctly....

@Qwinn -- If I owned a copy of PST, I'd install it just to see how long it took so that perhaps we can get past this stupid discussion on how long everything takes. If I think about it and I get some REAL time, I'll see if the library still has a copy. Then we can put your mods through the installation wringer and see how long it really takes so we can end this once and for all...

@Miloch --

It looks like your function is setting a bunch of null variables, and even writing nulls (which really shouldn't be necessary if the default inserted bytes are zero, which they are).

I just have two things to say on this...
1) if you are making code that no one else will use and that you know specifically what needs to be done -- there is no need to write null entries
2) if you are making code that other people will use and as such don't know what they will need to do -- the null entries must be written as well

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


#138 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 10 June 2009 - 01:45 PM

ANY external file that I use and contains code to be called up, whether it be function, macro or immediate patch/action code is assigned as a tph file (although I prefer the later as inlined files if I know I'm going to use it more than once in the same component).

And now we see the contradiction in your set ways, as you've admitted (and as I've seen) you don't use external files at all, but only inlined ones :P.

So what if it adds .012345 seconds per use. I don't care! It saved me at least over 30 minutes in coding if not more...

And so would any other macro or function that did the same. As I said earlier, I don't care if you're set in your ways and deadset for one method over another. Don't quash the discussion of alternative methods, 'k? It does no harm, and I don't understand the need for "bad attitude" as you say.

2) if you are making code that other people will use and as such don't know what they will need to do -- the null entries must be written as well

No, nulls do not need to be written over nulls. If you really want them to be there but serving no purpose, you can comment them out as Mike says.

Edit: I feel the need to reiterate, no one's bashing Qwinn's macros, so quit defending them already. They're cool, very cool, but they're not immortal gods set in stone :P.

Edited by Miloch, 10 June 2009 - 01:47 PM.

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


#139 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 10 June 2009 - 02:23 PM

ANY external file that I use and contains code to be called up, whether it be function, macro or immediate patch/action code is assigned as a tph file (although I prefer the later as inlined files if I know I'm going to use it more than once in the same component).

And now we see the contradiction in your set ways, as you've admitted (and as I've seen) you don't use external files at all, but only inlined ones :P.

but it is still a .tph file. The next update of the fixpack will include tph files as well as qwinn' macros...

So what if it adds .012345 seconds per use. I don't care! It saved me at least over 30 minutes in coding if not more...

And so would any other macro or function that did the same. As I said earlier, I don't care if you're set in your ways and deadset for one method over another. Don't quash the discussion of alternative methods, 'k? It does no harm, and I don't understand the need for "bad attitude" as you say.

'bad attitude' because I personally have troubles when dealing with conflict. I get upset and sometimes say or write things that I shouldn't. So for my own sake I need to avoid getting into heated debate of any kind... As far as alternative methods... perhaps a dedicated thread to such discussion would pull in more opinions and ideas...

2) if you are making code that other people will use and as such don't know what they will need to do -- the null entries must be written as well

No, nulls do not need to be written over nulls. If you really want them to be there but serving no purpose, you can comment them out as Mike says.

They serve a purpose because modder X may just decide they need to write a value there. If it's commented out, they can't do that. I am NOT supplying my code in such a manner that the user HAS to edit it before it can be used. I want my code to be plug-n-play compatible, not require batteries which aren't included... In other words, the code must be fully functional out of the box

Edit: I feel the need to reiterate, no one's bashing Qwinn's macros, so quit defending them already. They're cool, very cool, but they're not immortal gods set in stone :P.

Never said that they were immortal gods set in stone... but perhaps as has already been suggested we move some of this discussion to another thread so as to not over bloat the TUTORIAL with discussions on whether or not functions are better than macros or worse than direct patch code in timing and what not...

Now I'm going to send a pm to GeN1e regarding the library of writes that was discussed here and then I'm going to log out and try to enjoy what is left of my evening... So hold off on any rebuttals cause I won't see them until tomorrow...

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


#140 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 10 June 2009 - 03:54 PM

Miloch:

No one is saying there's issues with your macros


is not compatible with:

I don't see any way to improve the runtime of the macros as they exist. Sorry if that's a dealbreaker for you.

It is.


There's a whoooooole lot of middle ground between rejecting the idea that the runtime issues are so severe that the macros should not be used at all, and insisting they are "immortal gods set in stone". Please don't insinuate that I insisted on the latter merely for rejecting the former.

As for UB install taking 20 seconds on your machine, dunno what to tell you, I'm on a 4+ year old Dell that ran me about $400 then. Not exactly a high end machine here. *shrug*

EDIT: The timing list given in the debug file includes the time the installation sits at a prompt. Every second hanging at a prompt counts as "stuff not covered elsewhere".

EDIT 2:

Parsing TP2 files				0.015
EXTEND_TOP					   0.016
parsing .tra files			   0.016
unmarshal KEY					0.016
parsing .baf files			   0.016
tp2 uninstall					0.030
parsing .ids files			   0.031
Parsing TPA files				0.048
parsing .d files				 0.064
unmarshal DLG					0.077
parsing .bcs files			   0.079
marshal BCS					  0.108
COPY							 0.141
marshal DLG					  0.173
READ_*						   0.186
unmarshal TLK					0.204
ACTION_READLN					0.281
loading files					0.282
saving files					 0.532
eval_pe						  0.556
COMPILE						  0.578
process_patch2				   1.552
marshal and save TLK			 1.938
stuff not covered elsewhere	  3.732
TOTAL						   10.671

Considering 20% is just saving the TLK file, and another 35% of it includes time spent hanging at prompts, I'm really not sure where I'm supposed to be cutting this down any significant amount. We really are talking fractions of seconds of processing spent over 12 complex uses of my Process macro. *shrug*

Qwinn

Edited by Qwinn, 10 June 2009 - 04:29 PM.