Skip to content

[(BGEE, BG2) bug] High-level divine spell fixes

CamDawgCamDawg Member, Developer Posts: 3,438
edited August 2012 in Fixed
Holy power and champion's strength are capped at level 18. Champion's strength also has some errors when cast at levels 16 and 17.

None of these bugs affect BGEE, but here's the fix anyway:
// holy power missing level 19, 20 abilities
COPY_EXISTING ~sppr412.spl~ ~override~
READ_LONG 0x64 "abil_off"
READ_SHORT 0x68 "abil_num"
READ_LONG 0x6a "fx_off"
READ_SHORT 0x70 "fx_num"
SET "lev19_exist" = 0
SET "lev20_exist" = 0
SET "new_abil" = 0
FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
READ_SHORT ("%abil_off%" + 0x10 + (0x28 * "%index%")) "min_lev"
PATCH_IF ("%index%" = ("%abil_num%" - 1)) BEGIN // last header
READ_SHORT ("%abil_off%" + 0x1e + (0x28 * "%index%")) "abil_fx_num"
READ_SHORT ("%abil_off%" + 0x20 + (0x28 * "%index%")) "abil_fx_idx"
READ_ASCII ("%abil_off%" + (0x28 * "%index%")) "abil_clone" (0x28)
READ_ASCII ("%fx_off%" + (0x30 * ("%abil_fx_idx%"))) "fx_clone" (0x30 * "%abil_fx_num%")
SET "new_fx" = "%abil_fx_num%"
SET "start_fx" = ("%abil_fx_idx%" + "%abil_fx_num%")
END ELSE
PATCH_IF ("%min_lev%" = 19) BEGIN
SET "lev19_exist" = 1
END
PATCH_IF ("%min_lev%" = 20) BEGIN
SET "lev20_exist" = 1
END
END
PATCH_IF ("%lev19_exist%" = 0) BEGIN
SET "level" = 19
INSERT_BYTES ("%fx_off%" + (0x30 * "%start_fx%")) (0x30 * "%new_fx%")
WRITE_EVALUATED_ASCII ("%fx_off%" + (0x30 * "%start_fx%")) "%fx_clone%"
FOR (index2 = 0 ; index2 < new_fx ; index2 = index2 + 1) BEGIN
READ_SHORT ("%fx_off%" + (0x30 * ("%index2%" + "%start_fx%"))) "opcode"
PATCH_IF ("%opcode%" = 54) BEGIN // thac0 bonus
WRITE_LONG ("%fx_off%" + 0x04 + (0x30 * ("%index2%" + "%start_fx%"))) (21 - "%level%")
END ELSE
PATCH_IF ("%opcode%" = 18) BEGIN // hp bonus
WRITE_LONG ("%fx_off%" + 0x04 + (0x30 * ("%index2%" + "%start_fx%"))) "%level%"
END
READ_BYTE ("%fx_off%" + 0x0c + (0x30 * ("%index2%" + "%start_fx%"))) "timing"
READ_LONG ("%fx_off%" + 0x0e + (0x30 * ("%index2%" + "%start_fx%"))) "duration"
PATCH_IF (("%duration%" > 5) AND (("%timing%" = 0) OR ("%timing%" = 3))) BEGIN // for durations longer than a round, limited timing modes
WRITE_LONG ("%fx_off%" + 0x0e + (0x30 * ("%index2%" + "%start_fx%"))) (6 * "%level%")
END
END
INSERT_BYTES ("%fx_off%" ) 0x28
WRITE_EVALUATED_ASCII ("%fx_off%" ) "%abil_clone%"
WRITE_SHORT ("%fx_off%" + 0x10) "%level%"
SET "new_abil" = "%new_abil%" + 1
SET "fx_off" = ("%fx_off%" + 0x28)
SET "start_fx" = ("%start_fx%" + "%new_fx%")
END
PATCH_IF ("%lev20_exist%" = 0) BEGIN
SET "level" = 20
INSERT_BYTES ("%fx_off%" + (0x30 * "%start_fx%")) (0x30 * "%new_fx%")
WRITE_EVALUATED_ASCII ("%fx_off%" + (0x30 * "%start_fx%")) "%fx_clone%"
FOR (index2 = 0 ; index2 < new_fx ; index2 = index2 + 1) BEGIN
READ_SHORT ("%fx_off%" + (0x30 * ("%index2%" + "%start_fx%"))) "opcode"
PATCH_IF ("%opcode%" = 54) BEGIN // thac0 bonus
WRITE_LONG ("%fx_off%" + 0x04 + (0x30 * ("%index2%" + "%start_fx%"))) (21 - "%level%")
END ELSE
PATCH_IF ("%opcode%" = 18) BEGIN // hp bonus
WRITE_LONG ("%fx_off%" + 0x04 + (0x30 * ("%index2%" + "%start_fx%"))) "%level%"
END
READ_BYTE ("%fx_off%" + 0x0c + (0x30 * ("%index2%" + "%start_fx%"))) "timing"
READ_LONG ("%fx_off%" + 0x0e + (0x30 * ("%index2%" + "%start_fx%"))) "duration"
PATCH_IF (("%duration%" > 5) AND (("%timing%" = 0) OR ("%timing%" = 3))) BEGIN // for durations longer than a round, limited timing modes
WRITE_LONG ("%fx_off%" + 0x0e + (0x30 * ("%index2%" + "%start_fx%"))) (6 * "%level%")
END
END
INSERT_BYTES ("%fx_off%" ) 0x28
WRITE_EVALUATED_ASCII ("%fx_off%" ) "%abil_clone%"
WRITE_SHORT ("%fx_off%" + 0x10) "%level%"
SET "new_abil" = "%new_abil%" + 1
SET "fx_off" = ("%fx_off%" + 0x28)
SET "start_fx" = ("%start_fx%" + "%new_fx%")
END
PATCH_IF ("%new_abil%" > 0) BEGIN
SET "abil_num" = ("%abil_num%" + "%new_abil%")
WRITE_SHORT 0x68 "%abil_num%"
WRITE_LONG 0x6a "%fx_off%"
// re-index everything
FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
WRITE_SHORT ("%abil_off%" + 0x20 + (0x28 * "%index%")) "%fx_num%"
READ_SHORT ("%abil_off%" + 0x1e + (0x28 * "%index%")) "abil_fx_num"
SET "fx_num" = "%fx_num%" + "%abil_fx_num%"
END
END
BUT_ONLY_IF_IT_CHANGES

