Jump to content


Photo

ADD_KNOWN_SPELL


  • Please log in to reply
4 replies to this topic

#1 Topaz

Topaz
  • Member
  • 24 posts

Posted 22 October 2004 - 11:06 AM

Hi,

I would like to change the spell books of every mage in BGTutu. IMHO spell memorization in BGI sucks. Doing it manually results mostly in crashes because some offset isn't correct and so on. So this a very itchy subject. I have accomplished this already trough scripting, but that's kinda bulky. One important issue is that I don't want every mage to have memorized the same spell (variation could be scripted of course).

I don't have much experience in tp2 coding, but would this outline do the trick?:

COPY_EXISTING_REGEXP ~.*\.cre~ ~override~
   READ_BYTE 0x234 "level" //problem with dual/multiclassed:what is level1/level2?
   READ_BYTE 0x273 "class"
   READ_LONG 0x2a0 "knownSpellsOffset" 
   READ_LONG 0x2a8 "memorizationOffset" 
   READ_LONG 0x2b0 "memorizedSpellsOffset"
   
   //Some way to delete all known wizard spells, then rebuild them
   ADD_KNOWN_SPELL ~SPWI112~ #0 ~wizard~

   IF "%level%"=1
     WRITE_SHORT ("%memorizationOffset%" + 48) 1 //72 should be 48 in hex
     SET "#spellsLvl1"=1 //in this case n is 1
   IF "%level%"=2
     WRITE_SHORT ("%memorizationOffset%" + 48) 1 
     SET "#spellsLvl1"=1 //in this case n is 1
     WRITE_SHORT ("%memorizationOffset%" + 52) 1 
     SET "#spellsLvl2"=1 //in this case n is 1
   IF "%level%"=3
     WRITE_SHORT ("%memorizationOffset%" + 48) 2 
     WRITE_SHORT ("%memorizationOffset%" + 52) 1 
//... and so on. i don't have a list at hand.

   //Some way to delete all memorized wizard spells, then rebuild them
   IF "%level%"=1
     WRITE_ASCII ("%memorizedSpellsOffset%") ~spwi112~

IF_EVAL ("%class%"=1 OR "%class%"=13 OR "%class%"=14) //trueclass,mage/thief, mage/cleric,...

Also need to do specialist mages...

Edited by Topaz, 24 October 2004 - 05:22 PM.


#2 CamDawg

CamDawg

    ALL GLORY TO THE HYPNOTOAD

  • Modder
  • 1505 posts

Posted 22 October 2004 - 12:22 PM

If you're looking for spell substitution, try looking at the latest Cleric Remix tp2. I wrote a whole routine that changes memorized spells for clerics. In the mod we introduce sphere restrictions, so it basically replaces spells to which they should not have access with spells that are allowed for their class/kit. It would be a lot simpler than removing and rebuilding the mem spell block, and would help maintain diversity in the spell books since everyone would not end up with a similar repertoire.

The same coding, with some changes, would be applicable to any type of substitution for spell books. The other change you'll need to examine are changing the spellcasting scripts for enemy mages so they'll actually use their new spells. ;)

Why is this Hypnotoad video so popu... ALL GLORY TO THE HYPNOTOAD.
____
The Gibberlings Three - Home of IE Mods

The BG2 Fixpack - All the fixes of Baldurdash, plus a few hundred more. Now available, with more fixes being added in every release.


#3 Topaz

Topaz
  • Member
  • 24 posts

Posted 24 October 2004 - 05:17 PM

I took a good look at your code, Cam, and although it gives me a lot of ideas how to bring things in practice, it substitutes spells, and pretty intricately btw. I really can't say which piece of code is responsible for spell substition based on the sphere. As you probably realize, I want to substitute and add spells if necessary.

