Jump to content

Recommended Posts

Here is one I just wrote.
Eh... ok. So I don't have to continue this project? I did ask whether you wanted just a blank value in missile.ids or a copy of the projectl.ids value (which I think is at least marginally more descriptive than "unnamed" or a blank) and never heard back from you...

 

I should just stop coding for a while and ask for in-built WeiDU functions for everything...

Share this post


Link to post

So, I need to run #2 to pad entries in MISSILE, and after that append to both projectil.ids and missile.ids? I can do both things in ADD_PROJECTILE just fine :fish:

Share this post


Link to post
So, I need to run #2 to pad entries in MISSILE, and after that append to both projectil.ids and missile.ids? I can do both things in ADD_PROJECTILE just fine :O
Sounds good to me.

 

Edit: I'm going to copy Galactygon's other question from SHS here too. No sense in me trying to code a solution if bigg's willing to do it :fish:.

Because various components use the same projectiles, and I would like to avoid adding a projectile that already exists, how would I determine if that projectile already exists in the PROJECTL.IDS? The other thing about projectiles, how would I assign projectiles based on finding the filename rather than the entry, as variables are lost when the user installs component A, quits, and goes back to install component B?
Is there anti-redundancy code in ADD_PROJECTILE that will avoid adding duplicate projectiles? If not, can we add it? Edited by Miloch

Share this post


Link to post

Here is an update to the "Update missile.ids" macro I've written a week ago. Now it really makes sure that the projectl.ids and missile.ids are shifted by one entry, and accounts for an oversight with 2 hardcoded projectiles introduced in BGII.

 

DEFINE_ACTION_MACRO ~UPDATE_MISSILE_AND_PROJECTL_IDS~ BEGIN

COPY_EXISTING ~MISSILE.ids~ ~override~
COUNT_2DA_ROWS 1 missile_rowcount
SET missile_rowcount -= 1
READ_2DA_ENTRY missile_rowcount 0 0 last_missile_entry
BUT_ONLY_IF_IT_CHANGES
COPY_EXISTING ~PROJECTL.ids~ ~override~
COUNT_2DA_ROWS 1 projectl_rowcount
SET projectl_rowcount -= 1
READ_2DA_ENTRY projectl_rowcount 0 0 last_projectl_entry
BUT_ONLY_IF_IT_CHANGES

OUTER_WHILE ( last_projectl_entry < last_missile_entry - 1) BEGIN
OUTER_SET last_projectl_entry = last_projectl_entry + 1
APPEND ~PROJECTL.IDS~ ~%last_projectl_entry% ~
END
OUTER_WHILE ( last_projectl_entry > last_missile_entry - 1) BEGIN
OUTER_SET last_missile_entry = last_missile_entry + 1
APPEND ~MISSILE.IDS~ ~%last_missile_entry% Unnamed~
END

END

 

-Galactygon

Share this post


Link to post
The other thing about projectiles, how would I assign projectiles based on finding the filename rather than the entry, as variables are lost when the user installs component A, quits, and goes back to install component B?

 

I ran into the same problem while working on RR v4.0 where several components use a new projectile which is added by the first component. Unfortunately, if I install the first component, quit the installer and then try to install another component which uses the new projectile I'll either duplicate the projectile entry (if I add it again) or my spell patching fails since the projectile variable is no longer in the buffer.

 

For the moment, I've made a temporary workaround for this by recording the numeric IDs of all projectiles which I add to a custom 2DA file. I can then use READ_2DA_VALUE to turn this back into a variable and use it for spell patching at a later point.

 

//  Add new projectiles

ADD_PROJECTILE ~RR/RR_CORE/PRO/RR#VRNP.PRO~
ADD_PROJECTILE ~RR/RR_CORE/PRO/RR#VRPO.PRO~

// Write the numeric projectile IDs to the 2DA so that they can be accessed at any time, for example, if a component which requires these numbers is installed at a later point when they are no longer inside the buffer

COPY ~RR/LIB/RR#EVAL.2DA~ ~override~
APPEND ~RR#EVAL.2DA~ ~RR#VRNP %RR#VRNP%~ UNLESS ~RR#VRNP~ 
APPEND ~RR#EVAL.2DA~ ~RR#VRPO %RR#VRPO%~ UNLESS ~RR#VRPO~

 