// champion's strength missing level 19,20 headers, wrong durations at levels 17,18
COPY_EXISTING ~sppr507.spl~ ~override~ // champion's strength
READ_LONG 0x64 "abil_off"
READ_SHORT 0x68 "abil_num"
READ_LONG 0x6a "fx_off"
READ_SHORT ("%abil_off%" + 0x10 + (("%abil_num%" - 1) * 0x28)) "min_level" // min level of last ability header
FOR (index = min_level + 1 ; index < 21 ; index = index + 1) BEGIN
READ_ASCII ("%abil_off%" + (("%abil_num%" - 1) * 0x28)) "abil_clone" (0x28) // reads last ability as block
READ_SHORT ("%abil_off%" + 0x1e + (("%abil_num%" - 1) * 0x28)) "abil_fx_num" // reads number of fx from last ability
READ_SHORT ("%abil_off%" + 0x20 + (("%abil_num%" - 1) * 0x28)) "abil_fx_idx" // reads index of last effects from last ability
// create effects for next level based off previous level effects
FOR (index2 = 0 ; index2 < abil_fx_num ; index2 = index2 + 1) BEGIN
READ_ASCII ("%fx_off%" + (("%abil_fx_idx%" + "%index2%") * 0x30)) "clone_fx" (0x30) // reads entire effect
INSERT_BYTES ("%fx_off%" + (("%abil_fx_idx%" + "%abil_fx_num%" + "%index2%") * 0x30)) 0x30
WRITE_ASCIIE ("%fx_off%" + (("%abil_fx_idx%" + "%abil_fx_num%" + "%index2%") * 0x30)) "%clone_fx%" // clones effect
END
// effects created, now add new ability
INSERT_BYTES ("%abil_off%" + ("%abil_num%" * 0x28)) 0x28
WRITE_EVALUATED_ASCII ("%abil_off%" + ("%abil_num%" * 0x28)) "%abil_clone%" // clones last ability
WRITE_SHORT ("%abil_off%" + 0x10 + ("%abil_num%" * 0x28)) "%index%" // min level
WRITE_SHORT ("%abil_off%" + 0x20 + ("%abil_num%" * 0x28)) ("%abil_fx_num%" + "%abil_fx_idx%") // corrects fx index
SET "fx_off" = ("%fx_off%" + 0x28)
SET "abil_num" = "%abil_num%" + 1
END
WRITE_SHORT 0x68 "%abil_num%"
WRITE_LONG 0x6a "%fx_off%"
// fixes durations for new abilities and levels 17,18
FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
READ_SHORT ("%abil_off%" + 0x10 + ("%index%" * 0x28)) "min_lev"
READ_SHORT ("%abil_off%" + 0x1e + ("%index%" * 0x28)) "abil_fx_num"
READ_SHORT ("%abil_off%" + 0x20 + ("%index%" * 0x28)) "abil_fx_idx"
PATCH_IF ("%min_lev%" = 1) BEGIN
SET "min_lev" = 9
END
FOR (index2 = 0 ; index2 < abil_fx_num ; index2 = index2 + 1) BEGIN
READ_LONG ("%fx_off%" + 0x0e + (("%abil_fx_idx%" + "%index2%") * 0x30)) "duration"
PATCH_IF ("%duration%" > 5) BEGIN // if more than one round
WRITE_LONG ("%fx_off%" + 0x0e + (("%abil_fx_idx%" + "%index2%") * 0x30)) ("%min_lev%" * 18) // 3 rounds/level
END
END
END
BUT_ONLY_IF_IT_CHANGES
Post edited by Bhryaen on
AndreaColombo

Comments

  • CamDawgCamDawg Member, Developer Posts: 3,438
    Actually, I'll just make this my thread of divine magic fixes that won't affect BGEE.

    Righteous magic has incorrect durations; one effect at level 10 and one at level 20.
    // two durations are incorrect for righteous magic; stacking handled below
    COPY_EXISTING ~sppr513.spl~ ~override~
    READ_LONG 0x64 "abil_off"
    READ_SHORT 0x68 "abil_num"
    READ_LONG 0x6a "fx_off"
    WHILE ("%abil_num%" > 0) BEGIN
    SET "abil_num" = ("%abil_num%" - 1)
    READ_SHORT ("%abil_off%" + 0x10 + (0x28 * "%abil_num%")) "min_lev"
    PATCH_IF ("%min_lev%" = 10) BEGIN // if melee
    READ_SHORT ("%abil_off%" + 0x1e + (0x28 * "%abil_num%")) "abil_fx_num"
    READ_SHORT ("%abil_off%" + 0x20 + (0x28 * "%abil_num%")) "abil_fx_idx"
    WHILE ("%abil_fx_num%" > 0) BEGIN
    SET "abil_fx_num" = ("%abil_fx_num%" - 1)
    READ_SHORT ("%fx_off%" + (0x30 * ("%abil_fx_idx%" + "%abil_fx_num%"))) "opcode"
    PATCH_IF ("%opcode%" = 250) BEGIN // max damage per hit
    WRITE_LONG ("%fx_off%" + 0x0e + (0x30 * ("%abil_fx_idx%" + "%abil_fx_num%"))) 60 // duration
    END
    END
    END ELSE
    PATCH_IF ("%min_lev%" = 20) BEGIN // if melee
    READ_SHORT ("%abil_off%" + 0x1e + (0x28 * "%abil_num%")) "abil_fx_num"
    READ_SHORT ("%abil_off%" + 0x20 + (0x28 * "%abil_num%")) "abil_fx_idx"
    WHILE ("%abil_fx_num%" > 0) BEGIN
    SET "abil_fx_num" = ("%abil_fx_num%" - 1)
    READ_SHORT ("%fx_off%" + (0x30 * ("%abil_fx_idx%" + "%abil_fx_num%"))) "opcode"
    PATCH_IF ("%opcode%" = 142) BEGIN // display portrait icon
    WRITE_LONG ("%fx_off%" + 0x0e + (0x30 * ("%abil_fx_idx%" + "%abil_fx_num%"))) 120 // duration
    END
    END
    END
    END
    BUT_ONLY_IF_IT_CHANGES
    AndreaColombo
  • CamDawgCamDawg Member, Developer Posts: 3,438
    False dawn actually works by casting a second spell on the caster. However, the caster's own magical protections could block it.
    // power issue with false dawn
    COPY_EXISTING ~sppr609.spl~ ~override~
    READ_LONG 0x64 "abil_off"
    READ_SHORT 0x68 "abil_num"
    READ_LONG 0x6a "fx_off"
    FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN // fix existing effects
    READ_SHORT ("%abil_off%" + 0x1e + (0x28 * "%index%")) "abil_fx_num"
    READ_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 * ("%abil_fx_idx%" + "%index2%"))) "opcode"
    PATCH_IF ("%opcode%" = 146) BEGIN
    WRITE_BYTE ("%fx_off%" + 0x03 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) 0 // power
    END
    END
    END
    BUT_ONLY_IF_IT_CHANGES
    AndreaColombo
  • CamDawgCamDawg Member, Developer Posts: 3,438
    Gate's (divine) range is listed as 20 yards and gate (arcane) as visual range. The actual spell uses 15 feet.

    The visual range for the BG2 engine is 30 feet, and spells are not allowed to be cast beyond that anyway, so both are fixed to have a range of 30 feet.
    // gate should be visual sight range
    COPY_EXISTING ~sppr703.spl~ ~override~
    ~spwi905.spl~ ~override~
    READ_LONG 0x64 "abil_off"
    READ_SHORT 0x68 "abil_num"
    READ_LONG 0x6a "fx_off"
    FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
    WRITE_SHORT ("%abil_off%" + 0x0e + (0x28 * "%index%")) 30
    END
    BUT_ONLY_IF_IT_CHANGES
    AndreaColombo
  • CamDawgCamDawg Member, Developer Posts: 3,438
    Casting speed fixes for regeneration and improved chaos shield (arcane):
    // casting speed fixes
    COPY_EXISTING ~sppr711.spl~ ~override~ // regeneration
    ~spwi723.spl~ ~override~ // improved chaos shield
    READ_LONG 0x64 "abil_off" ELSE 0
    READ_SHORT 0x68 "abil_num" ELSE 0
    FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
    WRITE_SHORT ("%abil_off%" + 0x12 + (0x28 * "%index%")) 7
    END
    BUT_ONLY_IF_IT_CHANGES
    AndreaColombo
  • CamDawgCamDawg Member, Developer Posts: 3,438
    Energy blades (arcane and divine) have the wrong power levels on their effects:
      COPY_EXISTING ~sppr721.spl~ ~override~
    ~spwi920.spl~ ~override~
    READ_LONG 0x64 "abil_off"
    READ_SHORT 0x68 "abil_num"
    READ_LONG 0x6a "fx_off"
    READ_LONG 0x34 "level"
    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"
    FOR (index2 = 0 ; index2 < abil_fx_num ; index2 = index2 + 1) BEGIN
    WRITE_BYTE ("%fx_off%" + 0x03 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) "%level%" // power is wrong in effects
    END
    END
    BUT_ONLY_IF_IT_CHANGES
    AndreaColombo
  • CamDawgCamDawg Member, Developer Posts: 3,438
    Conjure earth elemental also summons a hostile (red-circled) elemental; the summoned elemental should match the allegiance of the summoner:
    // greater earth elem (cleric) is hostile, should match summoner's allegiance
    COPY_EXISTING ~SPEART3P.EFF~ ~override~
    WRITE_LONG 0x20 0x0 // set to Match target
    BUT_ONLY_IF_IT_CHANGES
    AndreaColombo
  • SethDavisSethDavis Member Posts: 1,812
    edited July 2012
    checking this one now

    [EDIT] @CamDawg 's fixes have been applied.
  • Avenger_teambgAvenger_teambg Member, Developer Posts: 5,862
    This cannot be confirmed ingame, but also irrelevant yet.
    I can confirm: speart3p.eff will summon a caster-friendly elemental
    improved chaos shield and regeneration has their casting time set to 7
    false dawn now applies the spell on self without resistance checks
    righteous magic level 10 checked.

    note: "The visual range for the BG2 engine is 30 feet, and spells are not allowed to be cast beyond that anyway, so both are fixed to have a range of 30 feet." I thought, the no LOS needed flag overrides this restriction. Anyway, i agree that gating into fog of far or over doors would be fishy.
  • TanthalasTanthalas Member Posts: 6,738
    @Avenger_teambg

    If you position your other party members (or use Wizard's eye) in a way that makes your target visible you can actually cast spells like Spook from outside your normal field of vision.
  • Avenger_teambgAvenger_teambg Member, Developer Posts: 5,862
    Tanthalas said:

    @Avenger_teambg

    If you position your other party members (or use Wizard's eye) in a way that makes your target visible you can actually cast spells like Spook from outside your normal field of vision.

    So, Spook's range is incorrect? The spell description explicitly says: Range: 30 ft.
    @CamDawg, i though you fixed all ranges ;)
  • CamDawgCamDawg Member, Developer Posts: 3,438

    note: "The visual range for the BG2 engine is 30 feet, and spells are not allowed to be cast beyond that anyway, so both are fixed to have a range of 30 feet." I thought, the no LOS needed flag overrides this restriction. Anyway, i agree that gating into fog of far or over doors would be fishy.

    I think LOS allows you to go through doors and whatnot, but I didn't think it went beyond visual range. It's been a loooong time since I tested, though.
    Tanthalas said:

    If you position your other party members (or use Wizard's eye) in a way that makes your target visible you can actually cast spells like Spook from outside your normal field of vision.

    Has this ever been confirmed? I know the spell claims this but I've never actually casted anything beyond 30'.





  • TanthalasTanthalas Member Posts: 6,738
    edited August 2012
    @CamDawg
    The forums aren't letting me post pics (I'll provide them tomorrow).

    But if I leave a Wizard's Eye (another party member works too) near my target, I can cast Spook from double the limit of the normal visual range.

    On the other hand, Fireball has a range of "Visual range of the caster" and it can't be cast from farther using Wizard's Eye.

    EDIT: I haven't done extensive testing, but for now only Spook allowed casting from outside the normal visual range.
  • TanthalasTanthalas Member Posts: 6,738
    edited August 2012
    @CamDawg

    First screenshot is me casting Spook at the limit of my visual range:

    [SNIP]

    Second screenshot is me using Wizard's Eye to see my target from further away and casting Spook:

    [SNIP]
    Post edited by Bhryaen on
  • Avenger_teambgAvenger_teambg Member, Developer Posts: 5,862
    edited August 2012
    Spook has the no LOS needed flag set. It is apparently intentional in BG2 that you can cast spook via wizard eye. So @CamDawg, i think i win a cookie :D
  • CamDawgCamDawg Member, Developer Posts: 3,438
    A cookie is on its way, along with a whole more range fixes. :/
    AndreaColombo
Sign In or Register to comment.