Jump to content

Melf's Meteors - 1 attack?


Kulyok

Recommended Posts

As per the title: I've installed BG2 Fixpack V1, and my sorceress can only cast Melf's Minute Meteors once per round. Got the savegame ready, too. No Beta fixes installed.

 

 

When used with Melf's Minute Meteors, a blade's Offensive Spin could cause the attacks per round to drop to 0.5 due to an overflow issue in the engine. As a workaround, blades can no longer cast Offensive Spin when wielding Minute Meteors.

 

Might it be this one?

 

 

Btw, I see that Skull Traps can now be cast right across the screen, just like Fireballs. Is it intentional?

Link to comment
As per the title: I've installed BG2 Fixpack V1, and my sorceress can only cast Melf's Minute Meteors once per round. Got the savegame ready, too. No Beta fixes installed.

Will check it out. It should be setting them to 5 and not allowing anything else to modify that. :)

 

Btw, I see that Skull Traps can now be cast right across the screen, just like Fireballs. Is it intentional?

As part of the Spell Range Fixes, yes--Skull Trap's listed range is 20 yards. By way of comparison, visual range is ~30 feet, so it's now effectively the same range as Fireball (which is visual range).

Link to comment

Yes, this is strange indeed. (Your character is a sorcerer, right? Not a mage?)

 

Besides Fixpack, I have Unfinished Business, Quest Pack, last Tweaks(but they never provoked such behavior before), DBG, Banter Pack, Xan and Kivan installed. I guess it's neither of these...

Link to comment

Based on John's report here, it looks like we've discovered a new method of engine flakiness. I've recoded this fix slightly to only block the ApR modifications of Boon of Lathander and Offensive Spin with a shell spell hack:

 

// Melf's Minute Meteors causing an attack per round overflow bug with certain spells; see spcl521.spl and spcl741
COPY_EXISTING ~melfmet.itm~  ~override~ // Melf's Minute Meteor
 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"
READ_SHORT	0x70  "glb_fx_num"
FOR ("i"="%abil_num%"; "%i%">0; "i"-=1) BEGIN
  READ_SHORT  ("%abil_off%"+(0x38*"%i%")+0x20)		"abil_fx_idx"
  WRITE_SHORT ("%abil_off%"+(0x38*"%i%")+0x20)		("%abil_fx_idx%"+0x02)
END // FOR i, repairing extended header effect indices
PATCH_IF	  ("%abil_off%">"%fx_off%") BEGIN
  WRITE_LONG  0x64  ("%abil_off%"+0x60)
  SET		"abil_off"=("%abil_off%"+0x60)
END // PATCH_IF offset re-ordering
WRITE_SHORT   0x70 ("%glb_fx_num%"+0x02)
INSERT_BYTES  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x00) 0x30	   // new while equipped effect
  WRITE_SHORT ("%fx_off%"+(0x30*"%glb_fx_num%")+0x00) 206		// protection from spell
  WRITE_BYTE  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x02)   1		// target: self
  WRITE_LONG  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x04) 0xffffffff // no string
  WRITE_BYTE  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x0c) 2		  // timing mode: while equipped
  WRITE_BYTE  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x12) 100		// min probability 100%
  WRITE_ASCII ("%fx_off%"+(0x30*"%glb_fx_num%")+0x14) ~spcl521a~ // spell
INSERT_BYTES  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x00) 0x30	   // new while equipped effect
  WRITE_SHORT ("%fx_off%"+(0x30*"%glb_fx_num%")+0x00) 206		// protection from spell
  WRITE_BYTE  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x02)   1		// target: self
  WRITE_LONG  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x04) 0xffffffff // no string
  WRITE_BYTE  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x0c) 2		  // timing mode: while equipped
  WRITE_BYTE  ("%fx_off%"+(0x30*"%glb_fx_num%")+0x12) 100		// min probability 100%
  WRITE_ASCII ("%fx_off%"+(0x30*"%glb_fx_num%")+0x14) ~spcl741a~ // spell
 END // PATCH_IF filesize sanity check
 BUT_ONLY_IF_IT_CHANGES // COPY_EXISTING ~melfmet.itm~ closed