With this, I can acccess the numeric IDs at a later point with relative ease:

 

// Assign the new party-only projectile (RR#VRPO.PRO) to various Bard songs

COPY_EXISTING ~RR#EVAL.2DA~ ~override~
READ_2DA_ENTRY 0 1 2 ~RR#VRNP~ // Get the numeric ID of RR#VRNP.PRO from the RR#EVAL.2DA
READ_2DA_ENTRY 1 1 2 ~RR#VRPO~ // Get the numeric ID of RR#VRPO.PRO from the RR#EVAL.2DA

COPY_EXISTING ~SPCL542A.SPL~ ~override~ // Skald's regular song
		  ~RR#BDF02.SPL~ ~override~ // Default Bard's regular song
		  ~RR#BBL02.SPL~ ~override~ // Blade's regular song
 READ_LONG  0x64 ab_off
 READ_SHORT 0x68 ab_num
 FOR(i=0; i<ab_num; i+=1) BEGIN
WRITE_SHORT (ab_off+i*0x28+0x26) %RR#VRPO%
 END 
BUT_ONLY_IF_IT_CHANGES

// Assign the new no-party projectile (RR#VRNP.PRO) to the regular Jester song and the Weapons Display ability

COPY_EXISTING ~SPCL751A.SPL~ ~override~ // Jester's regular song
		  ~RR#WDIS.SPL~  ~override~ // Blade's Weapon's display ability
 READ_LONG  0x64 ab_off
 READ_SHORT 0x68 ab_num
 FOR(i=0; i<ab_num; i+=1) BEGIN
WRITE_SHORT (ab_off+i*0x28+0x26) %RR#VRNP%
 END 
BUT_ONLY_IF_IT_CHANGES

Share this post


Link to post

I'm wondering if that could be done just by reading some unique binary data of your projectile or something. So any word on this (yes/no/maybe)?

Is there anti-redundancy code in ADD_PROJECTILE that will avoid adding duplicate projectiles? If not, can we add it?

Share this post


Link to post

I have it easy because all of my components that use projectiles have a REQUIRE_COMPONENT ~0~ @x or something like that, so I can add projectiles in the zeroth component and find them in the other components.

 

Usually I have the spells/items in bundles since the macro does not discard the last projectile_file it looked for unless the user re-sprints it.

 

For spells:

// Updating projectiles
COPY_EXISTING ~SPPR218.spl~ ~override~
	  ~SPPR024A.spl~ ~override~
	  ~SPPR025A.spl~ ~override~
	  ~SPPR026A.spl~ ~override~
	  ~SPPR027A.spl~ ~override~
	  ~SPPR211A.spl~ ~override~
SPRINT projectile_file "LC_TRAV5"
LAUNCH_PATCH_MACRO ~ADD_PROJECTILE_FILENAME_SPL~

 

Or if I want to patch each extended header a new projectile value:

COPY_EXISTING ~SPWI614B.spl~ ~override~
SET ext_header_to_patch = 1
SPRINT projectile_file "LC_DFG01"
LAUNCH_PATCH_MACRO ~ADD_PROJECTILE_FILENAME_SPL~
SET ext_header_to_patch = 2
SPRINT projectile_file "LC_DFG02"
LAUNCH_PATCH_MACRO ~ADD_PROJECTILE_FILENAME_SPL~
...

 

For items it would be something like this:

COPY_EXISTING ~SHAMMR.itm~ ~override~
	  ~SHAMMR2.itm~ ~override~
	  ~SHAMMR3.itm~ ~override~
SPRINT projectile_file "LC_TRAV5"
LAUNCH_PATCH_MACRO ~ADD_PROJECTILE_FILENAME_ITM~

 

And here is the full macro. Finding the projectile entry in the projectl.ids can take some time: roughly 20 searches can take 2-3 seconds. So unless I bundle the spells/items, it will slow the installation by several seconds.

 

I am thinking of having the searcher start from row 265 or something rather than 0, and then cycle through the projectl.ids so it's faster.

 

Here is the full macro:

