Jump to content


Photo

Area Modding Tool & Tutorial by Qwinn


  • Please log in to reply
164 replies to this topic

#61 Miloch

Miloch

    Barbarian

  • Modder
  • 6579 posts

Posted 01 June 2009 - 11:30 PM

It can easily do deletes. You just have to do the DELETE_BYTES yourself, set the variable "Q_ManualInsert" to 1 so that it skips doing the INSERT_BYTES, and then set the variable that normally tells the macro how many of that type of record you want to create to a negative number. The macro then goes through and updates all the offsets for you.

Guess I'll wait for plainab to come chew that over and update his code. I get it in theory, but like him, I'd need to puzzle it out or see it in practice.

If you want the simple explanation of how to use my macros, including the list of variables that need to be set to make it work, see post #29.

Read it, but... it's not exactly a working example. You seem to be forgetting I'm a half-orc <_<.

So if I want to add a new container (including the 6 vertices that define it)...
COPY_EXISTING ~ar9999.are~ ~override~
  SET "Q_New_Conta" = 1 // Number of New Containers
  SET "Q_New_Vertx" = 6 // Number of New Vertexes
  PATCH_INCLUDE ~Q_ARE_InitVars~
  PATCH_INCLUDE ~Q_AREAdd_InitVars~
Eh? Don't you want to SET your variables before calling the macro so it can pick them up, then do a PATCH_INCLUDE for external macros instead of LAUNCH_PATCH_MACRO? Then what? How do I define the vertices? I gathered I invoke another macro, but I didn't really see any actual code there, just some variable lists.

And if it seems like you're explaining the same thing over and over, remember again you're dealing with a half-orc, and this is all in the name of posterity and clarity, and that one day you can say RTFM with authority because it's all clearly defined and even included with WeiDU and its documentation (one day) :).

(Incidentally, have you thought about adding BG2 animations to PS:T? Because it looks like the reverse movement may be gaining ground again, and perhaps it can be reverse engineered to benefit PS:T mods.)

Edited by Miloch, 01 June 2009 - 11:33 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


#62 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 01 June 2009 - 11:43 PM

So if I want to add a new container (including the 6 vertices that define it)...

COPY_EXISTING ~ar9999.are~ ~override~
  SET "Q_New_Conta" = 1 // Number of New Containers
  SET "Q_New_Vertx" = 6 // Number of New Vertexes
  PATCH_INCLUDE ~Q_ARE_InitVars~
  PATCH_INCLUDE ~Q_AREAdd_InitVars~
Eh? Don't you want to SET your variables before calling the macro so it can pick them up, then do a PATCH_INCLUDE for external macros instead of LAUNCH_PATCH_MACRO? Then what? How do I define the vertices? I gathered I invoke another macro, but I didn't really see any actual code there, just some variable lists.


No. It should be like this, as post #29 shows:

COPY_EXISTING ~ar9999.are~ ~override~
  LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
  LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
  SET "Q_New_Conta" = 1 // Number of New Containers
  SET "Q_New_Vertx" = 6 // Number of New Vertexes

Then you would run the Process macro, then you would do your writes.

The LAUNCH_PATCH_MACRO commands work fine. I don't know why PATCH_INCLUDE would be better.

As for setting the variables before launching the first two macros, that would be bad and wouldn't work. What those first two macros do is initialize variables, so they would merely overwrite those two variables you did to 0. The fact that they do nothing other than initialize variables is hopefully evident from the fact that they both have "InitVars" in their name :) They don't do anything else. After you've initialized every variable, then you set the variables for your session. And THEN you do:

LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

Which is the macro that actually does all the work.

Then you do your writes, starting at the offsets contained in the Q_NewOffset_XXXXX variables as I listed them.

Qwinn

Edited by Qwinn, 01 June 2009 - 11:52 PM.


#63 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 01 June 2009 - 11:53 PM

Then what? How do I define the vertices? I gathered I invoke another macro, but I didn't really see any actual code there, just some variable lists.


See a working example in post #4.

Qwinn

#64 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 12:02 AM

(Incidentally, have you thought about adding BG2 animations to PS:T? Because it looks like the reverse movement may be gaining ground again, and perhaps it can be reverse engineered to benefit PS:T mods.)


No one else has shown any interest whatsoever in doing content mods for PS:T yet, I'm afraid.

Qwinn

#65 Miloch

Miloch

    Barbarian

  • Modder
  • 6579 posts