In your tp2, I noticed you use WHILEs much as you would use an IF:
WHILE ((("%class%" = 3) OR ... AND (0 < "%ms_num%")). Won't this cause an infinite loop because those conditions will always be true?

Is ADD_KNOWN_SPELL strictly needed? Will setting unknown spells as memorized crash the game?

Could this pseudocode outline work?:

SET "#spellsLvl2"=n //there are n 2nd level spells; n is set only once per level; look at 1st post to see where n would be set.
SET "counter"=1 

WHILE ("%counter%" =< "%#spellsLvl2%") // i want n level 2 spells added

ItemslotOffset=ItemslotOffset+'sizeofspell';
ItemsOffset=ItemsOffset+'sizeofspell';
numMemorizedSpells=numMemorizedSpells+1;
INSERT_BYTES ("%memorizedSpellsOffset%" + "%numMemorizedSpells%" * 'sizeofspell') 'sizeofspell';
"%counter%"++;

Once I have theze bytes inserted make spell choices...somewhat random:
WRITE_ASCII both "adding" and replacing spells.

Edited by Topaz, 24 October 2004 - 05:28 PM.


#4 CamDawg

CamDawg

    ALL GLORY TO THE HYPNOTOAD

  • Modder
  • 1505 posts

Posted 24 October 2004 - 06:50 PM

Heh. I forgot how ugly that spell sub routine is. :)