// This patch macro adds a projectile to a spell file by looking for the filename of the .pro that is in the
// PROJECTL.IDS. You have to specify (more accurately, SPRINTs) the variable "projectile_file" to the desired file,
// and set the variable "ext_header_to_patch" to some value 0 or greater. If "ext_header_to_patch" is zero, or you
// do not specify "ext_header_to_patch", all extended headers are patched. On the other hand, if you specify
// some number like 1 instead to "ext_header_to_patch", it only patches that extended header. For example, setting
// "ext_header_to_patch" to 1 beforehand only patches the first extended header. Note that you will have to set
// "ext_header_to_patch" each time you run the macro if want to patch only a range of extended headers rather than all of
// them. You will also have to set "projectile_file" each time you wish to change between different projectiles.

DEFINE_PATCH_MACRO ~ADD_PROJECTILE_FILENAME_SPL~ BEGIN
PATCH_IF ((SOURCE_SIZE > 0x71) AND (VARIABLE_IS_SET "%projectile_file%") ) THEN BEGIN // Just in case
	// If no variable is set by the user, there is no parse error, but instead there is a warning sign, and
	// this macro takes over and simply sets the projectile index in the specified header(s) to "1-None"
	PATCH_IF !( VARIABLE_IS_SET "%projectile_file%" ) BEGIN
		SET projectile_num = 0
		SPRINT projectile_name ""
		PATCH_PRINT "Warning: no projectile filename was specified, so setting projectile index to None"
	END
	// If the last projectile is not what we are looking for, we launch this macro to look for it.
	// We often don't need it if we are copying and patching several spells that use the same projectile.
	// This radically cuts the installation time.
	PATCH_IF !( "%projectile_file%" STRING_COMPARE_CASE "%projectile_name%" = 0) BEGIN
		INNER_ACTION BEGIN
			LAUNCH_ACTION_MACRO ~GET_PROJECTILE_ENTRY~
		END
	END
	PATCH_IF !( VARIABLE_IS_SET "%ext_header_to_patch%" ) BEGIN
		SET ext_header_to_patch = 0
	END
	READ_LONG  0x64 ext_off
	READ_SHORT 0x68 ext_num
	FOR (outerloops = 0; outerloops < ext_num; outerloops += 1) BEGIN
		PATCH_IF ((outerloops + 1 = ext_header_to_patch) OR (ext_header_to_patch = 0)) BEGIN
			// We don't like redundancy
			READ_SHORT ( outerloops * 0x28 + ext_off + 0x26 ) to_patch_or_not_to_patch
			PATCH_IF (to_patch_or_not_to_patch != projectile_num + 1) BEGIN
				WRITE_SHORT ( outerloops * 0x28 + ext_off + 0x26 ) (projectile_num + 1)
			END
		END
	END
	SET ext_header_to_patch = 0
END
END

// This patch macro adds a projectile to an item file by looking for the filename of the .pro that is in the
// PROJECTL.IDS. You have to specify (more accurately, SPRINTs) the variable "projectile_file" to the desired file,
// and set the variable "ext_ability_to_patch" to some value 0 or greater. If "ext_ability_to_patch" is zero, or you
// do not specify "ext_ability_to_patch", all extended abilities are patched. On the other hand, if you specify
// some number like 1 instead to "ext_ability_to_patch", it only patches that extended ability. For example, setting
// "ext_ability_to_patch" to 1 beforehand only patches the first extended ability. Note that you will have to set
// "ext_ability_to_patch" each time you run the macro if want to patch only a range of extended abilities rather than all of
// them. You will also have to set "projectile_file" each time you wish to change between different projectiles.

