diff --git a/readme.md b/readme.md index b8e9f16..082ac8d 100644 --- a/readme.md +++ b/readme.md @@ -42,11 +42,21 @@ The full table: | 24 | 4 | 4 | 4 | 4 | 3 | 2 | 0 | | 25 | 4 | 4 | 4 | 4 | 4 | 3 | 1 | -__COMPATIBILITY:__ This component overlaps with a proposed Tweaks Anthology component and partially overlaps with Scales of Balance's Stat-based Bonus Spells. Compatibility against the latter is untested. +__COMPATIBILITY:__ This component overwrites Tweaks Anthology's Alter Wisdom-Based Divine Bonus Spell Table component and partially overwrites Scales of Balance's Stat-based Bonus Spells. + +## Component 10000 Bag of Spilling + +There is a possibility that installing too many content/item mods pushes out some of the crucial items from a creature's inventory. This component goes through all creatures and collect all such supposed to be __droppable__ but no longer available items and collects them into an unstealable one-way Bag of Spilling to the creature's eighth inventory slot. Undroppable items lost due to megamod installations are not recovered. + +See [here](https://www.gibberlings3.net/forums/topic/35016-do-cres-drop-all-their-assigned-items-or-is-there-a-limit-split-from-please-check-my-install-list-26-eet) for the scenario this component covers. + +For other modders: all the inventory data are exported to plaintext to weidu_external\zgtweaks\equipdump\(spilled-)FILENAME format for possible review. Undroppable spilled items are also listed and commented out. + +__COMPATIBILITY:__ This component needs to come last in your install order. Due to the principle this mod component works, it is possible it exposes a bug in itself and/or in a different mod. Please report any suspicious content you see in these bags. ## Acknowledgements -Thanks for argent77, subtledoctor and CamDawg for code snippets. +Thanks for argent77, subtledoctor, CamDawg and Luke for code snippets. ## Disclaimer diff --git a/zgtweaks/copy/ZGTBAG.BAM b/zgtweaks/copy/ZGTBAG.BAM new file mode 100644 index 0000000..df4da22 Binary files /dev/null and b/zgtweaks/copy/ZGTBAG.BAM differ diff --git a/zgtweaks/copy/ZGTBAG.ITM b/zgtweaks/copy/ZGTBAG.ITM new file mode 100644 index 0000000..4d2210a Binary files /dev/null and b/zgtweaks/copy/ZGTBAG.ITM differ diff --git a/zgtweaks/copy/ZGTBAG.STO b/zgtweaks/copy/ZGTBAG.STO new file mode 100644 index 0000000..f5945e3 Binary files /dev/null and b/zgtweaks/copy/ZGTBAG.STO differ diff --git a/zgtweaks/english/setup.tra b/zgtweaks/english/setup.tra index 2a7375d..7e12145 100644 --- a/zgtweaks/english/setup.tra +++ b/zgtweaks/english/setup.tra @@ -10,4 +10,17 @@ @100 = ~Mixed PnP-BG wisdom-based bonus spells table~ -@1000 = ~This component can only be installed on the Enhanced Edition version of the games.~ \ No newline at end of file +@1000 = ~This component can only be installed on the Enhanced Edition version of the games.~ +@1001 = ~This component can only be installed on the Enhanced Edition and original Baldur's Gate II version of the games.~ + +@10000 = ~Bag of Spilling (move bugged supposed-to-be-available items to a bag in the creature's inventory)~ +@10001 = ~Bag of Spilling~ +@10002 = ~This coarse bag of holding stores various items. Despite your attempts, you cannot use it to store more items into it and you can only take out the items stored within. You can feel these items were somehow forgotten by their previous owner. + +Weight: 5~ +@10003 = ~Coarse Bag of Holding~ +@10004 = ~This bag of holding looks unusual. + +STATISTICS: + +Weight: 5~ \ No newline at end of file diff --git a/zgtweaks/library/spilling.tpa b/zgtweaks/library/spilling.tpa new file mode 100644 index 0000000..fe96142 --- /dev/null +++ b/zgtweaks/library/spilling.tpa @@ -0,0 +1,240 @@ + +/** + * Patch function. Converts any decimal number into a hexadecimal number. + * INT_VAR value The decimal number to convert. + * INT_VAR minDigits Minimum number of digits for the returned hex value. (default: 1) + * INT_VAR prefix A flag that indicates whether the returned number will be prefixed with "0x". (default: 0) + * RET hexNumber The converted hexadecimal number as string. + */ + DEFINE_PATCH_FUNCTION TO_HEX_NUMBER + INT_VAR + value = 0 + minDigits = 1 + prefix = 0 + RET + hexNumber + BEGIN + SET minDigits = (minDigits < 1) ? 1 : minDigits + SET minDigits = (minDigits > 8) ? 8 : minDigits + TEXT_SPRINT hexNumber ~~ + PATCH_DEFINE_ARRAY digit BEGIN ~0~ ~1~ ~2~ ~3~ ~4~ ~5~ ~6~ ~7~ ~8~ ~9~ ~A~ ~B~ ~C~ ~D~ ~E~ ~F~ END + + PATCH_IF (value < 0) BEGIN + SET signed = 1 + SET value = 0 - value + END ELSE BEGIN + SET signed = 0 + END + + WHILE (value != 0) BEGIN + SET curDigit = value BAND 0xf + SET value = value BLSR 4 + TEXT_SPRINT hexDigit $EVAL digit(~%curDigit%~) + TEXT_SPRINT hexNumber ~%hexDigit%%hexNumber%~ + END + + WHILE (STRING_LENGTH ~%hexNumber%~ < minDigits) BEGIN + TEXT_SPRINT hexNumber ~0%hexNumber%~ + END + + PATCH_IF (prefix) BEGIN + TEXT_SPRINT hexNumber ~0x%hexNumber%~ + END + + PATCH_IF (signed) BEGIN + TEXT_SPRINT hexNumber ~-%hexNumber%~ + END + END + + // Action version of TO_HEX_NUMBER + DEFINE_ACTION_FUNCTION TO_HEX_NUMBER + INT_VAR + value = 0 + minDigits = 4 + prefix = 0 + RET + hexNumber + BEGIN + OUTER_PATCH ~~ BEGIN + LPF TO_HEX_NUMBER INT_VAR value = value minDigits = minDigits prefix = prefix RET hexNumber END + END + END + +DEFINE_PATCH_FUNCTION DUMP_CRE_ITEM +RET + spill +BEGIN + DEFINE_ASSOCIATIVE_ARRAY itemflags BEGIN + 0 => "NONE" + 1 => "IDENTIFIED" + 2 => "UNSTEALABLE" + 4 => "STOLEN" + 8 => "UNDROPPABLE" + 5 => "IDENTIFIED&STOLEN" + 3 => "IDENTIFIED&UNSTEALABLE" + 9 => "IDENTIFIED&UNDROPPABLE" + 10 => "UNSTEALABLE&UNDROPPABLE" + 12 => "STOLEN&UNDROPPABLE" + 13 => "IDENTIFIED&STOLEN&UNDROPPABLE" + 11 => "IDENTIFIED&UNSTEALABLE&UNDROPPABLE" + END + + DEFINE_ASSOCIATIVE_ARRAY itemslots BEGIN + 0 => "HELMET" + 1 => "ARMOR" + 2 => "SHIELD" + 3 => "GLOVES" + 4 => "LRING" + 5 => "RRING" + 6 => "AMULET" + 7 => "BELT" + 8 => "BOOTS" + 9 => "WEAPON1" + 10 => "WEAPON2" + 11 => "WEAPON3" + 12 => "WEAPON4" + 13 => "QUIVER1" + 14 => "QUIVER2" + 15 => "QUIVER3" + 16 => "QUIVER4" + 17 => "CLOAK" + 18 => "QITEM1" + 19 => "QITEM2" + 20 => "QITEM3" + 21 => "INV1" + 22 => "INV2" + 23 => "INV3" + 24 => "INV4" + 25 => "INV5" + 26 => "INV6" + 27 => "INV7" + 28 => "INV8" + 29 => "INV9" + 30 => "INV10" + 31 => "INV11" + 32 => "INV12" + 33 => "INV13" + 34 => "INV14" + 35 => "INV15" + 36 => "INV16" + END + + SPRINT path ~./weidu_external/zgtweaks/equipdump/%SOURCE_RES%~ + SPRINT spilledpath ~./weidu_external/zgtweaks/equipdump/spilled-%SOURCE_RES%~ + + SPRINT data ~~ + SPRINT spilleddata ~~ + + INNER_ACTION BEGIN +<<<<<<<< %path% +>>>>>>>> + +<<<<<<<< %spilledpath% +>>>>>>>> + END + + READ_LONG 0x2b8 slot_off ELSE 0 + READ_LONG 0x2bc itm_off ELSE 0 + READ_LONG 0x2c0 itm_num ELSE 0 + + SET spill = 0 + SPRINT bagslot ~~ + SET inv8 = 0 + FOR (index = 0; index < itm_num; ++index) BEGIN + SET currentitem = itm_off + index * 0x14 + READ_ASCII currentitem currentitem_name (8) NULL + READ_SHORT (currentitem + 0x08) currentitem_duration + READ_SHORT (currentitem + 0x0a) currentitem_charges1 + READ_SHORT (currentitem + 0x0c) currentitem_charges2 + READ_SHORT (currentitem + 0x0e) currentitem_charges3 + READ_LONG (currentitem + 0x10) currentitem_flags_value + SPRINT currentitem_flags $itemflags("%currentitem_flags_value%") + SET found = 0 + + FOR (index2 = 0 ; index2 < 36 ; ++index2) BEGIN + READ_SHORT (slot_off + (index2 * 0x02)) ref + PATCH_IF ref = index BEGIN + found = 1 + PATCH_IF index2 = 28 BEGIN // cache INV8 slot for the bag + SPRINT bagslot ~~~~~ ~%currentitem_name%~ #%currentitem_charges1% #%currentitem_charges2% #%currentitem_charges3% ~%currentitem_flags%~ ~~~~~ + PATCH_IF currentitem_flags_value < 8 BEGIN + inv8 = 1 + END ELSE BEGIN // mark if undroppable + inv8 = 2 + END + END ELSE BEGIN + SET equip = 0 + SET twohanded = 0 + SPRINT currentitem_slot $itemslots("%index2%") + + PATCH_IF (index2 > 8 AND index2 < 13) BEGIN + READ_SHORT (slot_off + (38 * 0x02)) equipped_weapon + PATCH_IF index2 - 9 = equipped_weapon BEGIN + equip = 1 + END + + READ_SHORT (slot_off + (2 * 0x02)) shield + PATCH_IF shield = 0xFFFF BEGIN + twohanded = 1 + END + END + + PATCH_IF equip = 1 BEGIN + PATCH_IF twohanded = 1 BEGIN + TEXT_SPRINT append_line ~~~~~ADD_CRE_ITEM ~%currentitem_name%~ #%currentitem_charges1% #%currentitem_charges2% #%currentitem_charges3% ~%currentitem_flags%~ ~%currentitem_slot%~ EQUIP TWOHANDED %WNL%~~~~~ + SPRINT data ~%data% %append_line%~ + END ELSE BEGIN + TEXT_SPRINT append_line ~~~~~ADD_CRE_ITEM ~%currentitem_name%~ #%currentitem_charges1% #%currentitem_charges2% #%currentitem_charges3% ~%currentitem_flags%~ ~%currentitem_slot%~ EQUIP %WNL%~~~~~ + SPRINT data ~%data% %append_line%~ + END + END ELSE BEGIN + TEXT_SPRINT append_line ~~~~~ADD_CRE_ITEM ~%currentitem_name%~ #%currentitem_charges1% #%currentitem_charges2% #%currentitem_charges3% ~%currentitem_flags%~ ~%currentitem_slot%~ %WNL%~~~~~ + SPRINT data ~%data% %append_line%~ + END + END + END + END + + PATCH_IF found = 0 BEGIN // do not stash undroppable items + PATCH_IF currentitem_flags_value < 8 BEGIN + TEXT_SPRINT append_line ~~~~~ADD_STORE_ITEM ~%currentitem_name%~ #%currentitem_charges1% #%currentitem_charges2% #%currentitem_charges3% ~%currentitem_flags%~ #1 %WNL%~~~~~ + END ELSE BEGIN + TEXT_SPRINT append_line ~~~~~// ADD_STORE_ITEM ~%currentitem_name%~ #%currentitem_charges1% #%currentitem_charges2% #%currentitem_charges3% ~%currentitem_flags%~ #1 %WNL%~~~~~ + END + SPRINT spilleddata ~%spilleddata% %append_line%~ + spill = 1 + END + END + + PATCH_IF spill = 0 BEGIN // restore inv8 item if there were no overflow + PATCH_IF inv8 > 0 BEGIN + TEXT_SPRINT append_bag ~~~~~ADD_CRE_ITEM %bagslot% ~INV8~ %WNL%~~~~~ + SPRINT data ~%data% %append_bag%~ + END + END ELSE BEGIN + PATCH_IF inv8 = 1 BEGIN + TEXT_SPRINT append_bag ~~~~~ADD_STORE_ITEM %bagslot% #1 %WNL%~~~~~ + SPRINT spilleddata ~%spilleddata% %append_bag%~ + END + PATCH_IF inv8 = 2 BEGIN + TEXT_SPRINT append_bag ~~~~~// ADD_STORE_ITEM %bagslot% #1 %WNL%~~~~~ + SPRINT spilleddata ~%spilleddata% %append_bag%~ + END + INNER_ACTION BEGIN +<<<<<<<< ./weidu_external/zgtweaks/graionbuffer.buf +%spilleddata% +>>>>>>>> + COPY ~%spilledpath%~ ~%spilledpath%~ + APPEND_FILE_EVALUATE ~./weidu_external/zgtweaks/graionbuffer.buf~ + END + END + + INNER_ACTION BEGIN +<<<<<<<< ./weidu_external/zgtweaks/graionbuffer.buf +%data% +>>>>>>>> + COPY ~%path%~ ~%path%~ + APPEND_FILE_EVALUATE ~./weidu_external/zgtweaks/graionbuffer.buf~ + END +END + diff --git a/zgtweaks/zgtweaks.ini b/zgtweaks/zgtweaks.ini index ef1a414..5d44fc7 100644 --- a/zgtweaks/zgtweaks.ini +++ b/zgtweaks/zgtweaks.ini @@ -6,4 +6,4 @@ Readme = https://github.com/GraionDilach/RandomGraionTweaks/blob/master/readme.m Forum = https://www.gibberlings3.net/forums/topic/34458-random-graion-tweaks/ Download = https://github.com/GraionDilach/RandomGraionTweaks LabelType = GloballyUnique -After = EET, abel_nonrandom_treasures +After = EET, abel_nonrandom_treasures, stratagems diff --git a/zgtweaks/zgtweaks.tp2 b/zgtweaks/zgtweaks.tp2 index 1cf835d..f3d2d1b 100644 --- a/zgtweaks/zgtweaks.tp2 +++ b/zgtweaks/zgtweaks.tp2 @@ -1,6 +1,6 @@ -BACKUP ~weidu_external/backup/zgtweaks~ // location to store files for uninstall purposes +BACKUP ~weidu_external/zgtweaks/backup~ // location to store files for uninstall purposes AUTHOR ~Graion Dilach~ -VERSION ~1.2~ +VERSION ~1.3~ LANGUAGE ~English~ ~english~ ~zgtweaks/english/setup.tra~ @@ -263,3 +263,61 @@ LABEL ZG-BOBW-WISDOM-TABLE DESIGNATED 100 COPY ~%MOD_FOLDER%/2da/mxsplwis.2da~ ~override~ + +BEGIN @10000 +LABEL ZG-BAG-OF-SPILLING +DESIGNATED 10000 +REQUIRE_PREDICATE (GAME_IS ~bgee bg2ee iwdee eet soa tob tutu tutu_totsc bgt ca iwd_in_bg2~) @1000 + +MKDIR ~./weidu_external/zgtweaks/equipdump~ +ACTION_DEFINE_ARRAY spilled_creatures BEGIN END +OUTER_SET array_index = 0 + +INCLUDE ~zgtweaks\library\spilling.tpa~ + +PRINT ~Dumping creature item data...~ +SILENT + +COPY_EXISTING_REGEXP GLOB ~.*\.cre~ ~override~ + LPF DUMP_CRE_ITEM RET spill END + PATCH_IF spill = 1 BEGIN + SPRINT $spilled_creatures(~%array_index%~) ~%SOURCE_RES%~ + array_index += 1 + END +BUT_ONLY + +VERBOSE +PRINT ~Moving excessive items to bags...~ + +COPY ~%MOD_FOLDER%/copy/ZGTBAG.BAM~ ~override~ + +COPY ~%MOD_FOLDER%/copy/ZGTBAG.ITM~ ~weidu_external/zgtweaks~ + SAY NAME1 @10003 + SAY NAME2 @10001 + SAY DESC @10002 + SAY UNIDENTIFIED_DESC @10004 + +OUTER_SET bagindex = 0 +ACTION_PHP_EACH %spilled_creatures% AS crekey => crevalue BEGIN + OUTER_SET bagindex += 1 + ACTION_IF bagindex > 0xFFFF BEGIN + FAIL ~Ran out of bag indexes; component failed to install.~ + END + + LAF TO_HEX_NUMBER INT_VAR value = bagindex RET hexNumber END + + COPY ~weidu_external/zgtweaks/ZGTBAG.ITM~ ~override/ZGTB%hexNumber%.ITM~ + + COPY_EXISTING ~%crevalue%.cre~ ~override~ + REMOVE_CRE_ITEMS + PATCH_REINCLUDE ~weidu_external/zgtweaks/equipdump/%crevalue%~ + ADD_CRE_ITEM ~ZGTB%hexNumber%~ #0 #0 #0 ~IDENTIFIED&UNSTEALABLE~ ~INV1~ + BUT_ONLY + + COPY ~%MOD_FOLDER%/copy/ZGTBAG.STO~ ~override/ZGTB%hexNumber%.STO~ + SAY NAME2 @10001 + PATCH_REINCLUDE ~weidu_external/zgtweaks/equipdump/spilled-%crevalue%~ +END + + +