// use shell spells for ApR modification to avoid issues with MMM; see melfmet.itm
COPY_EXISTING ~spcl521.spl~ ~override/spcl521a.spl~ // offensive spin
		  ~spcl741.spl~ ~override/spcl741a.spl~ // boon of lathander
 WRITE_LONG NAME1 0xffffffff
 WRITE_LONG NAME2 0xffffffff
 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%"
WRITE_SHORT ("%abil_off%" + 0x26 + (0x28 * "%index%")) 1 // removes projectile
FOR (index2 = 0; index2 < abil_fx_num; index2 = index2 + 1) BEGIN
  READ_SHORT ("%fx_off%" +		(0x30 * "%index2%")) "opcode"
  PATCH_IF("%opcode%" != 1) BEGIN
	DELETE_BYTES ("%fx_off%" +		(0x30 * "%index2%")) 0x30 // delete effect
	SET "index2" = ("%index2%" - 1)
	SET "abil_fx_num" = ("%abil_fx_num%" - 1)
  END
END
WRITE_SHORT  ("%abil_off%" + 0x1e + (0x28 * "%index%")) "%abil_fx_num%"
 END
 BUT_ONLY_IF_IT_CHANGES

// use shell spells for ApR modification to avoid issues with MMM; see melfmet.itm
COPY_EXISTING ~spcl521.spl~ ~override~ // offensive spin
		  ~spcl741.spl~ ~override~ // boon of lathander
 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
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 * "%index2%")) "opcode"
  PATCH_IF("%opcode%" = 1) BEGIN
	WRITE_SHORT  ("%fx_off%" +		(0x30 * "%index2%")) 146				// cast spell
	WRITE_LONG   ("%fx_off%" + 0x08 + (0x30 * "%index2%")) 1				  // cast instantly
	WRITE_ASCIIE ("%fx_off%" + 0x14 + (0x30 * "%index2%")) ~%SOURCE_RES%a~ #8 //resref
  END
END
 END
 BUT_ONLY_IF_IT_CHANGES

 

Not nearly as pretty, but should hopefully feature less wonk.

Link to comment

There's also the casting sequence where you do Offensive Spin first and then cast Melf's, which can also overflow ;)