DEFINE_PATCH_MACRO ~ADD_PROJECTILE_FILENAME_ITM~ BEGIN
PATCH_IF ((SOURCE_SIZE > 0x71) AND (VARIABLE_IS_SET "%projectile_file%") ) THEN BEGIN // Just in case
	// If no variable is set by the user, there is no parse error, but instead there is a warning sign, and
	// this macro takes over and simply sets the projectile index in the specified header(s) to "1-None"
	PATCH_IF !( VARIABLE_IS_SET "%projectile_file%" ) BEGIN
		SET projectile_num = 0
		SPRINT projectile_name ""
		PATCH_PRINT "Warning: no projectile filename was specified, so setting projectile index to None"
	END
	// If the last projectile is not what we are looking for, we launch this macro to look for it.
	// We often don't need it if we are copying and patching several items that use the same projectile.
	// This radically cuts the installation time.
	PATCH_IF !( "%projectile_file%" STRING_COMPARE_CASE "%projectile_name%" = 0) BEGIN
		INNER_ACTION BEGIN
			LAUNCH_ACTION_MACRO ~GET_PROJECTILE_ENTRY~
		END
	END
	PATCH_IF !( VARIABLE_IS_SET "%ext_ability_to_patch%" ) BEGIN
		SET ext_ability_to_patch = 0
	END
	READ_LONG  0x64 ext_off
	READ_SHORT 0x68 abil_num
	FOR (outerloops = 0; outerloops < abil_num; outerloops += 1) BEGIN
		PATCH_IF ((outerloops + 1 = ext_ability_to_patch) OR (ext_ability_to_patch = 0)) BEGIN
			// We don't like redundancy
			READ_SHORT ( outerloops * 0x38 + ext_off + 0x2a ) to_patch_or_not_to_patch
			PATCH_IF (to_patch_or_not_to_patch != projectile_num + 1) BEGIN
				WRITE_SHORT ( outerloops * 0x38 + ext_off + 0x2a ) (projectile_num + 1)
			END
		END
	END
	SET ext_ability_to_patch = 0
END
END

// This patch macro adds an explosion projectile to a projectile file by looking for the filename of the .pro that is in the
// PROJECTL.IDS. You have to specify (more accurately, SPRINTs) the variable "projectile_file" to the desired file,
// and set "projectile_file" each time you wish to change between different projectiles.

DEFINE_PATCH_MACRO ~ADD_PROJECTILE_EXPLOSION_FILENAME_PRO~ BEGIN
PATCH_IF ((SOURCE_SIZE > 0x2ff) AND (VARIABLE_IS_SET "%projectile_file%") ) THEN BEGIN // Just in case. There has to be an explosion for this to work.
	// If no variable is set by the user, there is no parse error, but instead there is a warning sign, and
	// this macro takes over and simply sets the projectile index in the specified header(s) to "1-None"
	PATCH_IF !( VARIABLE_IS_SET "%projectile_file%" ) BEGIN
		SET projectile_num = 0
		SPRINT projectile_name ""
		PATCH_PRINT "Warning: no projectile filename was specified, so setting projectile index to None"
	END
	// If the last projectile is not what we are looking for, we launch this macro to look for it.
	// We often don't need it if we are copying and patching several items that use the same projectile.
	// This radically cuts the installation time.
	PATCH_IF !( "%projectile_file%" STRING_COMPARE_CASE "%projectile_name%" = 0) BEGIN
		INNER_ACTION BEGIN
			LAUNCH_ACTION_MACRO ~GET_PROJECTILE_ENTRY~
		END
	END
	READ_SHORT  0x21a explosion_projectile
	PATCH_IF (explosion_projectile != projectile_num + 1) BEGIN
		WRITE_SHORT 0x21a (projectile_num + 1)
	END
END
END

// This action macro looks for the projectile entry of the projectile "projectile_name".pro, where "projectile_name" is
// some variable you SPRINT before launching the action macro. Since looking for projectiles slows down the installation
// process, the macro does not reset the variable "projectile_name" each time it is launched unless the coder manually
// tells it to reset the variable. If the coder specifies a projectile file not in the PROJECTL.IDS, "projectile_num"
// returns a zero. This macro is used in conjunction with the two macros ADD_PROJECTILE_FILENAME_SPL and
// ADD_PROJECTILE_FILENAME_ITM.

DEFINE_ACTION_MACRO ~GET_PROJECTILE_ENTRY~ BEGIN

COPY_EXISTING ~PROJECTL.IDS~ ~override~
COUNT_2DA_ROWS 0 "projectl_rowcount"
SET we_are_done = 0
PATCH_IF (!( VARIABLE_IS_SET "%projectile_num%" ) OR !( VARIABLE_IS_SET "%projectile_name%" )) BEGIN
	SET projectile_num = 0
	SPRINT projectile_name ""
END
PATCH_IF (("%projectile_file%" STRING_COMPARE_CASE "%projectile_name%" = 0) OR ("%projectile_file%" STRING_COMPARE_CASE "" = 0)) BEGIN
	SET we_are_done = 1
END
FOR ( row=1; row<projectl_rowcount AND we_are_done = 0; row+=1 ) BEGIN
	READ_2DA_ENTRY row 0 2 projectile_num
	READ_2DA_ENTRY row 1 2 projectile_name
	PATCH_IF ( "%projectile_file%" STRING_COMPARE_CASE "%projectile_name%" = 0) BEGIN
		SET we_are_done = 1
	END
