[(BG2, BGEE) Bug] Slow kinda, sorta doesn't stack (0813)
If an already slowed creature gets hit with a second slow spell, their movement rate/ApR., etc. remain unchanged. However, the related effects of AC & THAC0 penalties stack. BG2FP worked around this by adding an immunity to other slow spells while slowed.
Note this patch includes immunities to BG2 slow spells not presently in BGEE as future-proofing.
Note this patch includes immunities to BG2 slow spells not presently in BGEE as future-proofing.
// slow shouldn't stack
COPY_EXISTING //~spin575.spl~ ~override~ // slow
~spin977.spl~ ~override~ // slow (golem)
~spin983.spl~ ~override~ // slow (innate)
~spwi312.spl~ ~override~ // slow (mage)
//~spwish25.spl~ ~override~ // slow (wish)
~spwm164.spl~ ~override~ // slow (wild surge)
PATCH_IF (SOURCE_SIZE > 0x71) THEN BEGIN // protects against invalid files
READ_LONG 0x64 "abil_off"
READ_SHORT 0x68 "abil_num"
READ_LONG 0x6a "fx_off"
SET "delta" = 0
FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
READ_SHORT ("%abil_off%" + 0x1e + (0x28 * "%index%")) "abil_fx_num"
READ_SHORT ("%abil_off%" + 0x20 + (0x28 * "%index%")) "abil_fx_idx"
SET "abil_fx_idx" = ("%abil_fx_idx%" + "%delta%")
WRITE_SHORT ("%abil_off%" + 0x20 + (0x28 * "%index%")) "%abil_fx_idx%"
FOR (index2 = 0 ; index2 < abil_fx_num ; index2 = index2 + 1) BEGIN
READ_SHORT ("%fx_off%" + (0x30 * ("%index2%" + "%abil_fx_idx%"))) "opcode"
PATCH_IF ("%opcode%" = 40) BEGIN // if slow opcode
READ_ASCII ("%fx_off%" + (0x30 * ("%index2%" + "%abil_fx_idx%"))) "clone_fx" (0x30) // read entire effect
SET "index2" = "%abil_fx_num%" // kills loop
END
END
FOR (index3 = 0 ; index3 < 6 ; index3 = index3 + 1) BEGIN
INSERT_BYTES ("%fx_off%" + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%"))) 0x30 // create new effect
WRITE_EVALUATED_ASCII ("%fx_off%" + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%"))) ~%clone_fx%~ // clones slow effect
WRITE_SHORT ("%fx_off%" + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%"))) 206 // spell immunity
WRITE_LONG ("%fx_off%" + 0x04 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%"))) 0xffffffff // string to display
END
WRITE_EVALUATED_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 5))) ~%SOURCE_RES%~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 4))) ~spin575~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 3))) ~spin983~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 2))) ~spwi312~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 1))) ~spwish25~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 0))) ~spin977~ #8 // resref
PATCH_IF ("%SOURCE_RES%" STRING_COMPARE_CASE "spin575" = 0) BEGIN
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 4))) ~spwm164~ #8 // resref
END ELSE
PATCH_IF ("%SOURCE_RES%" STRING_COMPARE_CASE "spin983" = 0) BEGIN
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 3))) ~spwm164~ #8 // resref
END ELSE
PATCH_IF ("%SOURCE_RES%" STRING_COMPARE_CASE "spwi312" = 0) BEGIN
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 2))) ~spwm164~ #8 // resref
END ELSE
PATCH_IF ("%SOURCE_RES%" STRING_COMPARE_CASE "spwish25" = 0) BEGIN
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 1))) ~spwm164~ #8 // resref
END ELSE
PATCH_IF ("%SOURCE_RES%" STRING_COMPARE_CASE "spin977" = 0) BEGIN
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 0))) ~spwm164~ #8 // resref
END
SET "delta" = "%delta%" + 6
WRITE_SHORT ("%abil_off%" + 0x1e + (0x28 * "%index%")) ("%abil_fx_num%" + 6)
END
END
BUT_ONLY_IF_IT_CHANGES
Post edited by Bhryaen on
3
Comments
[EDIT] Potentially fixed - Future proofing spells have been pulled in and @CamDawg's fix has been applied
-Galactygon
1. Place the penalties in a shell spell embedded in an opcode 272 that triggers every second while the shell spell has a duration of one second and includes an immunity opcode 206 to itself. If there are multiple overlapping 272s of the same shell spell, then only one of them will grant bonuses because it will block the rest of the shell spells. There are two problems with this implementation (a) opcode 272 in vanilla is unreliable because of stacking issues and haste/slow speeds up and slows down the frequency and (b) it's not a very clean
2. Hardcode the penalties into the slow opcode. This isn't a modder-friendly solution but works.
3. Overlapping effects Possibly the best solution, and the developers have hinted this will eventually make it.
The developers for IWD2 have opted to use solution 2 for the various spells and abilities, which is why there are so many different redundant opcodes that can be solved much more gracefully with a coherent, overlapping effect system.
-Galactygon
I'm not sure #2 would be all that bad. I think the situations where you'd want the penalties would dwarf the situations where you don't. On general principle I'd like to avoid hardcoding, but it did make it a lot easier for improved invisibility.
#3 is definitely rife with possibilities, but also rife with potential for a lot of bugs and shenanigans. Given the timeline for BGEE that may be better set as a long-term goal.
For the short term, I recommend #2 until #3 is implemented.
-Galactygon
I created a xvart with THAC0 10, AC 10, APR 4 and cast Slow from scrolls and then learned spells: The spell desc says this: So it works as such with no stacking. The only thing to mention would be that when multiple Slows are attempted, there is the appearance that the spell has failed by the caster. The successful casting shows up in the bottom text window and the casting happens, but the magic mote isn't sent from the caster as if having been interrupted with the spell fizzling.
I tested this one using a level 11 Khalid. Observed the same as Bhryaen.
@Bhryaen
I checked vBG2, and slow doesn't have an animation there either.
So there's no projectile mote in vBG2 on initial casting or on subsequent casts only? It's still Confirmed Fixed though- just mentioned that part as a note for CamDawg in case he thought that warranted further redress as an unintended result
There's never a projectile.