// Melf's Minute Meteors causing an attack per round overflow bug with certain spells
COPY_EXISTING ~melfmet.itm~  ~override~
 PATCH_IF (%SOURCE_SIZE% > 0x71) THEN BEGIN
   READ_LONG     0x64  "ho"
   READ_SHORT    0x68  "hc"
   READ_LONG     0x6a  "eo"
   READ_SHORT    0x70  "gc"
   FOR ("i" = 0x00; "i" < ("hc" * 0x38); "i" += 0x38) BEGIN
     READ_SHORT  ("ho" + "i" + 0x20) "ei"
     WRITE_SHORT ("ho" + "i" + 0x20) ("ei" + 0x02)
   END
   INSERT_BYTES  ("eo" + ("gc" * 0x30) + 0x00) (0x30 * 0x02)
     FOR ("j" = ("gc" * 0x30); "j" < (("gc" + 0x02) * 0x30); "j" += 0x30) BEGIN
       WRITE_SHORT ("eo" + "j" + 0x00) 0xce // opcode: protection from spell
       WRITE_BYTE  ("eo" + "j" + 0x02) 0x01 // target: self
       WRITE_LONG  ("eo" + "j" + 0x04) `0x0 // string displayed
       WRITE_BYTE  ("eo" + "j" + 0x0c) 0x02 // timing mode: while equipped
       WRITE_BYTE  ("eo" + "j" + 0x12) 0x64 // minimum probability 100%
     END
     WRITE_ASCII ("eo" + ("gc" * 0x30) + 0x14) ~spcl521d~ // resource reference
     WRITE_ASCII ("eo" + ("gc" * 0x30) + 0x44) ~spcl741d~ // resource reference
   WRITE_SHORT   0x70  ("gc" + 0x02)
 END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING ~spcl521.spl~  ~override/spcl521d.spl~
             ~spcl741.spl~  ~override/spcl741d.spl~
 PATCH_IF (%SOURCE_SIZE% > 0x71) THEN BEGIN
   WRITE_ASCIIT  0x10   ~~  // completion sound
   WRITE_SHORT   0x22  0x00 // casting graphics
   READ_LONG     0x64  "ho"
   READ_SHORT    0x68  "hc"
   READ_LONG     0x6a  "eo"
   READ_SHORT    0x70  "gc"
   FOR ("i" = "hc"; "i" > 0x00; "i" -= 0x01) BEGIN
     WRITE_LONG   ("ho" + (("i" - 0x01) * 0x28) + 0x12) 0x00 // casting time
     READ_SHORT   ("ho" + (("i" - 0x01) * 0x28) + 0x1e) "ec"
     WRITE_SHORT  ("ho" + (("i" - 0x01) * 0x28) + 0x1e) 0x02 //number of effects
     WRITE_SHORT  ("ho" + (("i" - 0x01) * 0x28) + 0x20) ("gc" + (("i" - 0x01) * 0x02))
     DELETE_BYTES ("eo" + ("ei" * 0x30) + 0x00) (("ec" - 0x02) * 0x30)
     WRITE_SHORT  ("eo" + ("ei" * 0x30) + 0x00) 0x01 // opcode: apr mod
     WRITE_BYTE   ("eo" + ("ei" * 0x30) + 0x02) 0x01 // target: self
     WRITE_LONG   ("eo" + ("ei" * 0x30) + 0x04) 0x01 // modifier
     WRITE_LONG   ("eo" + ("ei" * 0x30) + 0x08) 0x00 // type: cumulative
     WRITE_ASCIIT ("eo" + ("ei" * 0x30) + 0x14) ~~   // nulling resref
     WRITE_SHORT  ("eo" + ("ei" * 0x30) + 0x30) 0xce // opcode: protection from spell
     WRITE_BYTE   ("eo" + ("ei" * 0x30) + 0x32) 0x01 // target: self
     WRITE_LONG   ("eo" + ("ei" * 0x30) + 0x34) `0x0 // string displayed
     WRITE_ASCIIT ("eo" + ("ei" * 0x30) + 0x44) ~spwi325~ // melf's meteors
   END
 END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING ~spcl521.spl~  ~override/spcl521.spl~
             ~spcl741.spl~  ~override/spcl741.spl~
 PATCH_IF (%SOURCE_SIZE% > 0x71) THEN BEGIN
   READ_LONG     0x64  "ho"
   READ_SHORT    0x68  "hc"
   READ_LONG     0x6a  "eo"
   READ_SHORT    0x70  "gc"
   FOR ("i" = 0x00; "i" < ("hc" * 0x28); "i" += 0x28) BEGIN
     READ_SHORT         ("ho" + "i" + 0x1e) "ec"
     READ_SHORT         ("ho" + "i" + 0x20) "ei"
     FOR  ("j" = ("ei" * 0x30); "j" < (("ei" + "ec") * 0x30); "j" += 0x30) BEGIN
       READ_SHORT       ("eo" + "j" + 0x00) "op"
       PATCH_IF (("op" = 0x10) OR ("op" = 0x01)) THEN BEGIN
         WRITE_SHORT    ("eo" + "j" + 0x00) 0x92 // opcode: cast spell
         WRITE_LONG     ("eo" + "j" + 0x04) 0x00 // cast at level
         WRITE_LONG     ("eo" + "j" + 0x08) 0x00 // cast normally
         WRITE_BYTE     ("eo" + "j" + 0x0c) 0x01 // timing mode: instant/permanent
         WRITE_LONG     ("eo" + "j" + 0x0e) 0x00 // duration
         PATCH_IF          (NOT "%SOURCE_RES%" STRING_COMPARE_CASE "spcl521") THEN BEGIN
           WRITE_ASCII  ("eo" + "j" + 0x14) ~spcl521d~ // resref
         END ELSE PATCH_IF (NOT "%SOURCE_RES%" STRING_COMPARE_CASE "spcl741") THEN BEGIN
           WRITE_ASCII  ("eo" + "j" + 0x14) ~spcl741d~ // resref
         END
       END
     END
   END
 END
