diff --git a/TomeAndBlood/TomeAndBlood.tp2 b/TomeAndBlood/TomeAndBlood.tp2 index cfad2ff..fe65887 100755 --- a/TomeAndBlood/TomeAndBlood.tp2 +++ b/TomeAndBlood/TomeAndBlood.tp2 @@ -1,6 +1,6 @@ BACKUP ~weidu_external/backup/TomeAndBlood~ AUTHOR ~aquadrizzt~ -VERSION ~0.9.49~ +VERSION ~0.9.50~ ALWAYS @@ -620,7 +620,12 @@ REQUIRE_PREDICATE (FILE_EXISTS_IN_GAME ~enginest.2da~) @3 COPY_EXISTING ~sw1h01.itm~ ~override/qdtnb_arcanist.qd~ //detection for this component LAF semi_spontaneous_casting END -LAF semi_arcane_spells END +ACTION_IF !(FILE_EXISTS_IN_GAME ~d5__5E_casting_arcane.d5~) BEGIN + ACTION_IF !(FILE_EXISTS_IN_GAME ~d5_new_identify.d5~) BEGIN + LAF semi_spont_identify END + END + LAF semi_arcane_spells END +END LAF process_semi_spells END INCLUDE ~TomeAndBlood/comp/setup_arcanist.tpa~ diff --git a/TomeAndBlood/lib/semi_spontaneous.tpa b/TomeAndBlood/lib/semi_spontaneous.tpa index 2a888fb..4877c49 100755 --- a/TomeAndBlood/lib/semi_spontaneous.tpa +++ b/TomeAndBlood/lib/semi_spontaneous.tpa @@ -1,5 +1,5 @@ -// v10.12 - new combined semi_innate / point table optional +// v10.15 - addressing SDRT Wondrous Recall /* @@ -114,7 +114,10 @@ functions in this file: NB: putting spells in a sequencer will no exhaust any spell slots - semi_spont_identify - line 7450 - converts Identify to a spell you cast on the main screen, instead of using within the inventory screen + converts Identify to a spell you cast on the main screen, instead of using within the inventory screen + +- miscellaneous helper functions - line 7558 + some functions used by the above items */ @@ -846,6 +849,38 @@ ACTION_IF !(FILE_EXISTS_IN_GAME ~d5shm-7.spl~) BEGIN END +//quickly address wondrous recall_____________________________________________________ +// + +ACTION_IF (MOD_IS_INSTALLED ~d5_random_tweaks.tp2~ ~1611~) BEGIN + COPY_EXISTING ~sppr611.spl~ ~override~ + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-2~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-2~ END + BUT_ONLY + ACTION_IF (FILE_EXISTS_IN_GAME ~dvsrv4here.mrk~) BEGIN + ACTION_IF (FILE_EXISTS_IN_GAME ~potn43.spl~) BEGIN +// COPY_EXISTING ~sppr611.spl~ ~override/potn43.spl~ + COPY_EXISTING ~potn43.spl~ ~override~ + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-2~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-2~ END + IF_EXISTS BUT_ONLY + END + END +END + + //prepare prepare spells spell________________________________________________________ // OUTER_SET prep_message = RESOLVE_STR_REF(@203) @@ -3801,6 +3836,29 @@ ACTION_IF !(FILE_EXISTS_IN_GAME ~d5src-9.spl~) BEGIN END +//quickly address wondrous recall_____________________________________________________ +// +ACTION_IF (MOD_IS_INSTALLED ~d5_random_tweaks.tp2~ ~1611~) BEGIN + COPY_EXISTING ~sppr611.spl~ ~override~ + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-2~ END + BUT_ONLY + ACTION_IF (FILE_EXISTS_IN_GAME ~dvsrv4here.mrk~) BEGIN + ACTION_IF (FILE_EXISTS_IN_GAME ~potn43.spl~) BEGIN +// COPY_EXISTING ~sppr611.spl~ ~override/potn43.spl~ + COPY_EXISTING ~potn43.spl~ ~override~ + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5src-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5src-2~ END + IF_EXISTS BUT_ONLY + END + END +END + + //daily spell slot refresh____________________________________________________________ // COPY ~%MOD_FOLDER%/lib/semi_spont/d5zcast.bam~ ~override~ @@ -4944,6 +5002,29 @@ ACTION_IF !(FILE_EXISTS_IN_GAME ~d5shm-7.spl~) BEGIN END +//quickly address wondrous recall_____________________________________________________ +// +ACTION_IF (MOD_IS_INSTALLED ~d5_random_tweaks.tp2~ ~1611~) BEGIN + COPY_EXISTING ~sppr611.spl~ ~override~ + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-2~ END + BUT_ONLY + ACTION_IF (FILE_EXISTS_IN_GAME ~dvsrv4here.mrk~) BEGIN + ACTION_IF (FILE_EXISTS_IN_GAME ~potn43.spl~) BEGIN +// COPY_EXISTING ~sppr611.spl~ ~override/potn43.spl~ + COPY_EXISTING ~potn43.spl~ ~override~ + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-1~ END + LPF DELETE_EFFECT INT_VAR match_opcode = 321 STR_VAR match_resource = ~d5shm-2~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-1~ END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 321 target = 1 timing = 9 STR_VAR resource = ~d5shm-2~ END + IF_EXISTS BUT_ONLY + END + END +END + + //daily spell slot refresh____________________________________________________________ // COPY ~%MOD_FOLDER%/lib/semi_spont/d5zcast.bam~ ~override~ @@ -5268,8 +5349,8 @@ END // end define function DEFINE_ACTION_FUNCTION semi_innate_casting INT_VAR semi_innate_stat = 109 semi_innate_shift = 20 STR_VAR semi_innate_prefix = ~~ semi_innate_array = ~~ points_table = ~x~ table_spl = ~~ BEGIN -APPEND ~splprot.2da~ ~D5_INNATE_PTS%TAB%%semi_innate_stat%%TAB%-1%TAB%7~ UNLESS ~D5_INNATE_PTS~ -APPEND ~splprot.2da~ ~D5_INNATE=PTS%TAB%%semi_innate_stat%%TAB%-1%TAB%8~ UNLESS ~D5_INNATE=PTS~ +APPEND ~splprot.2da~ ~D5_INNATE_%semi_innate_stat%%TAB%%semi_innate_stat%%TAB%-1%TAB%7~ UNLESS ~D5_INNATE_%semi_innate_stat%~ +APPEND ~splprot.2da~ ~D5_INNATE=%semi_innate_stat%%TAB%%semi_innate_stat%%TAB%-1%TAB%8~ UNLESS ~D5_INNATE=%semi_innate_stat%~ APPEND ~splprot.2da~ ~D5_FATIGUE_0%TAB%30%TAB%0%TAB%1~ UNLESS ~D5_FATIGUE_0~ APPEND ~splprot.2da~ ~D5_FATIGUE_1%TAB%30%TAB%1%TAB%4~ UNLESS ~D5_FATIGUE_1~ @@ -5278,10 +5359,10 @@ COPY_EXISTING ~splprot.2da~ ~override~ READ_2DA_ENTRIES_NOW rows cols FOR (row = 1; row < rows; ++row) BEGIN READ_2DA_ENTRY_FORMER rows row 0 ~stat~ - PATCH_IF (~%stat%~ STRING_EQUAL_CASE ~D5_INNATE_PTS~) BEGIN + PATCH_IF (~%stat%~ STRING_EQUAL_CASE ~D5_INNATE_%semi_innate_stat%~) BEGIN SET fake_innate_slots = %row% END - PATCH_IF (~%stat%~ STRING_EQUAL_CASE ~D5_INNATE=PTS~) BEGIN + PATCH_IF (~%stat%~ STRING_EQUAL_CASE ~D5_INNATE=%semi_innate_stat%~) BEGIN SET fake_innate_equal = %row% END PATCH_IF (~%stat%~ STRING_EQUAL_CASE ~D5_FATIGUE_0~) BEGIN @@ -5567,10 +5648,10 @@ ACTION_PHP_EACH EVAL ~%semi_innate_array%~ AS semi => spell BEGIN ELSE BEGIN LPF ADD_SPELL_EFFECT INT_VAR opcode = 146 target = 2 power = 0 parameter2 = 1 timing = 1 STR_VAR resource = EVAL ~%cast_spell%~ END END + LPF ADD_SPELL_EFFECT INT_VAR opcode = 326 target = 1 parameter1 = 0 parameter2 = %fatigue_zero% timing = 1 STR_VAR resource = ~d5xxfat~ END LPF ADD_SPELL_EFFECT INT_VAR opcode = 146 target = 1 parameter2 = 1 timing = 1 STR_VAR resource = EVAL ~%semi_innate_prefix%x-1~ END LPF ADD_SPELL_EFFECT INT_VAR opcode = 146 target = 1 parameter2 = 1 timing = 1 duration = 0 STR_VAR resource = EVAL ~%semi_innate_prefix%172~ END LPF ADD_SPELL_EFFECT INT_VAR opcode = 146 target = 1 parameter2 = 1 timing = 4 duration = 1 STR_VAR resource = EVAL ~%semi_innate_prefix%pls~ END - LPF ADD_SPELL_EFFECT INT_VAR opcode = 326 target = 1 parameter1 = 0 parameter2 = %fatigue_zero% timing = 1 STR_VAR resource = ~d5xxfat~ END BUT_ONLY // make spells adding the innate spell CREATE SPL ~%give_spell%~ @@ -7556,4 +7637,710 @@ END // end define function //__________________________________________________________________________________ //__________________________________________________________________________________ +// MISCELLANEOUS HELPER FUNCTIONS + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +// found by Ardanis in Rogue Rebalancing, had apparently been written by Nythrun +// fixed two things, wrapped a function over it + +DEFINE_PATCH_FUNCTION ~FJ_SPL_ITM_REINDEX~ BEGIN + +PATCH_IF !(~%SOURCE_FILE%~ STRING_MATCHES_REGEXP ~^.+\.spl~) BEGIN + hs = 0x28 + WRITE_LONG 0xc ~-1~ //Identified name + WRITE_LONG 0x54 ~-1~ //Identified description + PATCH_FOR_EACH tz IN 0x44 0x48 0x58 0x5c BEGIN + WRITE_LONG tz 0 + END +END ELSE PATCH_IF !(~%SOURCE_FILE%~ STRING_MATCHES_REGEXP ~^.+\.itm~) BEGIN + hs = 0x38 +END +READ_LONG 0x64 hf //Extended header offset +READ_SHORT 0x68 hc //Extended header count +READ_LONG 0x6a fb //Feature block table offset +READ_SHORT 0x70 fc //Feature block count +PATCH_IF ((hf > fb) AND (hc > 0)) BEGIN // Ardanis: fixed "hc > 1" to "hc > 0" + READ_ASCII hf ~eh~ ELSE ~fail~ (hs * hc) + PATCH_IF (~%eh%~ STRING_EQUAL ~fail~) BEGIN + WHILE ((~%eh%~ STRING_EQUAL ~fail~) AND (hc > 0)) BEGIN + READ_ASCII hf ~eh~ ELSE ~fail~ (hs * hc) + hc -= 1 + END + END + DELETE_BYTES hf (hs * hc) + hf = 0x72 + WRITE_LONG 0x64 hf + WRITE_SHORT 0x68 hc + fb = (0x72 + (hs * hc)) + WRITE_LONG 0x6a fb + PATCH_IF !(~%eh%~ STRING_EQUAL ~fail~) BEGIN + INSERT_BYTES hf (hs * hc) + WRITE_ASCIIE hf ~%eh%~ + END +END ELSE PATCH_IF ((hf != 0x72) AND (hc = 0)) BEGIN + hf = 0x72 + WRITE_LONG 0x64 hf +END +FOR (i1 = 0; i1 < (hs * hc); i1 += hs) BEGIN + WRITE_SHORT (hf + i1 + 0x20) fc + READ_SHORT (hf + i1 + 0x1e) cx + fc += cx +END +PATCH_IF (SOURCE_SIZE > (0x72 + (hs * hc) + (0x30 * fc))) BEGIN + DELETE_BYTES (0x72 + (hs * hc) + (0x30 * fc)) (SOURCE_SIZE - (0x72 + (hs * hc) + (0x30 * fc))) +END + +// added by Ardanis +WRITE_SHORT 0x6e 0 + +END // end of function + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +DEFINE_PATCH_FUNCTION ~ADD_ITEM_HEADER~ + INT_VAR + type=3 + required_id=0 + location=3 + alt_dicesize=0 + target=1 + target_count=0 + range=0 + projectile_type=0 + alt_dicenumber=0 + speed=0 + alt_damage=0 + thaco=0 + dicesize=0 + school=0 + dicenumber=0 + sectype=0 + damage=0 + damage_type=0 + charges=0 + depletion=0 + flags=0 + projectile=1 + overhand=0 + backhand=0 + thrust=0 + is_bow=0 + is_xbow=0 + is_sling=0 + copy_header=0 + insert_point=~-1~ + STR_VAR + icon=~~ + RET + insert_point +BEGIN + LPF ~FJ_SPL_ITM_REINDEX~ END + hs=0x38 + + READ_LONG 0x64 ho + READ_SHORT 0x68 hc + READ_LONG 0x6a eo + insert_point = (insert_point>hc || insert_point<0) ? hc : insert_point + copy_header = (copy_header<0) ? 0 : copy_header + + PATCH_IF copy_header>hc BEGIN + PATCH_WARN ~Unable to copy %copy_header%th header, %SOURCE_FILE% contains only %hc% headers!~ + END ELSE BEGIN + INSERT_BYTES ho+insert_point*hs hs + hc+=1 + eo+=hs + PATCH_IF copy_header BEGIN + READ_SHORT ho+(copy_header - 1)*hs+0x1e ec + READ_SHORT ho+(copy_header - 1)*hs+0x20 ei + READ_ASCII eo+ei*0x30 effs (ec*0x30) + READ_ASCII ho+(copy_header - 1)*hs copy (hs) + WRITE_ASCIIE ho+insert_point*hs ~%copy%~ (hs) + END + WRITE_SHORT 0x68 hc + WRITE_LONG 0x6a eo + + READ_SHORT 0x70 ei // technically, it is a counter + FOR (i=ho;i fb) AND (hc > 0)) BEGIN // Ardanis: fixed "hc > 1" to "hc > 0" + READ_ASCII hf ~eh~ ELSE ~fail~ (hs * hc) + PATCH_IF (~%eh%~ STRING_EQUAL ~fail~) BEGIN + WHILE ((~%eh%~ STRING_EQUAL ~fail~) AND (hc > 0)) BEGIN + READ_ASCII hf ~eh~ ELSE ~fail~ (hs * hc) + hc -= 1 + END + END + DELETE_BYTES hf (hs * hc) + hf = 0x72 + WRITE_LONG 0x64 hf + WRITE_SHORT 0x68 hc + fb = (0x72 + (hs * hc)) + WRITE_LONG 0x6a fb + PATCH_IF !(~%eh%~ STRING_EQUAL ~fail~) BEGIN + INSERT_BYTES hf (hs * hc) + WRITE_ASCIIE hf ~%eh%~ + END +END ELSE PATCH_IF ((hf != 0x72) AND (hc = 0)) BEGIN + hf = 0x72 + WRITE_LONG 0x64 hf +END +FOR (i1 = 0; i1 < (hs * hc); i1 += hs) BEGIN + WRITE_SHORT (hf + i1 + 0x20) fc + READ_SHORT (hf + i1 + 0x1e) cx + fc += cx +END +PATCH_IF (SOURCE_SIZE > (0x72 + (hs * hc) + (0x30 * fc))) BEGIN + DELETE_BYTES (0x72 + (hs * hc) + (0x30 * fc)) (SOURCE_SIZE - (0x72 + (hs * hc) + (0x30 * fc))) +END +// added by Ardanis +WRITE_SHORT 0x6e 0 +END // end of function + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +DEFINE_PATCH_FUNCTION ~ADD_SPELL_HEADER~ + INT_VAR + type=1 + location=4 + target=1 + target_count=0 + range=0 + required_level=1 + speed=0 + projectile=1 + copy_header=0 + insert_point=~-1~ + STR_VAR + icon=~~ + RET + insert_point +BEGIN + LPF ~FJ_SPL_ITM_REINDEX~ END + hs=0x28 + READ_LONG 0x64 ho + READ_SHORT 0x68 hc + READ_LONG 0x6a eo + insert_point = (insert_point>hc || insert_point<0) ? hc : insert_point + copy_header = (copy_header<0) ? 0 : copy_header + PATCH_IF copy_header>hc BEGIN + PATCH_WARN ~Unable to copy %copy_header%th header, %SOURCE_FILE% contains only %hc% headers!~ + END ELSE BEGIN + INSERT_BYTES ho+insert_point*hs hs + hc+=1 + eo+=hs + PATCH_IF copy_header BEGIN + READ_SHORT ho+(copy_header - 1)*hs+0x1e ec + READ_SHORT ho+(copy_header - 1)*hs+0x20 ei + READ_ASCII eo+ei*0x30 effs (ec*0x30) + READ_ASCII ho+(copy_header - 1)*hs copy (hs) + WRITE_ASCIIE ho+insert_point*hs ~%copy%~ (hs) + END + WRITE_SHORT 0x68 hc + WRITE_LONG 0x6a eo + READ_SHORT 0x70 ei // technically, it is a counter + FOR (i=ho;i 0) BEGIN + APPEND ~splstate.ids~ ~%new_state_ind% %new_state_id%~ + END + END +END +//__________________________________________________________________________________ + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +//JOINABLE NPCS ARRAY MACRO__________________________________________________________ +// +DEFINE_ACTION_MACRO JOINABLE_NPC_ARRAYS BEGIN + //PDIALOG.2DA exists in all games + ACTION_DEFINE_ASSOCIATIVE_ARRAY JOINABLE_NPC_ARRAY_2da BEGIN ~PDIALOG~ => ~~ END + //Check PDIALOG.2DA file variants referenced in CAMPAIGN.2DA + ACTION_IF FILE_EXISTS_IN_GAME ~CAMPAIGN.2DA~ BEGIN + COPY_EXISTING ~CAMPAIGN.2DA~ ~CAMPAIGN.2DA~ + COUNT_2DA_ROWS 32 "cntrow" + FOR (i = 0; i < cntrow; i = i + 1) BEGIN + READ_2DA_ENTRY i 11 32 file + TO_UPPER file + DEFINE_ASSOCIATIVE_ARRAY JOINABLE_NPC_ARRAY_2da BEGIN ~%file%~ => ~~ END + END + BUT_ONLY + END + //Generate array with joinable NPC DV + ACTION_PHP_EACH JOINABLE_NPC_ARRAY_2da AS file => ~~ BEGIN + ACTION_IF FILE_EXISTS_IN_GAME ~%file%.2da~ BEGIN + COPY_EXISTING ~%file%.2da~ ~override~ + COUNT_2DA_ROWS 3 "cntrow" + FOR (i = 1; i < cntrow; i = i + 1) BEGIN + READ_2DA_ENTRY i 0 3 "dv" + TO_UPPER dv + DEFINE_ASSOCIATIVE_ARRAY JOINABLE_NPC_ARRAY_dv BEGIN ~%dv%~ => ~~ END + END + BUT_ONLY + END + END + //Generate array with joinable NPC cre files + COPY_EXISTING_REGEXP GLOB ~.+\.CRE~ ~override~ + READ_ASCII DEATHVAR "dv" (32) NULL + TO_UPPER dv + PATCH_IF VARIABLE_IS_SET $JOINABLE_NPC_ARRAY_dv(~%dv%~) BEGIN + DEFINE_ASSOCIATIVE_ARRAY JOINABLE_NPC_ARRAY BEGIN ~%SOURCE_FILE%~ => ~%dv%~ END + END + PATCH_IF NOT VARIABLE_IS_SET $JOINABLE_NPC_ARRAY_dv(~%dv%~) BEGIN + DEFINE_ASSOCIATIVE_ARRAY NON_JOINABLE_NPC_ARRAY BEGIN ~%SOURCE_FILE%~ => ~%dv%~ END + END + BUT_ONLY +END +//__________________________________________________________________________________ + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +///// \\\\\ +///// spell_to_innate \\\\\ +///// \\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ +/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\/////\\\\\ + +// converts spell to innate and lowers casting time by two + +DEFINE_PATCH_MACRO ~spell_to_innate~ BEGIN + + READ_LONG 0x64 abil_off ELSE 0 + READ_SHORT 0x68 abil_num ELSE 0 + READ_ASCII (abil_off + 0x04) bam (8) // reads the bam filename from ability + WRITE_SHORT 0x1C 4 // sets spell type to innate (4) + WRITE_LONG 0x34 1 // sets spell level to 1 to avoid scripting issues + WRITE_ASCIIE 0x3A "%bam%" #8 // writes the bam filename from abilities to spell icon + FOR (index = 0 ; index < abil_num ; ++index) BEGIN + WRITE_SHORT (abil_off + 0x02 + (0x28 * index)) 4 // changes ability icon location to innate (4) + READ_SHORT (abil_off + 0x12 + (0x28 * index)) speed // reads casting speed + PATCH_IF (speed > 3) BEGIN + WRITE_SHORT (abil_off + 0x12 + (0x28 * index)) (speed - 2) // reduces casting speed + END ELSE BEGIN + WRITE_SHORT (abil_off + 0x12 + (0x28 * index)) 0 // makes instant + END + END + +END + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +// fix kitlist IDS entries + +DEFINE_ACTION_FUNCTION fix_kitlist_missing_ids BEGIN + COPY_EXISTING ~kitlist.2da~ ~override~ + PRETTY_PRINT_2DA + PATCH_IF ~%entry%~ STR_EQ ~~ BEGIN + READ_2DA_ENTRY 1 0 1 "entry" + END + COUNT_2DA_COLS "cols" + SET cnt = 0 + REPLACE_EVALUATE ~^\(.+\)$~ BEGIN + PATCH_IF cnt >= 3 BEGIN + INNER_PATCH_SAVE MATCH1 ~%MATCH1%~ BEGIN + COUNT_REGEXP_INSTANCES ~ +~ num_matches + WHILE (num_matches < (cols - 1)) BEGIN + REPLACE_TEXTUALLY ~$~ ~ ZZZZZ~ + SET num_matches = num_matches + 1 + END + END + END ELSE BEGIN + SET cnt = cnt + 1 + END + END ~%MATCH1%~ + PRETTY_PRINT_2DA + BUT_ONLY + COPY_EXISTING ~kitlist.2da~ ~override~ + COUNT_2DA_ROWS 10 rows + FOR (row = 1; row < rows; ++row) BEGIN + SET val = (row - 12) + TEXT_SPRINT new_ids ~000040%val%~ + READ_2DA_ENTRY row 9 10 ids_val + PATCH_IF !(IS_AN_INT ~%ids_val%~) BEGIN + SET_2DA_ENTRY row 9 10 ~0x%new_ids%~ + END + END + BUT_ONLY +END + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +// Automatically fixes missing column entries in 2da files. Can be used as both patch and action function + +DEFINE_ACTION_FUNCTION 2DA_MISSING_COLS + INT_VAR + cols = 0 //minimum amount of columns that should have values (if not set function will automatically read max number of columns in file) + STR_VAR + 2da = ~~ //2da file that should be patched, e.g. kitlist + entry = ~~ //what entry should be set in missing columns (if not set function will automatically read default entry from loaded 2da, e.g. *) +BEGIN + ACTION_IF ~%2da%~ STR_EQ ~~ BEGIN + FAIL ~2DA_MISSING_COLS: %2da% STR_VAR not set~ + END + COPY_EXISTING ~%2da%.2da~ ~override~ + PRETTY_PRINT_2DA + PATCH_IF ~%entry%~ STR_EQ ~~ BEGIN + READ_2DA_ENTRY 1 0 1 "entry" + END + PATCH_IF cols = 0 BEGIN + COUNT_2DA_COLS "cols" + END + SET cnt = 0 + REPLACE_EVALUATE ~^\(.+\)$~ BEGIN + PATCH_IF cnt >= 3 BEGIN + INNER_PATCH_SAVE MATCH1 ~%MATCH1%~ BEGIN + COUNT_REGEXP_INSTANCES ~ +~ num_matches + WHILE (num_matches < (cols - 1)) BEGIN + REPLACE_TEXTUALLY ~$~ ~ %entry%~ + SET num_matches = num_matches + 1 + END + END + END ELSE BEGIN + SET cnt = cnt + 1 + END + END ~%MATCH1%~ + PRETTY_PRINT_2DA + BUT_ONLY +END + +DEFINE_PATCH_FUNCTION 2DA_MISSING_COLS + INT_VAR + cols = 0 //minimum amount of columns that should have values (if not set function will automatically read max number of columns in file) + STR_VAR + entry = ~~ //what entry should be used in missing columns (if not set function will automatically read default entry from loaded 2da, e.g. *) +BEGIN + PRETTY_PRINT_2DA + PATCH_IF ~%entry%~ STR_EQ ~~ BEGIN + READ_2DA_ENTRY 1 0 1 "entry" + END + PATCH_IF cols = 0 BEGIN + COUNT_2DA_COLS "cols" + END + SET cnt = 0 + REPLACE_EVALUATE ~^\(.+\)$~ BEGIN + PATCH_IF cnt >= 3 BEGIN + INNER_PATCH_SAVE MATCH1 ~%MATCH1%~ BEGIN + COUNT_REGEXP_INSTANCES ~ +~ num_matches + WHILE (num_matches < (cols - 1)) BEGIN + REPLACE_TEXTUALLY ~$~ ~ %entry%~ + SET num_matches = num_matches + 1 + END + END + END ELSE BEGIN + SET cnt = cnt + 1 + END + END ~%MATCH1%~ + PRETTY_PRINT_2DA +END + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +/* do this in the code...?? +OUTER_INNER_PATCH ~1~ BEGIN + WRITE_BYTE 0 0x09 + READ_ASCII 0 tab (1) // 0x09, tab + WRITE_BYTE 0 0x0d + READ_ASCII 0 mnl (1) // 0x0d, Mac +END +*/ + +DEFINE_PATCH_FUNCTION ~TRA2STR~ // given tra reference, returns string + STR_VAR tra = ~~ // e.g. ~@123~ + RET str +BEGIN + PATCH_IF ((~%tra%~ STRING_MATCHES_REGEXP ~@-?[0-9]+~) == 0) BEGIN + INNER_ACTION BEGIN + <<<<<<<< .../inlined/mi_tra2str.tph + OUTER_SPRINT str %tra% + >>>>>>>> + COPY - ~.../inlined/mi_tra2str.tph~ ~.../inlined/mi_tra2str.tph~ + EVALUATE_BUFFER + REINCLUDE ~.../inlined/mi_tra2str.tph~ + END + END + ELSE BEGIN + TEXT_SPRINT str ~%tra%~ + END +END + +DEFINE_ACTION_FUNCTION ~ADD_ITEM_TOOLTIPS~ + STR_VAR item = ~~ // e.g. ~sw1h01~ + tooltips = ~~ // e.g. ~@123 @124 6620~, takes combination of tra refs and strrefs for as many abilities as you need to specify +BEGIN + ACTION_IF (STRING_LENGTH ~%item%~ > 0) BEGIN + // generate our row to add to tooltip.2da + OUTER_TEXT_SPRINT row ~%item%~ + OUTER_PATCH ~ %tooltips%~ BEGIN // extract our tooltips from the tooltips string + REPLACE_EVALUATE ~[ %tab%]+\(@?-?[0-9]+\)~ BEGIN + PATCH_IF ((~%MATCH1%~ STRING_MATCHES_REGEXP ~@-?[0-9]+~) == 0) BEGIN // tra ref + // look up string for given tra reference + LAUNCH_PATCH_FUNCTION ~TRA2STR~ STR_VAR tra = EVALUATE_BUFFER ~%MATCH1%~ RET str = str END + // use REPLACE to get a strref for our new string + INNER_PATCH ~0~ BEGIN + REPLACE ~0~ ~%str%~ + READ_2DA_ENTRY 0 0 1 strref + END + TEXT_SPRINT row ~%row% %strref%~ // add to our row + END + ELSE BEGIN // strref + TEXT_SPRINT row ~%row% %MATCH1%~ // add to our row + END + END ~~ + END + + COPY_EXISTING ~tooltip.2da~ ~override~ + REPLACE_TEXTUALLY ~^[ %tab%]*%item%[ %tab%].*~ ~~ // remove previous row for this item if it exists + COUNT_2DA_ROWS 1 num_rows + INSERT_2DA_ROW num_rows 1 ~%row%~ // insert our row at the end + + // ensure all rows have -1 entries in unused columns + REPLACE_TEXTUALLY ~^[ %tab%]*0?[ %tab%]*1[ %tab%]+2[ %tab%]+3.*~ ~~ // remove column labels for now + COUNT_2DA_COLS num_cols + TEXT_SPRINT entries ~~ + TEXT_SPRINT col_labels ~~ + FOR (i = 1; i < (num_cols - 1); i += 1) BEGIN // for each number of columns less than there should be + TEXT_SPRINT entries ~%entries%[ %tab%]+[0-9-]+~ // generate regexp to detect this many columns + TEXT_SPRINT empties ~~ + FOR (j = (num_cols - 1); j > i; j -= 1) BEGIN // generate -1 entries for the number of missing columns + TEXT_SPRINT empties ~%empties% -1~ + END + REPLACE_TEXTUALLY ~^\([ %tab%]*[^ %tab%]+%entries%\)[ %tab%]*[%mnl%]?$~ ~\1%empties%~ // add -1 entries to all rows with this many missing columns + TEXT_SPRINT col_labels ~%col_labels% %i%~ // generate fresh column labels + END + INSERT_2DA_ROW 2 1 ~%col_labels% %i%~ // re-add column labels, with last entry where i == (num_cols - 1) + PRETTY_PRINT_2DA + REPLACE_TEXTUALLY ~2DA +~ ~2DA ~ + + END +END + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +DEFINE_PATCH_FUNCTION QD_ADD_EMPTY_SPELL_HEADER +INT_VAR + type = 1 + location = 4 + target = 1 + target_count = 0 + range = 0 + required_level = 1 + speed = 0 + projectile = 1 + copy_header = 0 + insert_point = ~-1~ +STR_VAR + icon = ~~ +RET + insert_point +BEGIN + SET hs = 0x28 + READ_LONG 0x64 ho + READ_SHORT 0x68 hc + READ_LONG 0x6a eo + SET insert_point = (insert_point > hc || insert_point < 0) ? hc : insert_point + SET copy_header = (copy_header < 0) ? 0 : copy_header + PATCH_IF (copy_header > hc) BEGIN + PATCH_WARN ~WARNING: Unable to copy %copy_header%th header, %SOURCE_FILE% contains only %hc% headers!~ + END ELSE BEGIN + INSERT_BYTES (ho + insert_point * hs) hs + SET hc += 1 + SET eo += hs + PATCH_IF (copy_header) BEGIN + READ_SHORT (ho + (copy_header - 1) * hs + 0x1e) ec + READ_SHORT (ho + (copy_header - 1) * hs + 0x20) ei + READ_ASCII (eo + ei * 0x30) effs (ec * 0x30) + READ_ASCII (ho + (copy_header - 1) * hs) copy (hs) + WRITE_ASCIIE (ho + insert_point * hs) ~%copy%~ (hs) + END + WRITE_SHORT 0x68 hc + WRITE_LONG 0x6a eo + READ_SHORT 0x70 ei // technically, it is a counter + FOR (i = ho; i < ho + hc * hs; i += hs) BEGIN + READ_SHORT (i + 0x1e) ec + WRITE_SHORT (i + 0x20) ei + SET ei += ec + END + PATCH_IF (copy_header) BEGIN + READ_SHORT (ho + insert_point * hs + 0x1e) ec + READ_SHORT (ho + insert_point * hs + 0x20) ei + INSERT_BYTES (eo + ei * 0x30) (ec * 0x30) + WRITE_ASCIIE (eo + ei * 0x30) ~%effs%~ (ec * 0x30) + END ELSE BEGIN + SET off = ho + insert_point * hs + WRITE_BYTE off type + WRITE_BYTE (off + 0x2) location + WRITE_ASCIIE (off + 0x4) ~%icon%~ (8) + WRITE_BYTE (off + 0xc) target + WRITE_BYTE (off + 0xd) target_count + WRITE_SHORT (off + 0xe) range + WRITE_SHORT (off + 0x10) required_level + WRITE_LONG (off + 0x12) speed + WRITE_SHORT (off + 0x26) projectile + END + END +END + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////