subtledoctor Posted December 8, 2019 Share Posted December 8, 2019 (edited) On 8/26/2019 at 12:41 AM, K4thos said: I remember reading about a function/macro that can assign spells to CLAB files and append new rows if needed (only if there are no free slot in the column left). I was sure that I will find it in this topic but can't see it mentioned in the first post. If anyone knows where to get this function please post a link. Not sure there's a lot of value in this, since CLAB files are functionally unlimited, there is no benefit to inserting something into existing rows, versus just APPENDing a new row. In fact there is actually a (minor) advantage in APPENDING, since you can use the first entry to denote what is being added in the new row. (E.g. when I apply an effect to cleric kits that disables Turn Undead, the first entry in that CLAB row is "NO_TURN" so it is easy to read the CLAB table later and see which spell does that.) Of course it's always possible I'm missing something, or not considering some use case! Meantime, I have adapted K4thos fix missing 2da entries function to specifically address missing IDS values in kitlist.2da. The original function doesn't work great here, since the default filler in that entry is not an integer, and even if it was it would not be "correct" (for the very limited definition of "correct" here). This function sets the IDS entry to (0x4000 + (kitlist row # - 12)). This should result in "correct" IDS numbers for any mod-added kits or kits that come after the mages and barbarian. (E.g. when applied to a kitlist.2da with a missing GRIZZLY_BEAR entry, it sets it to 0x00004027.) This does NOT add anything to KIT.IDS - I forget what rules would apply. The use case is limited to creating a well-formed kitlist.2da table for mods (like mine) that perform a lot of reads of that table for various purposes. Spoiler DEFINE_ACTION_FUNCTION fix_kitlist_missing_ids BEGIN COPY_EXISTING ~kitlist.2da~ ~override~ PRETTY_PRINT_2DA PATCH_IF ~%entry%~ STR_EQ ~~ BEGIN READ_2DA_ENTRY 1 0 1 "entry" END COUNT_2DA_COLS "cols" SET cnt = 0 REPLACE_EVALUATE ~^\(.+\)$~ BEGIN PATCH_IF cnt >= 3 BEGIN INNER_PATCH_SAVE MATCH1 ~%MATCH1%~ BEGIN COUNT_REGEXP_INSTANCES ~ +~ num_matches WHILE (num_matches < (cols - 1)) BEGIN REPLACE_TEXTUALLY ~$~ ~ ZZZZZ~ SET num_matches = num_matches + 1 END END END ELSE BEGIN SET cnt = cnt + 1 END END ~%MATCH1%~ PRETTY_PRINT_2DA BUT_ONLY COPY_EXISTING ~kitlist.2da~ ~override~ COUNT_2DA_ROWS 10 rows FOR (row = 1; row < rows; ++row) BEGIN SET val = (row - 12) TEXT_SPRINT new_ids ~000040%val%~ READ_2DA_ENTRY row 9 10 ids_val PATCH_IF !(IS_AN_INT %ids_val%) BEGIN SET_2DA_ENTRY row 9 10 ~0x%new_ids%~ END END BUT_ONLY END No variables, you just call the function with: LAF fix_kitlist_missing_ids END EDIT - updated a bit, now it works even if kitlist.2da has already been treated by the k4thos function and has "*" or some other non-integervalue in the KITIDS column. Edited January 9, 2020 by subtledoctor Quote Link to comment
Luke Posted January 9, 2020 Share Posted January 9, 2020 On 7/29/2018 at 1:23 PM, K4thos said: REPLACE_MULTILINE: Patch function that replaces set or all occurrences of the given regexp pattern in the file with the given string Do you perhaps have a function to add something to a certain section of UI.MENU (e.g., adding a button to LEFT_SIDEBAR_BOTTOM...) Quote Link to comment
subtledoctor Posted February 11, 2020 Share Posted February 11, 2020 On 1/2/2018 at 8:02 PM, CamDawg said: cd_new_portrait_icon, another action function, will find the next available entry and add your strref and bam file to the list. ... As above, it returns 'icon' with the value of the new entry for usage in your spells or items, and you still need to copy your BAM. Anyone know what the requirements are for what the source .BAM file has to look like? Does it need to be a particular size? Or can I just feed it, say, something like a SPWIxxxb.BAM file? Quote Link to comment
kjeron Posted February 11, 2020 Share Posted February 11, 2020 13x13 pixels. They autoscale down to size over the side-bar portrait, but not in the record screen, though they can be made to through some UI changes. Quote Link to comment
argent77 Posted April 2, 2020 Share Posted April 2, 2020 (edited) This is a set of functions that can be used to safely install pvrz-based tilesets without the danger of overwriting pvrz files from other mods or the game itself. It's an expanded version of the functionality already present in current WeiDU, so you can also install BAM V2 and MOS V2 files with it as well. PVRZ filenames used by tilesets are limited to a specific naming scheme. Since it affects the modder prefix of a file there is always a chance to conflict with files from other mods or the game itself. This functionality was requested a while back in the PPG Forums (by @Sam., iirc). I'll post it here because PPG is currently unavailable. The functions (caution: it's quite a lot of code): Spoiler /** * This function returns the PVRZ resource prefix based on the given TIS filename. * Available as ACTION and PATCH function. * * STR_VAR tis_res The TIS filename with or without .tis extension. * RET prefix The PVRZ resource prefix associated with the specified TIS filename. * Returns empty string on error. */ DEFINE_PATCH_FUNCTION TIS_RES_TO_PVRZ STR_VAR tis_res = ~~ RET prefix BEGIN // Make sure only filename without extension is specified PATCH_IF (~%tis_res%~ STRING_CONTAINS_REGEXP ~\.TIS$~ = 0) BEGIN LPF RES_OF_FILESPEC STR_VAR filespec = EVAL ~%tis_res%~ RET tis_res = res END END PATCH_IF (STRING_LENGTH ~%tis_res%~ > 1) BEGIN INNER_PATCH_SAVE prefix ~%tis_res%~ BEGIN DELETE_BYTES 1 1 END END ELSE BEGIN TEXT_SPRINT prefix ~~ END END DEFINE_ACTION_FUNCTION TIS_RES_TO_PVRZ STR_VAR tis_res = ~~ RET prefix BEGIN OUTER_PATCH ~foo~ BEGIN LPF TIS_RES_TO_PVRZ STR_VAR tis_res RET prefix END END END /** * This PATCH function updates all PVRZ references in the BAM V2, MOS V2, or TIS V1 file to the next unoccupied block * of PVRZ indices. It's intended to be used in combination with the action function "INSTALL_PVRZ". * * INT_VAR target_base_index Optional parameter. When specified, the function attempts to use a block of free PVRZ * indices starting at the specified value. * (default: 0 for TIS-related PVRZ files, 1000 otherwise) * RET original_base_index Returns the lowest PVRZ index used by the source BAM, MOS, or TIS. Returns -1 on error. * RET new_base_index Returns the lowest PVRZ index used by the target BAM, MOS, or TIS. Returns -1 on error. * RET index_range Returns the range of reserved PVRZ indices, i.e. the difference between the smallest * and biggest PVRZ index inclusive. Returns 0 on error. */ DEFINE_PATCH_FUNCTION UPDATE_PVRZ_INDICES INT_VAR target_base_index = "-1" RET original_base_index new_base_index index_range BEGIN SET original_base_index = "-1" SET new_base_index = "-1" SET index_range = 0 SET max_base_index = 99999 SET def_base_index = 1000 TEXT_SPRINT prefix ~MOS~ PATCH_IF (ENGINE_IS ~bgee bg2ee iwdee pstee~) BEGIN // initializations SET is_valid = 0 READ_ASCII 0 sig (8) PATCH_MATCH ~%sig%~ WITH ~BAM V2 ~ BEGIN READ_LONG 0x10 num_blocks READ_LONG 0x1c ofs_blocks SET block_size = 28 SET is_valid = 1 END ~MOS V2 ~ BEGIN READ_LONG 0x10 num_blocks READ_LONG 0x14 ofs_blocks SET block_size = 28 SET is_valid = 1 END ~TIS V1 ~ BEGIN READ_LONG 0xc block_size PATCH_IF (block_size = 12) BEGIN READ_LONG 0x08 num_blocks READ_LONG 0x10 ofs_blocks // getting tis resref... PATCH_IF (DIRECTORY_EXISTS ~%DEST_FILESPEC%~) BEGIN TEXT_SPRINT tis_res ~%SOURCE_RES%~ END ELSE BEGIN LPF RES_OF_FILESPEC STR_VAR filespec = EVAL ~%DEST_FILESPEC%~ RET tis_res = res END END // ...to derive pvrz prefix LPF TIS_RES_TO_PVRZ STR_VAR tis_res RET prefix END PATCH_IF (NOT ~%prefix%~ STR_EQ ~~) BEGIN SET max_base_index = 99 SET def_base_index = 0 SET is_valid = 1 END END END DEFAULT END PATCH_IF (is_valid) BEGIN PATCH_IF (target_base_index < 0) BEGIN SET target_base_index = def_base_index END PATCH_IF (target_base_index > max_base_index) BEGIN PATCH_LOG ~Target base index (%target_base_index%) is out of range. Using default value (%def_base_index%).~ SET target_base_index = def_base_index END // finding minimum and maximum pvrz index SET min = max_base_index + 1 SET max = "-1" FOR (i = 0; i < num_blocks; ++i) BEGIN SET ofs = ofs_blocks + i * block_size READ_LONG ofs page PATCH_IF (page >= 0) BEGIN PATCH_IF (page < min) BEGIN SET min = page END PATCH_IF (page > max) BEGIN SET max = page END END END PATCH_IF (min >= 0 && max >= min) BEGIN SET index_range = max - min + 1 LPF FIND_FREE_PVRZ_INDEX INT_VAR num_to_reserve = index_range start_index = target_base_index STR_VAR prefix RET free_index END PATCH_IF (free_index >= 0) BEGIN SET original_base_index = min SET new_base_index = free_index SET offset = new_base_index - original_base_index // updating pvrz references FOR (i = 0; i < num_blocks; ++i) BEGIN SET ofs = ofs_blocks + i * block_size WRITE_LONG ofs (THIS >= 0) ? (THIS + offset) : THIS END SET success = 1 END ELSE BEGIN PATCH_WARN ~Unable to find free block of PVRZ indices. No changes have been made.~ END END ELSE BEGIN PATCH_WARN ~File contains no pvrz references. No changes have been made.~ END END ELSE BEGIN PATCH_WARN ~Unsupported resource type or corrupted BAM V2, MOS V2, or pvrz-based TIS detected. No changes have been made.~ END END ELSE BEGIN PATCH_WARN ~Game is not supported.~ END END /** * This ACTION function copies the specified PVRZ file into the target folder and updates the PVRZ index. * It should be used in conjunction with "UPDATE_PVRZ_INDICES". * * INT_VAR original_base_index The current base index (returned by the function "UPDATE_PVRZ_INDICES" as * "original_base_index"). * INT_VAR new_base_index The new base index (returned by the function "UPDATE_PVRZ_INDICES" as * "new_base_index"). * INT_VAR backup Set to non-zero to have WeiDU create a backup that is restored when the mod is * uninstalled. Set to zero to forbid restoring the file when the mod is uninstalled. * (Default: 1 - create backup) * STR_VAR source_file The source file to copy. For BAM and MOS files, the filename must match the regular * expression "MOS[0-9]{4,5}\.PVRZ" (e.g. MOS0000.PVRZ, mos1592.pvrz or Mos12345.PVRZ). * For TIS files, the filename must match the regular expression "%prefix%[0-9][0-9]\.PVRZ" * Case is ignored. * STR_VAR target_folder The target folder to copy the source file into. (Default: override) * RET success Set to non-zero if the function returned successfully and set to zero on error. * RET SOURCE_*, DEST_* Returns all variables that are automatically set by a WeiDU COPY operation on success. */ DEFINE_ACTION_FUNCTION INSTALL_PVRZ INT_VAR original_base_index = "-1" new_base_index = "-1" backup = 1 STR_VAR source_file = ~~ target_folder = ~override~ RET success SOURCE_DIRECTORY SOURCE_FILESPEC SOURCE_FILE SOURCE_RES SOURCE_EXT SOURCE_SIZE DEST_DIRECTORY DEST_FILESPEC DEST_FILE DEST_RES DEST_EXT BEGIN OUTER_SET success = 0 ACTION_IF (ENGINE_IS ~bgee bg2ee iwdee pstee~) BEGIN ACTION_IF (original_base_index >= 0 && new_base_index >= 0 && FILE_EXISTS ~%source_file%~) BEGIN // Making sure that target points to a directory ACTION_IF (~%target_folder%~ STR_EQ ~~) BEGIN OUTER_TEXT_SPRINT target_folder ~.~ END ACTION_IF (DIRECTORY_EXISTS ~%target_folder%~) BEGIN LAF EXT_OF_FILESPEC STR_VAR filespec = EVAL ~%source_file%~ RET ext END LAF RES_OF_FILESPEC STR_VAR filespec = EVAL ~%source_file%~ RET res END END ELSE BEGIN LAF EXT_OF_FILESPEC STR_VAR filespec = EVAL ~%target_folder%~ RET ext END LAF RES_OF_FILESPEC STR_VAR filespec = EVAL ~%target_folder%~ RET res END LAF DIRECTORY_OF_FILESPEC STR_VAR filespec = EVAL ~%target_folder%~ RET target_folder = directory END END // initializations OUTER_SET failed = 0 ACTION_IF (~%res%~ STRING_MATCHES_REGEXP ~MOS[0-9][0-9][0-9][0-9][0-9]?$~ = 0) BEGIN OUTER_SET max_index = 99999 OUTER_TEXT_SPRINT fmt_index ~-4~ // separate pvrz prefix and index OUTER_PATCH_SAVE res_index ~%res%~ BEGIN READ_ASCII 0 res_prefix (3) DELETE_BYTES 0 3 END END ELSE ACTION_IF (~%res%~ STRING_MATCHES_REGEXP ~.+[0-9][0-9]$~ = 0) BEGIN OUTER_SET max_index = 99 OUTER_TEXT_SPRINT fmt_index ~-2~ // separate pvrz prefix and index OUTER_SET len = STRING_LENGTH ~%res%~ OUTER_PATCH_SAVE res_index ~%res%~ BEGIN READ_ASCII 0 res_prefix (len - 2) DELETE_BYTES 0 (len - 2) END END ELSE BEGIN OUTER_SET failed = 1 WARN ~Invalid source file specified: %source_file%. Skipping operation.~ END // update filename and install pvrz file ACTION_IF (NOT failed) BEGIN OUTER_SET offset = new_base_index - original_base_index OUTER_SET old_index = res_index OUTER_SET new_index = old_index + offset ACTION_IF (new_index >= 0 && new_index <= max_index) BEGIN // ensure required number of digits OUTER_SNPRINT ~%fmt_index%~ new_index ~0000%new_index%~ OUTER_TEXT_SPRINT new_res ~%res_prefix%%new_index%~ OUTER_TEXT_SPRINT target_filespec ~%target_folder%/%new_res%.%ext%~ ACTION_IF (backup) BEGIN COPY ~%source_file%~ ~%target_filespec%~ END ELSE BEGIN COPY + ~%source_file%~ ~%target_filespec%~ END OUTER_SET success = 1 END ELSE BEGIN WARN ~New PVRZ index is out of range: %new_index%. Skipping file.~ END END END ELSE BEGIN FAIL ~One or more required parameters are undefined.~ END END ELSE BEGIN WARN ~Game is not supported.~ END END /** * This PATCH function attempts to find the first available free PVRZ index of a contiguous block * which guarantees to fit at least "num_to_reserve" indices. * * INT_VAR num_to_reserve Find a contiguous block of at least this number of free indices * (range: [1..100] for TIS-related PVRZ files, [1..999] otherwise, default: 1) * INT_VAR start_index Index to start looking for (default: 0 for TIS-related PVRZ files, 1000 otherwise) * STR_VAR prefix Prefix of the PVRZ files associated with the BAM, MOS, or TIS file. For BAM and MOS files, * the prefix will be "MOS". For TIS files it will be the TIS filename minus the second * character. Use function TIS_RES_TO_PVRZ to derive the PVRZ prefix from a TIS filename. * (default: MOS) * RET free_index Returns the first available index matching the specified parameters if successful. * Returns -1 if no sufficiently large block of free slots could be found. */ DEFINE_PATCH_FUNCTION FIND_FREE_PVRZ_INDEX INT_VAR num_to_reserve = 1 start_index = "-1" STR_VAR prefix = ~MOS~ RET free_index BEGIN SET free_index = "-1" SET failed = 0 PATCH_IF (~%prefix%~ STR_EQ ~MOS~) BEGIN SET max_to_reserve = 999 SET max_start_index = 100000 PATCH_IF (start_index < 0) BEGIN SET start_index = 1000 END END ELSE PATCH_IF (STRING_LENGTH ~%prefix%~ > 0 && STRING_LENGTH ~%prefix%~ <= 6) BEGIN SET max_to_reserve = 100 SET max_start_index = 100 PATCH_IF (start_index < 0) BEGIN SET start_index = 0 END END ELSE BEGIN PATCH_WARN ~Invalid prefix specified: "%prefix%"~ SET failed = 1 END PATCH_IF (NOT failed && ENGINE_IS ~bgee bg2ee iwdee pstee~) BEGIN PATCH_IF (num_to_reserve < 1) BEGIN SET num_to_reserve = 1 PATCH_LOG ~Block size too small. Using default of 1.~ END ELSE PATCH_IF (num_to_reserve > max_to_reserve) BEGIN SET num_to_reserve = max_to_reserve PATCH_LOG ~Block size too big. Truncating to %max_to_reserve%.~ END PATCH_IF (start_index + num_to_reserve > max_start_index) BEGIN SET start_index = max_start_index - num_to_reserve PATCH_LOG ~Start index too big. Setting start index to %start_index%.~ END SET count = 0 FOR (index = start_index; index < max_start_index; ++index) BEGIN LPF a7#__is_free_pvrz INT_VAR index STR_VAR prefix RET is_free_index END PATCH_IF (is_free_index) BEGIN PATCH_IF (count = 0) BEGIN SET free_index = index END SET count += 1 // block found? PATCH_IF (count >= num_to_reserve) BEGIN SET index = max_start_index END END ELSE BEGIN // start counting anew SET count = 0 END END PATCH_IF (count < num_to_reserve) BEGIN SET free_index = "-1" END END ELSE BEGIN PATCH_WARN ~Game is not supported.~ END END /** * This ACTION function attempts to find the first available free PVRZ index of a contiguous block * which guarantees to fit at least "num_to_reserve" indices. * * INT_VAR num_to_reserve Find a contiguous block of at least this number of free indices * (range: [1..100] for TIS-related PVRZ files, [1..999] otherwise, default: 1) * INT_VAR start_index Index to start looking for (default: 0 for TIS-related PVRZ files, 1000 otherwise) * STR_VAR prefix Prefix of the PVRZ files associated with the BAM, MOS, or TIS file. For BAM and MOS files, * the prefix will be "MOS". For TIS files it will be the TIS filename minus the second * character. Use function TIS_RES_TO_PVRZ to derive the PVRZ prefix from a TIS filename. * (default: MOS) * RET free_index Returns the first available index matching the specified parameters if successful. * Returns -1 if no sufficiently large block of free slots could be found. */ DEFINE_ACTION_FUNCTION FIND_FREE_PVRZ_INDEX INT_VAR num_to_reserve = 1 start_index = "-1" STR_VAR prefix = ~MOS~ RET free_index BEGIN OUTER_PATCH ~foo~ BEGIN LPF FIND_FREE_PVRZ_INDEX INT_VAR num_to_reserve start_index STR_VAR prefix RET free_index END END END // Used internally. Determines whether the file MOSxxxx.PVRZ or %prefix%xx.PVRZ is still unoccupied, // where xxxx and xx are numeric indices. DEFINE_PATCH_FUNCTION a7#__is_free_pvrz INT_VAR index = 0 STR_VAR prefix = ~MOS~ RET is_free_index BEGIN SET max = (~%prefix%~ STR_EQ ~MOS~) ? 99999 : 99 PATCH_IF (index < 0) BEGIN SET index = 0 END ELSE PATCH_IF (index > max) BEGIN SET index = max END PATCH_IF (~%prefix%~ STR_EQ ~MOS~) BEGIN PATCH_IF (index <= 9999) BEGIN SNPRINT "-4" index ~0000%index%~ END END ELSE BEGIN SNPRINT "-2" index ~00%index%~ END TEXT_SPRINT cur_file ~%prefix%%index%.PVRZ~ SET is_free_index = (FILE_EXISTS_IN_GAME ~%cur_file%~ || FILE_EXISTS ~%USER_DIRECTORY%/override/%cur_file%~ || FILE_EXISTS ~lang/%EE_LANGUAGE%/override/%cur_file%~) ? 0 : 1 END Example usage: // Installing all TIS files from the specified folder ACTION_BASH_FOR ~%MOD_FOLDER%/tis~ ~^.+\.tis$~ BEGIN COPY ~%BASH_FOR_FILESPEC%~ ~override~ LPF UPDATE_PVRZ_INDICES RET original_base_index new_base_index END // Installing associated PVRZ files for each tileset individually ACTION_IF (new_base_index >= 0) BEGIN LAF TIS_RES_TO_PVRZ STR_VAR tis_res = EVAL ~%BASH_FOR_FILESPEC%~ RET prefix END ACTION_BASH_FOR ~%MOD_FOLDER%/tis~ ~^%prefix%.+\.pvrz$~ BEGIN LAF INSTALL_PVRZ INT_VAR original_base_index new_base_index STR_VAR source_file = EVAL ~%BASH_FOR_FILESPEC%~ RET success DEST_FILESPEC END ACTION_IF (NOT success) BEGIN FAIL ~Could not install "%BASH_FOR_FILESPEC%"!~ END END END ELSE BEGIN FAIL ~Could not install "%BASH_FOR_FILESPEC%"!~ END END Edited April 3, 2020 by argent77 Code changes Quote Link to comment
jastey Posted April 2, 2020 Share Posted April 2, 2020 1 hour ago, argent77 said: This is a set of functions that can be used to safely install pvrz-based tilesets without the danger of overwriting pvrz files from other mods or the game itself. This could use a separate thread as it should become standard for every mod adding areas to EE imho. Quote Link to comment
Weigo Posted April 3, 2020 Share Posted April 3, 2020 I wrote a small tool and function to alter the searchmap bitmap files. For Baldurans Seatower I made a new practical tool for an old problem. It was always a problem to edit searmap files, because you could only overwrite the existing file. When two different mods edit the same searchmap, it was always difficult to find a solution. Now I wrote a small tool and a function to solve this problem. The tool SRmap_modding_tool now compares the modded searchmap with the originals from the classic and ee version and creates a 2da file with all bitmap changes. The function is for the setup.tp2 file, which uses the 2da files to alter the existing bitmap with the changes. So two different mods can alter the searchmap file. Now a small instruction for mod authors: -First you need to use the tool to create a file that lists the search map changes. This you need to do once for your mod. -After that you include this "changes.tpa" inside your mod to patch the existing search map when the mod is installed. Put the SRmap_modding_tool in your Baldurs Gate installation. 1. Go into SRmap_modding_tool\area directory 2. Put the classic, ee and your modded/new searchmap bitmap in the fitting directory 3. Open the setup-SRmap_modding_tool.tp2 with an editor 4. Enter the names of the bitmap files without the extension in the lines filename_classic, filename_ee, filename_new ALWAYS //OUTER_SET areaname = ~AR1200~ OUTER_SPRINT originalfolder_classic ~%MOD_FOLDER%/area/original/classic~ //original unmodded searchmap folder from classic bg OUTER_SPRINT originalfolder_ee ~%MOD_FOLDER%/area/original/ee~ //original unmodded searchmap folder from ee bg OUTER_SPRINT filename_classic ~AR1200SR~ //original unmodded searchmap filename from classic bg OUTER_SPRINT filename_ee ~BG1200SR~ //original unmodded searchmap filename from ee bg OUTER_SPRINT newfolder ~%MOD_FOLDER%/area/new~ //modded searchmap folder OUTER_SPRINT filename_new ~AR8100SR~ //modded searchmap filename OUTER_SPRINT filename_changes_classic ~%filename_new%_changes_classic~ //filenames for the 2da files used by the mod OUTER_SPRINT filename_changes_ee ~%filename_new%_changes_ee~ //filenames for the 2da files used by the mod END 5. Save the file and start the tool. It will work a while 6. When it's finished. There are either two files "AR8100SR_changes_ee.2da" and "AR8100SR_changes_classic.2da" or if both files are identical there is only one file "AR8100SR_changes.2da" 7. Copy the 2da file from step 6 into your mod folder 8. Copy the alter_searchmap.tpa function to your mod functions. You find it in the SRmap_modding_tool\lib directory Spoiler DEFINE_ACTION_FUNCTION ~ALTER_SEARCHMAP~ INT_VAR STR_VAR path_to_2da_file = ~~ // full path to the *changes.2da file, e.g. ~mymod/bmp/AR3700SR_changes_ee.2da~ areaname = ~~ // area name, e.g. ~AR3700~ RET BEGIN COPY ~%path_to_2da_file%~ ~%path_to_2da_file%~ READ_2DA_ENTRIES_NOW ~newpixelarray~ 4 COUNT_2DA_ROWS 4 ~pixelnumber~ COPY_EXISTING ~%areaname%SR.bmp~ ~override~ FOR (cnt=0; cnt<pixelnumber; cnt=cnt+1) BEGIN READ_2DA_ENTRY_FORMER ~newpixelarray~ cnt 0 ~offset~ READ_BYTE ~offset~ ~oldpixel~ READ_2DA_ENTRY_FORMER ~newpixelarray~ cnt 2 ~newpixel~ READ_2DA_ENTRY_FORMER ~newpixelarray~ cnt 3 ~byte~ SET left_oldpixel = oldpixel / 16 SET right_oldpixel = oldpixel MODULO 16 SET left_newpixel = newpixel / 16 SET right_newpixel = newpixel MODULO 16 PATCH_IF (~%byte%~ STRING_EQUAL ~b~)=1 BEGIN SET setpixel = newpixel //PATCH_PRINT ~%offset%: oldpixel %oldpixel% - newpixel %newpixel% - setpixel %setpixel%~ //PATCH_PRINT ~%offset%: lo %left_oldpixel% ro %right_oldpixel% - ln %left_newpixel% rn %right_newpixel% - setpixel %setpixel%~ END PATCH_IF (~%byte%~ STRING_EQUAL ~r~)=1 BEGIN SET setpixel = left_oldpixel * 16 + right_newpixel END PATCH_IF (~%byte%~ STRING_EQUAL ~l~)=1 BEGIN SET setpixel = left_newpixel * 16 + right_oldpixel END WRITE_BYTE offset ~%setpixel%~ END END 9. Put following lines into your setup-mymod.tp2 INCLUDE ~%MOD_FOLDER%/lib/alter_searchmap.tpa~ LAF ALTER_SEARCHMAP STR_VAR path_to_2da_file = EVAL ~%MOD_FOLDER%/Ramazith/AR7238SR_changes.2da~ // full path to the *changes.2da file, e.g. ~mymod/bam/AR3700SR_changes_ee.2da~ areaname = EVAL ~AR7238~ // area name, e.g. ~AR3700~ END Enter your path to the 2da file and the areaname. For ee and classic differnces, you have to make a query with ACTION_IF Quote Link to comment
argent77 Posted April 3, 2020 Share Posted April 3, 2020 I have updated the PVRZ-related set of functions in my previous comment. It is now fully compatible with existing functionality that deals with installing BAM V2 and MOS V2 files already included in WeiDU . Quote Link to comment
subtledoctor Posted June 1, 2020 Share Posted June 1, 2020 (edited) On 2/11/2020 at 12:36 PM, subtledoctor said: Anyone know what the requirements are for what the source .BAM file has to look like? Does it need to be a particular size? Or can I just feed it, say, something like a SPWIxxxb.BAM file? On 2/11/2020 at 4:30 PM, kjeron said: 13x13 pixels. They autoscale down to size over the side-bar portrait, but not in the record screen, though they can be made to through some UI changes. FINAL EDIT - I think I figured it out. IGNORE ME! Is there any kind of guidance for making .BAM files for portrait icons? I need to make new portrait icons for Spell Deflection and SR's Greater Spell Deflection - it seems that opcode 201 just applies the same portrait icon, regardless of which spell is applying it or how many separate sources of Deflection there are. Since you can cast both Minor Deflecion and Spell Deflection on yourself, I would like a visual indicator of which is active. (FYI, the IESDP does not mention anything about opcode 201 displaying a portrait icon...) I tried going into the "Edit BAM" window in Near Infinity and reduce SPWI618C.BAM to 40%, which results in a 12x12 image, and to 45%, which results in a 14x14 image. But they are garbage - pixellated nonsense, unrecognizable. How does one make halfway-decent portrait icons? Alternatively, any idea how to find the one already used by opcode 201? Maybe I could just make three different recolored version of that. EDIT - found it in STATES.BAM. I'll probably just do recoloring. But it might be nice for other readers if anyone has advice on this. EDIT 2 - okay, I found the proper frame of STATES.BAM and saved that frame as a new .BAM file, then made two recolored versions of that .BAM file by adjusting the hue in Near Infinity's BAM editor, then I made a little test mod to add them with opcode 142 effects as in this example. Spoiler COPY ~test/d5mdefl.bam~ ~override~ LAF cd_new_portrait_icon INT_VAR string = RESOLVE_STR_REF(~Minor Deflection~) STR_VAR bam_file = ~d5mdefl~ RET icon END COPY_EXISTING ~spwi318.spl~ ~override~ LPF CLONE_EFFECT INT_VAR silent = 1 multi_match = 1 match_opcode = 201 opcode = 142 parameter2 = icon END IF_EXISTS BUT_ONLY COPY ~test/d5sdefl.bam~ ~override~ LAF cd_new_portrait_icon INT_VAR string = RESOLVE_STR_REF(~Spell Deflection~) STR_VAR bam_file = ~d5sdefl~ RET icon END COPY_EXISTING ~spwi522.spl~ ~override~ LPF CLONE_EFFECT INT_VAR silent = 1 multi_match = 1 match_opcode = 201 opcode = 142 parameter1 = 0 parameter2 = icon END IF_EXISTS BUT_ONLY COPY ~test/d5gdefl.bam~ ~override~ LAF cd_new_portrait_icon INT_VAR string = RESOLVE_STR_REF(~Greater Deflection~) STR_VAR bam_file = ~d5gdefl~ RET icon END COPY_EXISTING ~spwi701.spl~ ~override~ LPF CLONE_EFFECT INT_VAR silent = 1 multi_match = 1 match_opcode = 201 opcode = 142 parameter1 = 0 parameter2 = icon END IF_EXISTS BUT_ONLY It patches STATDESC.2da correctly, the opcode 142 effects are generated correctly, and in-game in the character record sheet, I can see the text next to where the portrait icon should be. But the portrait icons themselves are invisible. Any idea why? I'm attaching the three icons to this post. d5_deflect_icons.zip Edited June 20, 2020 by subtledoctor Quote Link to comment
Lauriel Posted June 19, 2020 Share Posted June 19, 2020 (edited) On 6/24/2017 at 4:31 PM, CamDawg said: Post 49, K4thos JOINABLE_NPC_ARRAY - 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) Where'd it go? I need this. Found it. The link was just broken. Had to meander through the pages to find it, but I did find it. This is a thing of beauty, boss! Edited June 20, 2020 by Lauriel Quote Link to comment
Bartimaeus Posted June 20, 2020 Share Posted June 20, 2020 (edited) On 6/1/2020 at 1:34 PM, subtledoctor said: It patches STATDESC.2da correctly, the opcode 142 effects are generated correctly, and in-game in the character record sheet, I can see the text next to where the portrait icon should be. But the portrait icons themselves are invisible. Any idea why? I'm attaching the three icons to this post. d5_deflect_icons.zip 3.32 kB · 0 downloads I would've replied earlier, but I didn't see this thread until now. Did you already fix it? Edited June 20, 2020 by Bartimaeus Quote Link to comment
subtledoctor Posted June 20, 2020 Share Posted June 20, 2020 @Lauriel NB that I have slightly updated K4thos’ code, my version of the function generates two arrays for use later: one of joinable NPCs and one of non-joinable NPCs. It’s a bit later in the thread, or you can see the code here, starting at line 209. @Bartimaeus yeah I eventually figured it out, I think. When creating those BAMs I had removed the extraneous frames, but not all the extraneous cycles. Or vice versa. Dealing with BAMs is annoying. Quote Link to comment
Bartimaeus Posted June 20, 2020 Share Posted June 20, 2020 3 hours ago, subtledoctor said: @Lauriel NB that I have slightly updated K4thos’ code, my version of the function generates two arrays for use later: one of joinable NPCs and one of non-joinable NPCs. It’s a bit later in the thread, or you can see the code here, starting at line 209. @Bartimaeus yeah I eventually figured it out, I think. When creating those BAMs I had removed the extraneous frames, but not all the extraneous cycles. Or vice versa. Dealing with BAMs is annoying. Yeah, I have no idea what any of it means, but I've had enough experience in clicking the buttons in the right order to figure it out, . Quote Link to comment
Lauriel Posted June 20, 2020 Share Posted June 20, 2020 5 hours ago, subtledoctor said: @Lauriel NB that I have slightly updated K4thos’ code, my version of the function generates two arrays for use later: one of joinable NPCs and one of non-joinable NPCs. It’s a bit later in the thread, or you can see the code here, starting at line 209. Thanks, @subtledoctor Quote Link to comment
Luke Posted August 10, 2020 Share Posted August 10, 2020 (edited) In case someone is looking for a way to send "level" to ADD_MEMORIZED_SPELL as a variable (or "charges1/2/3" to ADD_CRE_ITEM and the like): Spoiler // Replace "example" with your "%TP2_BASE_NAME%" // blank file <<<<<<<< .../example-inline/blank >>>>>>>> DEFINE_DIMORPHIC_FUNCTION "REINCLUDE_THIS" STR_VAR "input" = "" BEGIN COPY - ".../example-inline/blank" "override/temp_file.tph" DELETE_BYTES 0x0 BUFFER_LENGTH INSERT_BYTES 0x0 (STRING_LENGTH "%input%") WRITE_ASCIIE 0x0 "%input%" BUT_ONLY_IF_IT_CHANGES REINCLUDE "override/temp_file.tph" END // Example usage COPY_EXISTING "BANDIT.CRE" "override" SET test = 0 LPF REINCLUDE_THIS STR_VAR input = "ADD_CRE_ITEM ~SW1H01~ #%test% #%test% #%test% ~none~ ~inv~" END BUT_ONLY This is in principle quite powerful if you edit ALTER_ITEM_HEADER and the like to allow for it: Spoiler LPF ALTER_ITEM_HEADER INT_VAR header_type = 1 STR_VAR dicenumber = "THIS + 1" dicesize = "THIS + 5" END On the other hand, it's probably useful only in a 'functional programming' environment (yes, you're my master DavidW...) Edited October 16, 2020 by Luke Updated to WeiDU v247 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.