Jump to content
Sign in to follow this  
Nythrun

The uses and abuses of secondary types

Recommended Posts

(This space reserved for when I actually have type to explain what this does)

Share this post


Link to post

Macros used:

 

Array of ascii characters

OUTER_PATCH ~this_is_not_a_variable~ BEGIN
 FOR ("ix" = 0x0; "ix" < 0x100; "ix" += 0x1) BEGIN
WRITE_BYTE 0x0 "ix"
READ_ASCII 0x0 ~c~ (0x1)
SPRINT EVALUATE_BUFFER $t(~%ix%~) ~%c%~
 END
END

 

Fake SAY offset @%tra_ref%

DEFINE_ACTION_MACRO ~fj_plork_strref~ BEGIN
 <<<<<<<<nythruns/trash/plork.tpa
 DEFINE_ACTION_MACRO ~fj_plork_strref2~ BEGIN
OUTER_PATCH ~this_is_not_a_variable~ BEGIN
  SAY	   0x00 @placeholder
  READ_LONG 0x00 tra_ref
END
 END
 >>>>>>>>
 COPY - ~nythruns/trash/plork.tpa~ ~plork_temp.tpa~
REPLACE_TEXTUALLY EXACT_MATCH ~placeholder~ ~%temp_ref%~
 REINCLUDE ~plork_temp.tpa~
 LAUNCH_ACTION_MACRO ~fj_plork_strref2~
END

 

Dynamic add Secondary Type macro

DEFINE_ACTION_MACRO ~fj_add_sectype~ BEGIN
 ACTION_IF !(FILE_EXISTS ~override/msectype.2da~) THEN BEGIN
COPY_EXISTING ~msectype.2da~ ~override~
 END
 ACTION_IF !(FILE_CONTAINS ~override/msectype.2da~ EVALUATE_BUFFER ~^%sec_type%~) THEN BEGIN
COPY_EXISTING ~msectype.2da~ ~override~
  PATCH_IF SOURCE_SIZE BEGIN
	COUNT_2DA_ROWS 0x2 "r"
	INSERT_2DA_ROW "r" 0x2 ~%sec_type% %tra_ref%~
	SET EVALUATE_BUFFER "%sec_type%_sectype" = ("r" - 0x1)
  END
BUT_ONLY
 END ELSE BEGIN
COPY_EXISTING - ~msectype.2da~ ~override~
  PATCH_IF SOURCE_SIZE BEGIN
	FOR (COUNT_2DA_ROWS 0x2 "r"; "r" > 0x1; "r" -= 0x1) BEGIN
	  READ_2DA_ENTRY ("r" - 0x1) 0x0 0x2 ~v~
	  PATCH_IF (~%v%~ STRING_EQUAL_CASE ~%sec_type%~) THEN BEGIN
		SET EVALUATE_BUFFER "%sec_type%_sectype" = ("r" - 0x2)
		SET "r" = 0x0
	  END
	END
  END
// BUT_ONLY
 END
END

 

And everyone's favorite, nothing

<<<<<<<<null.inlined
>>>>>>>>

Share this post


Link to post

Sleep dispels on hit without exe patches or lingering effects:

Curative spell fashioned out of whole cloth to work around forum attachments. Don't do this, use a prefix too.

 OUTER_SPRINT ~sec_type~ ~Sleep~
OUTER_SPRINT ~tra_ref~  ~6299~
LAUNCH_ACTION_MACRO ~fj_add_sectype~

OUTER_SET "ho" = 0x72
OUTER_SET "hc" = 0x01
OUTER_SET "eo" = ("ho" + (0x28 * "hc"))
OUTER_SET "ec" = 0x02
COPY ~null.inlined~ ~override/cureslee.spl~
 PATCH_IF (SOURCE_SIZE = 0x00) THEN BEGIN