Posted 02 June 2009 - 12:14 AM

The LAUNCH_PATCH_MACRO commands work fine. I don't know why PATCH_INCLUDE would be better.

PATCH_INCLUDE calls an external .tpp (patch macro - .tph is obsolete). LAUNCH_PATCH_MACRO, I thought, required a reference inside a tp2 or inside WeiDU. PATCH_INCLUDE is far more compatible and distributable because you can just drop the existing macros in a mod folder rather than mess about with copy and pasting tp2 code.

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


#66 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 12:37 AM

My macro doesn't require any cutting or pasting. I just do this:

INCLUDE ~PST-UB/utils/Q_AREMacros.tph~

in my component's code. Then I run my macros. That's all. Not sure how that lacks portability.

Qwinn

#67 Miloch

Miloch

    Barbarian

  • Modder
  • 6579 posts

Posted 02 June 2009 - 12:44 AM

My macro doesn't require any cutting or pasting. I just do this:

INCLUDE ~PST-UB/utils/Q_AREMacros.tph~

in my component's code. Then I run my macros. That's all. Not sure how that lacks portability.

Well, it amounts to the same thing then, pretty much, though you have an extra line of code, since PATCH_INCLUDE (or just INCLUDE for actions) is the equivalent of doing the LAUNCH_x_MACRO without having to do an extra INCLUDE.

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


#68 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 12:53 AM

Well, I'm guessing that would mean I'd have to split my 5 macros into 5 different files. I prefer keeping them all together as a single file, makes searching for common variables, etc., between the parts easier.

Qwinn

Edited by Qwinn, 02 June 2009 - 01:35 AM.


#69 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 02 June 2009 - 12:25 PM

Well, I'm guessing that would mean I'd have to split my 5 macros into 5 different files. I prefer keeping them all together as a single file, makes searching for common variables, etc., between the parts easier.

Qwinn

Yes, after looking at it for a bit and getting my hands into the code, I'd have to say that having just one file is a lot more helpful than a bunch of smaller ones.
Yeah, each section could be done as an INCLUDE or PATCH_INCLUDE but I think ultimately it would be more lines of code because you can bring all the macros in one shot for the entire mod from then on it's just the launch lines to include.

As far as elegant, it takes a bit of work to understand at first but once you get it Qwinn's macros are pretty smooth as far as code goes.

Although, one thing I have learned is that FUNCTION acts just like MACRO, but you can include INT_VAR and STR_VAR in the defining process. Those two commands allow you to list a bunch of integer variables and string variables and set them to a default value rather than making a long list of SET whatever = 0 to initialize variables that the user may not enter.

@Miloch -- I thought about that code I posted for you a page or two back... I think I got it wrong. I'll look at it again and edit that post AND send you a PM with the corrected code. EDIT: Had it all adjusted and looking good. Even pasted into the earlier post, but was double checking everything when the power went out due to bad thunderstorm. :crying: I lost everything. I had not saved the file where I did the work. :wall: I went straight to copying the code into the post and skipped the save step. I'll have to work on this again... when it is not a really bad storm outside... :doh:

Edited by Sasha Al'Therin, 02 June 2009 - 02:09 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


#70 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 02:31 PM

As far as elegant, it takes a bit of work to understand at first but once you get it Qwinn's macros are pretty smooth as far as code goes.


Thank ya :)

Sorry to hear about the lost work :(

Although, one thing I have learned is that FUNCTION acts just like MACRO, but you can include INT_VAR and STR_VAR in the defining process.


I would've thought MACRO and FUNCTION would have different scope... I can call a macro that sets variables and have those variables still be set properly after the macro ends, but I thought the point of functions was that variables defined in one were limited in scope to that function only.

Qwinn

Edited by Qwinn, 02 June 2009 - 02:35 PM.


#71 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 02 June 2009 - 02:54 PM

Although, one thing I have learned is that FUNCTION acts just like MACRO, but you can include INT_VAR and STR_VAR in the defining process.


I would've thought MACRO and FUNCTION would have different scope... I can call a macro that sets variables and have those variables still be set properly after the macro ends, but I thought the point of functions was that variables defined in one were limited in scope to that function only.

I did read something like that but I don't always understand everything I read in the weidu readme. When asking the Bigg about doing something that would allow the user to SET and SPRINT only the variables they want to use in a macro without the macro designer having to initialize every single variable (your macros can't do that because of their multiple function nature), he said that FUNCTION would work just as well as MACRO and allow for giving a default value if the user doesn't set the variable...

