Author Topic: How to detect uses of custom secondary types  (Read 5489 times)

Offline the bigg

  • The Avatar of Fighter / Thieves
  • Planewalker
  • *****
  • Posts: 3804
  • Gender: Male
How to detect uses of custom secondary types
« on: November 12, 2010, 04:10:06 PM »
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).

Code: [Select]
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.
Author or Co-Author: WeiDU (http://j.mp/bLtjOn) - Widescreen (http://j.mp/aKAiqG) - Generalized Biffing (http://j.mp/aVgw3U) - Refinements (http://j.mp/bLHoCc) - TB#Tweaks (http://j.mp/ba02Eg) - IWD2Tweaks (http://j.mp/98OFYY) - TB#Characters (http://j.mp/ak8J55) - Traify Tool (http://j.mp/g1Ry9A) - Some mods that I won't mention in public
Maintainer: Semi-Multi Clerics (http://j.mp/9UeIwB) - Nalia Mod (http://j.mp/dng9l0) - Nvidia Fix (http://j.mp/aRWjjg)
Code dumps: Detect custom secondary types (http://j.mp/hVzzXG) - Stutter Investigator (http://j.mp/gdtBn8)

If possible, send diffs, translations and other contributions using Git (http://j.mp/aBZFrq).

 

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Warning: this topic has not been posted in for at least 120 days.
Unless you're sure you want to reply, please consider starting a new topic.

Name: Email:
Verification:
Type the letters shown in the picture
Listen to the letters / Request another image
Type the letters shown in the picture:
What color is grass?:
What is the seventh word in this sentence?:
What is five minus two (use the full word)?: