Jump to content
Sign in to follow this  

Enhanced ALTER_EFFECT functions

Recommended Posts

For various reasons I've been doing some coding recently where it's been convenient not to rely on SCS's function library, but to use the core WEIDU functions instead. In particular, I've been using ADD_[SPELL/ITEM]_EFFECT and [ALTER/CLONE/DELETE]_EFFECT. They're very nice but I found myself needing slightly more functionality, so I worked up a slightly modified version. They're available on the SCS repo in stratagems/lib/alter_effect.tpa.

There are four sets of changes, which I'll detail below.

Share this post

Link to post

1. flag matching and setting

Effects have flag data at 0x24-0x27 (the saving throw field) and 0x2c-0x2f (the 'special' field). The WEIDU functions only allow you to match or write these fields as LONG entries. My version gives you access to most of the main flags. Specifically, it defines the following variables:


along with the associated match_ variables (e.g., match_ignore_secondary, match_save_vs_spell).

Share this post

Link to post

2. Subfields of parameter2.

Certain opcodes (notably opcode 12, 'damage') split the parameter2 field into two subfields: each is a SHORT, located respectively at 0x8 and 0xa. My version lets you write to and match on these separately, via the variables 


Share this post

Link to post

3. Negative values of parameter1 and parameter2

This is minor - but for implementation reasons, in the original WEIDU versions of the functions, parameter1 and parameter2 have to take nonnegative values (otherwise they are ignored). My version lets them take negative values between -9 and -1. (The main application is if a parameter represents a string and you want to set it to -1.)

Share this post

Link to post

4. Function matching and patching

This one is very much for advanced users only! (If you're not happy defining your own functions, ignore this bit of the post.) It introduces two new STR variables:

	function (only for CLONE_EFFECT/ALTER_EFFECT)

Each should be set to the name of a PATCH_FUNCTION that expects to execute on a length-0x30 file with the structure of an EFFv1. The match_function should have one return value, 'value', which can be equal to either 0 or 1. If match_function is set, the function is executed on each EFF block, and then the CLONE/ALTER/DELETE is performed on each block for which the function returns value=1. When it is executed, if function is set then that function is executed on the cloned or altered block.

This is easiest to illustrate through examples. Firstly, suppose you want to delete all damage-resistance effects (that is, all opcodes in the ranges 27-31 and 84-89). Of course you could do it with 11 DELETE_EFFECTs, but that's tedious to type and inefficient to execute if you're applying it to many items (which, ok, is unlikely in this case, but there are more realistic cases). You can do it like this. First, define a function that returns 1 if the opcode is in the desired range:

	DEFINE_PATCH_FUNCTION is_damage_resistance
	RET value
	READ_BYTE 0x0 opcode
	PATCH_MATCH "%opcode%" WITH
	27 28 29 30 31 84 85 86 87 88 89 BEGIN
	SET value=1
	SET value=0

Then do this patch on the item or spell you're working on

	LPF DELETE_EFFECT STR_VAR match_function=is_damage_resistance END

Secondly, suppose you instead want to halve the efficacy of all damage-resistance powers. Define another function:

	DEFINE_PATCH_FUNCTION halve_parameter2
	WRITE_LONG 0x4  (LONG_AT 0x4) / 2

Then just apply the patch

	LPF ALTER_EFFECT STR_VAR match_function=is_damage_resistance function=halve_parameter2 END

Share this post

Link to post

4a. More advanced function matching/patching

Instead of a function name, you can set function or match_function to a string


Function_name should still be the name of an appropriate patch function, but if that function has a STR_VAR 'arguments', 'args' will be fed into that variable. In my applications, I defined functions 'opcode_is' and 'opcode_is_not', each of which took as argument a space-separated string of integers and returned 1 if the opcode was /wasn't in the string.

Share this post

Link to post
Posted (edited)
On 5/11/2019 at 12:09 PM, DavidW said:

3. Negative values of parameter1 and parameter2

(The main application is if a parameter represents a string and you want to set it to -1.)

Moreover, there may be issues with signed integers (i.e., all those values for which BIT31 - 0x80000000 is set to 1). For instance:

  match_opcode = 324 // Immunity from spell and message
  parameter1 = 0x80110FEF // the function won't write this value...
  parameter2 = 138 // STATE bit_eq specified value


Edited by Luke

Share this post

Link to post

Yes, but this fix won’t handle that case, because I didn’t need it. I wasn’t really aiming to do a systematic improvement of the toolset, just to share something I’d done for my own use.

Share this post

Link to post
On 5/11/2019 at 1:01 PM, DavidW said:

They're available on the SCS repo in stratagems/lib/alter_effect.tpa.


Fixed that for yöu. 

Share this post

Link to post
You are commenting as a guest. If you have an account, please sign in.
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.

Sign in to follow this