Jump to content

Expanded ALTER/CLONE/DELETE_EFFECT functions


Recommended Posts

ALTER_, CLONE_, and DELETE_EFFECT are pretty useful functions, but they (rather infamously) don't allow you to write in negative numbers into the effects you're modifying. I've always wanted to revisit these functions and address this, but it was always on my 'one of these days' to-do list and more or less ignored. Until today, when I was inspired to address this, and quite a bit more.

Introducing the _EX versions of these effects: ALTER_EFFECT_EX, CLONE_EFFECT_EX, and DELETE_EFFECT_EX. These function exactly the same way as the originals, but have additional variables that make these exceptionally flexible.

A short digression

A quick aside on how the original functions work, as it is very relevant to how the new ones work. For the current function family, it reads in all of the parameters of an effect, and then runs comparisons against the match_ variables and, if all of the match comparisons are valid, it then deletes it (DELETE_EFFECT) or writes in the new values (ALTER or CLONE). This is an example of how, say, the opcode is checked for a match:

PATCH_IF (((match_opcode        = o_opcode)        OR (match_opcode < 0)) AND 
          ((match_target        = o_target)        OR (match_target < 0)) AND
  // ... other parameter checks
  ) BEGIN

The original effect values are read into o_foo variables, so o_opcode is the opcode of the current effect being examined. Since the default value for the match_ variables are -1 (-10 for save bonuses), the latter parameter basically tells it to bypass this check if no match_opcode is specified. (Incidentally, the -1 default value is also why the functions don't handle negatives well.) Similarly, the code to change the effect (via ALTER or CLONE) has similar checks:

PATCH_IF (opcode >= 0)        BEGIN WRITE_SHORT (base        + (0x08 * fx_type)) opcode        END

Same idea; opcode's default value is -1, so it'll only write in a new opcode value if a non-default, positive value is specified in the function call.

So what's new?

The EX family introduces two new series of string variables for both the match and value variables with _ex suffixes. The match_foo_ex series inserts WeiDU code into the comparisons to allow for more flexibility. Let's say you're looking to delete effects that block a spell, which can be done with opcodes 206, 318, or 324. In the past you'd have to invoke DELETE_EFFECT for each of the three opcodes, but now we can simply use

DELETE_EFFECT_EX STR_VAR match_opcode_ex = ~((o_opcode = 206) OR (o_opcode = 318) OR (o_opcode = 324))~ match_resource = myspell END

The presence of an _ex variable will cause the function to ignore the normal version, e.g. in the example above match_opcode would be ignored because match_opcode_ex exists. match_resource is respected because there's no match_resource_ex specified. You could even extend this further by using resource field to remove all spell protections against divine magic by using a regexp with the resource field:

DELETE_EFFECT_EX STR_VAR match_opcode_ex = ~((o_opcode = 206) OR (o_opcode = 318) OR (o_opcode = 324))~ match_resource_ex = ~("%o_resource%" STRING_COMPARE_REGEXP "^[Ss][Pp][Pp][Rr][0-9]+" = 0)~ END

This would delete any 206/318/324 that targeted spells starting with SPPR-numeral.

The value variables also accept code. So if you wanted to, say, improve shields by increasing their base AC bonus by +1 across the board, this would work just dandy:

COPY_EXISTING_REGEXP GLOB ~^.+\.itm$~ ~override~
  READ_SHORT 0x1c type
  PATCH_IF type = 12 BEGIN // shield
    LPF ALTER_EFFECT_EX INT_VAR match_opcode = 0 match_parameter2 = 0 STR_VAR parameter1_ex = ~(THIS + 1)~ END // increase AC bonus by 1
  END  
  BUT_ONLY

You can also use some limited tests in the value fields, too, Let's say you're trying to boost transmuters at the expense of abjurers, so you want alterations to receive a universal -1 save penalty and abjurations a universal +1 save bonus:

COPY_EXISTING_REGEXP GLOB ~^.+\.spl$~ ~override~
  READ_SHORT 0x22 type
  PATCH_IF ((type = 10) OR (type = 12)) BEGIN // alteration, abjuration
    LPF ALTER_EFFECT_EX STR_VAR match_savingthrow_ex = ~(o_savingthrow != 0)~ savebonus_ex = ~((type = 12) ? (THIS + 1) : (THIS - 1))~ END
  END  
  BUT_ONLY

Let's throw in an ALTER_HEADER variant as well

I wrote an ALTER_HEADER function as well, but unlike my other functions, it never made it into WeiDU proper. I've added an ALTER_HEADER_EX variant as well, e.g. let's say you wanted to give spears a bit of a boost by giving them a +1 damage bonus:

COPY_EXISTING_REGEXP GLOB ~^.+\.itm$~ ~override~
  READ_SHORT 0x1c type
  PATCH_IF type = 29 BEGIN // spear
    LPF ALTER_HEADER_EX STR_VAR match_type_ex = ~((o_type = 1) OR (o_type = 2) OR (o_type = 4))~ damage_ex = ~(THIS + 1)~ END // melee or anged or launcher
  END  
  BUT_ONLY

Because there are (albeit unused) throwing spears in the game, it checks for melee, ranged, and even launcher headers and then bumps the damage by one. One difference for ALTER_HEADER is that, instead of 10 different bit field value_ex variables, there's just one (flags_ex) for the entire four bytes, since you can do whatever bit operations desired.

Some final words

These were written more or less in day, so I'm sure something is wrong somewhere--so I'm putting these out there and asking for some field testing. I'd also be happy to provide examples of how to utilize them in actual real-use scenarios if anyone would like to give them a shot.

The library with the functions is attached!

x_force.tph

Edited by CamDawg
added library
Link to comment

Nice!  Thanks @CamDawg

I skim read this twice and slow read it once - I might be missing it, but while I see relative negative usage (THIS - 1), I can't find a sample of matching on a negative.

One such use case is where one mod (IR) applies backstab penalties on weapons, and I want to find/match against all weapons with a negative BS penalty - I was unable to use something like: "match_parameter1=-1" due to the syntax/grammar error this triggers.

I had a TODO note to try out something I saw in another mod, "match_parameter1=(0 - 1)", but I never got to testing it (another area, I just saw 'match_parameter1="-1"`, but I can't remember if I tried that - maybe that was not in a match sense, but for assignment that I saw the string quote).

I think with the new _EX versions, I could write something like this:

  LPF ALTER_EFFECT
    INT_VAR silent=1
            match_opcode=0x107   // backstab (263)
            match_parameter1=(0 - 1)
            match_parameter2=0
            parameter1=1
  END

  LPF ALTER_EFFECT
    INT_VAR silent=1
            match_opcode=0x107   // backstab (263)
            match_parameter1=(0 - 2)
            match_parameter2=0
            parameter1=1
  END

into a single statement that would match on perhaps any negative BS value (this mod introduced ones at 0, negative 1, negative 2, and negative 3, and I would like to undo those changes and set them all to 1 perhaps).

So I assume this can be done with the weidu as a string that'll be evaluated, even without a THIS, but just the literal negative integer?

Link to comment

Oh right, the thing I led off with--"these can now do X"--and then I didn't provide any examples.

The _ex parameters don't have any restrictions, so you can literally just use

 LPF ALTER_EFFECT
    INT_VAR silent=1
            match_opcode=0x107   // backstab (263)
            match_parameter2=0
            parameter1=1
    STR_VAR match_parameter1_ex = (o_parameter1 < 0)            
  END

edit: and writing negative values is just as easy, e.g.

parameter1_ex = ~"-1"~

 

Edited by CamDawg
Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

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