Skip to content

Short introduction to WeiDU and simple mod template

13

Comments

  • CaloNordCaloNord Member Posts: 1,809
    @Wisp‌ I just wanted to thank you for starting this thread! I've never been a modder before but with a lot of the insights I've gotten recently from this thread and my own research I've been able to make 2 NPC's in a few hours, both of which I plan to work on extensively over the coming months and flesh them out! :)
    Thank you for the insight and assistance with getting off my ass! ;)
  • AstroBryGuyAstroBryGuy Member Posts: 3,437
    Wisp said:

    @AstroBryGuy‌
    Okay. Would you happen to know if MosPack is also dynamically linked? (I would guess it is.)
    I don't suppose you would be able to provide me with statically linked executables?

    @Wisp - I can use command line tools to change the library location from /usr/local/lib to the executable path. Then, a copy of libjpeg.8.dylib could be included in the bin-x64 directory. Would that be useful?
  • WispWisp Member Posts: 1,102


    @Wisp - I can use command line tools to change the library location from /usr/local/lib to the executable path. Then, a copy of libjpeg.8.dylib could be included in the bin-x64 directory. Would that be useful?

    @AstroBryGuy‌
    Sure, it's the next best thing. I'll probably (eventually) try to find someone to link them statically, but for all I know it might be a while.
  • AbelAbel Member Posts: 785
    Let's revive (again!) this useful thread!
    So, I'm working on something new and I figured I'd ask my questions as they come.

    Now, I want to delete an item effect. I know of the DELETE_ITEM_EFFECT macro. Problem is, it deletes effects by opcode/type. But I want to delete an effect for a specific opcode/type parameter. So, with this macro I can't discriminate between effects with the same opcode/type but different parameters.

    Before writing it myself, I wondered if there were any ready macro to achieve that goal.
  • argent77argent77 Member Posts: 3,478
    @Abel Have you tried DELETE_EFFECT? It allows you to specify more variables for matching.
  • AbelAbel Member Posts: 785
    edited March 2016
    Yes indeed, you're right! It works perfectly! I see CamDawg wrote it. Nice work on his part. Thanks for the quick and helpful answer @argent77, I can now contine my work!
  • AbelAbel Member Posts: 785
    edited March 2016
    @argent77 Wasn't long before I hit another wall! Minor annoyance... I wrote this:

    DEFINE_ASSOCIATIVE_ARRAY par1efftodel BEGIN 267 => 26018 267 => 26019 END PHP_EACH par1efftodel AS opcode => parameter BEGIN PATCH_PRINT ~1 %SOURCE_RES% %opcode% %parameter%~ LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = opcode match_parameter1 = parameter END END
    Thing is, PHP_EACH skips 267 => 26018 and goes straight to 267 => 26019. I guess it has to do with how arrays work. Maybe it doesn't accept a same value in the first column?

    I could write each LAUNCH_PATCH_FUNCTION DELETE_EFFECT but it's not clean and I have other, longer (not working) arrays.
  • argent77argent77 Member Posts: 3,478
    edited March 2016
    I'm not very experience with WeiDU arrays, but I think you're right with your assumption. Does it work when you swap the positions?

    DEFINE_ASSOCIATIVE_ARRAY par1efftodel BEGIN 26018 => 267 26019 => 267 END PHP_EACH par1efftodel AS parameter => opcode BEGIN PATCH_PRINT ~1 %SOURCE_RES% %opcode% %parameter%~ LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = opcode match_parameter1 = parameter END END
  • [Deleted User][Deleted User] Posts: 0
    edited March 2016
    The user and all related content has been deleted.
    Post edited by [Deleted User] on
  • AbelAbel Member Posts: 785
    edited March 2016
    argent77 said:

    I'm not very experience with WeiDU arrays, but I think you're right with your assumption. Does it work when you swap the positions?

    DEFINE_ASSOCIATIVE_ARRAY par1efftodel BEGIN 26018 => 267 26019 => 267 END PHP_EACH par1efftodel AS parameter => opcode BEGIN PATCH_PRINT ~1 %SOURCE_RES% %opcode% %parameter%~ LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = opcode match_parameter1 = parameter END END

    @argent77 Yes, it works! Problem is, in some cases I have identical numbers on both sides of the array...

    Swapping sides of the array shouldn't make a difference AFAIK.

    Does this really call for an associative array? Why not simply use a COPY_REGEXP and use the "match_" parameters of the function to control when the function takes effect? If you end it with a BUT_ONLY, it shouldn't take any longer to process...

    @subtledoctor How would I use COPY here? I've already copied the items that need patching and I know what values I need for the function variables.

    I thought about creating a 2DA like table. A table with entries is actually what I need. It could also have more than 2 columns.

    Edit: I ended up rewriting the code withg PHP_FOR_EACH. Not ideal but a still cleaner than launching the function for each set of parameters.

    [spoiler=Initial code with non working arrays] //DEFINE_ASSOCIATIVE_ARRAY par1efftodel BEGIN // 26018 => 267 // 26019 => 267 //END //DEFINE_ASSOCIATIVE_ARRAY par2efftodel BEGIN // 240 => 38 // 101 => 16 // 101 => 126 // 169 => 38 //END //DEFINE_ASSOCIATIVE_ARRAY resefftodel BEGIN // 206 => SPRA301 // 206 => SPIN572 // 206 => SPIN828 // 206 => SPWI305 // 206 => SPWI613 //END //PHP_EACH par1efftodel AS opcode => parameter BEGIN // PATCH_PRINT ~1 %SOURCE_RES% %opcode% %parameter%~ // LAUNCH_PATCH_FUNCTION DELETE_EFFECT // INT_VAR match_opcode = opcode match_parameter1 = parameter // END //END //PHP_EACH par2efftodel AS opcode => parameter BEGIN // PATCH_PRINT ~2 %SOURCE_RES% %opcode% %parameter%~ // LAUNCH_PATCH_FUNCTION DELETE_EFFECT // INT_VAR match_opcode = opcode match_parameter2 = parameter // END //END //PHP_EACH resefftodel AS opcode => resource BEGIN // PATCH_PRINT ~3 %SOURCE_RES% %opcode% %resource%~ // LAUNCH_PATCH_FUNCTION DELETE_EFFECT // INT_VAR match_opcode = opcode // STR_VAR match_resource = ~%resource%~ // END //END[/spoiler]
    [spoiler=New code] PATCH_FOR_EACH parameter IN 26018 26019 BEGIN LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = 267 match_parameter1 = parameter END END PATCH_FOR_EACH parameter IN 16 126 BEGIN LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = 101 match_parameter2 = parameter END END PATCH_FOR_EACH resource IN SPRA301 SPIN572 SPIN828 SPWI305 SPWI613 BEGIN PATCH_PRINT ~%resource%~ LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = 206 STR_VAR match_resource = EVAL ~%resource%~ //Needs EVAL?! wth is this?! END END LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = 240 match_parameter2 = 38 END LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = 169 match_parameter2 = 38 END[/spoiler]
    Post edited by Abel on
  • The user and all related content has been deleted.
  • AbelAbel Member Posts: 785
    edited March 2016
    @subtledoctor Yes, I just extracted a bit of the code from a COPY block!

    (And yes, variables in the STR_VAR portion of the DELETE/CLONE/ALTER_EFFECT functions need "EVAL.")

    I thought afterwards it made sense inside a function. It's not documented though. I had to look inside other modders' code.

    Edit: I just found out (there) I could have made it work with the associative arrays. Apparently, you can have identical values on the left side if you add another variable separated by a coma; so you can actually have more than two columns and repeated values as long as any set on the left is different.
    Will try it tomorrow, maybe...
  • CamDawgCamDawg Member, Developer Posts: 3,438
    edited March 2016
    Associative arrays are not just a two-piece list (though that's usually how you see them used); the key => value relationship matters. The keys on the left hand of an array need to be unique, though they can be mapped to identical values on the right. A duplicate key entry simply changes the value associated with the key, which is why you can do something like this:
    ACTION_CLEAR_ARRAY cd_prof_strings
    ACTION_DEFINE_ASSOCIATIVE_ARRAY cd_prof_strings BEGIN
    dots0 => 9588 // default iwdee/bg2ee/bgee prof string
    dots2 => 32117 // default iwdee/bg2ee specialization string
    dots3 => 32118 // default iwdee/bg2ee mastery string
    dots4 => 32119 // default iwdee/bg2ee high mastery string
    dots5 => 32120 // default iwdee/bg2ee grandmastery string
    END

    ACTION_IF NOT GAME_IS ~iwdee bg2ee eet~ BEGIN // override dots2-5 for bgee, sod

    ACTION_DEFINE_ASSOCIATIVE_ARRAY cd_prof_strings BEGIN
    dots2 => 24220 // bgee specialization string
    dots3 => 24221 // bgee mastery string
    dots4 => 24222 // bgee high mastery string
    dots5 => 24223 // bgee grandmastery string
    END

    END
    The second batch revalues the dots2-5 keys in a BGEE/SoD game, so you still end up with a 5 key array.
    Post edited by CamDawg on
  • AbelAbel Member Posts: 785
    Thanks for clearing that up! I ended up building a table-like array. It's a bit articifial but it's easy to read and understand:

    DEFINE_ASSOCIATIVE_ARRAY efftodel BEGIN //opcode parameter1 parameter2 resource => n° 267, 26018, "-1", SAME => 1 267, 26019, "-1", SAME => 2 240, "-1", 38, SAME => 3 101, "-1", 16, SAME => 4 101, "-1", 126, SAME => 5 169, "-1", 38, SAME => 6 206, "-1", "-1", SPRA301 => 7 206, "-1", "-1", SPIN572 => 8 206, "-1", "-1", SPIN828 => 9 206, "-1", "-1", SPWI305 => 10 206, "-1", "-1", SPWI613 => 11 126, "-1", "-1", SAME => 12 END PHP_EACH efftodel AS variable => value BEGIN PATCH_PRINT ~1) %variable_1% %variable_2% %SOURCE_RES%~ LAUNCH_PATCH_FUNCTION DELETE_EFFECT INT_VAR match_opcode = variable_0 match_parameter1 = variable_1 match_parameter2 = variable_2 STR_VAR match_resource = EVAL ~%variable_3%~ END END
    I tried to SET match_opcode, etc. oustide and pass its value to the DELETE_EFFECT as a macro but it didn't work. Anyway, I think this solution is much more readable so it doesn't matter much.
  • AbelAbel Member Posts: 785
    edited March 2016
    I'm editing existing NPCs dialogs. I've just discovered the WEIGHT # bit. I want to alter the first state NPCs says when talked to. Problem with this wonderful WEIGHT # is that it bypasses a simple APPEND_EARLY. Is it possible to set WEIGHT # dynamically? My fear is that I'd need to set a specific WEIGHT # and create conflicts with other mods.

    My ultimate goal is to make these NPCs join the party. I would extend their scripts but some NPCs will initiate dialog on sight. So it will cause problems if they join before (they would still try to start dialog but unable to). If made to join after well, that wouldn't be ideal (maybe the safest solution still).

    Thinking about it now, maybe I could add a (custom) variable to the script to prevent the NPC from initiating conversation.

    Anyway, what do you think about all this?

    Edit: I didn't think about extending the first (weighed) state. It's a possibility too.
  • AbelAbel Member Posts: 785
    Answering my own previous question as it seems nobody knew the answer. I went with a WEIGHT #-1. WeiDU automatically changed it to the lowest WEIGHT of the modded scripts. I don't know what would happen if another mod changed this though. The code (D file):
    [spoiler]BEGIN ~BLNPCJOIN~ APPEND_EARLY ~%npc%~ IF WEIGHT #-1 ~Global("BL_NPCSummoned","GLOBAL",1)~ THEN BEGIN BL_AnswerCall SAY ~Would you like me to assist with the case?~ IF ~~ THEN REPLY ~Yes! Please join me!~ DO ~SetGlobal("BL_NPCSummoned","GLOBAL",0) DestroyItem("MIHP1") JoinParty()~ EXIT IF ~~ THEN REPLY ~No! I don't need you! Begone!~ DO ~SetGlobal("BL_NPCSummoned","GLOBAL",0) DestroySelf()~ EXIT END END[/spoiler]
    Now, I have another question. I'm trying to manipulate strings. I want to extract a specific part.
    I see that INDEX or RINDEX will allow me to find the point from which my selection should start (or end). Trouble is, there doesn't seem to be any patch that allow me to select a string from this point. There's only a SNPRINT that selects the first n characters.
    So, is there a way to use WeiDU for that or does it need post-patching work?
  • AbelAbel Member Posts: 785
    edited April 2016
    Another question. Currently ADD_STORE_ITEM can overwrite an already existing item. But I want it to increase the stack/quantity instead. Has someone found a way to do this? Right now I can only imagine that the function itself would need some additional code.

    Edit: found the solution! Modified the stack value before adding the item (easier said than done with arrays). Needed some creative coding, but it looks better anyway.
    Post edited by Abel on
  • GrammarsaladGrammarsalad Member Posts: 2,582
    @Icecreamtub

    This is a very good place to start

    (This should be stickied)
  • WispWisp Member Posts: 1,102
    Abel said:

    Trouble is, there doesn't seem to be any patch that allow me to select a string from this point.

    Have a look at the SUBSTRING function.
  • AbelAbel Member Posts: 785
    I'm working on a new project and I've hit a wall with arrays or rather array declaration in functions/macros.
    So, said function/macro reads and/or sets an array. Array name isn't specified there since it must work for various arrays.
    So, code example:

    ACTION_DEFINE_ASSOCIATIVE_ARRAY logic BEGIN FALSE => 0 TRUE => 1 END DEFINE_ACTION_MACRO SET_ARRAY_VALUE BEGIN ACTION_PHP_EACH ~%array%~ AS key => val BEGIN OUTER_SET $~%array%~(~%key_0%~) = value END END OUTER_SPRINT array ~logic~ OUTER_SET value = 2 LAUNCH_ACTION_MACRO SET_ARRAY_VALUE
    Silly example, but the problem lies with the: 'OUTER_SET $~%array%~(~%key_0%~) = value' part. Only the PHP_EACH works well with an ~%array%~ variable.
    I've tried different syntaxes like ~$%array%~(~%key_0%~), ~$%array%(%key_0%)~, with EVAL, but nothing changes. Maybe there's trouble with the '$'.
    Anyway, any help woud be appreciated!
  • The user and all related content has been deleted.
  • AbelAbel Member Posts: 785
    edited July 2016
    Thanks for your input @subtledoctor. As I said, it's silly code I just typed.
    I need to change the values of a given array, hence why I use a SET inside the macro.
    Original code below will read each entry of an array, and use its key_1 which is an offset (in the predefined array) to get the value at this offset (for the copied resource) and then update the array with this value:
    [spoiler]DEFINE_PATCH_MACRO SET_RESOURCE_ARRAY_VALUES BEGIN PHP_EACH ~%array%~ AS key => val BEGIN //Loop through each entry of array //START READING DATA LAUNCH_PATCH_FUNCTION READ_DATA INT_VAR offset_to_read = key_1 STR_VAR data_type = EVAL ~%key_3%~ RET val = value END //UPDATE ARRAY VALUE PATCH_IF IS_AN_INT val BEGIN //For an integer value SET $~%array%~(~%key_0%~ ~%key_1%~ ~%key_2%~ ~%key_3%~ ~%key_4%~) = val END ELSE BEGIN //For a string value SPRINT $~%array%~(~%key_0%~ ~%key_1%~ ~%key_2%~ ~%key_3%~ ~%key_4%~) ~%val%~ END END END[/spoiler]

    Edit: I actually found the correct syntax and the conditions for the code to work at all.
    First, the correct writing is this: SET EVAL $~%array%~(~%key_0%~) = value. So, it seems EVAL is needed after all.
    Second, and it's more annoying, the keys and values must have been set before you can use this code. So you have to declare your array with the usual statement: SET $array(~%key_0%~) = value. Weird...
    Post edited by Abel on
  • AbelAbel Member Posts: 785
    WeiDU automatically uninstalls a previously installed mod when reinstalling it. I'd like to give the user the option to uninstall or not before reinstalling.
    I don't want to prevent uninstallation by skipping backup and log. I just want to make it 'optional'. Is that possible?
  • argent77argent77 Member Posts: 3,478
    I don't think so. There is the keyword NO_LOG_RECORD which prevents a mod component from creating a log record at all. But you can't set it dynamically based on user input.
  • AbelAbel Member Posts: 785
    edited July 2016
    Thanks for your answer @argent77. Maybe there's a way to code it but that looks troublesome.

    Edit: isn't there a way to copy the files to a folder where they won't get deleted at reinstall? Then paste them (or not) before patching?

    Yes, ok it's easy to do actually:
    COPY + ~override/%file%~ ~mymod/myfiles~
  • BCaesarBCaesar Member Posts: 480
    edited December 2016
    Ok I've read the first post a few times and read the others and I'm missing something.

    I have the latest version of WeiDU. I have all the files I want to copy (I already edited them all in Near Infinity). My mod is called Warrior Monk

    Step 1) I'm supposed to create a folder 'Warrior_Monk_Mod'. Done.

    Step 2) I'm supposed to create a sub-folder called 'Copy'. Done.

    Step 2) I'm supposed to put all of the files I want to install in the mod into the sub-folder 'Copy'. Done.

    And then here's where I completely lose it. I'm supposed to create a file called a TP2 file but I don't know how to do that. I could copy someone else's file and then rename it. But then I'm supposed to write things in my TP2 file but I don't know how to open a TP2 file.

    So how do I create a TP2 file and how do I open/edit a TP2 file?

    Thanks.
  • ArdanisArdanis Member Posts: 1,736
    TP2 is a renamed TXT file.
  • GrimLefourbeGrimLefourbe Member Posts: 637
    edited December 2016
    You can open it with Notepad++ and use Argent77's weidu highlighter for notepad++.
  • BCaesarBCaesar Member Posts: 480

    You can open it with Notepad++ and use Argent77's weidu highlighter for notepad++.

    Ardanis said:

    TP2 is a renamed TXT file.

    I got it to work! Thanks!

    Now I have another simple WeiDU question. The Mod is all finished here:
    https://forums.beamdog.com/discussion/62614/warrior-monk-mod-version-1-02-for-bg1-ee-now-with-weidu-installer

    But I do have one more thing I want to do. I want to modify the following parts of Dialog.tlk to reflect all the changes:
    32299 -Short Monk description
    31984- Sun Soul Monk Kit Description
    91981- Dark Moon Monk Kit Description
    24234- Monk Class Description

    They're the class/kit descriptions in game, so I want to edit those without screwing anything else up. Do you know how to do that in WeiDU?
  • agb1agb1 Member Posts: 249
    edited December 2016
    @BCaesar - take a look at the tp2 file for Wilson Chronicles (https://forums.beamdog.com/discussion/62741/wilson-chronicles-expansion-of-the-furry-paragon/p1).

    It reads an existing kit description by string reference number, replaces one line, and writes the modified result. And it uses @tra references. Should be a good template for you.
Sign In or Register to comment.