DavidW Posted September 25, 2023 Share Posted September 25, 2023 For once, a function of mine that doesn't rely on 127 other functions. This one (written in the context of Argent77's 'Magic Shop of Vergadain' mod) edits the UI to let you turn store options off by script. Apart from the specific function, it demos a general way to pass information from scripts to the UI that others might find useful. /* This EE-only function (by DavidW) allows you to restrict which store options (Buy/Sell, Drink, Rest, etc) are offered when a store is open, by adding commands to the script that summons the store. You use it like this: (i) run the function and return the INT_VAR 'inactive_strref' (ii) In the storekeeper's dlg file (or similar), jusst before the StartStore(xxx) command that you use to trigger the store, add commands like SetToken("DW_SIGNAL_STORE_REST",%inactive_strref%) The possible tokens are: DW_SIGNAL_STORE_IDENTIFY DW_SIGNAL_STORE_STEAL DW_SIGNAL_STORE_DONATE DW_SIGNAL_STORE_CURE DW_SIGNAL_STORE_DRINK DW_SIGNAL_STORE_REST Any token set will inactivate the associated option. Tokens remain set until the next time the store interface runs, so it's important only to set them just before opening the store, else they may hang around and mess up the next store. Anyone is welcome to borrow this; just credit me in your readme. v1 (9/24/23): initial version v2 (9/25/23): should handle stealing properly */ DEFINE_ACTION_FUNCTION ui_block_store_function RET inactive_strref BEGIN // have we been installed already? ACTION_IF !(FILE_EXISTS_IN_GAME "m_dw_sgd.lua" && RESOURCE_CONTAINS "m_dw_sgd.lua" "dwStorePanelLookup") BEGIN // if not, install // define token strings // the numbers in this array are frame numbers (counting from 0) in GUISTBBC.bam // 2 is a placeholder value (the old 'steal' icon isn't used in the EE interface, I think) ACTION_DEFINE_ASSOCIATIVE_ARRAY signal_tokens BEGIN 0=>DW_SIGNAL_STORE_BUYSELL 1=>DW_SIGNAL_STORE_IDENTIFY 2=>DW_SIGNAL_STORE_STEAL 3=>DW_SIGNAL_STORE_DONATE 4=>DW_SIGNAL_STORE_CURE 5=>DW_SIGNAL_STORE_DRINK 6=>DW_SIGNAL_STORE_REST END // put them in to dialog.tlk ACTION_PHP_EACH signal_tokens AS ind=>token BEGIN OUTER_SET $token_strref("%ind%")=RESOLVE_STR_REF("<%token%>") END // put the 'inactive' strref in too OUTER_SET active_strref=RESOLVE_STR_REF("ACTIVE") OUTER_SET inactive_strref=RESOLVE_STR_REF("INACTIVE") // install the data <<<<<<<<.../stratagems-inline/m_dw_sgd.lua dwStorePanelLookup={} %data% >>>>>>>> OUTER_SPRINT data "" ACTION_PHP_EACH token_strref AS ind=>strref BEGIN OUTER_SPRINT data "%data%dwStorePanelLookup[%ind%]=%strref%%WNL%" END ACTION_IF !FILE_EXISTS_IN_GAME "m_dw_sgd.lua" BEGIN COPY ".../stratagems-inline/m_dw_sgd.lua" override EVALUATE_BUFFER END ELSE BEGIN APPEND "m_dw_sgd.lua" ".../stratagems-inline/m_dw_sgd.lua" END // install the functions <<<<<<<<.../stratagems-inline/m_dw_sgf.lua function dwStorePanelEnabled(num) storeInd=storeScreen:GetPanelButtonSequence(num) if dwStorePanelLookup[storeInd] then if (Infinity_FetchString(dwStorePanelLookup[storeInd]))=="INACTIVE" then return false end end return storeScreen:GetPanelButtonEnabled(num) end function dwUpdateBuySellPanel() if (Infinity_FetchString(dwStorePanelLookup[0]))=="INACTIVE" then dwStoreForcePanel() else storeScreen:UpdateBuySellPanel() end end function dwUpdateIdentifyPanel() if (Infinity_FetchString(dwStorePanelLookup[1]))=="INACTIVE" then dwStoreForcePanel() else storeScreen:UpdateIdentifyPanel() end end function dwIsStealEnabled() if (Infinity_FetchString(dwStorePanelLookup[2]))=="INACTIVE" then return false end return storeScreen:IsStealEnabled() end function dwUpdateDonatePanel() if (Infinity_FetchString(dwStorePanelLookup[3]))=="INACTIVE" then dwStoreForcePanel() else storeScreen:UpdateDonatePanel() end end function dwUpdateBuySpellPanel() if (Infinity_FetchString(dwStorePanelLookup[4]))=="INACTIVE" then dwStoreForcePanel() else storeScreen:UpdateBuySpellPanel() end end function dwUpdateBuyDrinksPanel() if (Infinity_FetchString(dwStorePanelLookup[5]))=="INACTIVE" then dwStoreForcePanel() else storeScreen:UpdateBuyDrinksPanel() end end function dwUpdateRentRoomPanel() if (Infinity_FetchString(dwStorePanelLookup[6]))=="INACTIVE" then dwStoreForcePanel() else storeScreen:UpdateRentRoomPanel() end end function dwStoreForcePanel() if dwStorePanelEnabled(0) then setStoreMainPanel(0) elseif dwStorePanelEnabled(1) then setStoreMainPanel(1) elseif dwStorePanelEnabled(2) then setStoreMainPanel(2) else setStoreMainPanel(3) end end function dwStoreClose() --- reset all tokens %data% storeScreen:OnMainDoneButtonClick() end >>>>>>>> OUTER_SPRINT data "" ACTION_PHP_EACH signal_tokens AS ind=>token BEGIN OUTER_SPRINT data ~%data%%TAB%C:Eval('SetToken("%token%",%active_strref%)')%WNL%~ END ACTION_IF !FILE_EXISTS_IN_GAME "m_dw_sgf.lua" BEGIN COPY ".../stratagems-inline/m_dw_sgf.lua" OVERRIDE EVALUATE_BUFFER END ELSE BEGIN APPEND "m_dw_sgf.lua" ".../stratagems-inline/m_dw_sgf.lua" END // inject into ui.menu (simple enough that we might as well just REPLACE_TEXTUALLY) COPY_EXISTING "ui.menu" override REPLACE_TEXTUALLY "storeScreen:GetPanelButtonEnabled(\([0-9]\))" "dwStorePanelEnabled(\1)" REPLACE_TEXTUALLY "storeScreen:UpdateRentRoomPanel()" "dwUpdateRentRoomPanel()" REPLACE_TEXTUALLY "storeScreen:UpdateDonatePanel()" "dwUpdateDonatePanel()" REPLACE_TEXTUALLY "storeScreen:IsStealEnabled()" "dwIsStealEnabled()" REPLACE_TEXTUALLY "storeScreen:UpdateIdentifyPanel()" "dwUpdateIdentifyPanel()" REPLACE_TEXTUALLY "storeScreen:UpdateBuySellPanel()" "dwUpdateBuySellPanel()" REPLACE_TEXTUALLY "storeScreen:UpdateBuySpellPanel()" "dwUpdateBuySpellPanel()" REPLACE_TEXTUALLY "storeScreen:UpdateBuyDrinksPanel()" "dwUpdateBuyDrinksPanel()" REPLACE_TEXTUALLY "storeScreen:OnMainDoneButtonClick()" "dwStoreClose()" END ELSE BEGIN // if so, just return the strref of 'INACTIVE' OUTER_SET inactive_strref=RESOLVE_STR_REF("INACTIVE") END END Quote Link to comment
Luke Posted September 27, 2023 Share Posted September 27, 2023 (edited) Here is a more sophisticated version of spell_to_innate. It makes sure all nested subspells (if any) are of type "innate" and can make the specified innate ability uninterruptible (while casting). Spoiler // Example usage WITH_SCOPE BEGIN LAF "GET_UNIQUE_FILE_NAME" STR_VAR "extension" = "spl" RET "filename" END // LAF "MAKE_SPELL-LIKE_ABILITY" STR_VAR "source_spell" = "sppr450" // spell to clone "dest_spell" = EVAL "%filename%" // resource name of the cloned spell END END // Function definition DEFINE_ACTION_FUNCTION "MAKE_SPELL-LIKE_ABILITY" INT_VAR "level" = 0 // default: keep levels (in case "%source_spell%" scales with level), otherwise specify a level "location" = 2 // default: "Cast spell" button (F7) "uninterruptible" = 0 // boolean STR_VAR "source_spell" = "" // spell to clone "dest_spell" = "" // resource name of the cloned spell RET_ARRAY "make_spell-like_ability_reserved_hash" // this is only needed when the function calls itself (i.e., you can safely ignore it) BEGIN // Initialize OUTER_SET "last_valid_level" = "-1" OUTER_SET "last_valid_target" = 1 // COPY_EXISTING - "%source_spell%.spl" "override" PATCH_IF "%uninterruptible%" BEGIN READ_SLONG NAME1 "name" READ_LONG 0x18 "flags" END GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN PATCH_IF "%uninterruptible%" BEGIN SET "last_valid_target" = BYTE_AT ("%abilityOffset%" + 0xC) END // Return the last header whose "min_level" @ 0x10 is smaller or equal than "%level%" PATCH_IF (SHORT_AT ("%abilityOffset%" + 0x10) <= "%level%") BEGIN SET "last_valid_level" = SHORT_AT ("%abilityOffset%" + 0x10) END END BUT_ONLY_IF_IT_CHANGES // Clone the original spell ACTION_IF "%uninterruptible%" BEGIN LAF "GET_UNIQUE_FILE_NAME" STR_VAR "extension" = "spl" RET "shell_spell" = "filename" END END ELSE BEGIN OUTER_TEXT_SPRINT "shell_spell" "%dest_spell%" END COPY_EXISTING "%source_spell%.spl" "override/%shell_spell%.spl" // Header PATCH_IF "%uninterruptible%" BEGIN WRITE_LONG NAME1 "-1" WRITE_LONG 0x18 0 // flags END WRITE_SHORT 0x1C 4 // innate WRITE_LONG 0x1E 0 // exclusion flags // Extended header(s) PATCH_WITH_SCOPE BEGIN GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN PATCH_IF ("%last_valid_level%" != "-1") AND (SHORT_AT ("%abilityOffset%" + 0x10) != "%last_valid_level%") BEGIN WRITE_BYTE "%abilityOffset%" 0xFF // mark it for later deletion END ELSE BEGIN WRITE_SHORT ("%abilityOffset%" + 0x2) "%location%" WRITE_SHORT ("%abilityOffset%" + 0x10) ("%last_valid_level%" == "-1" ? THIS : 1) END END // Actual deletion LPF "DELETE_SPELL_HEADER" INT_VAR "header_type" = 0xFF END END // Feature block(s) -- make sure all op206/318/321/324/333 protect from / remove / cast the new resref LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 206 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 318 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 321 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 324 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 333 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END // Make sure any op146/148/326/333 cast an "innate" spell (if any) GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN GET_OFFSET_ARRAY2 "effectArray" "%abilityOffset%" SPL_V10_HEAD_EFFECTS PHP_EACH "effectArray" AS "effectIndex" => "effectOffset" BEGIN READ_ASCII ("%effectOffset%" + 0x14) "res" PATCH_MATCH SHORT_AT "%effectOffset%" WITH 146 148 326 333 WHEN ("%res%" STRING_COMPARE_CASE "%DEST_RES%") BEGIN PATCH_IF !(VARIABLE_IS_SET $"make_spell-like_ability_reserved_hash"("%res%")) BEGIN LPF "GET_UNIQUE_FILE_NAME" STR_VAR "extension" = "spl" RET "filename" END WRITE_ASCIIE ("%effectOffset%" + 0x14) "%filename%" #8 TEXT_SPRINT $"make_spell-like_ability_reserved_hash"("%res%") "%filename%" INNER_ACTION BEGIN LAF "MAKE_SPELL-LIKE_ABILITY" INT_VAR "level" "location" STR_VAR "source_spell" = EVAL "%res%" "dest_spell" = EVAL "%filename%" RET_ARRAY "make_spell-like_ability_reserved_hash" END END END ELSE BEGIN WRITE_ASCIIE ("%effectOffset%" + 0x14) $"make_spell-like_ability_reserved_hash"("%res%") #8 END END DEFAULT END END END BUT_ONLY_IF_IT_CHANGES // Make a dummy SPL file casting the real SPL file if "%uninterruptible%" ACTION_IF "%uninterruptible%" BEGIN ACTION_MATCH "%last_valid_target%" WITH 1 BEGIN // living actor OUTER_SET "opcode" = 146 // cast spell OUTER_SET "target" = 2 // projectile target END 4 BEGIN // any point within range OUTER_SET "opcode" = 148 // cast spell at point OUTER_SET "target" = 1 // self END 5 7 BEGIN // caster OUTER_SET "opcode" = 146 // cast spell OUTER_SET "target" = 1 // self END DEFAULT FAIL "MAKE_SPELL-LIKE_ABILITY: Should not happen" END COPY_EXISTING "%shell_spell%.spl" "override/%dest_spell%.spl" // Header WRITE_LONG NAME1 "%name%" WRITE_LONG 0x18 "%flags%" WRITE_SHORT 0x22 0 // casting animation WRITE_ASCII 0x10 "" #8 // casting sound // Extended header(s) PATCH_WITH_SCOPE BEGIN GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN PATCH_IF (SHORT_AT ("%abilityOffset%" + 0x10) != 1) BEGIN WRITE_BYTE "%abilityOffset%" 0xFF // mark it for later deletion END ELSE BEGIN WRITE_SHORT ("%abilityOffset%" + 0x12) 0 // casting speed WRITE_SHORT ("%abilityOffset%" + 0x26) IDS_OF_SYMBOL ("MISSILE" "None") // projectile END END // Actual deletion LPF "DELETE_SPELL_HEADER" INT_VAR "header_type" = 0xFF END END // Casting feature effects LPF ~ADD_SPELL_CFEFFECT~ INT_VAR "opcode" = 101 "target" = 1 "parameter2" = 12 END // Immunity to effect => Effect: Damage (`casting_speed=0` might not be enough, hence a 0-duration immunity to damage...) // Feature block(s) LPF ~DELETE_SPELL_EFFECT~ INT_VAR ~opcode_to_delete~ = ~-1~ END // delete everything LPF ~ADD_SPELL_EFFECT~ INT_VAR "opcode" "target" "timing" = 1 STR_VAR "resource" = EVAL "%SOURCE_RES%" END // Cast spell / Cast spell at point BUT_ONLY_IF_IT_CHANGES END END Edited September 27, 2023 by Luke Quote Link to comment
Jarno Mikkola Posted October 8, 2023 Share Posted October 8, 2023 I posted a similar thing else where, and so I'll post this here. Here's a weapon proficiency indexing in the ADD_KIT command: //https://gibberlings3.github.io/iesdp/files/2da/2da_tob/weapprof.htm //BG1 ------ BG2 Useless // ID 0 1 2 3 4 5 6 7 89 ~KITNAME 0 0 0 0 0 0 0 0 x x x x x x x x x x x x x x x x x x x x x x x x 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0~ //weapprof.2da // L S B S B S A M B L S A T K S D W C S H F M Q C L S D S 2 S S 2 E - - - - - - - - - - - - - - - - - - // a m o p l p x i a o h x w a c a a l p a l a u r o h a l H S i W x - - - - - - - - - - - - - - - - - - // r a w e u i e s s n o e o t i g r u e l a c a o n o r i a h n e t - - - - - - - - - - - - - - - - - - // g l a n k s t g r H a m g H b a b i e r s g t t n n e g a r - - - - - - - - - - - - - - - - - - // e l r t e i a S t a n i e a r e l t s B B g e l e p a - - - - - - - - - - - - - - - - - - //the zeroes are the needed values or the game can remain at the character level up screen Quote Link to comment
Incrementis Posted October 10, 2023 Share Posted October 10, 2023 (edited) This library (dynArrayFunctionalities.tph) is a byproduct of a small tool(actually nothing new) I am working on. It is available for the following operating systems: Windows (tested) Mac OS (not tested) Liunx (not tested) This library offers the possibility to create arrays whose elements can be overwritten without the need to create the same array again. It allows access and change of the elements in an array both inside and outside patching. Detailed Information can be found here on GitHub. The wiki also contains a small and rudimentary benchmark. To be on the safe side, this should be checked before using the library. I don't know if this is of any use to anyone but me, but you never know. Just don't forget to mention me by adding me in a little thank you section. EDIT: Allows pseudo-dyn arrays to set negative integer values. This applies to the outer patch version (tested). The patch version is expected to work equally. Please check the GitHub repository for future updates, as updating changes in many other places can be tedious and error-prone. I won't continue to update the changes here unless it's something very critical or explicitly contacted to do so. Linux version Spoiler // Never Forget: Comments can "lie", but code not so much ;P //-----------------------------------------------------------// // Contains self defined pseudo dynamic array functionalities// //-----------------------------------------------------------// // GLOBAL LIB VARIABLES(Don't change these) // ---------------------------------------- OUTER_SPRINT ~!_bufferValue~ ~~ OUTER_SPRINT ~!_arraySlots~ ~~ // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy these variables to another location and change their values before calling the macro. // This macro can not be used in patching. OUTER_SET ~!_slotNumbers~ = 0 OUTER_SPRINT ~!_setArrayName~ ~!_NULL~ // Purpose: Creates a dynamic array and patch dynamic array // ---------------------------------------------------------------------------------------------- // Parameters:| // ============ // !_slotNumbers -> The desired number of elements that the array can hold // !_setArrayName -> The array name which is needed for further "DYN_ARRAY" function arguments // ---------------------------------------------------------------------------------------------- DEFINE_ACTION_MACRO DYN_ARRAY_CREATE BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_slotNumbers~ = 0 // STRING ~!_setArrayName~ ~!_NULL~ // INTEGER index = 0 // STRING ~!_arraySlots~ ~~ // ---------------------------------------------- // Local variables which must not or can't be manipulated outside of macros LOCAL_SET index = 0 OUTER_SPRINT ~!_arraySlots~ ~~ // Checks if a proper array name is given ACTION_IF (~%!_setArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CREATE -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if slot numbers are not out of bounds ACTION_IF (~%!_slotNumbers%~ <= 0) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CREATE %!_setArrayName% -> The correct SlotNumbers are missing as an argument. Value must be greater than 0!~ END // Creates empty inline files which are needed // for buffering current values regarding dyn arrays and patch dyn arrays <<<<<<<<./weidu_external/workspace/!_temporaryArrayBuffer.tph >>>>>>>> <<<<<<<<./weidu_external/workspace/!_temporaryPatchArrayBuffer.tph >>>>>>>> COPY ~./weidu_external/workspace/!_temporaryArrayBuffer.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_setArrayName%Buffer.tph~ COPY ~./weidu_external/workspace/!_temporaryPatchArrayBuffer.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_setArrayName%Buffer.tph~ // Creates an inline file which content is needed to define the dynamic array. <<<<<<<<./weidu_external/workspace/!_temporaryArray.tph DEFINE_ACTION_MACRO ~!_%!_setArrayName%~ BEGIN ACTION_DEFINE_ARRAY ~%!_setArrayName%~ BEGIN >>>>>>>> // Creates an inline file which content is needed to define the dynamic patch array. <<<<<<<<./weidu_external/workspace/!_temporaryPatchArray.tph DEFINE_PATCH_MACRO ~!_%!_setArrayName%~ BEGIN PATCH_DEFINE_ARRAY ~%!_setArrayName%~ BEGIN >>>>>>>> // Copies the content of the temporary arrays to dynamic named files so that they can be reused for another array COPY ~./weidu_external/workspace/!_temporaryArray.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ EVALUATE_BUFFER COPY ~./weidu_external/workspace/!_temporaryPatchArray.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ EVALUATE_BUFFER // Includes array element slots as variables into the array (%LNL% means Linux New Line) OUTER_FOR(index = 0; index < ~!_slotNumbers~; ++index) BEGIN OUTER_SPRINT ~!_arraySlots~ ~%!_arraySlots% "%%!_setArrayName%%index%%"%LNL%~ END APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ ~%!_arraySlots%~ APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ ~%!_arraySlots%~ // Closes dynamic array and makes it usable by WeiDU with // e.g. INCLUDE/REINCLUDE (The tab space is for formatting) APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ ~ END END~ APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ ~ END END~ REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ // Resets macro variables OUTER_SET ~!_slotNumbers~ = 0 OUTER_SPRINT ~!_setArrayName~ ~!_NULL~ END// End of "DYN_ARRAY_CREATE" // Purpose: Reads the buffer file for the specified array into a file. // This function mustn't be used outside this library. // ---------------------------------------------------------------------------------------------- // Parameters:| // ============ // position -> The array slot position/index in which the new value will be written // UseArrayName -> The required name of the array in which the new values will be written. // bufferValue -> The required string containing the buffered values DEFINE_DIMORPHIC_FUNCTION DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = "-1" STR_VAR UseArrayName= ~!_NULL~ bufferValue = ~~ functionType= ~!_NULL~ BEGIN ACTION_IF (~%functionType%~ STRING_EQUAL ~PATCH~) THEN BEGIN // This little line does not work inside of a patch macros, // thus it is wrapped in this dimorphic function APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%UseArrayName%Buffer.tph~ ~%bufferValue%~ END ELSE ACTION_IF (~%functionType%~ STRING_EQUAL ~OUTER~) THEN BEGIN APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%UseArrayName%Buffer.tph~ ~%bufferValue%~ END ELSE BEGIN FAIL ~DEFINE_DIMORPHIC_FUNCTION DYN_ARRAY_BUFFER_TO_FILE %UseArrayName% -> The function type argument is missing or invalid. The allowed function types are PATCH and OUTER.~ END END// End of "DYN_ARRAY_BUFFER_TO_FILE" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the these variables to another location and change their values before calling the macro. // It is important to note that this macro has a patch version. OUTER_SET ~!_position~ = "-1" OUTER_SET ~!_maxSlots~ = "-1" OUTER_SET ~!_collected~= "-1" OUTER_SPRINT ~!_useArrayName~ ~!_NULL~ OUTER_SPRINT ~!_arrayValue~ ~!_NULL~ // Purpose: Replaces/sets values in a dynamic array // ------------------------------------------------ // Parameters:| // ============ // !_position -> The array slot position/index in which the new value will be written // !_maxSlots -> The highest value the argument for position/index is allowed to be. // The maximum is in general the max number of elments the array can contain // !_collected -> A flag that indicates whether or not the collection process is complete. // 0: Collection is in progress. // 1: Collection is complete. // !_useArrayName -> The array name in which the array value is written // !_arrayValue -> The value that is planned to be written to the array. DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_position~ = "-1" // INTEGER ~!_maxSlots~ = "-1" // INTEGER ~!_collected~= "-1" // STRING ~!_useArrayName~ ~!_NULL~ // INTEGER/STRING ~!_arrayValue~ ~!_NULL~ // STRING ~!_bufferValue~ ~~ // ---------------------------------------------- // Corrects number of elements to slot index OUTER_SET ~!_maxSlots~ = ~%!_maxSlots%~ - 1 // Checks if an array index is not given ACTION_IF (~%!_position%~ <= "-1") THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct position as an argument is missing. The position value must be greater than -1!~ END // Checks if a highest array slot number is not given or if it makes any sense ACTION_IF ( (~%!_maxSlots%~ <= "-1") OR (~%!_maxSlots%~ < ~%!_position%~) ) THEN BEGIN // Prepares value for error output OUTER_SET ~!_maxSlots~ = ~%!_maxSlots%~ + 1 FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct maxSlots as an argument is missing. The maxSlots value is %!_maxSlots%, but must be greater than -1 and greater %!_position%!~ END // Checks if an array name is not given ACTION_IF (~%!_useArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if an array index is not given ACTION_IF (~%!_collected%~ <= "-1" OR ~%!_collected%~ >= 2) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The argument for "!_collected" is %!_collected%. Allowed values are 0(for still collecting) and 1(value collection is done) !~ END // Checks if the array value is an integer and calls the appropriate function // to prepare the abstract array element information. ACTION_IF (IS_AN_INT ~%!_arrayValue%~) THEN BEGIN ACTION_IF (~%!_arrayValue%~ > "-1") THEN BEGIN // Positive values including 0 OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SET ~%!_useArrayName%%!_position%~ = %!_arrayValue%%LNL%~~~~~ END ELSE BEGIN // Negative values OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SET ~%!_useArrayName%%!_position%~ = "%!_arrayValue%"%LNL%~~~~~ END // If value is not integer then it is string END ELSE BEGIN OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SPRINT ~%!_useArrayName%%!_position%~ ~%!_arrayValue%~%LNL%~~~~~ END // If all values are collected then write it into array ACTION_IF (~%!_collected%~ = 1) THEN BEGIN LAF DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = ~%!_position%~ STR_VAR UseArrayName= EVAL~%!_useArrayName%~ bufferValue = EVAL~%!_bufferValue%~ functionType= EVAL~OUTER~ END // Writes into the dynamic array REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_useArrayName%Buffer.tph~ LAM ~!_%!_useArrayName%~ // Resets global lib variable OUTER_SPRINT ~!_bufferValue~ ~~ // Resets macro variables OUTER_SET ~!_position~ = "-1" OUTER_SET ~!_maxSlots~ = "-1" OUTER_SET ~!_collected~= "-1" OUTER_SPRINT ~!_useArrayName~ ~!_NULL~ OUTER_SPRINT ~!_arrayValue~ ~!_NULL~ END END// End of "DYN_ARRAY_SET_VALUES" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the commented SET variables to another location and change their values before calling the macro. // It is important to note that this macro has a outer version. //SET ~!_position~ = "-1" //SET ~!_maxSlots~ = "-1" //SET ~!_collected~= "-1" //SPRINT ~!_useArrayName~ ~!_NULL~ //SPRINT ~!_arrayValue~ ~!_NULL~ // Purpose: Replaces/sets patch values in a dynamic array // ------------------------------------------------------ // Parameters:| // ============ // !_position -> The array slot position/index in which the new value will be written // !_maxSlots -> The highest value the argument for position/index is allowed to be. // The maximum is in general the max number of elments the array can contain // !_collected -> A flag that indicates whether or not the collection process is complete. // 0: Collection is in progress. // 1: Collection is complete. // !_useArrayName -> The array name in which the array value is written // !_arrayValue -> The value that is planned to be written to the array. DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_position~ = "-1" // INTEGER ~!_maxSlots~ = "-1" // INTEGER ~!_collected~= "-1" // STRING ~!_useArrayName~ ~!_NULL~ // INTEGER/STRING ~!_arrayValue~ ~!_NULL~ // STRING ~!_bufferValue~ ~~ // ---------------------------------------------- // Corrects number of elements to slot index SET ~!_maxSlots~ = ~!_maxSlots~ - 1 // Checks if an array index is not given PATCH_IF (~%!_position%~ <= "-1") THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct position as an argument is missing. The position value must be greater than -1!~ END // Checks if a highest array slot number is not given or if it makes any sense PATCH_IF ( (~%!_maxSlots%~ <= "-1") OR (~%!_maxSlots%~ < ~%!_position%~) ) THEN BEGIN // Prepares value for error output SET ~!_maxSlots~ = ~!_maxSlots~ + 1 PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct maxSlots as an argument is missing. The maxSlots value is %!_maxSlots%, but must be greater than -1 and greater %!_position%!~ END // Checks if an array name is not given PATCH_IF (~%!_useArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if an array index is not given PATCH_IF (~%!_collected%~ <= "-1" OR ~%!_collected%~ >= 2) THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The argument for "!_collected" is %!_collected%. Allowed values are 0(for still collecting) and 1(value collection is done) !~ END // Checks if the array value is an integer and calls the appropriate function // to prepare the abstract array element information. PATCH_IF (IS_AN_INT ~%!_arrayValue%~) THEN BEGIN PATCH_IF (~%!_arrayValue%~ > "-1") THEN BEGIN // Positive values including 0 SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SET ~%!_useArrayName%%!_position%~ = %!_arrayValue%%LNL%~~~~~ END ELSE BEGIN // Negative values SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SET ~%!_useArrayName%%!_position%~ = "%!_arrayValue%"%LNL%~~~~~ END // If value is not integer then it is string END ELSE BEGIN SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SPRINT ~%!_useArrayName%%!_position%~ ~%!_arrayValue%~%LNL%~~~~~ END // If all values are collected then write it into array PATCH_IF (~%!_collected%~ = 1) THEN BEGIN LPF DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = ~%!_position%~ STR_VAR UseArrayName= EVAL~%!_useArrayName%~ bufferValue = EVAL~%!_bufferValue%~ functionType= EVAL~PATCH~ END // Writes into the dynamic array PATCH_REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_useArrayName%Buffer.tph~ LPM ~!_%!_useArrayName%~ // Resets global lib variable SPRINT ~!_bufferValue~ ~~ // Resets macro variables SET ~!_position~ = "-1" SET ~!_maxSlots~ = "-1" SET ~!_collected~= "-1" SPRINT ~!_useArrayName~ ~!_NULL~ SPRINT ~!_arrayValue~ ~!_NULL~ END END// End of "DYN_ARRAY_SET_VALUES" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the variable 1 to 1 to somewhere else where you need it // and change its value before before calling the macro.!!! // This macro can not be used in patching. OUTER_SPRINT ~!_deleteArray~ ~!_NULL~ // Purpose: Deletes all created dynamic array files for patch and outer version // ---------------------------------------------------------------------------- // Parameters:| // ============ // !_deleteArray -> The array name for which the files will be deleted // ------------------------------------------------------------------- DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // STRING ~!_deleteArray~ ~!_NULL~ // ---------------------------------------------- // ---WARNING: Will output an error if local variables are not placed directly at the beginning of macros LOCAL_SPRINT outerBufferFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_deleteArray%Buffer.tph~ LOCAL_SPRINT patchBufferFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_deleteArray%Buffer.tph~ LOCAL_SPRINT outerArrayFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_deleteArray%.tph~ LOCAL_SPRINT patchArrayFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_deleteArray%.tph~ // The macro fails if no array name is given because it needs to know which array to delete the files for. ACTION_IF (~%!_deleteArray%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEAR_BUFFER -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Deletes the buffer files for the specified array. ACTION_IF(FILE_EXISTS ~%outerBufferFilename%~) THEN BEGIN DELETE ~%outerBufferFilename%~ PRINT ~Deleted %outerBufferFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %outerBufferFilename%!~ END ACTION_IF(FILE_EXISTS ~%patchBufferFilename%~) THEN BEGIN DELETE ~%patchBufferFilename%~ PRINT ~Deleted %patchBufferFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %patchBufferFilename%!~ END // Deletes the definition files for the specified array. ACTION_IF(FILE_EXISTS ~%outerArrayFilename%~) THEN BEGIN DELETE ~%outerArrayFilename%~ PRINT ~Deleted %outerArrayFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %outerArrayFilename%!~ END ACTION_IF(FILE_EXISTS ~%patchArrayFilename%~) THEN BEGIN DELETE ~%patchArrayFilename%~ PRINT ~Deleted %patchArrayFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %patchArrayFilename%!~ END END// End of "DYN_ARRAY_CLEANUP" Mac version Spoiler // Never Forget: Comments can "lie", but code not so much ;P //-----------------------------------------------------------// // Contains self defined pseudo dynamic array functionalities// //-----------------------------------------------------------// // GLOBAL LIB VARIABLES(Don't change these) // ---------------------------------------- OUTER_SPRINT ~!_bufferValue~ ~~ OUTER_SPRINT ~!_arraySlots~ ~~ // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy these variables to another location and change their values before calling the macro. // This macro can not be used in patching. OUTER_SET ~!_slotNumbers~ = 0 OUTER_SPRINT ~!_setArrayName~ ~!_NULL~ // Purpose: Creates a dynamic array and patch dynamic array // ---------------------------------------------------------------------------------------------- // Parameters:| // ============ // !_slotNumbers -> The desired number of elements that the array can hold // !_setArrayName -> The array name which is needed for further "DYN_ARRAY" function arguments // ---------------------------------------------------------------------------------------------- DEFINE_ACTION_MACRO DYN_ARRAY_CREATE BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_slotNumbers~ = 0 // STRING ~!_setArrayName~ ~!_NULL~ // INTEGER index = 0 // STRING ~!_arraySlots~ ~~ // ---------------------------------------------- // Local variables which must not or can't be manipulated outside of macros LOCAL_SET index = 0 OUTER_SPRINT ~!_arraySlots~ ~~ // Checks if a proper array name is given ACTION_IF (~%!_setArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CREATE -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if slot numbers are not out of bounds ACTION_IF (~%!_slotNumbers%~ <= 0) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CREATE %!_setArrayName% -> The correct SlotNumbers are missing as an argument. Value must be greater than 0!~ END // Creates empty inline files which are needed // for buffering current values regarding dyn arrays and patch dyn arrays <<<<<<<<./weidu_external/workspace/!_temporaryArrayBuffer.tph >>>>>>>> <<<<<<<<./weidu_external/workspace/!_temporaryPatchArrayBuffer.tph >>>>>>>> COPY ~./weidu_external/workspace/!_temporaryArrayBuffer.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_setArrayName%Buffer.tph~ COPY ~./weidu_external/workspace/!_temporaryPatchArrayBuffer.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_setArrayName%Buffer.tph~ // Creates an inline file which content is needed to define the dynamic array. <<<<<<<<./weidu_external/workspace/!_temporaryArray.tph DEFINE_ACTION_MACRO ~!_%!_setArrayName%~ BEGIN ACTION_DEFINE_ARRAY ~%!_setArrayName%~ BEGIN >>>>>>>> // Creates an inline file which content is needed to define the dynamic patch array. <<<<<<<<./weidu_external/workspace/!_temporaryPatchArray.tph DEFINE_PATCH_MACRO ~!_%!_setArrayName%~ BEGIN PATCH_DEFINE_ARRAY ~%!_setArrayName%~ BEGIN >>>>>>>> // Copies the content of the temporary arrays to dynamic named files so that they can be reused for another array COPY ~./weidu_external/workspace/!_temporaryArray.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ EVALUATE_BUFFER COPY ~./weidu_external/workspace/!_temporaryPatchArray.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ EVALUATE_BUFFER // Includes array element slots as variables into the array (%MNL% means Macintosh New Line) OUTER_FOR(index = 0; index < ~!_slotNumbers~; ++index) BEGIN OUTER_SPRINT ~!_arraySlots~ ~%!_arraySlots% "%%!_setArrayName%%index%%"%MNL%~ END APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ ~%!_arraySlots%~ APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ ~%!_arraySlots%~ // Closes dynamic array and makes it usable by WeiDU with // e.g. INCLUDE/REINCLUDE (The tab space is for formatting) APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ ~ END END~ APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ ~ END END~ REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ // Resets macro variables OUTER_SET ~!_slotNumbers~ = 0 OUTER_SPRINT ~!_setArrayName~ ~!_NULL~ END// End of "DYN_ARRAY_CREATE" // Purpose: Reads the buffer file for the specified array into a file. // This function mustn't be used outside this library. // ---------------------------------------------------------------------------------------------- // Parameters:| // ============ // position -> The array slot position/index in which the new value will be written // UseArrayName -> The required name of the array in which the new values will be written. // bufferValue -> The required string containing the buffered values DEFINE_DIMORPHIC_FUNCTION DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = "-1" STR_VAR UseArrayName= ~!_NULL~ bufferValue = ~~ functionType= ~!_NULL~ BEGIN ACTION_IF (~%functionType%~ STRING_EQUAL ~PATCH~) THEN BEGIN // This little line does not work inside of a patch macros, // thus it is wrapped in this dimorphic function APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%UseArrayName%Buffer.tph~ ~%bufferValue%~ END ELSE ACTION_IF (~%functionType%~ STRING_EQUAL ~OUTER~) THEN BEGIN APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%UseArrayName%Buffer.tph~ ~%bufferValue%~ END ELSE BEGIN FAIL ~DEFINE_DIMORPHIC_FUNCTION DYN_ARRAY_BUFFER_TO_FILE %UseArrayName% -> The function type argument is missing or invalid. The allowed function types are PATCH and OUTER.~ END END// End of "DYN_ARRAY_BUFFER_TO_FILE" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the these variables to another location and change their values before calling the macro. // It is important to note that this macro has a patch version. OUTER_SET ~!_position~ = "-1" OUTER_SET ~!_maxSlots~ = "-1" OUTER_SET ~!_collected~= "-1" OUTER_SPRINT ~!_useArrayName~ ~!_NULL~ OUTER_SPRINT ~!_arrayValue~ ~!_NULL~ // Purpose: Replaces/sets values in a dynamic array // ------------------------------------------------ // Parameters:| // ============ // !_position -> The array slot position/index in which the new value will be written // !_maxSlots -> The highest value the argument for position/index is allowed to be. // The maximum is in general the max number of elments the array can contain // !_collected -> A flag that indicates whether or not the collection process is complete. // 0: Collection is in progress. // 1: Collection is complete. // !_useArrayName -> The array name in which the array value is written // !_arrayValue -> The value that is planned to be written to the array. DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_position~ = "-1" // INTEGER ~!_maxSlots~ = "-1" // INTEGER ~!_collected~= "-1" // STRING ~!_useArrayName~ ~!_NULL~ // INTEGER/STRING ~!_arrayValue~ ~!_NULL~ // STRING ~!_bufferValue~ ~~ // ---------------------------------------------- // Corrects number of elements to slot index OUTER_SET ~!_maxSlots~ = ~%!_maxSlots%~ - 1 // Checks if an array index is not given ACTION_IF (~%!_position%~ <= "-1") THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct position as an argument is missing. The position value must be greater than -1!~ END // Checks if a highest array slot number is not given or if it makes any sense ACTION_IF ( (~%!_maxSlots%~ <= "-1") OR (~%!_maxSlots%~ < ~%!_position%~) ) THEN BEGIN // Prepares value for error output OUTER_SET ~!_maxSlots~ = ~%!_maxSlots%~ + 1 FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct maxSlots as an argument is missing. The maxSlots value is %!_maxSlots%, but must be greater than -1 and greater %!_position%!~ END // Checks if an array name is not given ACTION_IF (~%!_useArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if an array index is not given ACTION_IF (~%!_collected%~ <= "-1" OR ~%!_collected%~ >= 2) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The argument for "!_collected" is %!_collected%. Allowed values are 0(for still collecting) and 1(value collection is done) !~ END // Checks if the array value is an integer and calls the appropriate function // to prepare the abstract array element information. ACTION_IF (IS_AN_INT ~%!_arrayValue%~) THEN BEGIN ACTION_IF (~%!_arrayValue%~ > "-1") THEN BEGIN // Positive values including 0 OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SET ~%!_useArrayName%%!_position%~ = %!_arrayValue%%MNL%~~~~~ END ELSE BEGIN // Negative values OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SET ~%!_useArrayName%%!_position%~ = "%!_arrayValue%"%MNL%~~~~~ END // If value is not integer then it is string END ELSE BEGIN OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SPRINT ~%!_useArrayName%%!_position%~ ~%!_arrayValue%~%MNL%~~~~~ END // If all values are collected then write it into array ACTION_IF (~%!_collected%~ = 1) THEN BEGIN LAF DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = ~%!_position%~ STR_VAR UseArrayName= EVAL~%!_useArrayName%~ bufferValue = EVAL~%!_bufferValue%~ functionType= EVAL~OUTER~ END // Writes into the dynamic array REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_useArrayName%Buffer.tph~ LAM ~!_%!_useArrayName%~ // Resets global lib variable OUTER_SPRINT ~!_bufferValue~ ~~ // Resets macro variables OUTER_SET ~!_position~ = "-1" OUTER_SET ~!_maxSlots~ = "-1" OUTER_SET ~!_collected~= "-1" OUTER_SPRINT ~!_useArrayName~ ~!_NULL~ OUTER_SPRINT ~!_arrayValue~ ~!_NULL~ END END// End of "DYN_ARRAY_SET_VALUES" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the commented SET variables to another location and change their values before calling the macro. // It is important to note that this macro has a outer version. //SET ~!_position~ = "-1" //SET ~!_maxSlots~ = "-1" //SET ~!_collected~= "-1" //SPRINT ~!_useArrayName~ ~!_NULL~ //SPRINT ~!_arrayValue~ ~!_NULL~ // Purpose: Replaces/sets patch values in a dynamic array // ------------------------------------------------------ // Parameters:| // ============ // !_position -> The array slot position/index in which the new value will be written // !_maxSlots -> The highest value the argument for position/index is allowed to be. // The maximum is in general the max number of elments the array can contain // !_collected -> A flag that indicates whether or not the collection process is complete. // 0: Collection is in progress. // 1: Collection is complete. // !_useArrayName -> The array name in which the array value is written // !_arrayValue -> The value that is planned to be written to the array. DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_position~ = "-1" // INTEGER ~!_maxSlots~ = "-1" // INTEGER ~!_collected~= "-1" // STRING ~!_useArrayName~ ~!_NULL~ // INTEGER/STRING ~!_arrayValue~ ~!_NULL~ // STRING ~!_bufferValue~ ~~ // ---------------------------------------------- // Corrects number of elements to slot index SET ~!_maxSlots~ = ~!_maxSlots~ - 1 // Checks if an array index is not given PATCH_IF (~%!_position%~ <= "-1") THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct position as an argument is missing. The position value must be greater than -1!~ END // Checks if a highest array slot number is not given or if it makes any sense PATCH_IF ( (~%!_maxSlots%~ <= "-1") OR (~%!_maxSlots%~ < ~%!_position%~) ) THEN BEGIN // Prepares value for error output SET ~!_maxSlots~ = ~!_maxSlots~ + 1 PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct maxSlots as an argument is missing. The maxSlots value is %!_maxSlots%, but must be greater than -1 and greater %!_position%!~ END // Checks if an array name is not given PATCH_IF (~%!_useArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if an array index is not given PATCH_IF (~%!_collected%~ <= "-1" OR ~%!_collected%~ >= 2) THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The argument for "!_collected" is %!_collected%. Allowed values are 0(for still collecting) and 1(value collection is done) !~ END // Checks if the array value is an integer and calls the appropriate function // to prepare the abstract array element information. PATCH_IF (IS_AN_INT ~%!_arrayValue%~) THEN BEGIN PATCH_IF (~%!_arrayValue%~ > "-1") THEN BEGIN // Positive values including 0 SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SET ~%!_useArrayName%%!_position%~ = %!_arrayValue%%MNL%~~~~~ END ELSE BEGIN // Negative values SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SET ~%!_useArrayName%%!_position%~ = "%!_arrayValue%"%MNL%~~~~~ END // If value is not integer then it is string END ELSE BEGIN SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SPRINT ~%!_useArrayName%%!_position%~ ~%!_arrayValue%~%MNL%~~~~~ END // If all values are collected then write it into array PATCH_IF (~%!_collected%~ = 1) THEN BEGIN LPF DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = ~%!_position%~ STR_VAR UseArrayName= EVAL~%!_useArrayName%~ bufferValue = EVAL~%!_bufferValue%~ functionType= EVAL~PATCH~ END // Writes into the dynamic array PATCH_REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_useArrayName%Buffer.tph~ LPM ~!_%!_useArrayName%~ // Resets global lib variable SPRINT ~!_bufferValue~ ~~ // Resets macro variables SET ~!_position~ = "-1" SET ~!_maxSlots~ = "-1" SET ~!_collected~= "-1" SPRINT ~!_useArrayName~ ~!_NULL~ SPRINT ~!_arrayValue~ ~!_NULL~ END END// End of "DYN_ARRAY_SET_VALUES" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the variable 1 to 1 to somewhere else where you need it // and change its value before before calling the macro.!!! // This macro can not be used in patching. OUTER_SPRINT ~!_deleteArray~ ~!_NULL~ // Purpose: Deletes all created dynamic array files for patch and outer version // ---------------------------------------------------------------------------- // Parameters:| // ============ // !_deleteArray -> The array name for which the files will be deleted // ------------------------------------------------------------------- DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // STRING ~!_deleteArray~ ~!_NULL~ // ---------------------------------------------- // ---WARNING: Will output an error if local variables are not placed directly at the beginning of macros LOCAL_SPRINT outerBufferFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_deleteArray%Buffer.tph~ LOCAL_SPRINT patchBufferFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_deleteArray%Buffer.tph~ LOCAL_SPRINT outerArrayFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_deleteArray%.tph~ LOCAL_SPRINT patchArrayFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_deleteArray%.tph~ // The macro fails if no array name is given because it needs to know which array to delete the files for. ACTION_IF (~%!_deleteArray%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEAR_BUFFER -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Deletes the buffer files for the specified array. ACTION_IF(FILE_EXISTS ~%outerBufferFilename%~) THEN BEGIN DELETE ~%outerBufferFilename%~ PRINT ~Deleted %outerBufferFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %outerBufferFilename%!~ END ACTION_IF(FILE_EXISTS ~%patchBufferFilename%~) THEN BEGIN DELETE ~%patchBufferFilename%~ PRINT ~Deleted %patchBufferFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %patchBufferFilename%!~ END // Deletes the definition files for the specified array. ACTION_IF(FILE_EXISTS ~%outerArrayFilename%~) THEN BEGIN DELETE ~%outerArrayFilename%~ PRINT ~Deleted %outerArrayFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %outerArrayFilename%!~ END ACTION_IF(FILE_EXISTS ~%patchArrayFilename%~) THEN BEGIN DELETE ~%patchArrayFilename%~ PRINT ~Deleted %patchArrayFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %patchArrayFilename%!~ END END// End of "DYN_ARRAY_CLEANUP" Windows version: Spoiler // Never Forget: Comments can "lie", but code not so much ;P //-----------------------------------------------------------// // Contains self defined pseudo dynamic array functionalities// //-----------------------------------------------------------// // GLOBAL LIB VARIABLES(Don't change these) // ---------------------------------------- OUTER_SPRINT ~!_bufferValue~ ~~ OUTER_SPRINT ~!_arraySlots~ ~~ // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy these variables to another location and change their values before calling the macro. // This macro can not be used in patching. OUTER_SET ~!_slotNumbers~ = 0 OUTER_SPRINT ~!_setArrayName~ ~!_NULL~ // Purpose: Creates a dynamic array and patch dynamic array // ---------------------------------------------------------------------------------------------- // Parameters:| // ============ // !_slotNumbers -> The desired number of elements that the array can hold // !_setArrayName -> The array name which is needed for further "DYN_ARRAY" function arguments // ---------------------------------------------------------------------------------------------- DEFINE_ACTION_MACRO DYN_ARRAY_CREATE BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_slotNumbers~ = 0 // STRING ~!_setArrayName~ ~!_NULL~ // INTEGER index = 0 // STRING ~!_arraySlots~ ~~ // ---------------------------------------------- // Local variables which must not or can't be manipulated outside of macros LOCAL_SET index = 0 OUTER_SPRINT ~!_arraySlots~ ~~ // Checks if a proper array name is given ACTION_IF (~%!_setArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CREATE -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if slot numbers are not out of bounds ACTION_IF (~%!_slotNumbers%~ <= 0) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CREATE %!_setArrayName% -> The correct SlotNumbers are missing as an argument. Value must be greater than 0!~ END // Creates empty inline files which are needed // for buffering current values regarding dyn arrays and patch dyn arrays <<<<<<<<./weidu_external/workspace/!_temporaryArrayBuffer.tph >>>>>>>> <<<<<<<<./weidu_external/workspace/!_temporaryPatchArrayBuffer.tph >>>>>>>> COPY ~./weidu_external/workspace/!_temporaryArrayBuffer.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_setArrayName%Buffer.tph~ COPY ~./weidu_external/workspace/!_temporaryPatchArrayBuffer.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_setArrayName%Buffer.tph~ // Creates an inline file which content is needed to define the dynamic array. <<<<<<<<./weidu_external/workspace/!_temporaryArray.tph DEFINE_ACTION_MACRO ~!_%!_setArrayName%~ BEGIN ACTION_DEFINE_ARRAY ~%!_setArrayName%~ BEGIN >>>>>>>> // Creates an inline file which content is needed to define the dynamic patch array. <<<<<<<<./weidu_external/workspace/!_temporaryPatchArray.tph DEFINE_PATCH_MACRO ~!_%!_setArrayName%~ BEGIN PATCH_DEFINE_ARRAY ~%!_setArrayName%~ BEGIN >>>>>>>> // Copies the content of the temporary arrays to dynamic named files so that they can be reused for another array COPY ~./weidu_external/workspace/!_temporaryArray.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ EVALUATE_BUFFER COPY ~./weidu_external/workspace/!_temporaryPatchArray.tph~ ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ EVALUATE_BUFFER // Includes array element slots as variables into the array (%WNL% means Windows New Line) OUTER_FOR(index = 0; index < ~!_slotNumbers~; ++index) BEGIN OUTER_SPRINT ~!_arraySlots~ ~%!_arraySlots% "%%!_setArrayName%%index%%"%WNL%~ END APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ ~%!_arraySlots%~ APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ ~%!_arraySlots%~ // Closes dynamic array and makes it usable by WeiDU with // e.g. INCLUDE/REINCLUDE (The tab space is for formatting) APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ ~ END END~ APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ ~ END END~ REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_setArrayName%.tph~ REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_setArrayName%.tph~ // Resets macro variables OUTER_SET ~!_slotNumbers~ = 0 OUTER_SPRINT ~!_setArrayName~ ~!_NULL~ END// End of "DYN_ARRAY_CREATE" // Purpose: Reads the buffer file for the specified array into a file. // This function mustn't be used outside this library. // ---------------------------------------------------------------------------------------------- // Parameters:| // ============ // position -> The array slot position/index in which the new value will be written // UseArrayName -> The required name of the array in which the new values will be written. // bufferValue -> The required string containing the buffered values DEFINE_DIMORPHIC_FUNCTION DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = "-1" STR_VAR UseArrayName= ~!_NULL~ bufferValue = ~~ functionType= ~!_NULL~ BEGIN ACTION_IF (~%functionType%~ STRING_EQUAL ~PATCH~) THEN BEGIN // This little line does not work inside of a patch macros, // thus it is wrapped in this dimorphic function APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%UseArrayName%Buffer.tph~ ~%bufferValue%~ END ELSE ACTION_IF (~%functionType%~ STRING_EQUAL ~OUTER~) THEN BEGIN APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%UseArrayName%Buffer.tph~ ~%bufferValue%~ END ELSE BEGIN FAIL ~DEFINE_DIMORPHIC_FUNCTION DYN_ARRAY_BUFFER_TO_FILE %UseArrayName% -> The function type argument is missing or invalid. The allowed function types are PATCH and OUTER.~ END END// End of "DYN_ARRAY_BUFFER_TO_FILE" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the these variables to another location and change their values before calling the macro. // It is important to note that this macro has a patch version. OUTER_SET ~!_position~ = "-1" OUTER_SET ~!_maxSlots~ = "-1" OUTER_SET ~!_collected~= "-1" OUTER_SPRINT ~!_useArrayName~ ~!_NULL~ OUTER_SPRINT ~!_arrayValue~ ~!_NULL~ // Purpose: Replaces/sets values in a dynamic array // ------------------------------------------------ // Parameters:| // ============ // !_position -> The array slot position/index in which the new value will be written // !_maxSlots -> The highest value the argument for position/index is allowed to be. // The maximum is in general the max number of elments the array can contain // !_collected -> A flag that indicates whether or not the collection process is complete. // 0: Collection is in progress. // 1: Collection is complete. // !_useArrayName -> The array name in which the array value is written // !_arrayValue -> The value that is planned to be written to the array. DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_position~ = "-1" // INTEGER ~!_maxSlots~ = "-1" // INTEGER ~!_collected~= "-1" // STRING ~!_useArrayName~ ~!_NULL~ // INTEGER/STRING ~!_arrayValue~ ~!_NULL~ // STRING ~!_bufferValue~ ~~ // ---------------------------------------------- // Corrects number of elements to slot index OUTER_SET ~!_maxSlots~ = ~%!_maxSlots%~ - 1 // Checks if an array index is not given ACTION_IF (~%!_position%~ <= "-1") THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct position as an argument is missing. The position value must be greater than -1!~ END // Checks if a highest array slot number is not given or if it makes any sense ACTION_IF ( (~%!_maxSlots%~ <= "-1") OR (~%!_maxSlots%~ < ~%!_position%~) ) THEN BEGIN // Prepares value for error output OUTER_SET ~!_maxSlots~ = ~%!_maxSlots%~ + 1 FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct maxSlots as an argument is missing. The maxSlots value is %!_maxSlots%, but must be greater than -1 and greater %!_position%!~ END // Checks if an array name is not given ACTION_IF (~%!_useArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if an array index is not given ACTION_IF (~%!_collected%~ <= "-1" OR ~%!_collected%~ >= 2) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The argument for "!_collected" is %!_collected%. Allowed values are 0(for still collecting) and 1(value collection is done) !~ END // Checks if the array value is an integer and calls the appropriate function // to prepare the abstract array element information. ACTION_IF (IS_AN_INT ~%!_arrayValue%~) THEN BEGIN ACTION_IF (~%!_arrayValue%~ > "-1") THEN BEGIN // Positive values including 0 OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SET ~%!_useArrayName%%!_position%~ = %!_arrayValue%%WNL%~~~~~ END ELSE BEGIN // Negative values OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SET ~%!_useArrayName%%!_position%~ = "%!_arrayValue%"%WNL%~~~~~ END // If value is not integer then it is string END ELSE BEGIN OUTER_SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% OUTER_SPRINT ~%!_useArrayName%%!_position%~ ~%!_arrayValue%~%WNL%~~~~~ END // If all values are collected then write it into array ACTION_IF (~%!_collected%~ = 1) THEN BEGIN LAF DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = ~%!_position%~ STR_VAR UseArrayName= EVAL~%!_useArrayName%~ bufferValue = EVAL~%!_bufferValue%~ functionType= EVAL~OUTER~ END // Writes into the dynamic array REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_useArrayName%Buffer.tph~ LAM ~!_%!_useArrayName%~ // Resets global lib variable OUTER_SPRINT ~!_bufferValue~ ~~ // Resets macro variables OUTER_SET ~!_position~ = "-1" OUTER_SET ~!_maxSlots~ = "-1" OUTER_SET ~!_collected~= "-1" OUTER_SPRINT ~!_useArrayName~ ~!_NULL~ OUTER_SPRINT ~!_arrayValue~ ~!_NULL~ END END// End of "DYN_ARRAY_SET_VALUES" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the commented SET variables to another location and change their values before calling the macro. // It is important to note that this macro has a outer version. //SET ~!_position~ = "-1" //SET ~!_maxSlots~ = "-1" //SET ~!_collected~= "-1" //SPRINT ~!_useArrayName~ ~!_NULL~ //SPRINT ~!_arrayValue~ ~!_NULL~ // Purpose: Replaces/sets patch values in a dynamic array // ------------------------------------------------------ // Parameters:| // ============ // !_position -> The array slot position/index in which the new value will be written // !_maxSlots -> The highest value the argument for position/index is allowed to be. // The maximum is in general the max number of elments the array can contain // !_collected -> A flag that indicates whether or not the collection process is complete. // 0: Collection is in progress. // 1: Collection is complete. // !_useArrayName -> The array name in which the array value is written // !_arrayValue -> The value that is planned to be written to the array. DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // INTEGER ~!_position~ = "-1" // INTEGER ~!_maxSlots~ = "-1" // INTEGER ~!_collected~= "-1" // STRING ~!_useArrayName~ ~!_NULL~ // INTEGER/STRING ~!_arrayValue~ ~!_NULL~ // STRING ~!_bufferValue~ ~~ // ---------------------------------------------- // Corrects number of elements to slot index SET ~!_maxSlots~ = ~!_maxSlots~ - 1 // Checks if an array index is not given PATCH_IF (~%!_position%~ <= "-1") THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct position as an argument is missing. The position value must be greater than -1!~ END // Checks if a highest array slot number is not given or if it makes any sense PATCH_IF ( (~%!_maxSlots%~ <= "-1") OR (~%!_maxSlots%~ < ~%!_position%~) ) THEN BEGIN // Prepares value for error output SET ~!_maxSlots~ = ~!_maxSlots~ + 1 PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The correct maxSlots as an argument is missing. The maxSlots value is %!_maxSlots%, but must be greater than -1 and greater %!_position%!~ END // Checks if an array name is not given PATCH_IF (~%!_useArrayName%~ STRING_EQUAL ~!_NULL~) THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Checks if an array index is not given PATCH_IF (~%!_collected%~ <= "-1" OR ~%!_collected%~ >= 2) THEN BEGIN PATCH_FAIL ~DEFINE_PATCH_MACRO DYN_ARRAY_SET_VALUES %!_useArrayName% -> The argument for "!_collected" is %!_collected%. Allowed values are 0(for still collecting) and 1(value collection is done) !~ END // Checks if the array value is an integer and calls the appropriate function // to prepare the abstract array element information. PATCH_IF (IS_AN_INT ~%!_arrayValue%~) THEN BEGIN PATCH_IF (~%!_arrayValue%~ > "-1") THEN BEGIN // Positive values including 0 SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SET ~%!_useArrayName%%!_position%~ = %!_arrayValue%%WNL%~~~~~ END ELSE BEGIN // Negative values SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SET ~%!_useArrayName%%!_position%~ = "%!_arrayValue%"%WNL%~~~~~ END // If value is not integer then it is string END ELSE BEGIN SPRINT ~!_bufferValue~ ~~~~~%!_bufferValue% SPRINT ~%!_useArrayName%%!_position%~ ~%!_arrayValue%~%WNL%~~~~~ END // If all values are collected then write it into array PATCH_IF (~%!_collected%~ = 1) THEN BEGIN LPF DYN_ARRAY_BUFFER_TO_FILE INT_VAR position = ~%!_position%~ STR_VAR UseArrayName= EVAL~%!_useArrayName%~ bufferValue = EVAL~%!_bufferValue%~ functionType= EVAL~PATCH~ END // Writes into the dynamic array PATCH_REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_useArrayName%Buffer.tph~ LPM ~!_%!_useArrayName%~ // Resets global lib variable SPRINT ~!_bufferValue~ ~~ // Resets macro variables SET ~!_position~ = "-1" SET ~!_maxSlots~ = "-1" SET ~!_collected~= "-1" SPRINT ~!_useArrayName~ ~!_NULL~ SPRINT ~!_arrayValue~ ~!_NULL~ END END// End of "DYN_ARRAY_SET_VALUES" // ---DEFAULT/INIT ARGUMENTS(Don't change these!) // USAGE: Copy the variable 1 to 1 to somewhere else where you need it // and change its value before before calling the macro.!!! // This macro can not be used in patching. OUTER_SPRINT ~!_deleteArray~ ~!_NULL~ // Purpose: Deletes all created dynamic array files for patch and outer version // ---------------------------------------------------------------------------- // Parameters:| // ============ // !_deleteArray -> The array name for which the files will be deleted // ------------------------------------------------------------------- DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // STRING ~!_deleteArray~ ~!_NULL~ // ---------------------------------------------- // ---WARNING: Will output an error if local variables are not placed directly at the beginning of macros LOCAL_SPRINT outerBufferFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_%!_deleteArray%Buffer.tph~ LOCAL_SPRINT patchBufferFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/values/!_patch%!_deleteArray%Buffer.tph~ LOCAL_SPRINT outerArrayFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_%!_deleteArray%.tph~ LOCAL_SPRINT patchArrayFilename ~./weidu_external/%MOD_FOLDER%/temp/arrays/!_patch%!_deleteArray%.tph~ // The macro fails if no array name is given because it needs to know which array to delete the files for. ACTION_IF (~%!_deleteArray%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEAR_BUFFER -> The correct array name as an argument is missing. The array name !_NULL is forbidden.~ END // Deletes the buffer files for the specified array. ACTION_IF(FILE_EXISTS ~%outerBufferFilename%~) THEN BEGIN DELETE ~%outerBufferFilename%~ PRINT ~Deleted %outerBufferFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %outerBufferFilename%!~ END ACTION_IF(FILE_EXISTS ~%patchBufferFilename%~) THEN BEGIN DELETE ~%patchBufferFilename%~ PRINT ~Deleted %patchBufferFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %patchBufferFilename%!~ END // Deletes the definition files for the specified array. ACTION_IF(FILE_EXISTS ~%outerArrayFilename%~) THEN BEGIN DELETE ~%outerArrayFilename%~ PRINT ~Deleted %outerArrayFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %outerArrayFilename%!~ END ACTION_IF(FILE_EXISTS ~%patchArrayFilename%~) THEN BEGIN DELETE ~%patchArrayFilename%~ PRINT ~Deleted %patchArrayFilename% belonging to %!_deleteArray% dynamic array~ END ELSE BEGIN WARN ~DEFINE_ACTION_MACRO DYN_ARRAY_CLEANUP -> Couldn't find and delete %patchArrayFilename%!~ END END// End of "DYN_ARRAY_CLEANUP" Edited January 29 by Incrementis Informing about changes and future updates Quote Link to comment
guyudennis Posted October 11, 2023 Share Posted October 11, 2023 Here is yet another "spell-2-innate" type of function, which is based on Subtledoctor's original function, while the op146/148 target matching portion is based on Luke's MAKE_SPELL-LIKE_ABILITY. Spoiler //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Borrowed and adapted from Subtledoctor's 5E Spellcasting: create wrapper spell from any existing payload spell // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// DEFINE_ACTION_FUNCTION PAYLOAD_SPELL_TO_WRAPPER_SPELL INT_VAR wrapper_type = 4 // default to innate (0 - special, 1 - wizard, 2 - priest, 3 - psionic, 4 - innate, 5 - bard song) wrapper_location = 4 // default to ability (0 - none, 1 - weapon, 2 - spell, 3 - item, 4 - ability) op148_fix = 0 // default to no fix (0 - no fix, 1 - fix spell range for op148) STR_VAR payload_spell = ~~ wrapper_spell = ~~ wrapper_name = ~~ // default to empty (payload spell name) wrapper_desc = ~~ // default to empty (payload spell description) RET debug_msg BEGIN COPY_EXISTING ~%payload_spell%.spl~ ~override/%wrapper_spell%.spl~ READ_STRREF NAME1 payload_name PATCH_IF (STRING_LENGTH ~%wrapper_name%~ > 0) BEGIN SAY NAME1 ~%wrapper_name%~ END READ_STRREF NAME1 wrapper_name PATCH_IF (STRING_LENGTH ~%wrapper_desc%~ > 0) BEGIN SAY UNIDENTIFIED_DESC ~%wrapper_desc%~ END WRITE_SHORT 0x1c wrapper_type PATCH_IF wrapper_type = 4 BEGIN WRITE_BYTE 0x27 0 // no sectype for innates END LPF ALTER_SPELL_HEADER INT_VAR location = wrapper_location END READ_LONG 0x64 abil_offset READ_SHORT 0x68 abil_number READ_BYTE (abil_offset + 0x0c) abil_target READ_SHORT (abil_offset + 0x0e) abil_range WHILE (abil_number > 1) BEGIN SET abil_number = (abil_number - 1) READ_SHORT (abil_offset + 0x10 + (0x28 * abil_number)) abil_minlv LPF DELETE_SPELL_HEADER INT_VAR header_type = "-1" min_level = abil_minlv END // delete all but the 1st ability header END PATCH_IF wrapper_type = 4 BEGIN WRITE_SHORT (abil_offset + 0x12) 0 // instant casting (speed) for innates END WRITE_SHORT (abil_offset + 0x26) 1 // set projectile to none LPF DELETE_EFFECT END // delete all existing spell extended effects PATCH_MATCH abil_target WITH 4 BEGIN // any point within range LPF ADD_SPELL_EFFECT INT_VAR opcode = 148 target = 1 parameter2 = 1 timing = 1 STR_VAR resource = EVAL ~%payload_spell%~ END // cast spell at point: payload spell PATCH_IF (op148_fix = 1) BEGIN PATCH_IF (abil_range < 35) BEGIN PATCH_IF (abil_range > 4) BEGIN LPF ALTER_SPELL_HEADER INT_VAR range = (abil_range - 3) END END PATCH_IF (abil_range < 5) BEGIN LPF ALTER_SPELL_HEADER INT_VAR target = 5 END END END END END 1 BEGIN // living actor LPF ADD_SPELL_EFFECT INT_VAR opcode = 146 target = 2 parameter2 = 1 timing = 1 STR_VAR resource = EVAL ~%payload_spell%~ END // caste spell at creature: payload spell END 5 7 BEGIN // caster LPF ADD_SPELL_EFFECT INT_VAR opcode = 146 target = 1 parameter2 = 1 timing = 1 STR_VAR resource = EVAL ~%payload_spell%~ END // caste spell at creature: payload spell END DEFAULT PATCH_FAIL ~PAYLOAD_SPELL_TO_WRAPPER_SPELL: ability target matching failure~ END BUT_ONLY OUTER_TEXT_SPRINT debug_msg ~Wrapper spell %wrapper_spell% (%wrapper_name%) of type %wrapper_type% created at location %wrapper_location% to launch payload spell %payload_spell% (%payload_name%).~ END The function would make a "wrapper spell" that would in turn launch a "payload spell", regardless if it's uninterruptible or not. For the wrapper spell, one can further define spell type, spell location, spell name, and spell description. Otherwise, it would retain the payload spell's most information intact (sectype would be changed to none and casting speed to zero in case of innate type), have only one ability header without any projectile, and have only one extended effect to launch the payload spell (via 146/148 depending on the payload spell's targeting). There is an additional boolean variable to enable Subtledoctor's original fix to op148's targeting. I could not reproduce the intended issue in game myself, so I made it default to no-fix. Sample usage: Spoiler LAF PAYLOAD_SPELL_TO_WRAPPER_SPELL INT_VAR wrapper_type = 4 wrapper_location = 4 STR_VAR payload_spell = EVAL ~sppr731~ // fire elemental transformation wrapper_spell = EVAL ~spdr701~ wrapper_name = EVAL ~optional unique wrapper name~ wrapper_desc = EVAL ~optional unique wrapper description~ RET debug_msg END PRINT ~%debug_msg%~ Thanks go to @subtledoctor and @jmerry for their patience and help. Quote Link to comment
jmerry Posted October 13, 2023 Share Posted October 13, 2023 Inspired by a case in which some other mod screwed up and named a file with the wrong extension, leading to a component in my mod choking on that file, here's a near-universal sanity check function for IE binary formats. This checks the signature (first eight bytes of the file) against its extension, and checks whether the file is large enough for its type. If everything matches, return true (1). Otherwise, return false (0). Many mods use sanity checks on size, but I'm not aware of any that also check for extension/signature matching. Go through all .SPL files, run CLONE_EFFECT to do the component's thing, fail because that one .SPL file is actually an EFF. Oops. A size check alone wouldn't have caught this, as an EFF's size (0x110) is more than twice the size of a minimal SPL (0x72). This function, however, would work. Documentation blurb: Spoiler // This is a PATCH function. file_sanity_check runs on almost any IE binary format and tests whether // the file has the proper type signature and is an appropriate size. The function will return 1 if // the file extension matches its signature and the file is sufficiently large, as determined by the // info array defined below. If the signature and extension don't match, the file is too small, or // the file type isn't one of those checked against, the function will return zero. // // This function assumes that the SOURCE_SIZE and SOURCE_EXT variables defined by the COPY operations // are valid for the current file. After all, if you're using this function, it should be the first // thing you do after opening a file. // // The function takes no arguments, and returns the integer "valid" as either 0 or 1. Full code, suitable for saving as a tpa file: Spoiler // This is a PATCH function. file_sanity_check runs on almost any IE binary format and tests whether // the file has the proper type signature and is an appropriate size. The function will return 1 if // the file extension matches its signature and the file is sufficiently large, as determined by the // info array defined below. If the signature and extension don't match, the file is too small, or // the file type isn't one of those checked against, the function will return zero. // // This function assumes that the SOURCE_SIZE and SOURCE_EXT variables defined by the COPY operations // are valid for the current file. After all, if you're using this function, it should be the first // thing you do after opening a file. // // The function takes no arguments, and returns the integer "valid" as either 0 or 1. DEFINE_PATCH_FUNCTION file_sanity_check RET valid BEGIN DEFINE_ASSOCIATIVE_ARRAY filetype_info BEGIN // Extension, min size => signature in first eight bytes of file ~ARE~, ~0x11C~ => ~AREAV1.0~ ~ARE~, ~0x12C~ => ~AREAV9.1~ ~BAM~, ~0x18~ => ~BAM V1 ~ ~BAM~, ~0x20~ => ~BAM V2 ~ ~BIF~, ~0x14~ => ~BIFFV1 ~ ~BIF~, ~0x14~ => ~BIF V1.0~ ~BIF~, ~0xC~ => ~BIFCV1.0~ ~CHR~, ~0x64~ => ~CHR V1.0~ ~CHR~, ~0x64~ => ~CHR V1.2~ ~CHR~, ~0x64~ => ~CHR V2.0~ ~CHR~, ~0x224~ => ~CHR V2.2~ ~CHR~, ~0x64~ => ~CHR V9.0~ ~CHU~, ~0x14~ => ~CHU V1 ~ ~CRE~, ~0x2D4~ => ~CRE V1.0~ ~CRE~, ~0x378~ => ~CRE V1.2~ ~CRE~, ~0x62D~ => ~CRE V2.2~ ~CRE~, ~0x33C~ => ~CRE V9.0~ ~DLG~, ~0x34~ => ~DLG V1.0~ ~EFF~, ~0x110~ => ~EFF V2.0~ ~GAM~, ~0xB8~ => ~GAMEV1.1~ ~GAM~, ~0xB4~ => ~GAMEV2.0~ ~GAM~, ~0xB4~ => ~GAMEV2.2~ ~ITM~, ~0x72~ => ~ITM V1 ~ ~ITM~, ~0x9A~ => ~ITM V1.1~ ~ITM~, ~0x92~ => ~ITM V2.0~ ~KEY~, ~0x18~ => ~KEY V1 ~ ~MOS~, ~0x18~ => ~MOS V1 ~ ~MOS~, ~0x18~ => ~MOS V2 ~ ~PLT~, ~0x18~ => ~PLT V1 ~ ~PRO~, ~0x100~ => ~PRO V1.0~ ~SAV~, ~0x8~ => ~SAV V1.0~ ~SPL~, ~0x72~ => ~SPL V1 ~ ~SPL~, ~0x82~ => ~SPL V2.0~ ~STO~, ~0x9C~ => ~STORV1.0~ ~STO~, ~0x9C~ => ~STORV1.1~ ~STO~, ~0xF0~ => ~STORV9.0~ ~TIS~, ~0x18~ => ~TIS V1 ~ ~TLK~, ~0x12~ => ~TLK V1 ~ ~VVC~, ~0x1EC~ => ~VVC V1.0~ ~WED~, ~0x20~ => ~WED V1.3~ ~WFX~, ~0x108~ => ~WFX V1.0~ ~WMP~, ~0x10~ => ~WMAPV1.0~ END SET valid = 0 PATCH_IF (%SOURCE_SIZE% >= 8) BEGIN // We need to read the eight-byte signature READ_ASCII 0 signature PHP_EACH filetype_info AS info => type BEGIN PATCH_IF (~%read_signature%~ STR_EQ ~%type%~) BEGIN PATCH_IF (~%SOURCE_EXT%~ STR_EQ ~%info_0%~ AND %SOURCE_SIZE% >= %info_1%) BEGIN SET valid = 1 END END END END END (Not tested. If there are any errors, please point them out so they can be corrected.) Quote Link to comment
Incrementis Posted October 25, 2023 Share Posted October 25, 2023 (edited) Hello folks, here's a macros I wrote myself for something else. It creates a file in a defined location (NOTE: The default location is the game folder). I have also written detailed documentation which can be found here on GitHub. Use it as you see fit. No credits are required because the code is too trivial, but if you still want to give me credits, I'm not against it either. Macros: Spoiler // Never Forget: Comments can "lie", but code not so much //--------------------------------------// // Contains self defined file operations// //--------------------------------------// // ---DEFAULT/INIT ARGUMENTS(Don't change this!) // USAGE: Copy the variable 1 to 1 to somewhere else where you need it // and change its value before before calling the macro. // This macro can not be used in patching. OUTER_SPRINT ~!_filename~ ~!_NULL~ // Purpose: Creates a file on a defined location(NOTE: default location is the gamefolder) // -------------------------------------------------------------------------------------- // Parameters:| // ============ // !_filename -> The name of the file or the path including the file(e.g. "weidu_external/workspace/filename.tph") DEFINE_ACTION_MACRO CREATE_FILE BEGIN // ALL VARIABLES IN THIS MACRO AND DEFAULT VALUES // ---------------------------------------------- // STRING ~!_filename~ ~!_NULL~ // ---------------------------------------------- // Checks if a proper file name is given ACTION_IF(~%!_filename%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_ACTION_MACRO CREATE_FILE -> The correct argument for filename is missing. The argument !_NULL is forbidden.~ END // Defines file inline then creates and copies file to location <<<<<<<<./weidu_external/workspace/temporaryFile.tph >>>>>>>> COPY ~./weidu_external/workspace/temporaryFile.tph~ ~./%!_filename%~ // Resets macro variable OUTER_SPRINT ~!_filename~ ~!_NULL~ END// End of "CREATE_FILE" Example: Spoiler // This will create a file with an extension in a specific folder/path. OUTER_SPRINT ~!_filename~ ~weidu_external/%MOD_FOLDER%/1.tph~ LAM CREATE_FILE If you want to add content to the file: Spoiler // This will append content to the file OUTER_SPRINT text ~HELLO WORLD!~ APPEND_OUTER ~./weidu_external/%MOD_FOLDER%/1.tph~ ~~~~~PRINT ~%text%~ ~~~~~ // Includes file, so "HELLO WORLD" can be printed. INCLUDE ~./weidu_external/%MOD_FOLDER%/1.tph~ Edited October 25, 2023 by Incrementis Small fix, but nothing that breaks the usability of the previous code Quote Link to comment
Incrementis Posted October 27, 2023 Share Posted October 27, 2023 (edited) Good evening everyone! This may be my last post in this thread for a long period of time(because I like to work slowly and have real life things happen, and because I'm relatively new to IE modding). Since I'm working on something else, it creates another library that I'm happy to share. Here are two dimorphic functions: HIGHEST_STR_REF_BY_COUNTING : Calculates the highest strref value in dialog.tlk by iteratively counting through the file. RESOLVE_STR_REF_WITH_STRINGS : Like RESOLVE_STR_REF, but takes only string values to resolve text and soundfile names. For more detailed information, see the documentation on GitHub. Use HIGHEST_STR_REF_BY_COUNTING as you see fit. No credits are required because the code is too trivial, but if you still want to give me credits, I'm not against it either. Use WeiDU's NEXT_STRREF instead to determine the highest strref! WARNING: This function works correctly for the en_US installation of the Enhanced Edition games, as they only have a dialog.tlk file in the "lang" folder. For the other languages, e.g. de_DE(German) the "lang" game folder contains two dialog.tlk files. This causes the "HIGHEST_STR_REF_BY_COUNTING" function to return twice the strref value, which is an incorrect value. RESOLVE_STR_REF_WITH_STRINGS took me a while to write, so just don't forget to mention me by adding me in a little thank you section. RESOLVE_STR_REF_WITH_STRINGS: Spoiler // Purpose: like RESOLVE_STR_REF, but takes only string values to resolve text // and soundfile names. // --------------------------------------------------------------------------- // Parameters:| // ============ // text -> The Text found in dialog.tlk // sound -> The name of the soundfile without ".wav" found in the dialog.tlk // strRef -> The string reference number which is found DEFINE_DIMORPHIC_FUNCTION RESOLVE_STR_REF_WITH_STRINGS STR_VAR text = ~!_NULL~ sound = ~!_NULL~ RET strRef BEGIN // Check if valid arguments are given. ACTION_IF (~%text%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_DIMORPHIC_FUNCTION RESOLVE_STR_REF_WITH_STRINGS -> The correct argument for text is missing. The argument !_NULL is forbidden.~ END // Checks if a valid voxSound is given ACTION_IF (~%sound%~ STRING_EQUAL ~!_NULL~) THEN BEGIN FAIL ~DEFINE_DIMORPHIC_FUNCTION RESOLVE_STR_REF_WITH_STRINGS -> The correct argument for sound is missing. The argument !_NULL is forbidden.~ END // Checks if sound name has more than 8 characters ACTION_IF (STRING_LENGTH ~%sound%~ > 8 ) THEN BEGIN OUTER_SET numbers = STRING_LENGTH ~%sound%~ FAIL ~DEFINE_DIMORPHIC_FUNCTION RESOLVE_STR_REF_WITH_STRINGS -> The argument '%sound%' for sound is %numbers% characters long. The maximum allowed length for this argument is 8 characters~ END // Core part of this function. This part takes the string parameters // and uses them in the same way as RESOLVE_STR_REF. <<<<<<<<./weidu_external/workspace/!_TemporaryResolveStrRef.tph OUTER_SET strRef = RESOLVE_STR_REF(~%text%~ [%sound%]) >>>>>>>> COPY ~./weidu_external/workspace/!_TemporaryResolveStrRef.tph~ ~./weidu_external/%MOD_FOLDER%/temp/values/!_TemporaryResolveStrRef.tph~ EVALUATE_BUFFER REINCLUDE ~./weidu_external/%MOD_FOLDER%/temp/values/!_TemporaryResolveStrRef.tph~ END// End of "RESOLVE_STR_REF_WITH_STRINGS" HIGHEST_STR_REF_BY_COUNTING: Deprecated Spoiler // Purpose: Calculates the highest strref value in dialog.tlk // by iteratively counting through the file. // ----------------------------------------------------------- // Parameters:| // ============ // strRef -> The highest strref value in dialog.tlk DEFINE_DIMORPHIC_FUNCTION HIGHEST_STR_REF_BY_COUNTING RET strRef BEGIN OUTER_SET strRef = 0 // Loops over dialog.tlk ALTER_TLK BEGIN SET strRef = strRef+1 END // Subtracting 1 from strRef to account for the fact that the last iteration // of the loop increments strRef even though it is not a valid strref value. OUTER_SET strRef = strRef - 1 END// End of "HIGHEST_STR_REF_BY_COUNTING" Example for HIGHEST_STR_REF_BY_COUNTING: Deprecated Spoiler BACKUP ~./weidu_external/dialogTLKtest/backup~ AUTHOR ~YOUR NAME~ VERSION ~v0.0.0~ // -------------- // Initialization // -------------- ALWAYS // LIBRARY INCLUDES(Don't change these) // ------------------------------------ INCLUDE ~%MOD_FOLDER%/lib/dialogTlkFunctionalities.tph~ END// End of "ALWAYS" // ----------- // Start Tests // ----------- BEGIN ~TLK-Testing~ // -- Gets Highest stringref value(dialog.tlk) LAF HIGHEST_STR_REF_BY_COUNTING RET max = strRef END // Prints maximum number of strrefs in dialog.tlk PRINT ~%max%~ // Example OUTER_SET min = max - 1000 OUTER_SET strref = min ALTER_TLK_RANGE min max BEGIN // Gets sound and text from string reference GET_STRREF strref refText GET_STRREF_S strref refSound // Print the text and mapped soundfile of the strref in dialog.tlk PATCH_PRINT ~%strref%: %refText% [%refSound%]~ SET strref = strref+1 END Edited January 16 by Incrementis Fixing smileys in code! Quote Link to comment
jmerry Posted October 27, 2023 Share Posted October 27, 2023 2 minutes ago, Incrementis said: Use HIGHEST_STR_REF_BY_COUNTING as you see fit. No credits are required because the code is too trivial, but if you still want to give me credits, I'm not against it either. And yet, it's still not as trivial as it should be. You see, if you look at the tlk format ... the number of strref entries is right there in the header. 4 bytes, offset 0xA. Just read that, and you're done. Much faster than iterating through the file, too. Quote Link to comment
Incrementis Posted October 27, 2023 Share Posted October 27, 2023 (edited) 4 minutes ago, jmerry said: And yet, it's still not as trivial as it should be. You see, if you look at the tlk format ... the number of strref entries is right there in the header. 4 bytes, offset 0xA. Just read that, and you're done. Much faster than iterating through the file, too. Thanks for the alternative. My idea is not to use bits and bytes to code things as much as possible, but that's me. EDIT: Regarding performance. It should be fast enough. Edited October 27, 2023 by Incrementis Forgot to mention something Quote Link to comment
CamDawg Posted December 12, 2023 Author Share Posted December 12, 2023 On 8/24/2017 at 2:00 AM, K4thos said: Action macro that generates JOINABLE_NPC_ARRAY table which can be used to patch joinable NPC CRE files (more reliable method than checking CRE BIO offset) https://github.com/K4thos/IE-code-repository/blob/master/joinable_npc_array.tpa Example usage: LAM JOINABLE_NPC_ARRAY ACTION_PHP_EACH JOINABLE_NPC_ARRAY AS cre => dv BEGIN PRINT ~%cre% => %dv%~ COPY_EXISTING ~%cre%~ ~override~ //your patching code END For anyone interested in using this beyond the EEs, I've adapted this for Tweaks Anthology to cover all games. oBG, oBG2, and the EEs all have a working pdialog so they're tied into the existing scheme. I use a static NPC list for oPsT and IWD2, if NPCs from IWD2EE are installed. I also log the non-joinables (as DV=0), since I have some components that target them specifically. I pulled it out of the macro and just INCLUDE as needed. Here's the main library, and some example uses: Max HP Creatures, targeting only non-joinable NPCs via IS_AN_INT ~%dv%~ or joinables with the inverse check. It can also be used to target specific NPCs, e.g. Imoen, Minsc, or Korgan. Quote Link to comment
DavidW Posted December 15, 2023 Share Posted December 15, 2023 This is partly just for amusement, but I can see possible places it would be useful in complicated mods: functionality to create arrays with global scope even inside a function. Example of use: INCLUDE "%MOD_FOLDER%/lib_globalize.tph" DEFINE_ACTION_FUNCTION fn BEGIN ACTION_CLEAR_ARRAY test_array ACTION_DEFINE_ASSOCIATIVE_ARRAY test_array BEGIN minsc=>awesome anomen=>annoying aerie=>wet sarevok=>treacherous END LAF globalize_array_save STR_VAR array=test_array END END DEFINE_ACTION_FUNCTION fn2 BEGIN ACTION_CLEAR_ARRAY test_array ACTION_DEFINE_ASSOCIATIVE_ARRAY test_array BEGIN viconia=>hot korgan=>psychopath edwin=>trap-fodder END LAF globalize_array_save INT_VAR append=1 STR_VAR array=test_array END END LAF fn END LAF globalize_array_load STR_VAR array=test_array RET_ARRAY test_array=array END ACTION_PHP_EACH test_array AS k=>v BEGIN PRINT "%k%: %v%" END LAF fn2 END LAF globalize_array_load STR_VAR array=test_array RET_ARRAY test_array=array END ACTION_PHP_EACH test_array AS k=>v BEGIN PRINT "%k%: %v%" END Library attached; see if you can guess how it works before looking! (Hint: it doesn't just involve reading in a textfile each time, though I'm unclear whether that would be quicker.) lib_globalize.tph Quote Link to comment
Incrementis Posted January 5 Share Posted January 5 Good morning everyone, I found some time to work on something, but even though it's not finished yet, it's created two libraries that I'm happy to share (Yes, I'm very slow, but hobbies are fun and rushing isn't). Here are four dimorphic functions: ERR_EVALUATE_FILE_EXISTANCE: Raises an error if the specified file exists and prevents further installation ERR_EVALUATE_GAME_EXISTANCE: Raises an error if the specified WeiDU game short is detected and prevents further installation WARN_EVALUATE_FILE_EXISTANCE: Raises a warning if the specified file exists WARN_EVALUATE_GAME_EXISTANCE: Raises a warning if the specified WeiDU game short is detected For more detailed information, see the documentation on GitHub. prefix "ERR" in "ERR_<function name>" indicates that this is an error function prefix "WARN" in "WARN_<function name>" indicates that this is a warning function No credits are required as sanity checks in mods help to better understand the code and mods and create a healthier environment so that everyone benefits. errors.tph Spoiler // Never Forget: Comments can "lie", but code not so much ;P //----------------------------------------// // Contains custom defined error functions// //----------------------------------------// // Purpose: Raises an error if the specified file exists and prevents further installation // --------------------------------------------------------------------------------------- // Parameters:| // ============ // file -> The name of the file to check for existence // message -> The error message to display upon file existence DEFINE_DIMORPHIC_FUNCTION ~ERR_EVALUATE_FILE_EXISTANCE~ STR_VAR file = ~~ message = ~~ BEGIN ACTION_IF (FILE_EXISTS ~%file%~) THEN BEGIN FAIL ~%message%~ END END // End of "ERR_EVALUATE_FILE_EXISTANCE" // Purpose: Raises an error if the specified WeiDU game short is detected and prevents further installation // -------------------------------------------------------------------------------------------------------- // Parameters:| // ============ // game -> The WeiDU game short identifier to check for installation // message -> The error message to display if the specified game is detected DEFINE_DIMORPHIC_FUNCTION ~ERR_EVALUATE_GAME_EXISTANCE~ STR_VAR game = ~~ message = ~~ BEGIN ACTION_IF (GAME_IS ~%game%~) THEN BEGIN FAIL ~%message%~ END END // End of "ERR_EVALUATE_GAME_EXISTANCE" warnings.tph Spoiler // Never Forget: Comments can "lie", but code not so much ;P //------------------------------------------// // Contains custom defined warning functions// //------------------------------------------// // Purpose: Raises a warning if the specified file exists // ------------------------------------------------------ // Parameters:| // ============ // file -> The name of the file to check for existence // message -> The warning message to display upon file existence DEFINE_DIMORPHIC_FUNCTION ~WARN_EVALUATE_FILE_EXISTANCE~ STR_VAR file = ~~ message = ~~ BEGIN ACTION_IF (FILE_EXISTS ~%file%~) THEN BEGIN PRINT ~--------~ PRINT ~WARNING:~ PRINT ~--------~ PRINT ~%message%~ END END // End of "WARN_EVALUATE_FILE_EXISTANCE" // Purpose: Raises a warning if the specified WeiDU game short is detected // ----------------------------------------------------------------------- // Parameters:| // ============ // game -> The WeiDU game short identifier to check for installation // message -> The warning message to display if the specified game is detected DEFINE_DIMORPHIC_FUNCTION ~WARN_EVALUATE_GAME_EXISTANCE~ STR_VAR game = ~~ message = ~~ BEGIN ACTION_IF (GAME_IS ~%game%~) THEN BEGIN PRINT ~--------~ PRINT ~WARNING:~ PRINT ~--------~ PRINT ~%message%~ END END // End of "WARN_EVALUATE_GAME_EXISTANCE" Possible use for error: Spoiler BEGIN ~Games incompatible~ // Creates an array with game shortcuts which are incompatible with mod (produces no error for BG:EE, see comment in array) ACTION_DEFINE_ARRAY games_incompatible BEGIN ~bg2~ ~tob~ ~iwd2~ ~pst~ ~bg1~ ~totsc~ ~iwd1~ ~how~ ~totlm~ ~tutu~ ~tutu_totsc~ ~bgt~ ~ca~ ~iwd_in_bg2~ //~bgee~ ~bg2ee~ ~eet~ ~iwdee~ ~pstee~ END // OUTSIDE OF PATCHING // ------------------- OUTER_SPRINT error ~Mod is incompatible with game! The Installation is aborted.~ // Checks all game shortcuts OUTER_FOR (index = 0; VARIABLE_IS_SET $games_incompatible(~%index%~); ++index) BEGIN // Gets specific game shortcut OUTER_TEXT_SPRINT game $games_incompatible(~%index%~) // Calls error LAF ERR_EVALUATE_GAME_EXISTANCE STR_VAR game = EVAL ~%game%~ message = EVAL ~%error%~ END END Possible use for warning: Spoiler // Creates an array with game shortcuts whose compatibilty with the mod is uncertain (produces no warning for BG:EE, see comment in array) ACTION_DEFINE_ARRAY games_insecure_compatibility BEGIN ~bg2~ ~tob~ ~iwd2~ ~pst~ ~bg1~ ~totsc~ ~iwd1~ ~how~ ~totlm~ ~tutu~ ~tutu_totsc~ ~bgt~ ~ca~ ~iwd_in_bg2~ //~bgee~ ~bg2ee~ ~eet~ ~iwdee~ ~pstee~ END // OUTSIDE OF PATCHING // ------------------- OUTER_SPRINT warning ~Insecure game compatibility detected! No guarantee for smooth functionality in case of successful installation. If you encounter an error after installation, this may be the cause.~ // Checks all game shortcuts OUTER_FOR (index = 0; VARIABLE_IS_SET $games_insecure_compatibility(~%index%~); ++index) BEGIN // Gets specific game shortcut OUTER_TEXT_SPRINT game $games_insecure_compatibility(~%index%~) // Calls warning LAF WARN_EVALUATE_GAME_EXISTANCE STR_VAR game = EVAL ~%game%~ message = EVAL ~%warning%~ END END Quote Link to comment
DavidW Posted January 10 Share Posted January 10 On 12/29/2022 at 1:45 AM, jmerry said: More than a year later ... definitely overcomplicated. The built-in operation READ_2DA_ENTRIES_NOW already does this. See here for an example use: https://www.gibberlings3.net/forums/topic/36117-weidu-question-scope-from-read_2da_entries_now/ A year later still... well, yes and no. The thing READ_2DA_ENTRIES_NOW spits out isn't a proper array: you can't PHP_EACH through it or return it from a function. (Effectively my function is a wrap for READ_2DA_ENTRIES_NOW that returns a proper array.) Quote Link to comment
DavidW Posted January 10 Share Posted January 10 Apropos this conversation, here's an SFO function which as it happens is self-contained. It attempts to diagnose whether a 2DA file is broken (or has incomplete lines, which technically is legal but annoys WEIDU), and then fix broken 2DA files by (i) forcing the first line to be '2DA V1.0' (ii) removing any entry beyond the first on the second line (iii) truncating any entries that lie beyond the range defined by the columns on the third line (iv) filling in any incomplete entries with the array's default character. Returns 'legal', which is 1 or 0, and 'fixed_file', which is just a string containing the full contents of the file. Optional argument: 'apply_to_file' (can be 1 or 0, default is 1); if set to 1, the changes are actually carried out on the file being patched; if set to 0, they're discarded (but contained in the 'fixed_file' variable - this is because my use case is nondestructive read). As with all my functions, this assumes AUTO_EVAL_STRINGS. DEFINE_PATCH_FUNCTION 2da_fix INT_VAR apply_to_file=1 RET legal fixed_file BEGIN COUNT_2DA_COLS colcount COUNT_2DA_ROWS 1 rowcount_one COUNT_2DA_ROWS 2 rowcount_two COUNT_2DA_ROWS colcount rowcount_max COUNT_2DA_ROWS (colcount - 1) rowcount_max_minus_one PATCH_IF rowcount_one>=4 BEGIN PATCH_MATCH colcount WITH 1 BEGIN // no salvageable 2da file has colcount=1 PATCH_FAIL "2da_sanity_check: current file (probably %SOURCE_FILE%) is unfixable" END 2 BEGIN // all rows should have 2 columns except the default and the column labels legal = (rowcount_one = rowcount_two + 2) END 3 BEGIN // there should be one 1-column row (the default), two 2-column rows (the sig and the column labels) and the rest 3-column legal = (rowcount_one = rowcount_max + 3) && (rowcount_two = rowcount_max + 2) END DEFAULT // there should be one 1-column row, 1 2-column row, 1 (N-1)-column row, and the rest N columns legal = (rowcount_one = rowcount_max + 3) && (rowcount_two = rowcount_max +2) && (rowcount_max_minus_one = rowcount_max + 1) END END ELSE BEGIN legal=1 // we can't fix problems in empty 2DAs END PATCH_IF legal BEGIN READ_ASCII 0x0 fixed_file (BUFFER_LENGTH) END ELSE BEGIN // get the contents READ_ASCII 0x0 data (BUFFER_LENGTH) // break into lines INNER_PATCH "%data%" BEGIN CLEAR_ARRAY lines count=0 REPLACE_EVALUATE "^\([^%WNL%%MNL%%LNL%]+\)" BEGIN SPRINT $lines("%count%") "%MATCH1%" ++count END "" END // fix first line if necessary SPRINT $lines(0) "2DA V1.0" // get default character and fix if needed SPRINT default_line $lines(1) INNER_PATCH "%default_line%" BEGIN REPLACE_EVALUATE "^\([^ %TAB%]+\)" BEGIN SPRINT default_entry "%MATCH1%" END "" END SPRINT $lines(1) "%default_entry%" // get the column count SPRINT column_line $lines(2) INNER_PATCH " %column_line%" BEGIN // extra space just in case count=0 REPLACE_EVALUATE "[ %TAB%]+[^ %TAB%]+" BEGIN ++count END "" END real_colcount=count // fix the remaining lines PHP_EACH lines AS line_num=>line BEGIN PATCH_IF line_num>2 BEGIN SPRINT line_new "" INNER_PATCH " %line%" BEGIN // extra space just in case count=0 REPLACE_EVALUATE "[ %TAB%]+\([^ %TAB%]+\)" BEGIN PATCH_IF count<=real_colcount BEGIN SPRINT line_new "%line_new%%MATCH1% " END ++count END "" END FOR (n=count;n<=real_colcount;++n) BEGIN SPRINT line_new "%line_new%%default_entry% " END SPRINT $lines("%line_num%") "%line_new%" END END // make the file SPRINT fixed_file "" PHP_EACH lines AS line_num=>line BEGIN SPRINT fixed_file "%fixed_file%%line%%WNL%" END // apply fix if required PATCH_IF apply_to_file BEGIN DELETE_BYTES 0x0 BUFFER_LENGTH INSERT_BYTES 0x0 STRING_LENGTH "%fixed_file%" WRITE_ASCII 0x0 "%fixed_file%" PRETTY_PRINT_2DA REPLACE_TEXTUALLY "2DA[ %TAB%]+V1\.0" "2DA V1.0" END END END Quote Link to comment
Recommended Posts
Join the conversation
You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.