In your tp2, I noticed you use WHILEs much as you would use an IF:
WHILE ((("%class%" = 3) OR ... AND (0 < "%ms_num%")). Won't this cause an infinite loop because those conditions will always be true?

If you'll look way down at the bottom, after all the STRING_COMPAREs, %ms_num% gets decremented every loop so it will eventually equal zero and end the WHILE loop. It's about 100 lines below the beginning of the loop, so it's a bit easy to miss. :)

Is ADD_KNOWN_SPELL strictly needed? Will setting unknown spells as memorized crash the game?


I guess it depends on your approach. I was looking to simply replace spells in the existing book, so I had no need to add spells. If you are looking to add spells, I would presume it would be a lot faster. Truth be told, I haven't really gotten a chance to play around with it yet.

Could this pseudocode outline work?:

SET "#spellsLvl2"=n //there are n 2nd level spells; n is set only once per level; look at 1st post to see where n would be set.
SET "counter"=1 

WHILE ("%counter%" =< "%#spellsLvl2%") // i want n level 2 spells added

ItemslotOffset=ItemslotOffset+'sizeofspell';
ItemsOffset=ItemsOffset+'sizeofspell';
numMemorizedSpells=numMemorizedSpells+1;
INSERT_BYTES ("%memorizedSpellsOffset%" + "%numMemorizedSpells%" * 'sizeofspell') 'sizeofspell';
"%counter%"++;

Once I have theze bytes inserted make spell choices...somewhat random:
WRITE_ASCII both "adding" and replacing spells.

View Post


Yeah, something like this would work. Unless you're going to give them more or less spells than they had previously, I would forego the teardown/rebuild approach, though that's a personal preference. I use a delta variable to track the number of spells removed from the spellbook, and it works great when I need to patch the offsets.

I'm going to walk through a very cut-down snippet of the spell sub routine--it sounds like you followed it, but I'll walk through it as a sort of mini-tutorial for anyone else who may want to try this. This routine will substitute the Aid spell for Barkskin in a cleric's spellbook for every cleric in the game. It can be expanded indefinitely--take a look at Cleric Remix (starting at line 1022 and through line 1192 in the current v0.8.8 beta tp2, though it lacks all of the informative comments below) for a very large example of this in action.

/* string compare is very slow to execute, so I usually print a small warning for the user before starting. */
PRINT ~This step can take a few minutes to execute. It is adjusting the spellbooks
of all clerics in the game.~

/* We're going through all creature files, so the C_E_R copies them all--but only if they change (see the last line) */
COPY_EXISTING_REGEXP GLOB ~.*\.cre~ ~override~

/* now we read in various information we need to safely patch the file. You may want to look into an editor and the IESDP to check what these offsets actually are and do. */
  READ_BYTE 0x273 "class" // character class
  READ_LONG 0x2A0 "sb_off" // hex offset of the spellbook listing
  READ_LONG 0x2A4 "sb_num" // number of spells in the spellbook
  READ_LONG 0x2A8 "meminfo_off" // hex offset of the memorization info
  READ_LONG 0x2B0 "ms_off" // hex offset of the memorized spells
  READ_LONG 0x2B4 "ms_num" // number of memorized spells
  READ_LONG 0x2B8 "slot_off" // hex offset of the item slot info
  READ_LONG 0x2BC "item_off" // hex offset of the item listings
  READ_LONG 0x2C4 "fx_off" // hex offset of the effects on the creature

/* these next two numbers will determine how many spells were originally in the spell book, and how much they change in the course of patching */
  SET "orig_sb_num" = "%sb_num%"
  SET "sb_delta" = 0

/* the class checks will only return true if the class matches one of the values for a cleric. The ms_num variable is the number of memorized spells--this loop will run once for each memorized spell. */
  WHILE ((("%class%" = 3) OR ("%class%" = 14) OR ("%class%" = 204) OR ("%class%" = 15) OR ("%class%" = 8) OR ("%class%" = 17)) AND (0 < "%ms_num%")) BEGIN // vanilla adjustments

/* in each pass, the name of a memorized spell is read into the "spell" variable. */
    READ_ASCII ("%ms_off%" + (("%ms_num%" - 1) * 0x0C)) "spell"

/* we start a new WHILE loop that contains the actual patching, if the spell name is Barkskin (SPPR202 is Barkskin) */
    WHILE ("SPPR202" STRING_COMPARE "%spell%" = 0) BEGIN // Aid for Barkskin

/* If it matches barkskin, then we simply write the name of the replacement spell--in this case, Aid SPPR201--in its place. */
      WRITE_ASCII ("%ms_off%" + (("%ms_num%" - 1) * 0x0C)) ~SPPR201~

/* setting "spell" to 0 will close the WHILE loop */
      SET "spell" = 0
    END

/* and now we close the larger WHILE loop by decrementing %ms_num%. Eventually it will reach zero and close the loop. */
  SET "ms_num" = ("%ms_num%" - 1)
  END

/* Now we start a new main WHILE loop to delete spells out of the spell book. Same class checks as above, but now we're using the number of spells in the spellbook (not memorized) to run the loop. */
  WHILE ((("%class%" = 3) OR ("%class%" = 14) OR ("%class%" = 204) OR ("%class%" = 15) OR ("%class%" = 8) OR ("%class%" = 17)) AND (0 < "%sb_num%")) BEGIN // vanilla adjustments

/* same as above--we're reading the name of each spell in the spellbook one at a time in each pass */
    READ_ASCII ("%sb_off%" + (("%sb_num%" - 1) * 0x0C)) "spell"

/* now we're checking each one--if it is Barkskin, then this loop goes into effect and deletes it */
    WHILE ("SPPR202" STRING_COMPARE "%spell%" = 0) BEGIN 

/* actual deletion of the bytes containing the spell */
      DELETE_BYTES ("%sb_off%" + (("%sb_num%" - 1) * 0x0C)) 0x0C

/* setting "spell" to zero closes the loop */
      SET "spell" = 0

/* this variable tracks how many spells (and hence how many bytes) get deleted. This is key as we'll need to adjust every hex offset in the file. */
      SET "sb_delta" = "%sb_delta%" + 1
    END

/* decrements the sb_num variable by 1 to eventually get it to 0 and close the loop. */
    SET "sb_num" = ("%sb_num%" - 1)
  END

/* now we simply close the patching by adjusting offsets for everything that comes after the bytes we deleted. If the offsets are not adjusted, the file is corrupted and can crash the game. First step is to adjust the number of spells in the spellbook.*/
  WRITE_LONG 0x2A4 ("%orig_sb_num%" - "%sb_delta%")

/* next we set a dummy variable to check if we've patched the memorized info offset already. */
  SET "meminfo_off_patch" = 0

/* The patching only occurs if two conditions are not met: if the meminfo offset is after where we deleted the bytes, it doens't need adjusting. The second check is the dummy variable to make sure we haven't patched it already. 
  WHILE (("%meminfo_off_patch%" = 0) AND NOT ("%meminfo_off%" < "%sb_off%")) BEGIN

/* replaces the former value with one adjusted to account for the deleted bytes */
    WRITE_LONG 0x2A8 ("%meminfo_off%" - ("%sb_delta%" * 0x0C))

/* sets the dummy variable to 1 to close the loop
    SET "meminfo_off_patch" = 1
  END

/* all of the other offset patches follow the same model as the meminfo offset patch. */
  SET "ms_off_patch" = 0
  WHILE (("%ms_off_patch%" = 0) AND NOT ("%ms_off%" < "%sb_off%")) BEGIN
    WRITE_LONG 0x2B0 ("%ms_off%" - ("%sb_delta%" * 0x0C))
    SET "ms_off_patch" = 1
  END
  SET "slot_off_patch" = 0
  WHILE (("%slot_off_patch%" = 0) AND NOT ("%slot_off%" < "%sb_off%")) BEGIN
    WRITE_LONG 0x2B8 ("%slot_off%" - ("%sb_delta%" * 0x0C))
    SET "slot_off_patch" = 1
  END
  SET "item_off_patch" = 0
  WHILE (("%item_off_patch%" = 0) AND NOT ("%item_off%" < "%sb_off%")) BEGIN
    WRITE_LONG 0x2BC ("%item_off%" - ("%sb_delta%" * 0x0C))
    SET "item_off_patch" = 1
  END
  SET "fx_off_patch" = 0
  WHILE (("%fx_off_patch%" = 0) AND NOT ("%fx_off%" < "%sb_off%")) BEGIN
    WRITE_LONG 0x2C4 ("%fx_off%" - ("%sb_delta%" * 0x0C))
    SET "fx_off_patch" = 1
  END

/* finally, we add this to the end to ensure that only files that actually change get copied--otherwise the override folder gets stuffed with files that don't need to be there. */
  BUT_ONLY_IF_IT_CHANGES

Hmm... now that I've written this much, I should probably just go ahead and make it a full blown tutorial. ;)

Why is this Hypnotoad video so popu... ALL GLORY TO THE HYPNOTOAD.
____
The Gibberlings Three - Home of IE Mods

The BG2 Fixpack - All the fixes of Baldurdash, plus a few hundred more. Now available, with more fixes being added in every release.


#5 Topaz

Topaz
  • Member
  • 24 posts

Posted 28 October 2004 - 05:03 AM

What do I have today: lots of questions and a weidu error! Some piece of my code can't be patched in. Syntax errors are all out, though... To be honest I don't understand the error message.

This might take a while.
Copying 1 file(s) ...
ERROR: [AERBOD01.CRE] -> [override/AERBOD01.CRE] Patching Failed (COPY) (Invalid_argument("String.sub"))

ERROR Installing [Updated and Tougher Mages for BGTutu], rolling back to previous state
Will uninstall 93 files for [TUTUMAGES_SETUP.TP2] component 0.
Uninstalled    93 files for [TUTUMAGES_SETUP.TP2] component 0.
ERROR: Invalid_argument("String.sub")
PLEASE email the file TUTUMAGES_SETUP.DEBUG to gravity665@hotmail.com


Here is my code so far, intermingled with questions...
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// Edit Spellbooks
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

PRINT ~This might take a while.~
COPY_EXISTING_REGEXP ~.*\.cre~ ~override~ 

READ_BYTE 0x234 "level" //problem with dual/multiclassed:what is level1/level2? 
READ_BYTE 0x273 "class" 
READ_LONG 0x2a0 "knownSpellsOffset" 
READ_LONG 0x2a8 "memorizationOffset" 
READ_LONG 0x2b0 "memorizedSpellsOffset" 
READ_LONG 0x2b4 "numMemorizedSpells" 
READ_LONG 0x244 "kit"
READ_LONG 0x2c4 "EffectsOffset"
READ_LONG 0x2bc "itemsOffset"
READ_LONG 0x2b8 "itemSlotOffset"

I want a REGEXP starting with an _ , to patch only Tutu content. I tried _.*\.cre, but WeiDU interpretes this as a real name, not a regexp. Can I use underscores?

Also, every time you use "%someVariable%" does it use the same value you read using READ_ or does it "auto-update"? (Prolly a very stupid question:))