BUT_ONLY_IF_IT_CHANGES

I'd be very interested to see if Whirlwind Attack/Greater Whirlwind attack also bug out in these games.

// Melf's Minute Meteors causing an attack per round overflow bug with certain spells
COPY_EXISTING ~melfmet.itm~ ~override~
 PATCH_IF (%SOURCE_SIZE% > 0x71) THEN BEGIN
READ_LONG  0x64 "ho"
READ_SHORT 0x68 "hc"
READ_LONG  0x6a "eo"
READ_SHORT 0x70 "gc"
FOR ("i" = 0x00; "i" < ("hc" * 0x38); "i" += 0x38) BEGIN
  READ_SHORT  ("ho" + "i" + 0x20) "ei"
  WRITE_SHORT ("ho" + "i" + 0x20) ("ei" + 0x02)
END
INSERT_BYTES ("eo" + ("gc" * 0x30) + 0x00) (0x30 * 0x02)
FOR ("j" = ("gc" * 0x30); "j" < (("gc" + 0x02) * 0x30); "j" += 0x30) BEGIN
  WRITE_SHORT ("eo" + "j" + 0x00) 0xce // opcode: protection from spell
  WRITE_BYTE  ("eo" + "j" + 0x02) 0x01 // target: self
  WRITE_LONG  ("eo" + "j" + 0x04) `0x0 // string displayed
  WRITE_BYTE  ("eo" + "j" + 0x0c) 0x02 // timing mode: while equipped
  WRITE_BYTE  ("eo" + "j" + 0x12) 0x64 // minimum probability 100%
END
WRITE_ASCII ("eo" + ("gc" * 0x30) + 0x14) ~spcl521d~ // resource reference
WRITE_ASCII ("eo" + ("gc" * 0x30) + 0x44) ~spcl741d~ // resource reference
WRITE_SHORT 0x70 ("gc" + 0x02)
 END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING ~spcl521.spl~ ~override/spcl521d.spl~
		  ~spcl741.spl~ ~override/spcl741d.spl~
 PATCH_IF (%SOURCE_SIZE% > 0x71) THEN BEGIN
WRITE_ASCIIT 0x10 ~~ // completion sound
WRITE_SHORT 0x22 0x00 // casting graphics
READ_LONG  0x64 "ho"
READ_SHORT 0x68 "hc"
READ_LONG  0x6a "eo"
READ_SHORT 0x70 "gc"
FOR ("i" = "hc"; "i" > 0x00; "i" -= 0x01) BEGIN
  WRITE_LONG   ("ho" + (("i" - 0x01) * 0x28) + 0x12) 0x00 // casting time
  READ_SHORT   ("ho" + (("i" - 0x01) * 0x28) + 0x1e) "ec"
  WRITE_SHORT  ("ho" + (("i" - 0x01) * 0x28) + 0x1e) 0x02 //number of effects
  READ_SHORT   ("ho" + (("i" - 0x01) * 0x28) + 0x20) "ei"
  WRITE_SHORT  ("ho" + (("i" - 0x01) * 0x28) + 0x20) ("gc" + (("i" - 0x01) * 0x02))
  DELETE_BYTES ("eo" + ("ei" * 0x30) + 0x00) (("ec" - 0x02) * 0x30)
  WRITE_SHORT  ("eo" + ("ei" * 0x30) + 0x00) 0x01 // opcode: apr mod
  WRITE_BYTE   ("eo" + ("ei" * 0x30) + 0x02) 0x01 // target: self
  WRITE_LONG   ("eo" + ("ei" * 0x30) + 0x04) 0x01 // modifier
  WRITE_LONG   ("eo" + ("ei" * 0x30) + 0x08) 0x00 // type: cumulative
  WRITE_ASCIIT ("eo" + ("ei" * 0x30) + 0x14) ~~ // nulling resref
  WRITE_SHORT  ("eo" + ("ei" * 0x30) + 0x30) 0xce // opcode: protection from spell
  WRITE_BYTE   ("eo" + ("ei" * 0x30) + 0x32) 0x01 // target: self
  WRITE_LONG   ("eo" + ("ei" * 0x30) + 0x34) `0x0 // string displayed
  WRITE_ASCIIT ("eo" + ("ei" * 0x30) + 0x44) ~spwi325~ // melf's meteors
