[(BGEE, BG2) bug] High-level divine spell fixes
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:
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
1
Comments
Righteous magic has incorrect durations; one effect at level 10 and one at level 20.
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.
[EDIT] @CamDawg 's fixes have been applied.
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.
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.
@CamDawg, i though you fixed all ranges
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.
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]