[(BGEE, BG2) bug] Animate dead (divine)
From the Fixpack:
The divine version of Animate Dead had a number of minor issues. It used the mage spell icon at most levels; it lacked headers for being cast at levels 6-9, meaning when it was cast at those levels it behaved as if the caster was level 5; when cast at level 5 it had a 25% chance of three summons instead of two; when cast at level 11 there was a 10% chance of no summons at all.
The code's old and ugly, but it works:
The divine version of Animate Dead had a number of minor issues. It used the mage spell icon at most levels; it lacked headers for being cast at levels 6-9, meaning when it was cast at those levels it behaved as if the caster was level 5; when cast at level 5 it had a 25% chance of three summons instead of two; when cast at level 11 there was a 10% chance of no summons at all.
The code's old and ugly, but it works:
// animate dead has several minor errors in effect headers and is missing headrs for levels 6-9
COPY_EXISTING ~sppr301.spl~ ~override~
READ_LONG 0x64 "abil_off"
READ_SHORT 0x68 "abil_num"
READ_LONG 0x6a "fx_off"
SET "lev6_exist" = 0
SET "lev7_exist" = 0
SET "lev8_exist" = 0
SET "lev9_exist" = 0
SET "new_abil" = 0
FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
WRITE_ASCII ("%abil_off%" + 0x04 + (0x28 * "%index%")) ~sppr301b~ // consistent icon
READ_SHORT ("%abil_off%" + 0x10 + (0x28 * "%index%")) "min_lev"
PATCH_IF ("%min_lev%" = 1) BEGIN // if first header
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%" = 177) BEGIN // last eff opcode
READ_BYTE ("%fx_off%" + 0x13 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) "prob_lo"
PATCH_IF ("%prob_lo%" = 0) BEGIN
WRITE_BYTE ("%fx_off%" + 0x03 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) 3 // power
WRITE_BYTE ("%fx_off%" + 0x12 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) 75 // probability
END ELSE BEGIN
WRITE_BYTE ("%fx_off%" + 0x13 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) 76 // probability
END
END
END
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%")
SET "insert" = ("%abil_off%" + (0x28 * ("%index%" + 1)))
END ELSE
PATCH_IF ("%min_lev%" = 6) BEGIN
SET "lev6_exist" = 1
END ELSE
PATCH_IF ("%min_lev%" = 7) BEGIN
SET "lev7_exist" = 1
END ELSE
PATCH_IF ("%min_lev%" = 8) BEGIN
SET "lev8_exist" = 1
END ELSE
PATCH_IF ("%min_lev%" = 9) BEGIN
SET "lev9_exist" = 1
END ELSE
PATCH_IF ("%min_lev%" = 11) BEGIN // level 11 header
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%" = 177) BEGIN // last eff opcode
READ_BYTE ("%fx_off%" + 0x13 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) "prob_lo"
PATCH_IF ("%prob_lo%" = 0) BEGIN
WRITE_BYTE ("%fx_off%" + 0x12 + (0x30 * ("%abil_fx_idx%" + "%index2%"))) 45 // probability
END
END
END
END
END
PATCH_IF ("%lev6_exist%" = 0) BEGIN
SET "level" = 6
INSERT_BYTES (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) (0x30 * "%new_fx%")
WRITE_EVALUATED_ASCII (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) "%fx_clone%"
FOR (index2 = 0 ; index2 < new_fx ; index2 = index2 + 1) BEGIN
READ_SHORT (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "opcode"
PATCH_IF ("%opcode%" = 177) BEGIN // last eff opcode
READ_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "prob_hi"
PATCH_IF ("%prob_hi%" != 100) BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (100 - ("%level%" * 5)) // probability
END ELSE BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x13 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (101 - ("%level%" * 5)) // probability
END
END
END
INSERT_BYTES ("%insert%" + (0x28 * "%new_abil%")) 0x28
WRITE_EVALUATED_ASCII ("%insert%" + (0x28 * "%new_abil%")) "%abil_clone%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x10) "%level%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x1e) "%new_fx%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x20) ("%start_fx%" * ("%new_abil%" + 1))
SET "new_abil" = "%new_abil%" + 1
END
PATCH_IF ("%lev7_exist%" = 0) BEGIN
SET "level" = 7
INSERT_BYTES (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) (0x30 * "%new_fx%")
WRITE_EVALUATED_ASCII (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) "%fx_clone%"
FOR (index2 = 0 ; index2 < new_fx ; index2 = index2 + 1) BEGIN
READ_SHORT (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "opcode"
PATCH_IF ("%opcode%" = 177) BEGIN // last eff opcode
READ_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "prob_hi"
PATCH_IF ("%prob_hi%" != 100) BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (100 - ("%level%" * 5)) // probability
END ELSE BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x13 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (101 - ("%level%" * 5)) // probability
END
END
END
INSERT_BYTES ("%insert%" + (0x28 * "%new_abil%")) 0x28
WRITE_EVALUATED_ASCII ("%insert%" + (0x28 * "%new_abil%")) "%abil_clone%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x10) "%level%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x1e) "%new_fx%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x20) ("%start_fx%" * ("%new_abil%" + 1))
SET "new_abil" = "%new_abil%" + 1
END
PATCH_IF ("%lev8_exist%" = 0) BEGIN
SET "level" = 8
INSERT_BYTES (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) (0x30 * "%new_fx%")
WRITE_EVALUATED_ASCII (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) "%fx_clone%"
FOR (index2 = 0 ; index2 < new_fx ; index2 = index2 + 1) BEGIN
READ_SHORT (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "opcode"
PATCH_IF ("%opcode%" = 177) BEGIN // last eff opcode
READ_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "prob_hi"
PATCH_IF ("%prob_hi%" != 100) BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (100 - ("%level%" * 5)) // probability
END ELSE BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x13 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (101 - ("%level%" * 5)) // probability
END
END
END
INSERT_BYTES ("%insert%" + (0x28 * "%new_abil%")) 0x28
WRITE_EVALUATED_ASCII ("%insert%" + (0x28 * "%new_abil%")) "%abil_clone%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x10) "%level%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x1e) "%new_fx%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x20) ("%start_fx%" * ("%new_abil%" + 1))
SET "new_abil" = "%new_abil%" + 1
END
PATCH_IF ("%lev9_exist%" = 0) BEGIN
SET "level" = 9
INSERT_BYTES (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) (0x30 * "%new_fx%")
WRITE_EVALUATED_ASCII (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%start_fx%" * ("%new_abil%" + 1)))) "%fx_clone%"
FOR (index2 = 0 ; index2 < new_fx ; index2 = index2 + 1) BEGIN
READ_SHORT (("%fx_off%" + (0x28 * "%new_abil%")) + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "opcode"
PATCH_IF ("%opcode%" = 177) BEGIN // last eff opcode
READ_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) "prob_hi"
PATCH_IF ("%prob_hi%" != 100) BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x12 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (100 - ("%level%" * 5)) // probability
END ELSE BEGIN
WRITE_BYTE (("%fx_off%" + (0x28 * "%new_abil%")) + 0x13 + (0x30 * ("%index2%" + "%start_fx%" + ("%new_abil%" * "%new_fx%")))) (101 - ("%level%" * 5)) // probability
END
END
END
INSERT_BYTES ("%insert%" + (0x28 * "%new_abil%")) 0x28
WRITE_EVALUATED_ASCII ("%insert%" + (0x28 * "%new_abil%")) "%abil_clone%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x10) "%level%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x1e) "%new_fx%"
WRITE_SHORT (("%insert%" + (0x28 * "%new_abil%")) + 0x20) ("%start_fx%" * ("%new_abil%" + 1))
SET "new_abil" = "%new_abil%" + 1
END
PATCH_IF ("%new_abil%" > 0) BEGIN
SET "abil_num" = ("%abil_num%" + "%new_abil%")
WRITE_SHORT 0x68 "abil_num"
WRITE_LONG 0x6a ("%fx_off%" + (0x28 * "%new_abil%"))
FOR (index = 0 ; index < abil_num ; index = index + 1) BEGIN
READ_SHORT ("%abil_off%" + 0x10 + (0x28 * "%index%")) "min_lev"
PATCH_IF ("%min_lev%" > 9) BEGIN // if after new inserted effects
READ_SHORT ("%abil_off%" + 0x20 + (0x28 * "%index%")) "abil_fx_idx"
WRITE_SHORT ("%abil_off%" + 0x20 + (0x28 * "%index%")) ("%abil_fx_idx%" + ("%new_abil%" * "%new_fx%"))
END
END
END
BUT_ONLY_IF_IT_CHANGES
Post edited by Bhryaen on
1
Comments
When I scroll through it fast enough there's this pleasant wavy effect.
I learned to code on Perl which is self-obfuscating. It taught me to use blatantly long variable names and comment, comment, comment.
Icons - check
Probabilities - check
Nitpick - The 3 effects could be replaced by 2, just like i suggested in the other summon spell.
- From level 5 to 9 my Cleric displayed the correct icon for the spell.
- In 50 casts of the spell, my level 5 Cleric never summoned 3 skeletons, max was always two.
- Probability of raising more than one skeleton was, for the most part, increased from levels 6 to 9:
Level 5 -> 10/52 -> 19%
Level 6 -> 15/50 -> 30%
Level 7 -> 25/50 -> 50%
Level 8 -> 23/54 -> 43%
Level 9 -> 23/54 -> 43%
I think the difference can be attributed to luck, 50 casts aren't enough for perfect results.
I can't check the level 11 problem in the game.
RESULTS:
1.
This one I don't know about. It seems like the icon that both the divine and arcane Animate Dead icon use are identical, no? I'm probably just not understanding the issue properly.
2. & 3. So my usual tendency to roll below the expected is proven unequivocally now: the game cheats me! And now I've caught it in the act! Ha!
Anyway clearly no chance of getting 3 boneheads at 5th lvl now, and a clear progression seen from 6-9.
4.
Since we can't level up past 9, this would otherwise be a moot point, but due to research on the ToBEex 13 thread I used @Avenger_teambg's +5 Caster Level Ring on a Level 6 Cleric to get these results: With 50 tries at a 10% chance of summoning nothing, it would have been a dud around 5 times, but worked ok.
CONCLUSION:
Confirmed Fixed... so long as the icon is ok.
I'll have to check BG2 too.
Yeah, I thought the difference was bigger, but it looks like its only that slight difference when you have the spell in your quickslot. So I think this one is confirmed fixed.