///////////////////////////////////////////////////////////////////////
// ADD_KNOWN_SPELL                                
///////////////////////////////////////////////////////////////////////
//Still not sure whether to use or not; If I use it, it
//should probably be synchronous with the memorized spells blocks
///////////////////////////////////////////////////////////////////////

//ADD_KNOWN_SPELL ~SPWI112~ #0 ~wizard~ 

///////////////////////////////////////////////////////////////////////
// Spell level memorization                     
///////////////////////////////////////////////////////////////////////
// This reads how many levels the mage has and sets a variable for every spell level
///////////////////////////////////////////////////////////////////////

SET "readLevel"=0

WHILE (("%level%"=1) AND ("%readLevel%"=0))
BEGIN
	SET "#spellLvl1" = 1
	SET "#spellLvl2" = 0
	SET "#spellLvl3" = 0
	SET "#spellLvl4" = 0 //just to be sure
	SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
	SET "readLevel"=1
END

WHILE (("%level%"=2) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 2
	SET "#spellLvl2" = 0
	SET "#spellLvl3" = 0
	SET "#spellLvl4" = 0 
	SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
	SET "readLevel"=1
END

WHILE (("%level%"=3) AND ("%readLevel%"=0)) 
BEGIN
  	SET "#spellLvl1" = 2
  	SET "#spellLvl2" = 1
	SET "#spellLvl3" = 0
	SET "#spellLvl4" = 0 
	SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
	SET "readLevel"=1
END

WHILE (("%level%"=4) AND ("%readLevel%"=0)) 
BEGIN
  SET "#spellLvl1" = 3
  	SET "#spellLvl2" = 2
	SET "#spellLvl3" = 0
	SET "#spellLvl4" = 0 
	SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
	SET "readLevel"=1
END

WHILE (("%level%"=5) AND ("%readLevel%"=0))
BEGIN
	SET "#spellLvl1" = 4
  	SET "#spellLvl2" = 2
  SET "#spellLvl3" = 1
  SET "#spellLvl4" = 0 
	SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=6) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 4
  	SET "#spellLvl2" = 2
  SET "#spellLvl3" = 2
  SET "#spellLvl4" = 0 
	SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=7) AND ("%readLevel%"=0))