END
 END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING ~spcl521.spl~ ~override/spcl521.spl~
		  ~spcl741.spl~ ~override/spcl741.spl~
 PATCH_IF (%SOURCE_SIZE% > 0x71) THEN BEGIN
READ_LONG  0x64 "ho"
READ_SHORT 0x68 "hc"
READ_LONG  0x6a "eo"
READ_SHORT 0x70 "gc"
FOR ("i" = 0x00; "i" < ("hc" * 0x28); "i" += 0x28) BEGIN
  READ_SHORT ("ho" + "i" + 0x1e) "ec"
  READ_SHORT ("ho" + "i" + 0x20) "ei"
  FOR ("j" = ("ei" * 0x30); "j" < (("ei" + "ec") * 0x30); "j" += 0x30) BEGIN
	READ_SHORT ("eo" + "j" + 0x00) "op"
	PATCH_IF (("op" = 0x10) OR ("op" = 0x01)) THEN BEGIN
	  WRITE_SHORT ("eo" + "j" + 0x00) 0x92 // opcode: cast spell
	  WRITE_LONG  ("eo" + "j" + 0x04) 0x00 // cast at level
	  WRITE_LONG  ("eo" + "j" + 0x08) 0x00 // cast normally
	  WRITE_BYTE  ("eo" + "j" + 0x0c) 0x01 // timing mode: instant/permanent
	  WRITE_LONG  ("eo" + "j" + 0x0e) 0x00 // duration
	  PATCH_IF (NOT "%SOURCE_RES%" STRING_COMPARE_CASE "spcl521") THEN BEGIN
		WRITE_ASCII ("eo" + "j" + 0x14) ~spcl521d~ // resref
	  END ELSE PATCH_IF (NOT "%SOURCE_RES%" STRING_COMPARE_CASE "spcl741") THEN BEGIN
		WRITE_ASCII ("eo" + "j" + 0x14) ~spcl741d~ // resref
	  END
	END
  END
END
 END
BUT_ONLY_IF_IT_CHANGES

Link to comment

The one CamDawg posted, or the one I did? Both should work fine.

 

(I didn't know codeboxes kill the formatting, so it's reposted for easy reading)

 

I just use this locally:

COPY_EXISTING ~melfmet.itm~  ~override~
		  ~eneblade.itm~ ~override~
 PATCH_IF (%SOURCE_SIZE% > 0x71) THEN BEGIN
READ_LONG  0x6a "eo"
READ_SHORT 0x70 "gc"
FOR ("i1" = 0x00; "i1" < ("gc" * 0x30); "i1" += 0x30) BEGIN
  READ_SHORT   ("eo" + "i1" + 0x00) "op"
  PATCH_IF ("op" = 0x01) THEN BEGIN
	WRITE_LONG ("eo" + "i1" + 0x04) 0x0a
	WRITE_LONG ("eo" + "i1" + 0x08) 0x00
  END
END
 END
BUT_ONLY_IF_IT_CHANGES

 

as either one of the previous will still not solve the longstanding bug with other APR granting items.

Link to comment

Well, thanks for checking up :D

 

By the way, in an unreleased mod I've been twiddling with there's an item that grants +100% cold resistance and displays the cold resistance portrait icon. I thought it would be nice to add an immunity to the cold resistance portrait icon so there wouldn't be duplicates cluttering up the attractive NPCs <CHARNAME> travels with.

 

The cold resistance icon sporadically disappears ;)

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...