INSERT_BYTES 0x00 (0x72 + (0x28 * "hc") + (0x30 * "ec"))
WRITE_ASCII  0x00 ~SPL V1  ~
WRITE_LONG   0x08 (` 0x00)
WRITE_LONG   0x0c (` 0x00)
WRITE_SHORT  0x38 0x01
WRITE_LONG   0x50 (` 0x00)
WRITE_LONG   0x54 (` 0x00)
WRITE_LONG   0x64 "ho"
WRITE_SHORT  0x68 "hc"
WRITE_LONG   0x6a "eo"
FOR ("i1" = 0x00; "i1" < ("hc" * 0x28); "i1" += 0x28) BEGIN
  WRITE_BYTE   ("ho" + "i1" + 0x00) 0x01
  WRITE_BYTE   ("ho" + "i1" + 0x02) 0x02
  WRITE_BYTE   ("ho" + "i1" + 0x0c) 0x01
  WRITE_SHORT  ("ho" + "i1" + 0x0e) 0x01
  WRITE_SHORT  ("ho" + "i1" + 0x10) ("i1" + 0x01)
  WRITE_SHORT  ("ho" + "i1" + 0x1e) "ec"
  WRITE_SHORT  ("ho" + "i1" + 0x20) ("i1" * "ec")
  WRITE_SHORT  ("ho" + "i1" + 0x26) 0x01
  FOR ("i2" = ("i1" * "ec" * 0x30); "i2" < (("i1" + 0x01) * "ec" * 0x30); "i2" += ("ec" * 0x30)) BEGIN
	WRITE_SHORT  ("eo" + "i2" + 0x00) 0xdd
	WRITE_BYTE   ("eo" + "i2" + 0x02) 0x02
	WRITE_LONG   ("eo" + "i2" + 0x04) 0x09
	WRITE_LONG   ("eo" + "i2" + 0x08) "Sleep_sectype"
	WRITE_BYTE   ("eo" + "i2" + 0x0c) 0x01
	WRITE_BYTE   ("eo" + "i2" + 0x12) 0x64
	WRITE_SHORT  ("eo" + "i2" + 0x30) 0x02
	WRITE_BYTE   ("eo" + "i2" + 0x32) 0x02
	WRITE_BYTE   ("eo" + "i2" + 0x3c) 0x01
	WRITE_BYTE   ("eo" + "i2" + 0x42) 0x64
  END
END
 END

COPY_EXISTING ~spwi116.spl~  ~override~
 PATCH_IF (SOURCE_SIZE > 0x71) THEN BEGIN
READ_LONG  0x18 "fl"
WRITE_LONG 0x18 ("fl" & 0xfffffbff)
WRITE_BYTE 0x27 "Sleep_sectype"
READ_LONG  0x64 "ho"
READ_SHORT 0x68 "hc"
READ_LONG  0x6a "eo"
FOR ("i1" = "hc" * 0x28; "i1" > 0x00; "i1" -= 0x28) BEGIN
  READ_SHORT   ("ho" + "i1" - 0x0a) "ec"
  READ_SHORT   ("ho" + "i1" - 0x08) "ei"
  WRITE_SHORT  ("ho" + "i1" - 0x0a) ("ec" + 0x01)
  READ_ASCII   ("eo" + ("ei" * 0x30)) ~ef~ (0x30)
  INSERT_BYTES ("eo" + (("ei" + "ec") * 0x30) + 0x00) 0x30
  WRITE_ASCIIE ("eo" + (("ei" + "ec") * 0x30) + 0x00) ~%ef%~
  WRITE_SHORT  ("eo" + (("ei" + "ec") * 0x30) + 0x00) 0xe8
  WRITE_LONG   ("eo" + (("ei" + "ec") * 0x30) + 0x04) 0x00
  WRITE_LONG   ("eo" + (("ei" + "ec") * 0x30) + 0x08) 0x00
  WRITE_ASCII  ("eo" + (("ei" + "ec") * 0x30) + 0x14) ~cureslee~ #8
END
READ_SHORT 0x70 "ei"
FOR ("i1" = 0x00; "i1" < "hc" * 0x28; "i1" += 0x28) BEGIN
  WRITE_SHORT "ho" + "i1" + 0x20 "ei"
  READ_SHORT  "ho" + "i1" + 0x1e "ec"
  SET "ei" += "ec"
END
 END

Share this post


Link to post

Improved Invisibility grants a save bonus, doesn't stack, and doesn't block itself

OUTER_SPRINT ~sec_type~ ~ImprovedInvisibility~
OUTER_SPRINT ~tra_ref~  ~4294967295~
LAUNCH_ACTION_MACRO ~fj_add_sectype~
COPY_EXISTING ~balth10.spl~  ~override~ // Shadow Stance!
		  ~spdr401.spl~  ~override~ // Invisible Stalker Improved Invisibility
		  ~spin544.spl~  ~override~ // PSIONIC _SUPERIOR_INVISIBILITY
		  ~spin687.spl~  ~override~ // Create Shadows
		  ~spin698.spl~  ~override~ // Cerebus Improved Invisibility
		  ~spwi405.spl~  ~override~ // Improved Invisibility (mage)
		  ~spwi505.spl~  ~override~ // Shadow Door (mage)
		  ~spwi607.spl~  ~override~ // Mislead
		  ~spwi721.spl~  ~override~ // Mass Invisibility
 PATCH_IF (SOURCE_SIZE > 0x71) THEN BEGIN
