Jump to content
the bigg

How to detect uses of custom secondary types

Recommended Posts

A common trick when creating advanced spell effects is to use Secondary Types (or Schools) to allow for advanced dispelling patterns and whatnot (the details of this are besides the scope of this tutorial).

 

The traditional method to do this was to pick a random number for your Secondary Type (or School). This has a compatibility drawback - if another mod picked your random number, the spells of the two mods would dispel each other (or other troubles).

 

The solution to this problem is to use the WeiDU command ADD_SECTYPE (or ADD_SCHOOL) to reserve a secondary type for your spells; this ensures that spells added by mods that use ADD_SECTYPE won't clash between them.

 

Converting a large mod to use ADD_SECTYPE might be non-trivial if lots of spells use custom secondary types - you have to check which effects in spells and items protect from, dispel, or reflect your custom secondary type. This tp2 snippet will scan all .eff, .spl, .itm and .cre files to see which files use which custom secondary types, and the offset where the sectype is used (note: the offset will be printed in decimal, not hexadecimal).

 

OUTER_SET school_threshold = 9
OUTER_SET sectype_threshold = 13

DEFINE_PATCH_MACRO ~check~ BEGIN
READ_LONG offset type
PATCH_IF (opcode = 202 || opcode = 204 || opcode = 220 || opcode = 223 || opcode = 227 || opcode = 229) && type > school_threshold THEN BEGIN
 PATCH_PRINT ~%SOURCE_FILE%: school %type% @ LONG %offset%~
END
PATCH_IF (opcode = 203 || opcode = 205 || opcode = 221 || opcode = 226 || opcode = 228 || opcode = 230)  && type > sectype_threshold THEN BEGIN
 PATCH_PRINT ~%SOURCE_FILE%: sectype %type% @ LONG %offset%~
END
END

COPY_EXISTING_REGEXP GLOB ~^.*\.spl$~ ~override~
 READ_SHORT 0x25 school
 READ_BYTE 0x27 sectype
 PATCH_IF school > school_threshold THEN BEGIN
PATCH_PRINT ~%SOURCE_FILE% is school %school% @ SHORT 37~
 END
 PATCH_IF sectype > sectype_threshold THEN BEGIN
PATCH_PRINT ~%SOURCE_FILE% is sectype %sectype% @ BYTE 39~
 END
BUT_ONLY

COPY_EXISTING_REGEXP GLOB ~^.*\.spl$~ ~override~
~^.*\.itm$~ ~override~
 READ_ASCII 0 signature (4)
 PATCH_IF ~%signature%~ STRING_EQUAL ~SPL ~ THEN BEGIN
header_length = 0x28
 END ELSE PATCH_IF  ~%signature%~ STRING_EQUAL ~ITM ~ THEN BEGIN
header_length = 0x38
 END ELSE BEGIN
INNER_ACTION BEGIN
  FAIL ~Malformed file signature "%signature%": %SOURCE_FILE%~
END
 END
 READ_LONG 0x64 "headoffset"  ELSE 0
 READ_SHORT 0x68 "headcount"  ELSE 0
 READ_LONG 0x6a "effectsoffset"  ELSE 0
 WHILE ("%headcount%" > 0) BEGIN
 READ_SHORT ("%headoffset%" + (("%headcount%" - 1 ) * header_length) + 0x1e) "count"  ELSE 0
 READ_SHORT ("%headoffset%" + (("%headcount%" - 1 ) * header_length) + 0x20) "effectsindex"  ELSE 0
 WHILE ("%count%" >0) BEGIN
	SET start = "%effectsoffset%" + (("%effectsindex%" + "%count%" - 1 )* 0x30)
	READ_SHORT start opcode
	SET offset = start + 8
	LPM ~check~
	SET "count" = ("%count%" -1)
 END
 SET "headcount" = "%headcount%" - 1
 END
 READ_SHORT 0x70 "count"  ELSE 0
 WHILE ("%count%" >0) BEGIN
	SET start = "%effectsoffset%" + (("%count%" - 1 )* 0x30)
	READ_SHORT start opcode
	SET offset = start + 8
	LPM ~check~
	SET "count" = ("%count%" -1)
 END
BUT_ONLY

COPY_EXISTING_REGEXP GLOB ~^.*\.cre$~ ~override~
 READ_BYTE 0x33 "effv"  ELSE 0
 READ_LONG 0x02c4 "offseteffs"  ELSE 0
 READ_LONG 0x02c8 "counteffs"   ELSE 0
 PATCH_IF ("%effv%" = 0) BEGIN  //effects V1, like itms or spells
	WHILE ("%counteffs%" > 0) BEGIN
	  SET start = "%offseteffs%" + (("%counteffs%" - 1 ) * 0x30)
	  READ_SHORT start opcode
	  SET offset = start + 8
	  LPM ~check~
	  SET "counteffs" = "%counteffs%" - 1
	END
 END
 PATCH_IF ("%effv%" = 1) BEGIN  //effects V2
	WHILE ("%counteffs%" > 0) BEGIN
	SET start = "%offseteffs%" + (("%counteffs%" - 1 ) * 0x108) - 8
	READ_LONG start + 0x10  "opcode"  ELSE 0
	SET offset = start + 0x20
	LPM ~check~
	SET "counteffs" = "%counteffs%" - 1
	END
 END
BUT_ONLY

COPY_EXISTING_REGEXP GLOB ~^.*\.eff$~ ~override~
 READ_LONG 0x10  "opcode"  ELSE 0
 SET offset = 0x20
 LPM ~check~
BUT_ONLY

 

You still need to remember (or figure out) what your custom sectype(s) do, add an ADD_SECTYPE for each custom sectype to your tp2, and make sure that, when you copy/create/patch each file, you use the custom sectype instead of the old one you hardcoded in (most likely, by adding one or more WRITE_SOMETHING when copying your file to the override, but your situation might require more advanced patching).

 

I hope you'll find this code useful, and don't hesitate to provide comments or corrections.

Share this post


Link to post
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...