Perhaps, the Bigg meant that I could define a FUNCTION with default values that the user would launch after setting their values and that the FUNCTION would then launch the actual MACRO. That might have been it...

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


#72 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 03:13 PM

Aaah, ok, if that's the case then yeah, I couldn't use it... I need to allow for the user to set some of the variables between the initialization and process stages.

he said that FUNCTION would work just as well as MACRO and allow for giving a default value if the user doesn't set the variable...


I would be nervous to use this in the case that, for some reason (perhaps a delete and then an insert), I used the macros twice within a single COPY_EXISTING, and the values set from the first use could carry over into the second. My way, it's absolutely sure that can't happen.

Qwinn

Edited by Qwinn, 02 June 2009 - 03:17 PM.


#73 Miloch

Miloch

    Barbarian

  • Modder
  • 6579 posts

Posted 02 June 2009 - 04:44 PM

@Miloch -- I thought about that code I posted for you a page or two back... I think I got it wrong. I'll look at it again and edit that post AND send you a PM with the corrected code. EDIT: Had it all adjusted and looking good. Even pasted into the earlier post, but was double checking everything when the power went out due to bad thunderstorm. :crying: I lost everything. I had not saved the file where I did the work. :wall: I went straight to copying the code into the post and skipped the save step. I'll have to work on this again... when it is not a really bad storm outside...

Doh. Well I was hoping it'd be easy to do with Qwinn's macro, as he implied.

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


#74 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 02 June 2009 - 04:59 PM

On the delete aspect of your macro...

How do you specify which entry of a given section gets deleted? I understand you set a negative entry for the section, but what if the entry you want to delete is in the middle?

Could you explain it using the following bits of code that I've just re-done (and better) for Miloch?


@Miloch -- here's the re-done code that I lost earlier due to a power outage... I saw you're browsing so hopefully you'll get this
@Qwinn -- look this over and see how Miloch can benefit from your macro rather than using what I put together...

Do note: I didn't test this, but I think it's pretty sound....

The tp2 code
INCLUDE ~somemode\somedir\DELETE_AMBIENT_ENTRY.tph~
COPY_EXISTING_REGEXP GLOB ~^\([^xX].*\|[xX][^rR].*\|[xX][rR][^2].*\|[xX][rR]2[^46].*\)\.are$~ ~override~
 PATCH_IF SOURCE_SIZE > 0x11b BEGIN //If a valid area
  LAUNCH_PATCH_MACRO ~Initializing_base_variables_for_updating~
  LAUNCH_PATCH_FUNCTION ~Lookup_Bad_Ambient_Sound_Refs_and_Wipe_out~
  LAUNCH_PATCH_FUNCTION ~Move_good_sounds_into_slots_less_than_sound_count_if_in_slot_greater_than_sound_count~ //<-- you may not need and it may not work
  LAUNCH_PATCH_MACRO ~Find_Ambient_Entries_with_no_sound_files_and_delete~ //launches the update macro which re-launches the initialzing macro
 END
BUT_ONLY_IF_IT_CHANGES
The DELETE_AMBIENT_ENTRY.tph contents
////////////////////////////////
//Contents of Lookup_Bad_Ambient_Sound_Refs_and_Wipe_out
//this can be function as nothing gets transfered to anywhere else -- ie next thing reads everything again
DEFINE_PATCH_FUNCTION ~Lookup_Bad_Ambient_Sound_Refs_and_Wipe_out~ BEGIN
 SET off_of_amb_c = 0x82								 //set offset value to read ambient count
 SET off_of_amb_o = 0x84								 //set offset value to read ambient offset
 READ_SHORT %off_of_amb_c% amb_c						 //Ambient count
 READ_LONG %off_of_amb_o% amb_o						  //Ambient offset
 SET amb_s = 0xd4										//set ambient entry size
 FOR (index=0;index<%amb_c%;index+=1) BEGIN			  //loop through ambient entries
  SET amb_e = (0xd4 * %index%)						   //set index into ambient entries
  READ_SHORT (%amb_o% + %amb_e% + 0x80) s_num			//Sound count
  SET ss = 0x30										  //start location of sounds refs
  SET sz = 0x8										   //size per entry of sound refs
  FOR (index2=0;index2<%sc%;index2+=1) BEGIN			 //loop through sound refs
   SET si = (%index2% * %sz%)							//index into sounds entries in current ambient entry
   READ_ASCII (mf + mb + %ss% + %si%) wav				//read sound file
