# Weidu macro libraries

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

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

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

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

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
BUT_ONLY_IF_IT_CHANGES
COPY_EXISTING ~PROJECTL.ids~ ~override~
COUNT_2DA_ROWS 1 projectl_rowcount
SET projectl_rowcount -= 1
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

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

// 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
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
FOR(i=0; i<ab_num; i+=1) BEGIN
WRITE_SHORT (ab_off+i*0x28+0x26) %RR#VRNP%
END
BUT_ONLY_IF_IT_CHANGES

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?

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~
SPRINT projectile_file "LC_DFG01"
SPRINT projectile_file "LC_DFG02"
...

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.

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
END
FOR (outerloops = 0; outerloops < ext_num; outerloops += 1) 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
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.

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

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

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

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

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.

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 index = 1
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

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
END ELSE
PATCH_IF ("%SOURCE_FILE%" STRING_MATCHES_REGEXP "^.+\.spl" = 0) BEGIN
END
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
FOR (___#index1 = 0; ___#index1 < ___#abil_num; ___#index1 += 1) BEGIN
WRITE_SHORT (___#abil_off + 0x1e + (___#header_size * ___#index1)) (___#abil_fx_num + 1)
FOR (___#index2 = 0; ___#index2 < ___#abil_num; ___#index2 += 1) BEGIN
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)
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

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

He explicitly checks for = 0 so his code is correct, I think.

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

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:

my patches

END

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

SET variable = x

Here is the current patch code:

  READ_LONG 0x64 ~abil_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.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

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

×

×
• Website