WRITE_BYTE  0x27 "ImprovedInvisibility_sec_type"
READ_LONG   0x64 "ho"
READ_SHORT  0x68 "hc"
READ_LONG   0x6a "eo"
READ_SHORT  0x70 "gc"
FOR ("i1" = ("hc" * 0x28); "i1"; "i1" -= 0x28) BEGIN
  READ_SHORT   ("ho" + "i1" - 0x0a) "ec"
  WRITE_SHORT  ("ho" + "i1" - 0x0a) ("ec" + 0x01)
  READ_SHORT   ("ho" + "i1" - 0x08) "ei"
  READ_ASCII   ("eo" + (0x30 * "ei") + 0x00) ~ef~ (0x30)
  INNER_PATCH_SAVE ~ef~ ~%ef%~ BEGIN
	WRITE_SHORT  0x00 0xdd
	WRITE_LONG   0x04 0x09
	WRITE_LONG   0x08 "ImprovedInvisibility_sectype"
	WRITE_BYTE   0x0c 0x01
	WRITE_LONG   0x0e 0x00
	WRITE_ASCII  0x14 ~~ #8
  END
  INSERT_BYTES ("eo" + (0x30 * "ei") + 0x00) 0x30
  WRITE_ASCIIE ("eo" + (0x30 * "ei") + 0x00) ~%ef%~
END
FOR ("i1" = 0x00; "i1" < ("hc" * 0x28); "i1" += 0x28) BEGIN
  READ_SHORT  ("ho" + "i1" + 0x1c) "ec"
  WRITE_SHORT ("ho" + "i1" + 0x20) "gc"
  SET "gc" += "ec"
END
PATCH_IF !(~%SOURCE_RES%~ STRING_EQUAL_CASE ~spwi721~) THEN BEGIN
  FOR ("i1" = ("hc" * 0x28); "i1"; "i1" -= 0x28) BEGIN
	READ_SHORT   ("ho" + "i1" - 0x0a) "ec"
	WRITE_SHORT  ("ho" + "i1" - 0x0a) ("ec" + 0x05)
	READ_SHORT   ("ho" + "i1" - 0x08) "ei"
	FOR ("i2" = (("ec" + "ei" - 0x01) * 0x30); "i2" > (("ei" - 0x01) * 0x30); "i2" -= 0x30) BEGIN
	  READ_LONG  ("eo" + "i2" + 0x0e) "dr"
	  PATCH_IF ("dr" > 0x07) THEN BEGIN
		READ_ASCII ("eo" + "i2" + 0x00) ~ef~ (0x30)
		INNER_PATCH_SAVE ~ef~ ~%ef%~ BEGIN
		  WRITE_LONG  0x04 0x04
		  WRITE_LONG  0x08 0x00
		  WRITE_ASCII 0x14 ~~ #8
		END
		SET "i2" = 0x00
	  END
	END
	INSERT_BYTES ("eo" + (0x30 * ("ei" + "ec")) + 0x00) (0x30 * 0x05)
	FOR ("i2" = 0x00; "i2" < 0x05; "i2" += 0x01) BEGIN
	  WRITE_ASCIIE ("eo" + (0x30 * ("ei" + "ec" + "i2"))) ~%ef%~
	  WRITE_SHORT  ("eo" + (0x30 * ("ei" + "ec" + "i2"))) (0x21 + "i2")
	END
  END
  FOR ("i1" = 0x00; "i1" < ("hc" * 0x28); "i1" += 0x28) BEGIN
	READ_SHORT  ("ho" + "i1" + 0x1c) "ec"
	WRITE_SHORT ("ho" + "i1" + 0x20) "gc"
	SET "gc" += "ec"
  END
END
 END