//blank out non-existant sound file references <-- this is in case other sound file references do exist
   PATCH_IF (NOT FILE_EXISTS_IN_GAME ~%wav%.wav~) BEGIN  //if registered sound file does not exist
	WRITE_ASCII (mf + mb + %ss% + %si%) ~~ (8)		   //write blank value
	WRITE_SHORT (mf + mb + 0x80) (%sc% - 1)			  //lower Sound count by one
   END												   //end patch that checks existance of sound file
  END													//end loop through sound refs
 END													 //end loop through ambient entries
END													  //end of function definition
////////////////////////////////
//Contents of Find_Ambient_Entries_with_no_sound_files_and_delete
//since returning variable is an array we need to use MACRO instead of FUNCTION
DEFINE_PATCH_MACRO ~Find_Ambient_Entries_with_no_sound_files_and_delete~ BEGIN
 SET off_of_amb_c = 0x82								 //set offset value to read ambient count
 SET off_of_amb_o = 0x84								 //set offset value to read ambient offset
 READ_SHORT %off_of_amb_c% amb_c						 //Ambient count
 READ_LONG %off_of_amb_o% amb_o						  //Ambient offset
 SET amb_s = 0xd4										//set ambient entry size
 FOR (index=0;index<%amb_c%;index+=1) BEGIN			  //loop through ambient entries
  SET amb_e = (0xd4 * %index%)						   //set index into ambient entries
  READ_SHORT (%amb_o% + %amb_e% + 0x80) s_num			//Sound count
  PATCH_IF (%s_num% <=0) BEGIN						   //See if number of sounds is 0 or less
   SET bytes = (0 - %amb_s%)							 //set bytes variable used in update macro: negative for delete; positive for insert
   DELETE_BYTES (%amb_o% + %amb_e%) %amb_s%			  //delete current entry
   WRITE_SHORT %off_of_amb_c% (%amb_c% - 1)			  //update ambient entry value
   LAUNCH_PATCH_MACRO ~Update_offsets_after_deleting_or_inserting_bytes~   //launch the update macro
//re-set to re-read the remaining ambient entries
   READ_SHORT %off_of_amb_c% amb_c					   //Ambient count
   READ_LONG %off_of_amb_o% amb_o						//Ambient offset
   SET index = 0										 //set index back to 0 and loop through ambients again.
  END
 END