BEGIN
    SET "#spellLvl1" = 4 
    SET "#spellLvl2" = 3
  SET "#spellLvl3" = 2
  SET "#spellLvl4" = 1
  SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=8) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 4 
  	SET "#spellLvl2" = 3
  SET "#spellLvl3" = 3
  SET "#spellLvl4" = 2
  SET "#spellLvl5" = 0
	SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=9) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 4 
  	SET "#spellLvl2" = 3
  SET "#spellLvl3" = 3
  SET "#spellLvl4" = 2
  SET "#spellLvl5" = 1
  SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=10) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 4 
  	SET "#spellLvl2" = 4
  SET "#spellLvl3" = 3
  SET "#spellLvl4" = 2
  SET "#spellLvl5" = 2
  SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=11) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 4 
  	SET "#spellLvl2" = 4
  SET "#spellLvl3" = 4
  SET "#spellLvl4" = 3
  SET "#spellLvl5" = 3
  SET "#spellLvl6" = 0
	SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=12) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 4 
  	SET "#spellLvl2" = 4
  SET "#spellLvl3" = 4
  SET "#spellLvl4" = 4
  SET "#spellLvl5" = 4
  SET "#spellLvl6" = 1
  SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=13) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 5 
  	SET "#spellLvl2" = 5
  SET "#spellLvl3" = 5
  SET "#spellLvl4" = 4
  SET "#spellLvl5" = 4
  SET "#spellLvl6" = 2
  SET "#spellLvl7" = 0
  SET "readLevel"=1
END

WHILE (("%level%"=14) AND ("%readLevel%"=0))
BEGIN
  	SET "#spellLvl1" = 5 
  	SET "#spellLvl2" = 5
  SET "#spellLvl3" = 5
  SET "#spellLvl4" = 4
  SET "#spellLvl5" = 4
  SET "#spellLvl6" = 2
  SET "#spellLvl7" = 1
  SET "readLevel"=1
