Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!


Axis & Allies 1942 Online is now available in Early Access! Buy it on Steam. The FAQ is available.
New Premium Module: Tyrants of the Moonsea! Read More
Attention, new and old users! Please read the new rules of conduct for the forums, and we hope you enjoy your stay!

[(BG2, BGEE) Bug] Slow kinda, sorta doesn't stack (0813)

CamDawgCamDawg Member, Developer Posts: 3,394
edited August 2012 in Fixed
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.
// 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
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
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
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 4))) ~spwm164~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 3))) ~spwm164~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 2))) ~spwm164~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 1))) ~spwm164~ #8 // resref
WRITE_ASCII ("%fx_off%" + 0x14 + (0x30 * ("%abil_fx_num%" + "%abil_fx_idx%" + 0))) ~spwm164~ #8 // resref
SET "delta" = "%delta%" + 6
WRITE_SHORT ("%abil_off%" + 0x1e + (0x28 * "%index%")) ("%abil_fx_num%" + 6)

Post edited by Bhryaen on


  • SethDavisSethDavis Member Posts: 1,812
    edited July 2012
    checking this one now

    [EDIT] Potentially fixed - Future proofing spells have been pulled in and @CamDawg's fix has been applied

  • GalactygonGalactygon Member, Developer Posts: 378
    This will have a major drawback of slow becoming non-refreshable before the duration expires. I've used this as a player many times.


  • AndreaColomboAndreaColombo Member Posts: 5,326
    @Galactygon - is there a way around it that still fixes the stackability of those penalties?

  • GalactygonGalactygon Member, Developer Posts: 378
    I have 3 ideas:
    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.


  • CamDawgCamDawg Member, Developer Posts: 3,394
    #1 is interesting--set it up like True Sight with a bunch of delayed castings--but I'm curious how that behaves, performance-wise.

    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.

  • GalactygonGalactygon Member, Developer Posts: 378
    #1: I've tested and used this type of implementation - it's a bit clunky because the intervals of 272 are not exact so you will have snaps of one or two frames where the penalties are not applied. So I'd rather not see it in a polished version when there are cleaner ways to implement this.

    For the short term, I recommend #2 until #3 is implemented.


  • BhryaenBhryaen Member Posts: 2,874
    Confirmed Fixed... ?

    I created a xvart with THAC0 10, AC 10, APR 4 and cast Slow from scrolls and then learned spells:
    UberXvart     THAC0  AC APR    Movt
    Before Slow 10 10 4 Normal
    One Slow 14 14 4 Half
    Two Slow 14 14 4 Half
    Three Slow 14 14 4 Half
    The spell desc says this:
    A slow spell causes creatures to move and attack at half of their normal rates. It negates haste, but does not otherwise affect magically speeded or slowed creatures. Slowed creatures have an armor class penalty of +4 to AC, and an attack penalty of -4. Creatures save at -4 vs the spell.
    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.

  • TanthalasTanthalas Member Posts: 6,738
    Confirmed Fixed in Build 0815.

    I tested this one using a level 11 Khalid. Observed the same as Bhryaen.

    I checked vBG2, and slow doesn't have an animation there either.

  • BhryaenBhryaen Member Posts: 2,874
    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

  • TanthalasTanthalas Member Posts: 6,738
Sign In or Register to comment.