END
////////////////////////////////
//Contents of Move_good_sounds_into_slots_less_than_sound_count_if_in_slot_greater_than_sound_count
//this has no variables to carry over so it can be a function
DEFINE_PATCH_FUNCTION ~Move_good_sounds_into_slots_less_than_sound_count_if_in_slot_greater_than_sound_count~ BEGIN
 SET off_of_amb_c = 0x82												  //set offset value to read ambient count
 SET off_of_amb_o = 0x84												  //set offset value to read ambient offset
 READ_SHORT %off_of_amb_c% amb_c										  //Ambient count
 READ_LONG %off_of_amb_o% amb_o										   //Ambient offset
 SET amb_s = 0xd4														 //set ambient entry size
 FOR (index=0;index<%amb_c%;index+=1) BEGIN							   //loop through ambient entries
  SET amb_e = (0xd4 * %index%)											//set index into ambient entries
  READ_SHORT (%amb_o% + %amb_e% + 0x80) s_num							 //Sound count
  SET ss_1 = 0x30														 //sound 1
  SET ss_2 = 0x38														 //sound 2
  SET ss_3 = 0x40														 //sound 3
  SET ss_4 = 0x48														 //sound 4
  SET ss_5 = 0x50														 //sound 5
  SET ss_6 = 0x58														 //sound 6
  SET ss_7 = 0x60														 //sound 7
  SET ss_8 = 0x68														 //sound 8
  SET ss_9 = 0x70														 //sound 9
  SET ss_10 = 0x78														//sound 10
  PATCH_FOR_EACH ~s1~ IN ~1~ ~2~ ~3~ ~4~ ~5~ ~6~ ~7~ ~8~ ~9~ ~10~ BEGIN   //loop through numbers treat as string and number -- hope it works
   READ_ASCII (%amb_o% + %amb_e% + $ss(%s1%) sf						   //read sound file
   PATCH_IF (FILE_EXISTS_IN_GAME ~%sf%.wav~) AND (%s1% > %s_num% ) BEGIN  //sound file exists and slot is greater than the count number
	PATCH_PRINT ~%sf%.wav is in sound slot %s1%. There are %s_num% sounds in this ambient entry.~
	FOR (index2=1;index2<(%s_num%+1);index2+=1) BEGIN					 //loop through sounds
	 READ_ASCII (%amb_o% + %amb_e% + $ss(%index2%) sound				  //read sound file again
	 PATCH_IF (NOT FILE_EXISTS_IN_GAME ~%sound%.wav~)
		  AND ( (%index2% < %s1%) AND (%index2% <= %s_num%) BEGIN		 //sound file does not exist and slot is less than earlier slot
	  PATCH_PRINT ~Moving %sf%.wav from slot %s1% to slot %index2%.
This puts %sf%.wav within %s_num% slots from the start of sound file offsets.~
	  WRITE_EVALUATED_ASCII (%amb_o% + %amb_e% + $ss(%index2%) ~%sf%~ (8) //write good file in current slot
	  WRITE_EVALUATED_ASCII (%amb_o% + %amb_e% + $ss(%s1%) ~~ (8)		 //erase good file from old slot
	 END																  //end patch where sound does not exist and slot is within count
	END																   //end loop through sound slots
   END																	//end patch where sound exists but slot is greater than count
  END																	 //end PFE
 END																	  //end ambient entry loop
END																	   //end function
////////////////////////////////
//Contents of Initilizing_base_variables_for_updating
//The variables here need to get used in the update process so we need to use macro
DEFINE_PATCH_MACRO ~Initializing_base_variables_for_updating~ BEGIN
  SET loc_actor = 0x54
  SET loc_spawn = 0x60
  SET loc_entrance = 0x68
  SET loc_container = 0x70
  SET loc_item = 0x78
  SET loc_vertex = 0x7c
  SET loc_ambient = 0x84
  SET loc_variable = 0x88
  SET loc_door = 0xa8
  SET loc_explored = 0xa0
  SET loc_anim = 0xb0
  SET loc_tiled = 0xb8
  SET loc_song = 0xbc
  SET loc_rest = 0xc0
  PATCH_IF !(GAME_IS ~pst~) BEGIN
   SET loc_amapBG2 = 0xc4
   SET loc_pro_traps = 0xcc
  END
  PATCH_IF (GAME_IS ~pst~) BEGIN
   SET loc_amapPST = 0xc8
  END
//Get the offset entries could use the variables set above instead of the hard set entries, but don't matter
  READ_LONG %loc_actor% actor_off
  READ_LONG %loc_spawn% spawn_off
  READ_LONG %loc_entrance% entrance_off
  READ_LONG %loc_container% container_off
  READ_LONG %loc_item% item_off
  READ_LONG %loc_vertex% vertex_off
  READ_LONG %loc_ambient% ambient_off
  READ_LONG %loc_variable% variable_off
  READ_LONG %loc_door% door_off
  READ_LONG %loc_explored% explored_off
  READ_LONG %loc_anim% anim_off
  READ_LONG %loc_tiled% tiled_off
  READ_LONG %loc_song% song_off
  READ_LONG %loc_rest% rest_off
  PATCH_IF !(GAME_IS ~pst~) BEGIN
   READ_LONG %loc_amapBG2% amapBG2_off
   READ_LONG %loc_pro_traps% pro_traps_off
  END
  PATCH_IF (GAME_IS ~pst~) BEGIN
   READ_LONG %loc_amapPST% amapPST_off
  END
END										 //end macro
////////////////////////////////
//Contents of Initilizing_base_variables_for_updating
//We carry variables in but don't take anyting out
DEFINE_PATCH_MACRO ~Update_offsets_after_deleting_or_inserting_bytes~ BEGIN
  PATCH_FOR_EACH ~string~ IN
   ~actor~ ~spawn~ ~entrance~ ~container~ ~item~ ~vertex~ ~ambient~ ~variable~ ~door~ ~explored~
   ~anim~ ~tiled~ ~song~ ~rest~ ~amapBG2~ ~pro_traps~ ~amapPST~ BEGIN
  SET offset = $loc(%string%)
  PATCH_IF ($%string%(off) >= %amb_o%) AND (NOT ~%string%~ STRING_EQUAL_CASE ~ambient~) BEGIN
   WRITE_LONG %offset% (%actor_off% + %bytes%)
  END
  PATCH_IF !(GAME_IS ~pst~) AND ( (~%string%~ STRING_EQUAL_CASE ~amapBG2~)
								  (~%string%~ STRING_EQUAL_CASE ~pro_traps~) ) BEGIN
   PATCH_IF ($%string%(off) >= %amb_o%) BEGIN
	WRITE_LONG %offset% (%actor_off% + %bytes%)
   END
  END
  PATCH_IF (GAME_IS ~pst~) AND (~%string%~ STRING_EQUAL_CASE ~amapPST~) BEGIN
   PATCH_IF ($%string%(off) >= %amb_o%) BEGIN
	WRITE_LONG %offset% (%actor_off% + %bytes%)
   END
  END
  LAUNCH_PATCH_MACRO ~Initializing_base_variables_for_updating~  //re-initalizes the base variables so that we can properly do the next update
END //end the FUNCTION definition
Additional comments regarding this: LAUNCH_PATCH_FUNCTION ~Move_good_sounds_into_slots_less_than_sound_count_if_in_slot_greater_than_sound_count~ //<-- you may not need and it may not work
It was just an idea that I had, I figured that it was possible in a multi sound file ambient entry that a middle file was bad. With the sound count being reduced by one, I figured that the last good one might not get read because it was outside of the new sound count. So I attempted to create something that would move it, but I don't know if I can treat a PFE string that has been assigned a number as an actual number later on. If so, then this might work. But you may not even need it at all...

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


#75 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 05:01 PM

Is it not, Miloch? If you're still having trouble, tell me what. Post #29 explains what's going on, Post #4 gives a working example. I think you even already posted the necessary code, the only thing missing being your writes which you can cut and paste from your own macro.

Here, here's the whole thing:

COPY_EXISTING ~ar9999.are~ ~override~
  LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
  LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
  SET "Q_New_Conta" = 1
  SET "Q_New_Vertx" = 6
  LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

  Your writes here.  Start writing your container at Q_NewOffset_Conta.  Start writing your vertexes at New_Offset_Vertx.

BUT_ONLY_IF_IT_CHANGES

That's it.

Qwinn

#76 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 05:06 PM

How do you specify which entry of a given section gets deleted? I understand you set a negative entry for the section, but what if the entry you want to delete is in the middle?


As I said, you have to handle the DELETE_BYTES yourself. So if you want to delete a record in the middle, you target your DELETE_BYTES to that specific record. Then you simply tell the macro to reduce the size of the relevant section by 1 (by giving it a negative number).

If you were deleting the 3rd actor in a list of 15, for example, or the 1st, or the 12th, the offsets of all the other sections don't care. They just need to be reduced by the size of one actor record.

HOWEVER, yes, there is an exception: If what you are deleting contains vertexes, such as a container or trigger, there's an extra step: getting rid of the vertexes. To do that, you use the Vertex macros to edit the record that "owns" the vertexes (trigger, container, whatever) and tell it the new number of vertexes is 0. That'll wipe 'em all out for you. Then you can delete the trigger or container record safely via the normal DELETE_BYTES method we just discussed.

Qwinn

Edited by Qwinn, 02 June 2009 - 05:10 PM.


#77 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 05:19 PM

Sasha, my macros wouldnt' help you identify "bad" ambient sounds. But if you ran a program to identify them and tell you what the offsets of the bad records were (or even just "the 3rd, 4th and 8th ambient records are bad", then you could use my macro to delete them.

Let's say that example is what we have. You determined that the 3rd, 4th and 8th ambient records need to be deleted. Here's what you'd do. (And note, I'm using the variables set up by my own InitVars procedure, I don't even need to look up the sizes or offsets or whatever).

(Note that I'm deleting the sections in reverse order so that the offsets of the second and third DELETE_BYTES aren't moving targets)

COPY_EXISTING ~ar9999.are~ ~override~
  LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
  LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~

  DELETE_BYTES ("Q_Off_Ambie" + ("Q_Siz_Ambie * 7))  "Q_Siz_Ambie"  // Deletes 8th ambient sound
  DELETE_BYTES ("Q_Off_Ambie" + ("Q_Siz_Ambie * 3))  "Q_Siz_Ambie"  // Deletes 4th ambient sound
  DELETE_BYTES ("Q_Off_Ambie" + ("Q_Siz_Ambie * 2))  "Q_Siz_Ambie"  // Deletes 3rd ambient sound
	
  SET Q_Manual_Insert = 1   // This tells the macro not to insert any bytes

  SET Q_New_Ambie = 0 - 3
  LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~

 BUT_ONLY_IF_IT_CHANGES

That's it.

Qwinn

Edited by Qwinn, 02 June 2009 - 05:20 PM.


#78 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 02 June 2009 - 05:30 PM

@Miloch -- I thought about that code I posted for you a page or two back... I think I got it wrong. I'll look at it again and edit that post AND send you a PM with the corrected code. EDIT: Had it all adjusted and looking good. Even pasted into the earlier post, but was double checking everything when the power went out due to bad thunderstorm. :crying: I lost everything. I had not saved the file where I did the work. :wall: I went straight to copying the code into the post and skipped the save step. I'll have to work on this again... when it is not a really bad storm outside...

Doh. Well I was hoping it'd be easy to do with Qwinn's macro, as he implied.

It might be, but I'm not sure how you specify which entry within the ambient entries gets deleted. We know that a negative entry in the "number of sections to add" allows for an update of deleted bytes. My current process is designed specifically for your task, but the initializing macro and update macro could be ported into other sections as needed.

I know you like short two letter variables, but I like variables I can understand when I look at them and Qwinn's are some where in the middle of our two ideals
------------------------------------------------------------------------
Okay, so I've got to learn to wait 5 minutes before I start posting... (we're up to 3 of Qwinn's posts to 1 of mine) :doh:
So forget what I've already typed and go with the following...

And AGAIN Qwinn gets a post out while I'm typing... To answer that post (the one where you give an example) I think I figured that out. Check below and see if the changes I made would do the job properly. If so, then Miloch can give it a proper run and see if it does do what he wants done...

INCLUDE ~somemod\somedir\DELETE_AMBIENT_ENTRY.tph~
INCLUDE ~somemod\somedir\Q_AREMacros.tph~
COPY_EXISTING_REGEXP GLOB ~^\([^xX].*\|[xX][^rR].*\|[xX][rR][^2].*\|[xX][rR]2[^46].*\)\.are$~ ~override~
 PATCH_IF SOURCE_SIZE > 0x11b BEGIN //If a valid area
  LAUNCH_PATCH_MACRO ~Q_ARE_InitVars~
  LAUNCH_PATCH_MACRO ~Q_AREAdd_InitVars~
  SET "Q_Game" = 2 //1 for PST engine; 2 for BG2 engine; 3 for IWD and BG engines -- based on where I got the original code from
  SET "Q_ManualInsert" = 1
  LAUNCH_PATCH_FUNCTION ~Lookup_Bad_Ambient_Sound_Refs_and_Wipe_out~
  LAUNCH_PATCH_FUNCTION ~Move_good_sounds_into_slots_less_than_sound_count_if_in_slot_greater_than_sound_count~ //<-- you may not need and it may not work
  LAUNCH_PATCH_MACRO ~Find_Ambient_Entries_with_no_sound_files_and_delete~ //launches the update macro which re-launches the initialzing macro
 END
BUT_ONLY_IF_IT_CHANGES
And then in the ~Find_Ambient_Entries_with_no_sound_files_and_delete~ macro inside the DELETE_AMBIENT_ENTRY.tph we make the following changes:
DEFINE_PATCH_MACRO ~Find_Ambient_Entries_with_no_sound_files_and_delete~ BEGIN
 SET off_of_amb_c = 0x82								 //set offset value to read ambient count
 SET off_of_amb_o = 0x84								 //set offset value to read ambient offset
 READ_SHORT %off_of_amb_c% amb_c						 //Ambient count
 READ_LONG %off_of_amb_o% amb_o						  //Ambient offset
 SET amb_s = 0xd4										//set ambient entry size
 FOR (index=0;index<%amb_c%;index+=1) BEGIN			  //loop through ambient entries
  SET amb_e = (0xd4 * %index%)						   //set index into ambient entries
  READ_SHORT (%amb_o% + %amb_e% + 0x80) s_num			//Sound count
  PATCH_IF (%s_num% <=0) BEGIN						   //See if number of sounds is 0 or less
   DELETE_BYTES (%amb_o% + %amb_e%) %amb_s%			  //delete current entry
   WRITE_SHORT %off_of_amb_c% (%amb_c% - 1)			  //update ambient entry value
   SET Q_NewAmbie = (0 -1)
   LAUNCH_PATCH_MACRO ~Q_AREAdd_Process~
//re-set to re-read the remaining ambient entries
   READ_SHORT %off_of_amb_c% amb_c					   //Ambient count
   READ_LONG %off_of_amb_o% amb_o						//Ambient offset
   SET index = 0										 //set index back to 0 and loop through ambients again.
  END
 END
END
Other changes inside the DELETE_AMBIENT_ENTRY.tph file would include ditching the Initializing macro and update macro

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


#79 Qwinn

Qwinn
  • Modder
  • 3092 posts

Posted 02 June 2009 - 05:37 PM

Well, you do a lot of reads there that I don't think are necessary cause my InitVars macros set up those values for you. Why look up and set "amb_s" as the size of an ambient record when you know "Q_Siz_Ambie" is already set up with that value for you? Same for all the offsets and stuff. Seriously, I often use -just- the InitVars macros to get those values and save me the trouble of looking them up and doing all the reads and sets. I think by not familiarizing yourself with the naming conventions and using those established variables you're losing a lot of the value of my macros and introducing a greater possibility of error. But whatever.

Now, this:

WRITE_SHORT %off_of_amb_c% (%amb_c% - 1)

Is unnecessary, and in fact would break things. The macro updates counts for you also. You might need to update your "amb_c" variable there though. I personally would've just used Q_Num_Ambie for that value, and after I was done with a delete it would have been automatically updated for me.

Otherwise, the overall concept seems valid. Haven't tested or anything, but I can certainly see what you're trying to do. Would you like me to rewrite it using the macro established variables?

Qwinn

Edited by Qwinn, 02 June 2009 - 05:56 PM.


#80 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 02 June 2009 - 06:13 PM

Sasha, my macros wouldnt' help you identify "bad" ambient sounds. But if you ran a program to identify them and tell you what the offsets of the bad records were (or even just "the 3rd, 4th and 8th ambient records are bad", then you could use my macro to delete them.

Since Miloch already had initial code to replace non-existent sound files with empty space, it was logical to extend that code and check for specific ambient entries that matched certain criteria. So the 'program' is weidu. But since it is difficult to carry out the offset or the entry number (without appending to another file), I set up the MACRO to delete one entry at a time and update and then repeat as needed. Of course, I had to go front to back. Perhaps if I went back to front, I could have incremented the number of entries deleted and called the macro only once outside of the loop structure.

Either way, it should still work...


Well, you do a lot of reads there that I don't think are necessary cause my InitVars macros set up those values for you. Why look up and set "amb_s" as the size of an ambient record when you know "Q_Siz_Ambie" is already set up with that value for you? Same for all the offsets and stuff. Seriously, I often use -just- the InitVars macros to get those values and save me the trouble of looking them up and doing all the reads and sets. But whatever.

Cause it was already set up and I wasn't going to go back in there and edit everything just to use the same variable name as your file. Now if I'd known for definite how to use your macro with the delete ahead of time, sure I could have easily applied your variable names...


Now, this:

WRITE_SHORT %off_of_amb_c% (%amb_c% - 1)

Is unnecessary, and in fact would break things. The macro updates counts for you also.

Qwinn

Carry over from my original process that was without your macro, I didn't even think about it... It is easy to delete.

Other than that you think it will work? If so, I'll correct locally and send to Miloch.

Hey, doing all this code that mirrors what your macros do but using for now variables that help me realize what I'm doing actually help me to better understand what it is that your macros do. Now that I've put some things together for both adding and subtracting... I just might be able to start fresh and direct with your macro and variables next time... Now to get those sets figured out...

Got some ideas...
1) Start a 'library' where any modder who wants to use your macro can copy the list of writes for any given section. Of course, somebody has to first have used writes for this to work. Your mods would be the initial source and then after that others can share any new sections that they've needed to list the writes for.
2) Once all the writes are available it'll make it easier to create an optional MACRO/FUNCTION that calls up all your macros and lists all the writes allowing the user to just copy the area file and list their sets and sprints. Yet, this might not be so needed if there is an easy to access 'library' with pre-existing lists of writes for each section.

My thoughts on these are towards the end user of your macros. Why should each person go through the initial work of cross-referencing with IESDP/NI making sure all their data is being put in the correct spot? This can cause mistakes which can lead to errors and other problems. If the initial people who make writes for the various sections commented them well and shared them in a 'library', I think anyone could pick up your macros and use them.

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