Angel Posted August 7, 2017 Share Posted August 7, 2017 (edited) Oh, this is great! Any chance for a 'shawdowed' option (i.e. like shades or shadow monsters in iwdee)? Eh, didn't expect such a response to a relatively simple function. Is nobody interested in my erase-journal-o-matic for BGT? :-) And yeah, writing variants should not be too hard, if I'd know what makes a monster a shade or shadow. Here's a variant that makes the monster illusionary. DEFINE_PATCH_FUNCTION make_illusion INT_VAR power_level = "-1" BEGIN WRITE_LONG 0x0010 THIS | BIT1 // No corpse WRITE_LONG 0x0014 0 // XP WRITE_LONG 0x001c 0 // Gold WRITE_BYTE 0x0270 IDS_OF_SYMBOL("ea" "neutral") WRITE_BYTE 0x0275 IDS_OF_SYMBOL("gender" "illusionary") // Add unstealable&undroppable flags to carried items GET_OFFSET_ARRAY itm_array CRE_V10_ITEMS PHP_EACH itm_array AS int => itm_offset BEGIN WRITE_LONG (itm_offset + 0x0010) (THIS | (BIT1 | BIT3)) END // Handle power level if specified PATCH_IF (power_level >= 0) BEGIN WRITE_LONG 0x0018 power_level END END Edited August 22, 2017 by Angel Quote Link to comment
CamDawg Posted August 7, 2017 Author Share Posted August 7, 2017 Another small one, turn a creature into a summoned creature. This is GOLD. Gonna make good use of this. Anyone know of a macro that is the obverse of SNPRINT - instead of retaining the first x characters of a string, I want to remove the first x characters and keep the rest. (Basically I want to automate switching out the modder prefix for a different one.) In a patch context, this will take the file name sppr101/spwi101 and set the new_res variable to abcd101: INNER_PATCH_SAVE new_res ~%SOURCE_RES%~ BEGIN REPLACE_TEXTUALLY ~^[Ss][Pp][WwPp][IiRr]~ ~abcd~ END In an action context, it's the same syntax except with OUTER_INNER_PATCH_SAVE. Quote Link to comment
Grammarsalad Posted August 8, 2017 Share Posted August 8, 2017 (edited) Oh, this is great! Any chance for a 'shawdowed' option (i.e. like shades or shadow monsters in iwdee)? Eh, didn't expect such a response to a relatively simple function. Is nobody interested in my erase-journal-o-matic for BGT? :-) And yeah, writing variants should not be too hard, if I'd know what makes a monster a shade or shadow. Here's a variant that makes the monster illusionary. DEFINE_PATCH_FUNCTION make_illusion INT_VAR power_level = 1 BEGIN WRITE_LONG 0x0010 THIS | BIT1 // No corpse WRITE_LONG 0x0014 0 // XP WRITE_LONG 0x0018 power_level WRITE_LONG 0x001c 0 // Gold WRITE_BYTE 0x0270 IDS_OF_SYMBOL("ea" "neutral") WRITE_BYTE 0x0275 IDS_OF_SYMBOL("gender" "illusionary") // Add unstealable&undroppable flags to carried items GET_OFFSET_ARRAY itm_array CRE_V10_ITEMS PHP_EACH itm_array AS int => itm_offset BEGIN WRITE_LONG (itm_offset + 0x0010) (THIS | (BIT1 | BIT3)) END END Oh, I love all of these! I just have a specific issue that this will help with. Basically, I have some bugs with a couple of summoning spells. I think the issue has something to do with imported animations. I'm just going to convert existing creatures, and this'll help. It's great timing. I had to look up what made a creature 'shadow-like'. I think the only thing required is that the creature has TRANS60.ITM equipped (I'm pretty sure). That's easy enough for me to add, though. Thanks... Edit: as for illusionary creatures, I'll probably use it just because it's right there! Edited August 8, 2017 by Grammarsalad Quote Link to comment
K4thos Posted August 24, 2017 Share Posted August 24, 2017 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.tpaExample 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 Quote Link to comment
Sam. Posted October 5, 2017 Share Posted October 5, 2017 (edited) It hasn't been extensively tested yet, but here is a function library to do stuff with tilesets: PS_Tileset Note that if you want to add bitmap tiles to a PVRz-based tileset, you will need to run Tile2EE to convert it to a palette-based tileset first, then convert it back. ps_tileset_lib ps_tileset_repair_headerRepairs a couple of errors in tileset headers: missing header and wrong version number ps_tileset_remove_tilesRemoves tiles from a tileset ps_tileset_add_tilesAdds or replaces tiles in a tileset ps_tileset_create_tilesetCreates a tileset from a number of tiles ps_tileset_export_tilesExports tiles from a tileset ps_tileset_infoGathers and reports basic or verbose information from a tileset ps_tileset_replace_palette_entryReplaces palette entries in a tile with a new color ps_tileset_recolor_pixelRecolors a pixel in a tile without changing the color of every pixel using the same palette entry ps_zlib_compressZ-lib compresses a file ps_zlib_decompressZ-lib decompresses a file Edited October 5, 2017 by Sam. Quote Link to comment
argent77 Posted October 15, 2017 Share Posted October 15, 2017 This is a patch function that can be used to add multiple effects to items or spells without much effort. It uses a simple syntax with short keywords to keep effect definitions plain and simple. I'm currently using it to dynamically add many game dependent effects to spells.The function code: // Automates adding spell effects to items or spells, based on a code sequence. // Code format: "param1=value1,param2=value2;...second effect..." // Supported parameters: op (Opcode), tgt (Target), tmg (Timing), pwr (Power), p1 (Parameter1), p2 (Parameter2), // rd (Resist/Dispel), dur (Duration), pro1 (Probability1), pro2 (Probability2), res (Resource), // dnum (Dice Number), dsize (Dice Size), stype (Save Type), sbonus (Save Bonus), spec (Special), ip (Insert Point) // All parameters except "Opcode" are optional. DEFINE_PATCH_FUNCTION a7_auto_apply_spl_effect INT_VAR // default values if not specified in "effect_codes" def_target = 0 def_timing = 0 def_power = 0 def_parameter1 = 0 def_parameter2 = 0 def_resist_dispel = 0 def_duration = 0 def_probability1 = 100 def_probability2 = 0 def_dicenumber = 0 def_dicesize = 0 def_savetype = 0 def_savebonus = 0 def_special = 0 def_insertpoint = "-1" STR_VAR // Supported functions: ADD_SPELL_EFFECT, ADD_SPELL_CFEFFECT, ADD_ITEM_EFFECT, ADD_ITEM_EQEFFECT and (limited) ADD_CRE_EFFECT function_name = ~~ // The code string with effect definitions effect_codes = ~~ def_resource = ~~ BEGIN PATCH_IF (NOT ~%function_name%~ STR_EQ ~~) BEGIN // parsing effect entries SET entries = 0 SET strlen = STRING_LENGTH ~%effect_codes%~ INNER_PATCH ~%effect_codes%~ BEGIN SET curOfs = 0 WHILE (curOfs < strlen) BEGIN SET ofs = INDEX_BUFFER(~;~ curOfs) PATCH_IF (ofs < 0) BEGIN SET ofs = strlen END READ_ASCII curOfs entry (ofs - curOfs) TEXT_SPRINT EVAL ~entries_%entries%~ ~%entry%~ SET entries += 1 SET curOfs = ofs + 1 END END // parsing effect parameters SET effects = 0 FOR (idx = 0; idx < entries; ++idx) BEGIN TEXT_SPRINT entry EVAL ~%entries_%idx%%~ SET strlen = STRING_LENGTH ~%entry%~ INNER_PATCH ~%entry%~ BEGIN SET curOfs = 0 WHILE (curOfs < strlen) BEGIN SET ofs = INDEX_BUFFER(~,~ curOfs) PATCH_IF (ofs < 0) BEGIN SET ofs = strlen END READ_ASCII curOfs param (ofs - curOfs) INNER_PATCH ~%param%~ BEGIN SET ofs2 = INDEX_BUFFER(~=~) PATCH_IF (ofs2 > 0) BEGIN READ_ASCII 0 v1 (ofs2) READ_ASCII (ofs2+1) v2 (BUFFER_LENGTH - ofs2 - 1) TEXT_SPRINT EVAL ~effects_%idx%_%v1%~ ~%v2%~ END END SET curOfs = ofs + 1 END END END SET effects = entries // adding effects FOR (idx = 0; idx < effects; ++idx) BEGIN SET opcode = (VARIABLE_IS_SET EVAL ~effects_%idx%_op~) ? EVAL ~effects_%idx%_op~ : ~-1~ SET target = (VARIABLE_IS_SET EVAL ~effects_%idx%_tgt~) ? EVAL ~effects_%idx%_tgt~ : def_target SET timing = (VARIABLE_IS_SET EVAL ~effects_%idx%_tmg~) ? EVAL ~effects_%idx%_tmg~ : def_timing SET power = (VARIABLE_IS_SET EVAL ~effects_%idx%_pwr~) ? EVAL ~effects_%idx%_pwr~ : def_power SET param1 = (VARIABLE_IS_SET EVAL ~effects_%idx%_p1~) ? EVAL ~effects_%idx%_p1~ : def_parameter1 SET param2 = (VARIABLE_IS_SET EVAL ~effects_%idx%_p2~) ? EVAL ~effects_%idx%_p2~ : def_parameter2 SET resist_dispel = (VARIABLE_IS_SET EVAL ~effects_%idx%_rd~) ? EVAL ~effects_%idx%_rd~ : def_resist_dispel SET duration = (VARIABLE_IS_SET EVAL ~effects_%idx%_dur~) ? EVAL ~effects_%idx%_dur~ : def_duration SET prob1 = (VARIABLE_IS_SET EVAL ~effects_%idx%_pro1~) ? EVAL ~effects_%idx%_pro1~ : def_probability1 SET prob2 = (VARIABLE_IS_SET EVAL ~effects_%idx%_pro2~) ? EVAL ~effects_%idx%_pro2~ : def_probability2 SET dicenumber = (VARIABLE_IS_SET EVAL ~effects_%idx%_dnum~) ? EVAL ~effects_%idx%_dnum~ : def_dicenumber SET dicesize = (VARIABLE_IS_SET EVAL ~effects_%idx%_dsize~) ? EVAL ~effects_%idx%_dsize~ : def_dicesize SET savetype = (VARIABLE_IS_SET EVAL ~effects_%idx%_stype~) ? EVAL ~effects_%idx%_stype~ : def_savetype SET savebonus = (VARIABLE_IS_SET EVAL ~effects_%idx%_sbonus~) ? EVAL ~effects_%idx%_sbonus~ : def_savebonus SET special = (VARIABLE_IS_SET EVAL ~effects_%idx%_spec~) ? EVAL ~effects_%idx%_spec~ : def_special SET insertpoint = (VARIABLE_IS_SET EVAL ~effects_%idx%_ip~) ? EVAL ~effects_%idx%_ip~ : def_insertpoint PATCH_IF (VARIABLE_IS_SET EVAL ~effects_%idx%_res~) BEGIN TEXT_SPRINT resource EVAL ~%effects_%idx%_res%~ END ELSE BEGIN TEXT_SPRINT resource ~%def_resource%~ END PATCH_IF (opcode >= 0) BEGIN LPF ~%function_name%~ INT_VAR opcode = opcode target = target timing = timing parameter1 = param1 parameter2 = param2 power = power resist_dispel = resist_dispel duration = duration probability1 = prob1 probability2 = prob2 dicenumber = dicenumber dicesize = dicesize savingthrow = savetype savebonus = savebonus special = special insert_point = insertpoint STR_VAR resource = EVAL ~%resource%~ END END END END END Example (adds fully configured effects "Display String" and "Play Visual Effect" to a spell): COPY ~%MOD_FOLDER%/spells/myspell.spl~ ~override~ LPF a7_auto_apply_spl_effect INT_VAR // some predefined parameters for all effects def_target = 2 // Preset target def_savetype = 1 // Save vs. Spell def_savebonus = "-2" STR_VAR function_name = ~ADD_SPELL_EFFECT~ effect_codes = ~op=139,tmg=1,p1=8203;op=215,tmg=1,dur=2,p2=1,res=ICARMOR~ END Quote Link to comment
CamDawg Posted October 16, 2017 Author Share Posted October 16, 2017 Background: if you look at a spell with save-for-half-damage like fireball, you'll note that at the seventh-level fireball has two damage opcodes--one does 4d6 fire damage with no save, and second one does 3d6 fire damage but can be negated outright with a save. The upshot is 7d6 damage that is not-quite-halved to 4d6 on a successful save. More egregious examples of poorly-split damage exist, e.g. Storm of Vengeance splits its listed 1d6s as 2d3s; Burning Hands splits its 1d3 as 2d2. EE adds a new flag to the damage opcode (bit 8 in the special field) that allows the engine to do this calculation without having to force two damage opcodes and allowing true save-for-half damage. We're finally getting around to using this in the EEs. CD_DOUBLE_DAMAGE is a macro designed to find these double damage opcodes in items and spells and combine them into one using this new flag. It's not a particularly smart algorithm, as it will find the first damage opcode matching its parameters on a given ability and then try to merge it with any other matching damage opcode that is within a die roll and within one point of the static damage field. You could add spells or items in your mod with the traditional damage splits and then run this macro on them if an EE is detected. Fireball is easy because it just has the pair of damage opcodes on every header. Something like Earthquake, with its three pairs of damage over time, would require this to be run three times DEFINE_PATCH_FUNCTION CD_DOUBLE_DAMAGE // defines what we're going to check INT_VAR header = "-1" header_type = "-1" m_power = "-1" m_type = "-1" m_damtype = "-1" m_timing = "-1" m_dispel = "-1" m_duration = "-1" m_prob1 = "-1" m_prob2 = "-1" m_dicesize = "-1" m_flags = "-1" debug = 0BEGIN SPRINT debug_message ~%SOURCE_FILE% report:~ READ_ASCII 0x00 sig (3) SET abil_length = 0x28 PATCH_IF ("%sig%" STRING_COMPARE_CASE "ITM" = 0) BEGIN SET abil_length = 0x38 END READ_LONG 0x64 abil_off ELSE 0 READ_SHORT 0x68 abil_num ELSE 0 READ_LONG 0x6a fx_off ELSE 0 SET fx_delta = 0 FOR (index = 0 ; index WRITE_SHORT (abil_off + 0x20 + (abil_length * index)) (THIS + fx_delta) READ_SHORT (abil_off + (abil_length * index)) o_header_type PATCH_IF (((header = index) OR (header ((header_type = o_header_type) OR (header_type SET damage = 0 READ_SHORT (abil_off + 0x1e + (abil_length * index)) abil_fx_num READ_SHORT (abil_off + 0x20 + (abil_length * index)) abil_fx_idx FOR (index2 = 0 ; index2 READ_SHORT (fx_off + (0x30 * (abil_fx_idx + index2))) opcode PATCH_IF (opcode = 12) BEGIN PATCH_IF damage = 0 BEGIN READ_BYTE (fx_off + 0x02 + (0x30 * (abil_fx_idx + index2))) o_power READ_LONG (fx_off + 0x04 + (0x30 * (abil_fx_idx + index2))) o_amount READ_SHORT (fx_off + 0x08 + (0x30 * (abil_fx_idx + index2))) o_type READ_SHORT (fx_off + 0x0a + (0x30 * (abil_fx_idx + index2))) o_damtype READ_BYTE (fx_off + 0x0c + (0x30 * (abil_fx_idx + index2))) o_timing READ_BYTE (fx_off + 0x0d + (0x30 * (abil_fx_idx + index2))) o_dispel READ_LONG (fx_off + 0x0e + (0x30 * (abil_fx_idx + index2))) o_duration READ_BYTE (fx_off + 0x12 + (0x30 * (abil_fx_idx + index2))) o_prob1 READ_BYTE (fx_off + 0x13 + (0x30 * (abil_fx_idx + index2))) o_prob2 READ_LONG (fx_off + 0x1c + (0x30 * (abil_fx_idx + index2))) o_dicenum READ_LONG (fx_off + 0x20 + (0x30 * (abil_fx_idx + index2))) o_dicesize READ_LONG (fx_off + 0x24 + (0x30 * (abil_fx_idx + index2))) o_save READ_LONG (fx_off + 0x28 + (0x30 * (abil_fx_idx + index2))) o_savebonus READ_LONG (fx_off + 0x2c + (0x30 * (abil_fx_idx + index2))) o_flags PATCH_IF (((o_power = m_power) OR (m_power ((o_type = m_type) OR (m_type ((o_damtype = m_damtype) OR (m_damtype ((o_timing = m_timing) OR (m_timing ((o_dispel = m_dispel) OR (m_dispel ((o_duration = m_duration) OR (m_duration ((o_prob1 = m_prob1) OR (m_prob1 ((o_prob2 = m_prob2) OR (m_prob2 ((o_dicesize = m_dicesize) OR (m_dicesize ((o_flags = m_flags) OR (m_flags SET o_index = index2 SET damage += 1 // matches PATCH_IF (((o_save & BIT0) = 0) AND // no save vs. spell ((o_save & BIT1) = 0) AND // no save vs. breath ((o_save & BIT2) = 0) AND // no save vs. death ((o_save & BIT3) = 0) AND // no save vs. wand ((o_save & BIT4) = 0)) BEGIN // no save vs. polymorph SET o_save_here = 0 END ELSE BEGIN SET o_save_here = 1 END END END ELSE BEGIN // damage > 0, o_ vars set READ_BYTE (fx_off + 0x02 + (0x30 * (abil_fx_idx + index2))) c_power READ_LONG (fx_off + 0x04 + (0x30 * (abil_fx_idx + index2))) c_amount READ_SHORT (fx_off + 0x08 + (0x30 * (abil_fx_idx + index2))) c_type READ_SHORT (fx_off + 0x0a + (0x30 * (abil_fx_idx + index2))) c_damtype READ_BYTE (fx_off + 0x0c + (0x30 * (abil_fx_idx + index2))) c_timing READ_BYTE (fx_off + 0x0d + (0x30 * (abil_fx_idx + index2))) c_dispel READ_LONG (fx_off + 0x0e + (0x30 * (abil_fx_idx + index2))) c_duration READ_BYTE (fx_off + 0x12 + (0x30 * (abil_fx_idx + index2))) c_prob1 READ_BYTE (fx_off + 0x13 + (0x30 * (abil_fx_idx + index2))) c_prob2 READ_LONG (fx_off + 0x1c + (0x30 * (abil_fx_idx + index2))) c_dicenum READ_LONG (fx_off + 0x20 + (0x30 * (abil_fx_idx + index2))) c_dicesize READ_LONG (fx_off + 0x24 + (0x30 * (abil_fx_idx + index2))) c_save READ_LONG (fx_off + 0x28 + (0x30 * (abil_fx_idx + index2))) c_savebonus READ_LONG (fx_off + 0x2c + (0x30 * (abil_fx_idx + index2))) c_flags PATCH_IF ((o_power = c_power) AND (o_type = c_type) AND (o_damtype = c_damtype) AND (o_timing = c_timing) AND (o_dispel = c_dispel) AND (o_duration = c_duration) AND (o_prob1 = c_prob1) AND (o_prob2 = c_prob2) AND (o_dicesize = c_dicesize) AND (o_flags = c_flags)) BEGIN PATCH_IF (((c_save & BIT0) = 0) AND // no save vs. spell ((c_save & BIT1) = 0) AND // no save vs. breath ((c_save & BIT2) = 0) AND // no save vs. death ((c_save & BIT3) = 0) AND // no save vs. wand ((c_save & BIT4) = 0)) BEGIN // no save vs. polymorph SET c_save_here = 0 END ELSE BEGIN SET c_save_here = 1 END PATCH_IF ((o_amount = c_amount) OR (o_amount = (c_amount + 1)) OR (o_amount = (c_amount - 1))) BEGIN PATCH_IF ((c_dicenum = c_dicenum) OR (c_dicenum = (c_dicenum + 1)) OR (c_dicenum = (c_dicenum - 1))) BEGIN PATCH_IF (((c_save_here = 0) OR (o_save_here = 0)) AND (c_save_here + o_save_here != 0)) BEGIN // one, but not both saves must be zero SPRINT debug_message ~%debug_message%\r\n == MATCH! on on %SOURCE_FILE%, header %index%, trying to combine damage~ PATCH_IF o_save_here = 0 BEGIN // no save vs. polymorph SET n_save = c_save SET n_savebonus = c_savebonus END ELSE BEGIN SET n_save = o_save SET n_savebonus = o_savebonus END SET n_amount = o_amount + c_amount SET n_dicenum = o_dicenum + c_dicenum DELETE_BYTES (fx_off + (0x30 * (abil_fx_idx + index2))) 0x30 // delete second damage effect SET index2 -= 1 SET fx_delta -= 1 SET abil_fx_num -= 1 // update damage #1 with new values WRITE_LONG (fx_off + 0x04 + (0x30 * (abil_fx_idx + o_index))) n_amount // combined static damage WRITE_LONG (fx_off + 0x1c + (0x30 * (abil_fx_idx + o_index))) n_dicenum // combined dice rolls WRITE_LONG (fx_off + 0x24 + (0x30 * (abil_fx_idx + o_index))) n_save // save type WRITE_LONG (fx_off + 0x28 + (0x30 * (abil_fx_idx + o_index))) n_savebonus // save bonus WRITE_LONG (fx_off + 0x2c + (0x30 * (abil_fx_idx + o_index))) (THIS BOR BIT8) // add magic save-for-half flag END ELSE BEGIN SPRINT debug_message ~%debug_message%\r\n basic parameters of damage match, but saves vary on %SOURCE_FILE%, header %index%~ END END ELSE BEGIN SPRINT debug_message ~%debug_message%\r\n basic parameters of damage match, but number of dice rolls varies on %SOURCE_FILE%, header %index%~ END END ELSE BEGIN SPRINT debug_message ~%debug_message%\r\n basic parameters of damage match, but static damage varies on %SOURCE_FILE%, header %index%~ END END ELSE BEGIN SPRINT debug_message ~%debug_message%\r\n basic parameters of damage don't match on %SOURCE_FILE%, header %index%~ END END // patch_if damage = 1 END // patch_if opcode = 12 END // end fx loop PATCH_IF damage = 0 BEGIN SPRINT debug_message ~%debug_message%\r\n no damage opcode matching search parameters found on %SOURCE_FILE%, header %index%~ END WRITE_SHORT (abil_off + 0x1e + (abil_length * index)) abil_fx_num END // end header type/number check END // end abil loop PATCH_IF debug BEGIN INNER_PATCH_SAVE debug_message ~%debug_message%~ BEGIN REPLACE_TEXTUALLY ~\\r\\n~ ~~ END PATCH_PRINT ~%debug_message%~ ENDEND Quote Link to comment
CamDawg Posted November 20, 2017 Author Share Posted November 20, 2017 (edited) On 7/26/2017 at 6:25 AM, CamDawg said: As presently written, you can't specify a tra file for it. I'll poke it a bit and make it work. Long overdue, but here's cd_extend_bg_area_script that accepts tra files. Sample usage: LAF cd_extend_bg_area_script STR_VAR area = ar1000 script = ~path/to/script~ tra_file = ~path/to/tra.tra~ END Omit the .baf extension from the script parameter, but include .tra for tra_file. Poor planning on my part, but it works. Spoiler DEFINE_ACTION_FUNCTION cd_extend_bg_area_script INT_VAR extend_top = 0 STR_VAR area = "" script = "" tra_file = "" BEGIN // make sure we have area scripts assigned COPY_EXISTING ~%area%.are~ ~override~ READ_ASCII 0x94 a_script PATCH_IF ("%script%" STRING_COMPARE_CASE ~~ = 0) BEGIN // if blank PATCH_IF GAME_IS ~tutu tutu_totsc~ BEGIN // if Tutu WRITE_ASCIIE 0x95 ~%SOURCE_RES%~ #7 WRITE_ASCII 0x94 ~_ar~ END ELSE BEGIN // bgt WRITE_ASCIIE 0x94 ~%SOURCE_RES%~ #8 END READ_ASCII 0x94 a_script END BUT_ONLY <<<<<<<<./inlined-macro/cd_extend_bg_area_script.tpa EXTEND_BOTTOM ~%a_script%.bcs~ ~%script%.baf~ EVALUATE_BUFFER USING ~%tra_file%~ >>>>>>>> ACTION_IF extend_top = 1 THEN BEGIN COPY ~./inlined-macro/cd_extend_bg_area_script.tpa~ ~./inlined-macro/cd_extend_bg_area_script.tpa~ REPLACE_TEXTUALLY ~^EXTEND_BOTTOM~ ~EXTEND_TOP~ END ACTION_IF ("%tra_file%" STRING_COMPARE_CASE "" = 0) THEN BEGIN COPY ~./inlined-macro/cd_extend_bg_area_script.tpa~ ~./inlined-macro/cd_extend_bg_area_script.tpa~ REPLACE_TEXTUALLY ~ EVALUATE_BUFFER USING ~ ~ EVALUATE_BUFFER // USING ~ END REINCLUDE ~./inlined-macro/cd_extend_bg_area_script.tpa~ END Edited September 30, 2021 by CamDawg borked formatting Quote Link to comment
Roxanne Posted November 23, 2017 Share Posted November 23, 2017 (edited) Add a new actor to an area. This is a simple wrapper around fj_area_struct that saves having to type a bunch of variables. DEFINE_PATCH_FUNCTION add_area_actor BEGIN PATCH_IF FILE_EXISTS_IN_GAME "%cre_resref%.cre" BEGIN INNER_PATCH_FILE "%cre_resref%.cre" BEGIN READ_STRREF 0x0008 cre_name END END ELSE BEGIN PATCH_FAIL "Adding non-existent actor %cre_resref% to area!" END LAUNCH_PATCH_FUNCTION fj_are_structure INT_VAR fj_loc_x = x_position fj_loc_y = y_position fj_dest_x = x_position fj_dest_y = y_position fj_orientation = orientation STR_VAR fj_structure_type = "actor" fj_name = "%cre_name%" fj_cre_resref = "%cre_resref%" END END Clear all actors from an area. Useful if you want to give a generic house in BG1 some new purpose. DEFINE_PATCH_MACRO remove_all_area_actors BEGIN FOR (i = SHORT_AT 0x0058; i > 0; --i) BEGIN LAUNCH_PATCH_FUNCTION fj_are_structure INT_VAR fj_delete_mode = i - 1 STR_VAR fj_structure_type = "actor" END END END Add a simple trap to an area. Care should be taken that the trap form a long thin rectangle, or thieves may not be able to get close enough to disarm it. Another wrappper around fj_area_struct to save typing because I'm lazy. :-) DEFINE_PATCH_FUNCTION add_simple_trap INT_VAR trap_detect = 10 trap_remove = 10 STR_VAR trap_script = "gtar" BEGIN PATCH_IF ll_x < ul_x BEGIN SET min_x = ll_x END ELSE BEGIN SET min_x = ul_x END PATCH_IF lr_x > ur_x BEGIN SET max_x = lr_x END ELSE BEGIN SET max_x = ur_x END PATCH_IF ul_y < ur_y BEGIN SET min_y = ul_y END ELSE BEGIN SET min_y = ur_y END PATCH_IF ll_y > lr_y BEGIN SET max_y = ll_y END ELSE BEGIN SET max_y = lr_y END LAUNCH_PATCH_FUNCTION fj_are_structure INT_VAR fj_type = 0 // Trap fj_box_left = min_x fj_box_top = min_y fj_box_right = max_x fj_box_bottom = max_y fj_trap_active = 1 fj_loc_x = (min_x + max_x) / 2 fj_loc_y = (min_y + max_y) / 2 fj_alt_x = (min_x + max_x) / 2 fj_alt_y = (min_y + max_y) / 2 fj_trap_detect = trap_detect fj_trap_remove = trap_remove fj_flags = BIT3 fj_vertex_0 = ul_x + (ul_y << 16) fj_vertex_1 = ur_x + (ur_y << 16) fj_vertex_2 = lr_x + (lr_y << 16) fj_vertex_3 = ll_x + (ll_y << 16) STR_VAR fj_structure_type = "region" fj_name = "%trap_name%" fj_reg_script = "%trap_script%" END END Batch-add new actors to an area from a table. Table takes the form <resref> <xpos> <ypos> <orientation>. Uses add_area_actor(). DEFINE_PATCH_FUNCTION add_area_actors_from_2da STR_VAR path_to_2da = "none" BEGIN PATCH_IF FILE_EXISTS "%path_to_2da%" BEGIN INNER_PATCH_FILE "%path_to_2da%" BEGIN COUNT_2DA_COLS cols COUNT_2DA_ROWS cols rows READ_2DA_ENTRIES_NOW __actor_data cols END FOR (i = 0; i < rows; ++i) BEGIN READ_2DA_ENTRY_FORMER __actor_data i 0 cre_resref READ_2DA_ENTRY_FORMER __actor_data i 1 x_position READ_2DA_ENTRY_FORMER __actor_data i 2 y_position READ_2DA_ENTRY_FORMER __actor_data i 3 orientation LAUNCH_PATCH_FUNCTION add_area_actor INT_VAR x_position y_position orientation STR_VAR cre_resref END END END ELSE BEGIN PATCH_FAIL "add_area_actors_from_2da called with invalid path %path_to_2da%!" END END I have a question whether these functions can be modified in such a way that I can either: - remove an individual cre (actor) from an are-file - replace an individual cre (actor) from an are-file Currently I just modify the resource name (cre-file name) at the respective offset in the are-file. This works fine, but may be a bit fragile as some other modder may one day decide to change the same are-file in a way that changes the current offset. Has anyone done this? Background In EET, I change the fixed appearance of a vanilla NPC by a scripted appearance where either the vanilla creature OR the continuous NPC from a previous campaign is triggered. In my upcoming mod, Corwin from SoD can join the PC already during the BG1 part as soon as Baldur's Gate City becomes available. I kind of extend the NPC forward... Of course, when she re-joins in the SoD campaign, I use the same continuos creature. Bad thing in SoD coding is, that her appearance there is from the cre being part of an are-file. I have already changed that, so actually the problem is solved - just maybe not permanently, if some other modder touches a cruicial part of the respective are-file. What I do at the moment is to go into the are-file actors part, go to actorXX and in the *character* field change the resource. (A rabbit appears instead of the NPC) The NPC is created by the area script now instead, thus allowing me to select based on some globals set/not set previously. Edited November 23, 2017 by Roxanne Quote Link to comment
Aquadrizzt Posted November 26, 2017 Share Posted November 26, 2017 (edited) Figured I'd throw my multiclass macro up here too. It allows you to assign class features to multiclass kits in the 2.0+ engine, and does so with only a single line added to each trueclass clab. It's maintained on GitHub for those who want to download the library directly. Actual macro code is available here (it's quite long). Syntax looks like this (and assumes that you have a few base files present somewhere in your mod structure): LAF qd_multiclass STR_VAR kit_name = ~kitname~ //the internal name for your kit (e.g. QDMAGUS) kit_clab = ~kitclab~ //the internal name of your kit's clab file, without the .2da extension base_class = ~X~ // this can take 6 values: [F]ighter, [P]riest, [D]ruid, [R]anger, [M]age, [T]hief mc_dir = ~your/file/structure~ // the directory containing the three files, as noted above END You can use it to make kitted multi-classes (Fighter/Wild Mage), multi-class kits (Bladesinger as a Fighter/Mage kit) or even multi-kit setups (Berserker/Priest of Talos), all with relatively painless syntax. If anyone knows how to make weidu generate completely blank spells consistently, then this macro could be further refined to not need a link back to a directory. Edited November 26, 2017 by Aquadrizzt Quote Link to comment
CamDawg Posted November 26, 2017 Author Share Posted November 26, 2017 If anyone knows how to make weidu generate completely blank spells consistently, then this macro could be further refined to not need a link back to a directory. Check Ardanis' CREATE_SPELL in the second post. Quote Link to comment
Wisp Posted November 26, 2017 Share Posted November 26, 2017 (edited) WeiDU's CREATE can make spells. Edited November 26, 2017 by Wisp Quote Link to comment
Aquadrizzt Posted November 26, 2017 Share Posted November 26, 2017 Lol completely missed that. Thanks! Worked like a charm once I dropped it in. Quote Link to comment
Wisp Posted November 26, 2017 Share Posted November 26, 2017 Note that CREATE takes patches, so you can just write CREATE SPL ~QD_MC_01~ LPF ADD_SPELL_HEADER 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.