END
PATCH_IF ( we_are_done = 0 ) BEGIN
	SET projectile_num = 0
	SPRINT projectile_name ""
END
BUT_ONLY_IF_IT_CHANGES

END

 

-Galactygon

Share this post


Link to post

WRITE_SOUNDSET does not appear to work in WeiDU v208. I believe it worked in Gort's library, so I don't know what changed.

OUTER_SET overwrite = 0
OUTER_SPRINT npc ~edwin7.cre~
OUTER_SPRINT soundset ~bg2edwin~
LAUNCH_ACTION_MACRO READ_SOUNDSET
OUTER_SPRINT npc ~_edwin2.cre~
OUTER_SPRINT soundset ~bg2edwin~
LAUNCH_ACTION_MACRO WRITE_SOUNDSET

Generates:

ERROR locating resource for 'COPY'
Resource [^_edwin2.cre$] not found in KEY file:
[./chitin.key]
Stopping installation because of error.

This is on Tutu, where _edwin2.cre exists obviously.

 

More typos in the documentation too - there are misplaced \item flags around READ_SOUND\item SET etc.

Share this post


Link to post

Typos are already fixed.

 

Don't know why the macro uses the REGEXP variant.

Can you check if a COPY_EXISTING_REGEXP ~^_edwin2.cre$~ ~override~ works on Tutu?

This should be case insensitive, but also try uppercased if it fails.

Share this post


Link to post
Don't know why the macro uses the REGEXP variant.
I don't know either, and I just noticed that was in Gort's code too. It should almost certainly be just COPY_EXISTING ~%npc%~ ~override~.
Can you check if a COPY_EXISTING_REGEXP ~^_edwin2.cre$~ ~override~ works on Tutu?
It does not. Since all the Tutu resources are already in the override, GLOB would have to be enabled (and should've been anyway if you were doing a real regexp copy like this, but unnecessary in this case).

 

While you're at it, you might want to put ELSEs between the PATCH_IFs in WRITE_SOUNDSET, since they are all mutually exclusive based on the value of %overwrite%. Might improve runtime by a trifling amount.

Share this post


Link to post

I have improved Gort's ADD_ITEM_EFFECT and ADD_SPELL_EFFECT macros, and unified them.

 

Here are the imrovements:

1.) The macro is called ~ADD_EFFECT_EXTENDED_HEADER~, and may be used to patch both items and spells alike.

2.) You do not need to set variables before launching the macro, and they are remembered from the last use. The variables are automatically set to 0, except for probability1 which is set to 100. This kept bothering me, and it is more of a safety check than a new feature.

3.) The macro doesn't have to add the effect as the last effect in the header. This is crucial in places where opcode 206 is used to protect against cumulative effects. This can be set using a new variable called "index". Not setting "index", setting "index" to 0 or some value that is greater than the number of effects will simply add the new effect as the last effect. Setting "index" to some valid value will insert the effect between existing effects, bumping them by one when necessary. For example, if you set "index" to 1, this macro make sure the new effect is triggered first.

 

For example, this piece of code would add Opcode #146 (Cast spell on creature), target self, timing mode permanent, etc. to STAF10.itm. The "header" variable is set to 2, and the "index" variable is set to 1, so it will add the effect as the first effect of the second extended header/ability (assuming the second header exists).

 

COPY_EXISTING ~STAF10.itm~ ~override~
SET opcode = 146
SET target = 1
SET timing = 1
SET parameter1 = 1
SET parameter2 = 1
SPRINT resource ~CAS01~
SET header = 2
SET index = 1
LAUNCH_PATCH_MACRO ~ADD_EFFECT_EXTENDED_HEADER~
BUT_ONLY_IF_IT_CHANGES

 

And below is the full macro. The formatting looks odd because the forum code cuts off the end of long lines, so you might have to copy and paste them in order to read what's happening

 

-Galactygon

 

// For any generic spell or item
DEFINE_PATCH_MACRO ~ADD_EFFECT_EXTENDED_HEADER~ BEGIN