END

//for specialist mages: increase numspells/lvl with 1

SET "readKit"=0
WHILE ((("%kit%"=64) OR ("%kit%"=128) OR ("%kit%"=256) OR ("%kit%"=512) OR ("%kit%"=1024) OR ("%kit%"=2048) OR ("%kit%"=4096) OR ("%kit%"=8192)) AND ("%readKit%"=0))
BEGIN
	SET "#spellLvl1" = ("%#spellLvl1%" +1)
	SET "#spellLvl2" = ("%#spellLvl2%" +1)
	SET "#spellLvl3" = ("%#spellLvl3%" +1)
	SET "#spellLvl4" = ("%#spellLvl4%" +1)
	SET "#spellLvl5" = ("%#spellLvl5%" +1)
	SET "#spellLvl6" = ("%#spellLvl6%" +1)
	SET "#spellLvl7" = ("%#spellLvl7%" +1)
       SET "readKit"=1
/***************************************************************************
*Patch #spells memorizable, #spells memorizable? and Memorized spell count. All 3 should be the same.
*If you want to check out Memorized spell count in NI, look at the offset to which Memorized Spells Offset (2b0) points,
*and add 12 (0xC) to it. Logically, this value should be equal to the #spells memorizable field.
*Mostly it is not, even in BGII. The #spells memorizable field is mostly incorrect.
***************************************************************************/
//SET "n" = 0
//WHILE ("%n%" < 8)
WRITE_SHORT ("%memorizationOffset%" + 0x72 /*+ n*0x10*/)        "%#spellLvl1%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74)        "%#spellLvl1%"
  WRITE_SHORT ("%memorizationOffset%" + 0x7C)        "%#spellLvl1%"
  
WRITE_SHORT ("%memorizationOffset%" + 0x72 + 0x10) "%#spellLvl2%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74 + 0x10) "%#spellLvl2%"
  WRITE_SHORT ("%memorizationOffset%" + 0x7C + 0x10) "%#spellLvl2%"
  
WRITE_SHORT ("%memorizationOffset%" + 0x72 + 0x20) "%#spellLvl3%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74 + 0x20) "%#spellLvl3%"
  WRITE_SHORT ("%memorizationOffset%" + 0x7C + 0x20) "%#spellLvl3%"
  
WRITE_SHORT ("%memorizationOffset%" + 0x72 + 0x30) "%#spellLvl4%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74 + 0x30) "%#spellLvl4%"
  WRITE_SHORT ("%memorizationOffset%" + 0x7C + 0x30) "%#spellLvl4%"
  
WRITE_SHORT ("%memorizationOffset%" + 0x72 + 0x40) "%#spellLvl5%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74 + 0x40) "%#spellLvl5%"
  WRITE_SHORT ("%memorizationOffset%" + 0x7C + 0x40) "%#spellLvl5%"
  
WRITE_SHORT ("%memorizationOffset%" + 0x72 + 0x50) "%#spellLvl6%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74 + 0x50) "%#spellLvl6%"
  WRITE_SHORT ("%memorizationOffset%" + 0x7C + 0x50) "%#spellLvl6%"
  
WRITE_SHORT ("%memorizationOffset%" + 0x72 + 0x60) "%#spellLvl7%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74 + 0x60) "%#spellLvl7%"
  WRITE_SHORT ("%memorizationOffset%" + 0x7C + 0x60) "%#spellLvl7%"

Is it possible to use symbolic addresses, and variables instead of constants?
This works: WRITE_SHORT ("%memorizationOffset%" + 0x72 /*+ n*0x10*/) 5

But does this?:  WRITE_SHORT ("%memorizationOffset%" + 0x72 /*+ n*0x10*/)        "%#spellLvl1%"

Also, I tried to combine all this code in a while loop:

SET "n" = 0
WHILE ("%n%" < 8)
       WRITE_SHORT ("%memorizationOffset%" + 0x72 + "%n%"*0x10)    "%#spellLvl1%"
	WRITE_SHORT ("%memorizationOffset%" + 0x74 + "%n%"*0x10)    "%#spellLvl1%"
       WRITE_SHORT ("%memorizationOffset%" + 0x7C + "%n%"*0x10)    "%#spellLvl1%"
       SET "n" = "%n%" + 1

Now it is necessary that with each increment of n,
the accessed variable "%#spellLvl(n+1)%" changes, otherwise the number of lvl 1 spells would be set for all levels. Is this possible?

///////////////////////////////////////////////////////////////////////
// Memorized Spells: reserve spaces                
///////////////////////////////////////////////////////////////////////
// based on total number of spells
///////////////////////////////////////////////////////////////////////

SET "totalNumMemorizedSpells" = ("%#spellLvl1%" + "%#spellLvl2%" + "%#spellLvl3%" + "%#spellLvl4%" + "%#spellLvl5%" + "%#spellLvl6%" + "%#spellLvl7%")

WHILE ("%numMemorizedSpells%" <= "%totalNumMemorizedSpells%") 
BEGIN
	WRITE_LONG 0x2c4 ("%EffectsOffset%" + 0x6)
	WRITE_LONG 0x2bc ("%itemsOffset%" + 0x6)
	WRITE_LONG 0x2b8 ("%itemSlotOffset%" + 0x6)
  INSERT_BYTES ("%memorizedSpellsOffset%" + ("%numMemorizedSpells%" *0x6)) 0x06
  WRITE_LONG 0x2b4 ("%numMemorizedSpells%" + 1)
END

WHILE("%numMemorizedSpells%" > "%totalNumMemorizedSpells%") //if there are more spells memorized than is allowed by the rules
BEGIN
	WRITE_LONG 0x2c4 ("%EffectsOffset%" - 0x6)
	WRITE_LONG 0x2bc ("%itemsOffset%" - 0x6)
	WRITE_LONG 0x2b8 ("%itemSlotOffset%" - 0x6)
  DELETE_BYTES ("%memorizedSpellsOffset%" + ("%numMemorizedSpells%" *0x6)) 0x06
  WRITE_LONG 0x2b4 ("%numMemorizedSpells%" - 1)
END

///////////////////////////////////////////////////////////////////////
// Memorized Spells: fill in names         
///////////////////////////////////////////////////////////////////////
// based on number of spells per level
// I replace spells. Without STRING_COMPARE. The "choosing algoritm" makes choices and ///fills in.
///////////////////////////////////////////////////////////////////////
SET "n1" = 0
WHILE("%n1%" <= "%#spellLvl1%"-1)
BEGIN	
	WRITE_ASCII ("%memorizedSpellsOffset%" + "%n1%" * 0x6) ~spwi112~ 
	SET "n1" = "%n1%"+1
END	
	
IF_EVAL (("%class%" = 1) OR ("%class%" = 13) OR ("%class%" = 14) OR ("%class%" = 206) OR ("%class%" = 7) OR ("%class%" = 17) OR ("%class%" = 10)) 
//truclass,m/t,m/c,bard_all,f/m,f/m/c,f/m/t

Okay, this is the end of the code you just waded trough. But one more (pretty important) question, please. As you might have noticed, the fill in names block will always fill in spwi112. That's not what I want to do... How do I access a set of strings that get patched in here? Maybe I sound unclear (I get that a lot), because I don't know enough about tp2's, but at this time I see it could be solved by making a set of strings, containing all spells, needed, and let the tp2 code jump from spell to spell... This smells like a 2da file a lot. Is it possible to make a dummy 2da file that WeiDU reads?

Unless you're going to give them more or less spells than they had previously, I would forego the teardown/rebuild approach, though that's a personal preference.


That's exactly wahat I'm gonna do... but the teardown approach is a bit drastic since strings are pretty easy to overwrite.
Something I still don't get however (and this may sound stupid :)) is this:

/* Now we start a new main WHILE loop to delete spells...*/

Why do you want to delete Barkskin if you have just replaced it with Aid? I mean, ther is *no* spell called Barkskin anymore.  :wacko:

Edited by Topaz, 28 October 2004 - 06:01 AM.