// BUT_ONLY
COPY_EXISTING ~jwtrue.spl~   ~override~ // Goofy FX
		  ~spcl232.spl~  ~override~ // True Sight (inquisitor)
		  ~spcl232d.spl~ ~override~ // True Sight (inquisitor) (triggered spell)
		  ~spcl732.spl~  ~override~ // True Sight (priest of Hat)
		  ~sppr309.spl~  ~override~ // Invisibility Purge
		  ~sppr505.spl~  ~override~ // True Seeing (priest)
		  ~sppr505d.spl~ ~override~ // True Seeing (priest) (triggered spell)
	   // ~sppr950.spl~  ~override~ // True Sight (clone)
		  ~spwi203.spl~  ~override~ // Detect Invisibility
		  ~spwi224.spl~  ~override~ // Glitterdust
		  ~spwi515.spl~  ~override~ // Oracle
		  ~spwi609.spl~  ~override~ // True Sight (wizard)
		  ~spwi609d.spl~ ~override~ // True Sight (wizard) (triggered spell)
 PATCH_IF (SOURCE_SIZE > 0x71) THEN BEGIN
READ_LONG   0x64 "ho"
READ_SHORT  0x68 "hc"
READ_LONG   0x6a "eo"
READ_SHORT  0x70 "gc"
FOR ("i1" = ("hc" * 0x28); "i1"; "i1" -= 0x28) BEGIN
  READ_SHORT   ("ho" + "i1" - 0x0a) "ec"
  WRITE_SHORT  ("ho" + "i1" - 0x0a) ("ec" + 0x01)
  READ_SHORT   ("ho" + "i1" - 0x08) "ei"
  FOR ("i2" = (("ec" + "ei" - 0x01) * 0x30); "i2" > (("ei" - 0x01) * 0x30); "i2" -= 0x30) BEGIN
	  READ_BYTE  ("eo" + "i2" + 0x02) "tt"
	  PATCH_IF ("tt" = 0x02) THEN BEGIN
		READ_ASCII ("eo" + "i2" + 0x00) ~ef~ (0x30)
		INNER_PATCH_SAVE ~ef~ ~%ef%~ BEGIN
		  WRITE_SHORT 0x00 0xdd
		  WRITE_LONG  0x04 0x09
		  WRITE_LONG  0x08 "ImprovedInvisibility_sectype"
		  WRITE_BYTE  0x0c 0x01
		  WRITE_LONG  0x0e 0x00
		  WRITE_ASCII 0x14 ~~ #8
		END
		SET "i2" = 0x00
	  END
	END
  END
  INSERT_BYTES ("eo" + (0x30 * "ei") + 0x00) 0x30
  WRITE_ASCIIE ("eo" + (0x30 * "ei") + 0x00) ~%ef%~
END
FOR ("i1" = 0x00; "i1" < ("hc" * 0x28); "i1" += 0x28) BEGIN
  READ_SHORT  ("ho" + "i1" + 0x1c) "ec"
  WRITE_SHORT ("ho" + "i1" + 0x20) "gc"
  SET "gc" += "ec"
END
 END
// BUT_ONLY

Share this post


Link to post

ha, I thought I was the only one who was tinkering with it=). I've made some code that makes potions effects refreshable and non-stackable, but never got to release it. There were 2 issues, though - I could only make them dispel self within a second - immediate dispel didn't work with any order of effects, and each time such dispel used a hardcoded line from mssectype.2da appears. If there's no line or there is an immunity to it, then an empty line appears anyway. So I considered it non-suitable for the fixpack. Did you manage to avoid these? I'm too lazy to read your code thoroughly=)

Share this post


Link to post

I won't doubt that these work, but the code is a little hard to read if all the variables are a bunch of abbreviations that aren't immediately obvious as to what they represent.

Share this post


Link to post

I'm sorry, I ran out of time just after starting this and won't be able to get back to it for a bit.

 

@Gort: I'm not sure what you're meaning with immediate dispel didn't work - I've never had to do anything fancy to get that. Remove SecType, Immunity to String 0 seconds works to prevent strings from running when they ought not, blocking them completely I only know how to do with a mix of global effects or an attached .eff.

 

People have been messing around with this stuff since before I was born :)

 

@A64 Yes, it's all but useless, as there's abbreviated code to illustrate a walkthrough that's unwritten, sorry :help: I didn't even start on dealing with nulling everyone's second favorite .bam or what the SAY off %var% is for. I'll get back to it.

 

Didn't mean to reach for your thunder on your Real Dalestyle .exe patch by the way, Sleep is just something people've been talking about ;)