PATCH_IF (SOURCE_SIZE > 0x71 AND ( 	"%SOURCE_FILE%" STRING_MATCHES_REGEXP "^.+\.itm" = 0 OR
					"%SOURCE_FILE%" STRING_MATCHES_REGEXP "^.+\.spl" = 0
) ) THEN BEGIN // Just in case
PATCH_IF ("%SOURCE_FILE%" STRING_MATCHES_REGEXP "^.+\.itm" = 0) BEGIN
	SET ___#header_size = 0x38
END ELSE
PATCH_IF ("%SOURCE_FILE%" STRING_MATCHES_REGEXP "^.+\.spl" = 0) BEGIN
	SET ___#header_size = 0x28
END
PATCH_IF !(VARIABLE_IS_SET "%header%") BEGIN
	SET header = 0
END
PATCH_IF !(VARIABLE_IS_SET "%index%") BEGIN
	SET index = 0
END
PATCH_IF !(VARIABLE_IS_SET "%opcode%") BEGIN
	SET opcode = 0
END
PATCH_IF !(VARIABLE_IS_SET "%target%") BEGIN
	SET target = 0
END
PATCH_IF !(VARIABLE_IS_SET "%timing%") BEGIN
	SET timing = 0
END
PATCH_IF !(VARIABLE_IS_SET "%resist_dispel%") BEGIN
	SET resist_dispel = 0
END
PATCH_IF !(VARIABLE_IS_SET "%power%") BEGIN
	SET power = 0
END
PATCH_IF !(VARIABLE_IS_SET "%parameter1%") BEGIN
	SET parameter1 = 0
END
PATCH_IF !(VARIABLE_IS_SET "%parameter2%") BEGIN
	SET parameter2 = 0
END
PATCH_IF !(VARIABLE_IS_SET "%duration%") BEGIN
	SET duration = 0
END
PATCH_IF !(VARIABLE_IS_SET "%probability1%") BEGIN
	SET probability1 = 100
END
PATCH_IF !(VARIABLE_IS_SET "%probability2%") BEGIN
	SET probability2 = 0
END
PATCH_IF !(VARIABLE_IS_SET "%resource%") BEGIN
	SPRINT resource ""
END
PATCH_IF !(VARIABLE_IS_SET "%dicenumber%") BEGIN
	SET dicenumber = 0
END
PATCH_IF !(VARIABLE_IS_SET "%dicesize%") BEGIN
	SET dicesize = 0
END
PATCH_IF !(VARIABLE_IS_SET "%savingthrow%") BEGIN
	SET savingthrow = 0
END
PATCH_IF !(VARIABLE_IS_SET "%savebonus%") BEGIN
	SET savebonus = 0
