CamDawg Posted December 12, 2022 Share Posted December 12, 2022 (edited) 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 December 12, 2022 by CamDawg added library Quote Link to comment
ahungry Posted December 12, 2022 Share Posted December 12, 2022 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? Quote Link to comment
CamDawg Posted December 12, 2022 Author Share Posted December 12, 2022 (edited) 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 December 12, 2022 by CamDawg Quote Link to comment
Recommended Posts
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.