Jump to content

Patching BG1 NPC Items for BGT


cmorgan

Recommended Posts

Hey, pro5 or anyone conversant:

 

I have a macro

DEFINE_PATCH_MACRO ~tutu_items_to_bgt~ BEGIN
 READ_LONG  0x2bc "itm_off" ELSE 0
 READ_LONG  0x2c0 "itm_num" ELSE 0
 FOR (index = 0; index < itm_num; index = index + 1) BEGIN
READ_ASCII ("%itm_off%" + (0x14 * "%index%")) "item"
PATCH_IF ("%item%" STRING_COMPARE_CASE "_DAGG03" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "DAGG03" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_BOW08" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "BOW08" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_AROW01" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "AROW01" #8
END ELSE

etc, etc.

END
 END
END

 

pro5, your code does the same thing, but a little differently...

 

		READ_LONG 0x2b8 ~itemslot~
	READ_LONG 0x2bc ~itemoffset~
	SET ~currentloc~=~itemoffset~
	WHILE (~currentloc~<~itemslot~) BEGIN
		READ_ASCII ~currentloc~ ~itemcarried~	 
		PATCH_IF !(~%itemcarried%~ STRING_COMPARE_CASE ~_RING94~) THEN BEGIN
			WRITE_ASCII ~currentloc~ ~RING94~ #8
		END
		PATCH_IF !(~%itemcarried%~ STRING_COMPARE_CASE ~_B1-8~) THEN BEGIN
			WRITE_ASCII ~currentloc~ ~B1-8~ #8
		END
	SET ~currentloc~=~currentloc~+0x14
	END

 

 

I see two differences -

 

yours reads from

READ_LONG 0x2b8 ~itemslot~

READ_LONG 0x2bc ~itemoffset~

 

while the code ripped off from CamDawg reads

READ_LONG 0x2bc "itm_off" ELSE 0

READ_LONG 0x2c0 "itm_num" ELSE 0

 

and

 

yours uses SET WHILE

 

CamDawgs uses FOR

 

I *think* I understand the usage; what I want to try to do is create one macro that can be called that checks all items for all of these in one pass, easily called after everything in a component is installed.

 

Even though it would be less efficient in terms of cycle tme, it would be very efficient from coding/adding to. I can just do

 

ACTION_IF FILE_EXISTS ~data/BG1ARE.bif~ THEN BEGIN
COPY_EXISTING ~X#XZGU01.CRE~ ~override~
		  ~X#XZGU02.CRE~ ~override~
		  ~X#XZGU03.CRE~ ~override~
PATCH_IF (SOURCE_SIZE > 0x2d3) BEGIN
  LAUNCH_PATCH_MACRO ~tutu_items_to_bgt~
END
END

 

 

 

 

How would I best code a check for all items carried or held, compare them with the known conversion hiccups, and patch? I think I can use either one, but it troubles me, as _STAF07 should have been caught by the FOR code, and wasn't...

Link to comment
How would I best code a check for all items carried or held, compare them with the known conversion hiccups, and patch? I think I can use either one, but it troubles me, as _STAF07 should have been caught by the FOR code, and wasn't...

It would be caught, but the macro is never applied to X#ANDART:

 

// ...
COPY_EXISTING ~TAKIYAH.CRE~ ~override~
 WRITE_ASCII 0x280 ~takiyah~ #32 // death variable

END

/* Andarthe */
COPY ~BG1NPC/Phase2/CRE/X#ANDART.CRE~ ~override~
 SAY NAME1 @363
 SAY NAME2 @363
 SAY INITIAL_MEETING @341
 SAY BATTLE_CRY1 @341
 SAY DAMAGE @342
 SAY DYING @343
 SAY SELECT_COMMON1 @345
 WRITE_ASCII 0x248 ~X#ANDART~ #8 // override script
 WRITE_ASCII 0x2CC ~X#ANDART~ #8 // dialog
 WRITE_ASCII 0x280 ~andarthe~ #32 // death variable
 ADD_CRE_ITEM ~STAF17~ #0 #0 #0 ~IDENTIFIED&UNSTEALABLE&UNDROPPABLE~ ~WEAPON2~ EQUIP TWOHANDED

/* Beador */
COPY ~BG1NPC/Phase2/CRE/X#BEADOR.CRE~ ~override~
// ...

 

It's actually irrelevant, because he's given STAF17 here. To make it perfectly clean, use REPLACE_CRE_ITEM instead. It does same thing as ADD_CRE_ITEM but if the target slot's occupied, current item is destroyed rather than forced into inventory.

Link to comment

I don't suppose there's a .2da list of the Tutu specific item resrefs, is there? :p

 

If you had something like this

COPY_EXISTING_REGEXP GLOB ~^.+\.cre$~ ~override~
 PATCH_IF (%SOURCE_SIZE% > 0x2d3) THEN BEGIN
   READ_LONG   0x2bc "ilo"
   READ_LONG   0x2c0 "ilc"
   FOR ("i1" = "ilo"; "i1" < ("ilo" + (0x14 * "ilc")); "i1" += 0x14) BEGIN
     READ_BYTE "i1" "underscore"
     PATCH_IF ("underscore" = 0x5f) THEN BEGIN
       READ_ASCII "i1" "item"
       INNER_PATCH_FILE ~tutu2bgt.2da~ BEGIN
         FOR ("i2" = 0x01; "i2" < ("xx" + 0x01); "i2" += 0x01) BEGIN
           READ_2DA_ENTRY %i2% 1 2 "match"
           PATCH_IF (%match% STRING_EQUAL_CASE "item") THEN BEGIN
             READ_2DA_ENTRY %i2% 2 2 "replace"
           END
         END
       END
       WRITE_ASCII "i1" %replace% #8
     END
   END
 END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~^.+\.bcs$~ ~override~
 PATCH_IF (%SOURCE_SIZE% > 0x04) THEN BEGIN
   DECOMPILE_BCS_TO_BAF
     FOR ("i1" = 0x01; "i1" < ("xx" + 0x01); "i1" += 0x01) BEGIN
       INNER_PATCH_FILE ~tutu2bgt.2da~ BEGIN
         READ_2DA_ENTRY %i1% 1 2 "match"
         READ_2DA_ENTRY %i1% 2 2 "replace"
       END
       REPLACE_TEXTUALLY ~%match%~ ~%replace%~
     END
   COMPILE_BAF_TO_BCS
 END
BUT_ONLY_IF_IT_CHANGES

Link to comment

Wow! Just connected the dots - that is what you folks were talking about on BG1NPC with 2da patching - wicked cool.

 

Opinions - yes, we need to do repeated patching rather than at the end, because independent components may or may not be installed. Technically, we might be able to just put a single regexp glob at the end of a component to recheck the creatures, instead of doing it line by line, creature by creature. Right now I have creatures or tutu, then creatures for bgt with each creature patched independently.

 

which one is going to be quicker and more efficient, patching via the first code repeatedly, patching via pro5's code semi-repeatedly, or running the big recheck at the end of each major component?

 

Most of all, con you folks teach me what the difference between

READ_LONG 0x2b8 ~itemslot~

and

READ_LONG 0x2c0 "itm_num" ELSE 0

is functionally?

Link to comment

CamDawg's code says:

 

Go to the offset where the list of items starts, and read each one until we've counted a number equal to the count of items in the creature file. If there isn't anything where the pointer should be to that offset, assume zero.

 

pro5's code says:

 

Go to the offset where the list of items starts, and read in 0x14 byte chunks until you reach the point in the creature where the item slot assignation is listed, because that's usually after the item list.

 

They should be functionally identical and patch everything in the same way, unless a modder has put together a creature in a non-standard order.

 

FOR loops and WHILE loops aren't really different :p

 

You might it best to use a regexp locally to spit out a list of everything that needs patching, and then patch just those things (I do rather a lot of this :p ) e.g. :

 

COPY ~blank.log~ ~override/tutu_items_to_bgt.log~

APPEND ~tutu_items_to_bgt.log~ ~COPY_EXISTING~

COPY_EXISTING_REGEXP GLOB ~^.+\.cre$~ ~override~
 PATCH_IF (%SOURCE_SIZE% > 0x2d3) THEN BEGIN
SET "tutu_item" = 0x00
READ_STRREF 0x008 "ln"
READ_LONG   0x2bc "ilo"
READ_LONG   0x2c0 "ilc"
FOR ("i1" = "ilo"; "i1" < ("ilo" + (0x14 * "ilc")); "i1" += 0x14) BEGIN
  READ_BYTE "i1" "underscore"
  PATCH_IF ("underscore" = 0x5f) THEN BEGIN
	SET "tutu_item" = 0x01
  END
END
PATCH_IF ("tutu_item" = 0x01) THEN BEGIN
  INNER_ACTION BEGIN
	APPEND ~tutu_items_to_bgt.log~ ~~~~~~%SOURCE_RES%~ ~override~ // %ln% ~~~~~
  END
END
 END
BUT_ONLY_IF_IT_CHANGES

Link to comment

OK, if I am readying and understanding correctly, pro5's code is cool because it looks through the list until it sees the item slots; CamDwg's is cool because it identifies the number of items assigned and works through that number. If I have this correct, then the more robust way of coding this is to use CamDawg's way, so that if a .cre is built in a non-standard order (which DLTCEP shows in many different mods, including BG1 NPCs, with the "reordering: harmless non-standard order" or some such message).

 

The silliness I am doing to each creature can be taken out, and at the end of the component can be run via INCLUDE to catch any and all creatures with items checking to see if they have Tutu item resrefs and patching them accordingly (dropping many individual item checks with one check for the "main component", and one check at the end for each of the few romance components that add creatures).

 

Steps to take:

  1. remove any LAUNCH_PATCH_MACRO calls to allow the .cre errors already fixed to resurface.
  2. Install the adjusted internal on a clean BGT install.
  3. Run Nythrun's Item Catch-All on the BGT installation.
    /* Nythrun's Item Catch-All */
    COPY ~blank.log~ ~override/tutu_items_to_bgt.log~
    
    APPEND ~tutu_items_to_bgt.log~ ~COPY_EXISTING~
    
    COPY_EXISTING_REGEXP GLOB ~^.+\.cre$~ ~override~
     PATCH_IF (%SOURCE_SIZE% > 0x2d3) THEN BEGIN
    SET "tutu_item" = 0x00
    READ_STRREF 0x008 "ln"
    READ_LONG   0x2bc "ilo"
    READ_LONG   0x2c0 "ilc"
    FOR ("i1" = "ilo"; "i1" < ("ilo" + (0x14 * "ilc")); "i1" += 0x14) BEGIN
      READ_BYTE "i1" "underscore"
      PATCH_IF ("underscore" = 0x5f) THEN BEGIN
    	SET "tutu_item" = 0x01
      END
    END
    PATCH_IF ("tutu_item" = 0x01) THEN BEGIN
      INNER_ACTION BEGIN
    	APPEND ~tutu_items_to_bgt.log~ ~~~~~~%SOURCE_RES%~ ~override~ // %ln% ~~~~~
      END
    END
     END
    BUT_ONLY_IF_IT_CHANGES


  4. Open the file: tutu_items_to_bgt.log and paste the contents as
     DEFINE_PATCH_MACRO ~bg1npc_items_to_bgt~ BEGIN
     ALLOW_MISSING ~crename1.cre~   // allows running this when some components are not installed, like perhaps a romance creature???
    						~crename2.cre~
    						~crename3.cre~
     COPY_EXISTING ~crename1.cre~ ~override~
    						~crename2.cre~ ~override~
    						~crename3.cre~ ~override~
     READ_LONG  0x2bc "itm_off" ELSE 0
     READ_LONG  0x2c0 "itm_num" ELSE 0
     FOR (index = 0; index < itm_num; index = index + 1) BEGIN
    READ_ASCII ("%itm_off%" + (0x14 * "%index%")) "item"
    PATCH_IF ("%item%" STRING_COMPARE_CASE "_DAGG03" = 0) BEGIN
      WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "DAGG03" #8
    END ELSE
    PATCH_IF ("%item%" STRING_COMPARE_CASE "_BOW08" = 0) BEGIN
      WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "BOW08" #8
    END ELSE
    PATCH_IF ("%item%" STRING_COMPARE_CASE "_AROW01" = 0) BEGIN
      WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "AROW01" #8
    END ELSE
    etc, etc., with all of the associated resource names that need conversion
    END
     END
    END


  5. Use REPLACE_CRE_ITEM instead of ADD_CRE_ITEM in all Tutu/BGT .cre entries, so that equipped items are not forced into entry and given as extra "gifts" to the player after this runs.
  6. Individually add pro5's script fixes as they are isolated incidents instead of a large list of materials (I erased a bunch of these by using C_E from BGT resources).

The 2da table I save as a wicked cool idea for dealing with several other problems, but leave off this time because the above code would be faster.

 

Does this look like it will fix the problem efficiently? Fallacies in my logic?

Link to comment

ALLOW_MISSING is a flag that goes in the .tp2 header. When WeiDu is processing this kind of command:

COPY_EXISTING ~imoen.cre~	~override~
		  ~edwin.cre~	~override~
		  ~idontexist.cre~ ~override~

It will error out and stop running the .tp2, which means you don't get to install. ALLOW_MISSING ~idontexist.cre~ in the header will tell WeiDU to make up a zero byte ~idontexist.cre~ if it can't find one in the game to copy (this is, incidentally, another reason to include those filesize sanity checks - if you only PATCH_IF when the file size is greater than zero, WeiDU won't copy that invented zero byte file into the override because of BUT_ONLY_IF_IT_CHANGES :p )

Link to comment

OK, once I remembered mod-making 101, and actually created a backup folder and a blank blank.log, everything went great - wicked cool :p

The good news is that for item corretion, we are looking at very little. Instead of doing individual lines and a big library fix, the following .cres popped up: in override/tutu_items_to_bgt.log,

COPY_EXISTING
~X#AJANFI~ ~override~ // Ajantis, The Knight 
~X#AJDOUG~ ~override~ // Douglas 
~X#ANDART~ ~override~ // Andarthe 
~X#BEADO1~ ~override~ // Beador 
~X#BEADOR~ ~override~ // Beador 
~X#CORAFI~ ~override~ // Coran, The Peerless Archer 
~X#GARWYL~ ~override~ // Myr'Cutio 
~X#GARZ01~ ~override~ // Zombie 
~X#GARZ02~ ~override~ // Zombie 
~X#GARZ03~ ~override~ // Zombie 
~X#GARZ04~ ~override~ // Zombie 
~X#JELLY~ ~override~ // Green Slime 
~X#MARETH~ ~override~ // Maretha 
~X#NATAN~ ~override~ // Natan 
~X#SLIME~ ~override~ // Green Slime 
~X#XVART1~ ~override~ // Xvart 
~X#XVART2~ ~override~ // Xvart 
~X#XZGU01~ ~override~ // Flaming Fist Officer 
~X#XZGU03~ ~override~ // Flaming Fist Battle Wizard

This matches pro5s findings plus my original findings. All of these creatures are already ALLOW_MISSING at the top of the tp2, as we set up for Tutu Walking Speeds check.

So, although it is overkill when pro5 has already done the work, I have learned alot - and will set this up as a macro for the experience.

Although the 0 file is copied at the beginning, we can just do a check for this at the end of each of the component installs which has any of the creatures (only 4 components, I think) tailored to the list of .cres available for speed:

 COPY_EXISTING  ~X#AJANFI~ ~override~ // Ajantis, The Knight 
		~X#AJDOUG~ ~override~ // Douglas 
	~X#ANDART~ ~override~ // Andarthe 
	~X#BEADO1~ ~override~ // Beador 
	~X#BEADOR~ ~override~ // Beador 
	~X#CORAFI~ ~override~ // Coran, The Peerless Archer 
	~X#GARWYL~ ~override~ // Myr'Cutio 
	~X#GARZ01~ ~override~ // Zombie 
	~X#GARZ02~ ~override~ // Zombie 
	~X#GARZ03~ ~override~ // Zombie 
	~X#GARZ04~ ~override~ // Zombie 
	~X#JELLY~ ~override~ // Green Slime 
	~X#MARETH~ ~override~ // Maretha 
	~X#NATAN~ ~override~ // Natan 
	~X#SLIME~ ~override~ // Green Slime 
	~X#XVART1~ ~override~ // Xvart 
	~X#XVART2~ ~override~ // Xvart 
	~X#XZGU01~ ~override~ // Flaming Fist Officer 
	~X#XZGU03~ ~override~ // Flaming Fist Battle Wizard
	  PATCH_IF (SOURCE_SIZE > 0x2d3) BEGIN
		LAUNCH_PATCH_MACRO ~tutu_items_to_bgt~
			   END	
		   BUT_ONLY_IF_IT_CHANGES 

In D:\BGTtest7\BG1NPC\LIB\macro_tutu_items_to_bgt.tph

 
DEFINE_PATCH_MACRO ~tutu_items_to_bgt~ BEGIN
 READ_LONG  0x2bc "itm_off" ELSE 0
 READ_LONG  0x2c0 "itm_num" ELSE 0
 FOR (index = 0; index < itm_num; index = index + 1) BEGIN
READ_ASCII ("%itm_off%" + (0x14 * "%index%")) "item"
PATCH_IF ("%item%" STRING_COMPARE_CASE "_DAGG03" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "DAGG03" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_BOW08" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "BOW08" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_AROW01" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "AROW01" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_POTN37" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "POTN37" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_POTN36" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "POTN36" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_POTN45" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "POTN45" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_MISC33" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "MISC33" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_DAGG01" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "DAGG01" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_AGEBRAC" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "MAGEBRAC" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_HELM09" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "HELM09" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_PLAT01" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "PLAT01" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SHLD01" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SHLD01" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SW1H04" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SW1H04" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SHLD08" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SHLD08" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SW1H08" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SW1H08" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SCRL96" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SCRL96" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_STAF02" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "STAF02" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_CHAN04" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "CHAN04" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_BOW03" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "BOW03" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SW1H07" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SW1H07" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SW2H01" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SW2H01" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_HELM11" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "HELM11" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_PLAT04" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "PLAT04" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_STAF07" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "STAF07" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_CHAN05" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "CHAN05" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_SW1H24" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "SW1H24" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_RING94" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "RING94" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_RING95" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "RING95" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_B1-8" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "B1-8" #8
END ELSE
PATCH_IF ("%item%" STRING_COMPARE_CASE "_JELLGR1" = 0) BEGIN
  WRITE_ASCII ("%itm_off%" + (0x14 * "%index%")) "JELLGR1" #8
END
 END
END

I think I nested that right... and I think the BUT_ONLY works there - no time to test tonight, but always appreciate feedback...

 

ok, so codebox is not the best way to get the nexting viewed... live n' learn :p

Link to comment

Archived

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

×
×
  • Create New...