END
READ_LONG  0x64 ___#abil_off
READ_SHORT 0x68 ___#abil_num
READ_LONG  0x6a ___#fx_off
FOR (___#index1 = 0; ___#index1 < ___#abil_num; ___#index1 += 1) BEGIN
	PATCH_IF (___#index1 = (header - 1)) OR (header = 0) BEGIN //header=1 means ___#index1=0
		READ_SHORT  (___#abil_off + 0x1e + (___#header_size * ___#index1)) ___#abil_fx_num
		READ_SHORT  (___#abil_off + 0x20 + (___#header_size * ___#index1)) ___#abil_fx_idx
		WRITE_SHORT (___#abil_off + 0x1e + (___#header_size * ___#index1)) (___#abil_fx_num + 1)
		FOR (___#index2 = 0; ___#index2 < ___#abil_num; ___#index2 += 1) BEGIN
			READ_SHORT (___#abil_off + ___#index2 * ___#header_size + 0x20) ___#1effect_index
			PATCH_IF (___#1effect_index > ___#abil_fx_idx) BEGIN //if ability after current effect
				WRITE_SHORT (___#index2 * ___#header_size + ___#abil_off + 0x20) (___#1effect_index + 1) //increase 1 effect ___#index1 by 1
			END
		END
		//no offsets to correct
		SET ___#tot_off = (___#fx_off + (___#abil_fx_num + ___#abil_fx_idx) * 0x30)
		INSERT_BYTES 		(___#tot_off)		0x30
		PATCH_IF ( index = 0 OR index > ___#abil_fx_num + 1 ) THEN BEGIN
			SET ___#write_off = ___#tot_off
		END ELSE BEGIN
			SET ___#write_off = (___#fx_off + (index - 1 + ___#abil_fx_idx) * 0x30)
			FOR (___#index3 = ___#abil_fx_num; ___#index3 > index - 1; ___#index3 -= 1) BEGIN
				SET ___#old_off = (___#fx_off + (___#index3 - 1 + ___#abil_fx_idx) * 0x30)
				SET ___#new_off = (___#fx_off + (___#index3 + ___#abil_fx_idx) * 0x30)
				READ_SHORT		  (___#old_off)		___#opcode
				READ_BYTE   		(___#old_off + 0x02) ___#target
				READ_BYTE   		(___#old_off + 0x03) ___#power
				READ_LONG   		(___#old_off + 0x04) ___#parameter1
				READ_LONG   		(___#old_off + 0x08) ___#parameter2
				READ_BYTE   		(___#old_off + 0x0c) ___#timing
				READ_BYTE   		(___#old_off + 0x0d) ___#resist_dispel
				READ_LONG   		(___#old_off + 0x0e) ___#duration
				READ_BYTE   		(___#old_off + 0x12) ___#probability1
				READ_BYTE   		(___#old_off + 0x13) ___#probability2
				READ_ASCII			(___#old_off + 0x14) ___#resource
				READ_LONG   		(___#old_off + 0x1c) ___#dicenumber
				READ_LONG   		(___#old_off + 0x20) ___#dicesize
				READ_LONG   		(___#old_off + 0x24) ___#savingthrow
				READ_LONG   		(___#old_off + 0x28) ___#savebonus
				WRITE_SHORT		  (___#new_off)		___#opcode
				WRITE_BYTE   		(___#new_off + 0x02) ___#target
				WRITE_BYTE   		(___#new_off + 0x03) ___#power
				WRITE_LONG   		(___#new_off + 0x04) ___#parameter1
				WRITE_LONG   		(___#new_off + 0x08) ___#parameter2
				WRITE_BYTE   		(___#new_off + 0x0c) ___#timing
				WRITE_BYTE   		(___#new_off + 0x0d) ___#resist_dispel
				WRITE_LONG   		(___#new_off + 0x0e) ___#duration
				WRITE_BYTE   		(___#new_off + 0x12) ___#probability1
				WRITE_BYTE   		(___#new_off + 0x13) ___#probability2
				WRITE_EVALUATED_ASCII 	(___#new_off + 0x14) "%___#resource%" (8)
				WRITE_LONG   		(___#new_off + 0x1c) ___#dicenumber
				WRITE_LONG   		(___#new_off + 0x20) ___#dicesize
				WRITE_LONG   		(___#new_off + 0x24) ___#savingthrow
				WRITE_LONG   		(___#new_off + 0x28) ___#savebonus
			END
		END
		WRITE_SHORT		  (___#write_off)		opcode
		WRITE_BYTE   		(___#write_off + 0x02) target
		WRITE_BYTE   		(___#write_off + 0x03) power
		WRITE_LONG   		(___#write_off + 0x04) parameter1
		WRITE_LONG   		(___#write_off + 0x08) parameter2
		WRITE_BYTE   		(___#write_off + 0x0c) timing
		WRITE_BYTE   		(___#write_off + 0x0d) resist_dispel
		WRITE_LONG   		(___#write_off + 0x0e) duration
		WRITE_BYTE   		(___#write_off + 0x12) probability1
		WRITE_BYTE   		(___#write_off + 0x13) probability2
		WRITE_EVALUATED_ASCII 	(___#write_off + 0x14) ~%resource%~ (8)
		WRITE_LONG   		(___#write_off + 0x1c) dicenumber
		WRITE_LONG   		(___#write_off + 0x20) dicesize
		WRITE_LONG   		(___#write_off + 0x24) savingthrow
		WRITE_LONG   		(___#write_off + 0x28) savebonus
	END
END
END

END

Edited by Galactygon

Share this post


Link to post

I think you will need to invert your logic on the SPL/ITM check as discussed here (or better yet, use the newer SOURCE_EXT syntax).

Share this post


Link to post

Yes, I have confirmed it works for items and spells alike. The only limitations are it cannot patch casting feature blocks or equipped effects, and it can take a second or two to bump effects if they are in the hundreds (which is mainly something I have to deal with).

 

Feel free to replace STRING_MATCHES_REGEXP with SOURCE_EXT.

 

-Galactygon

Share this post


Link to post

I have created some patch code where after a list of SET's I can add a new ability header. For a single purpose I could just replace the variables with exact values and be done with it. But I'd like to turn it into a patch_macro for my use and the use of others. What else is needed to turn this into a macro? Do I need to make a bunch of null/zeroed LOCAL_SET's in case someone doesn't need to use a certain variable? Anything else I need to know? Has someone already done this?

 

I assume that in the macro section of the tp2 I would put:

DEFINE_PATCH_MACRO ~ADD_ABILITY_HEADER~ BEGIN

my patches

END

 

and in the component section of the tp2 I would put my list of:

SET variable = x

LAUNCH_PATCH_MACRO ~ADD_ABILITY_HEADER~

 

Here is the current patch code:

  READ_LONG 0x64 ~abil_loc~
 READ_SHORT 0x68 ~abil_num~
 READ_SHORT 0x6a ~fx_loc~
 SET abil_size = 56
 SET new_abil_loc = (%abil_loc% +(%abil_num% *%abil_size))  //sets new header at end of existing header list if any
 SET new_fx_loc = (%fx_loc% + %abil_size%)				  //increases effects location by ability size
 INSERT_BYTES %new_abil_loc% %abil_size%					//insert enough bytes for one ability at new location
  WRITE_SHORT 0x68 (%abil_num% + 1)						  //update number of headers in file
  WRITE_LONG 0x6a (%new_fx_loc%)							 //update effects location in file
  WRITE_BYTE  (%new_abil_loc% + 0x0) ~%attack_type%~			  // attack type
  WRITE_BYTE  (%new_abil_loc% + 0x1) ~%id_req%~				   // id required 0-yes 1-no
  WRITE_BYTE  (%new_abil_loc% + 0x2) ~%use_location%~			 // use location -- followed by a 3 byte unknown
  WRITE_EVALUATED_ASCII (%new_abil_loc% + 0x4) ~%use_icon%~	   // use icon
  WRITE_BYTE  (%new_abil_loc% + 0xc) ~%target_type%~			  // type of target
  WRITE_BYTE  (%new_abil_loc% + 0xd) ~%target_count%~			 // target count
  WRITE_SHORT (%new_abil_loc% + 0xe) ~%range%~					// range
  WRITE_BYTE  (%new_abil_loc% + 0x10) ~%proj_type%~			   // projectile type
  WRITE_BYTE  (%new_abil_loc% + 0x12) ~%speed%~				   // speed
  WRITE_BYTE  (%new_abil_loc% + 0x14) ~%thac0_bonus%~			 // THAC0 bonus
  WRITE_BYTE  (%new_abil_loc% + 0x16) ~%d_sides%~				 // dice sides
  WRITE_SHORT (%new_abil_loc% + 0x18) ~%d_rolls%~				 // dice rolls
  WRITE_SHORT (%new_abil_loc% + 0x1a) ~%damage_bonus%~			// damage_bonus
  WRITE_SHORT (%new_abil_loc% + 0x1c) ~%damage_type%~			 // damage type
  WRITE_SHORT (%new_abil_loc% + 0x22) ~%charges%~				 // charges
  WRITE_SHORT (%new_abil_loc% + 0x24) ~%charge_removal%~		  // charge removal
  WRITE_SHORT (%new_abil_loc% + 0x26) ~%flag%~					// flag -- followed by a 2 byte unknown
  WRITE_SHORT (%new_abil_loc% + 0x2a) ~%proj_anim%~			   // projectile animation
  WRITE_SHORT (%new_abil_loc% + 0x2c) ~%overhand%~				// overhand
  WRITE_SHORT (%new_abil_loc% + 0x2e) ~%backhand%~				// backhand
  WRITE_SHORT (%new_abil_loc% + 0x30) ~%thrust%~				  // thrust
  WRITE_SHORT (%new_abil_loc% + 0x32) ~%bow%~					 // bow
  WRITE_SHORT (%new_abil_loc% + 0x34) ~%xbow%~					// crossbow
  WRITE_SHORT (%new_abil_loc% + 0x36) ~%sling%~				   // sling

The reason I wanted to do this is that I am going to use Weidu's newly included ADD_ITEM_EFFECT macro from Gort, but the item I'm using doesn't have an ability header to begin with.

Share this post


Link to post
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...