Share this post


Link to post
@A64 Yes, it's all but useless, as there's abbreviated code to illustrate a walkthrough that's unwritten, sorry :) I didn't even start on dealing with nulling everyone's second favorite .bam or what the SAY off %var% is for. I'll get back to it.

 

Didn't mean to reach for your thunder on your Real Dalestyle .exe patch by the way, Sleep is just something people've been talking about :help:

No need for apologies. Take my thunder as you like it, I am totally supportive of, and much prefer, patches that don't require smashing bits and pieces of the .exe up. ;)

Share this post


Link to post

so, Nythrun, have you tried this in game? Improved Invisibility, in particular? I have some problems getting this to work.

Share this post


Link to post

For a moment I was wondering who written such an unhelpful tutorial, hee. Yes, sorry - I'd forgotten this thread existed.

 

It's been a staple technique in my Frowny Face Empire for a couple years now, and I'm not quite vain enough to assume other people aren't using it as well.

 

What's giving you trouble? For the simpler uses there are only three things you need to do.

 

Add the new secondary type to msectype.2da, sequentially. Brief/ugly/unweird code:

COPY_EXISTING msectype.2da override
 COUNT_2DA_ROWS 2 rows
 INSERT_2DA_ROW rows 2 ~ImprovedInvisibility stringdisplay~
 REPLACE ~\bstringdisplay~ @1 // @1 = ~Improved Invisibility removed~
 READ_2DA_ENTRY rows 1 2 ImprovedInvisibilityRemovalString
 SET ImprovedInvisibilitySectype = rows - 1
UNLESS ImprovedInvisibility

 

Then add in two new effects at the beginning of each extended header of each spell that's participating in this tomfoolery.

 

The first of these is a zero duration immunity to string display, preventing the "Improved Invisibility removed" string from running iff there's not already some kind of Improved Invisibility active. Set the power level to greater than what the next effect will be removing, at least for now - there are tricksier ways to do this involving external resources. Since you've just added that string to the .tlk, a

WRITE_LONG effect_offset + 0x30 * effect_number + 0x04 ImprovedInvisibilityRemovalString

needs adding under your COPY to override.

 

The second effect you add is a remove by secondary type (opcode 221, I think?). Set the highest level removed to the highest power level you need to knock off (for Improved Invisibility, that'd be seven, so you can avoid cumulativity with Mass Invisibility).

WRITE_LONG effect_offset + 0x30 * effect_number + 0x04 7

You need also to add in what the new dynamically secondary type is:

WRITE_LONG effect_offset + 0x30 * effect_number + 0x08 ImprovedInvisibilitySectype

 

The third and last step is changing the secondary type in the spell header of whichever spell you're copying to the new one you've added:

WRITE_BYTE 0x27 ImprovedInvisibilitySectype

 

And that's it, pretty much.

 

/edit

 

Actually, if you just want Improved Invisibility, skip the string display prevention entirely - that's not one of the places it'll matter, I think.

Edited by Nythrun

Share this post


Link to post
@Gort: I'm not sure what you're meaning with immediate dispel didn't work - I've never had to do anything fancy to get that. Remove SecType, Immunity to String 0 seconds works to prevent strings from running when they ought not, blocking them completely I only know how to do with a mix of global effects or an attached .eff.

 

I should have been reading this earlier, but in case you are still around, Nythrun I have been unable to make this work.

 

I have tried using #101 protection from opcode (set to opcode #139) as well as #267 protection from display specific string, but none of this prevented a string from being displayed when I dispelled the sectype.

 

I have had trouble with this for years, and I hope it is me missing something rather than the engine being uncool.

 

-Galactygon

Share this post


Link to post

A small bit of my knowledge - there is no need to update msectype.2da, secondary types seem to work perfectly with or without it (they did for).

Share this post


Link to post
A small bit of my knowledge - there is no need to update msectype.2da, secondary types seem to work perfectly with or without it (they did for).

 

Yes, they will. However it makes it harder for mods (or anything else) to find a unique secondary type to use, as it would mean scanning all games files. However, as some secondry types are hard-coded and do not appear in msectype.2da anyway...

Share this post


Link to post
However, as some secondry types are hard-coded and do not appear in msectype.2da anyway...

 

Could you please elaborate? I haven't seen or heard of anything like this.

 

-Galactygon

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.

Sign in to follow this  

×
×
  • Create New...