Skip to content

-HOW TO DO STUFF IN WEIDU-

1234579

Comments

  • switswit Member, Translator (NDA) Posts: 495
    edited March 2019
    edit: nevermind
  • kjeronkjeron Member Posts: 2,367
    edited March 2019
    swit wrote: »
    edit: nevermind
    AddKit() requires a kit-class match in order to remove the old kit - otherwise it removes the default CLAB file for the current class(es).

    At this stage:
    ChangeClass(Myself,BARD)
        AddKit(BLADE)
    
    It's going to remove the effects in CLABBA01, because the current bard "kit" is "trueclass" - if you level up, that is the CLAB file that will be applied.
    It works this way because of Multi/Dual classes - it needs to know which CLAB file to apply/remove for each class, and uses the trueclass CLAB file for any class without a matching kit.
  • switswit Member, Translator (NDA) Posts: 495
    thanks, looks like you've managed to read the message before the edit :)
  • switswit Member, Translator (NDA) Posts: 495
    edited March 2019
    kjeron wrote: »
    Only script actions work:
    AddKit(KIT) // Remove existing kit CLAB features and apply new kits CLAB level by level.
    AddSuperKit(KIT) // Retain existing kit CLAB features and apply new kits CLAB level by level.
    ChangeStat(Myself,KIT,#,ADD/SET) // Retain existing kit CLAB features, does not apply new kits CLAB.

    for a moment I had an idea about implementing 3rd ed multiclass system in EE engine using AddKit() / AddSuperKit(). Storing each class level in a local variable or EEex stat (either of them assigned via custom level-up GUI screen coded in Lua) and implementing class specific features after each level using AddKit, with a help of ChangeClass (just to be able to use AddKit) and ChangeStat (to temporary assign LEVEL based on local variable value, so that correct CLAB columns are used). This would make the system highly customizable and easy to work with, but the idea fell flat due to problems with CLAB cleaning.

    @kjeron, I assume there is no way to add multiple kits via AddKit and later remove those kits CLAB features one by one, right? I've experimented with changing classes before AddKit usage and created dummy kits with empty CLABS for each class, but even with this I can't make the AddKit CLAB cleaning work reliably for multiple kits. Too bad there is no RemoveKit action.
    Post edited by swit on
  • [Deleted User][Deleted User] Posts: 0
    edited March 2019
    The user and all related content has been deleted.
  • switswit Member, Translator (NDA) Posts: 495
    edited March 2019
    yep, the implementation that I came up with above after reading the quoted kjeron's post was more like a cosmetic/usability improvement, not something strictly needed to implement 3rd style multiclassing system. With EEex that allows setting and reading local variables from within GUI, as well as adjusting the buttons available for the class on the fly, the only thing crucial for a robust system without awkward workarounds is the arcane spells, divine spells, and thief abilities availability (and from what I read @Bubb has been experimenting with it too).

    Gramnarsalad and Aquadrizzt and I have talked it through, and mostly figured it out in concept.
    Where are you guys discussing this stuff and why I'm not part of these conversations? :P
  • semiticgoddesssemiticgoddess Member Posts: 14,903
    I need to make a slight tweak to the WEAPPROF.2da. All I want to do is let Archers get Grandmastery in slings and darts, so I need to change a 2 to a 5 on lines 30 and 31.
  • [Deleted User][Deleted User] Posts: 0
    edited March 2019
    The user and all related content has been deleted.
    semiticgoddess
  • GwendolyneGwendolyne Member Posts: 461
    edited November 2019
    Before rewriting hundreds lines of code, I would know if WeiDU understands that
    ACTION_DEFINE_ASSOCIATIVE_ARRAY GW_anim_skel BEGIN
    ~%tsu%skelwa~ => 1
    ~skelwa01~=> 1
    ~%tss%kelwa02~=> 1
    ~%tss%kelwa03~=> 1
    ~skelwa04~=> 1
    ~skelwasu~=> 1
    ...
    END
    

    is equivalent to
    ACTION_FOR_EACH nb IN ~%tsu%skelwa~ ~skelwa01~ ~%tss%kelwa02~ ~%tss%kelwa03~ ~skelwa04~ ~skelwasu~ ... BEGIN
    

    In other words, does ACTION_DEFINE_ASSOCIATIVE_ARRAY action accept variables?


    Post edited by Gwendolyne on
  • kjeronkjeron Member Posts: 2,367
    Gwendolyne wrote: »
    In other words, does ACTION_DEFINE_ASSOCIATIVE_ARRAY action accepts variables?
    Yes
  • GwendolyneGwendolyne Member Posts: 461
    thanks!
  • CallirgosCallirgos Member Posts: 105
    edited February 2020
    Hi I'm trying to figure out if I should use "Replace" or "Replace_Say"

    I have a unique .DLG I created for an Innkeeper's rumors. I've set up all the logic for the states and responses, so I want to keep that intact. I have 10 states that use string 33999, because those are the states I want to put unique/new text into.

    The WEIDU readme says that REPLACE will replace the whole state, but I want to keep the logic I set up. It also says that REPLACE_SAY will "destructively" replace the text. What does "destructively" mean, exactly?

    What command should I use in my TP2 file?
  • ScofieldScofield Member Posts: 119
    edited March 2020
    Hi guys,

    I hope somebody can help me out with the following:

    I've created a new 'display portrait icon' for a new ability (spell) that I'd like to add to STATDESC.2DA.
    Now, I can just do this - that adds the BAM file (ULTRA4D.BAM) I created to an empty row.

    COPY_EXISTING ~STATDESC.2DA~ ~override~
    SET_2DA_ENTRY 188 2 2 ~ULTRA4D~

    This is all fine but I just can't figure out how to add a description string to it.

    I would basically need to add a new string to dialog.tlk, and then use its reference number (XX) to add it to STATDESC.2DA like this:

    SET_2DA_ENTRY 188 1 2 ~XX~

    I don't know how to do this properly so it would be compatible with both BG1 and BG2 since the reference number would need to be different. How do I do this? @subtledoctor
  • SystemSystem Administrator Posts: 199
    edited March 2020
    HOW TO MAKE STAT-BASED EFFECTS WITH OPCODE 326

    I think I'll try to do this in a simple list/recipe style. We'll see how it goes. The example was, how to apply an effect like extra spells based on INT score. But, understand this: opcode 326 does no handle dynamic effects very well. You simply can't do something like DEX-based thac0 bonuses that change whenever your DEX score changes, the way the vanilla DEX AC bonuses work. Sorry, too bad, so sad. I have tried and tried and tried to make a 'Finesse' effect, and it has never worked to my satisfaction. So I suggest you think in terms of permanent effects. Instead of INT-based spells, I'll deal with something simpler that I'm working on right now: extra proficiencies at level 1 for high INT.

    1. First, make your effect spells. Opcode 326 triggers a spell, so you need to make a .spl file. Let's put aside the details of how this spell works - it uses my new feat system and it's based on the idea of reducing your initial proficiency cap from 2 pips to 1 pip, and then letting you get back up to 2 pips, in certain weapons, only if you are smart enough. So smart warriors will have an advantage over dumb ones. I'll cover the feat system thing in a future post, so for now let's just say this: we'll make a spell that uses opcode 233 to increment proficiency in long swords by one point. Put this .spl file somewhere in your mod folder and write a COPY line in your .tp2 file to copy it into the game. Let's call it "d5LSprof.spl."
    COPY ~IntMod/files/d5LSprof.spl~ ~override~
    2. Next, get your stat ready to be analyzed. Opcode 326 reads SPLPROT.2da. That file already has a line for "INT>=[value]" so if we only want to make a single effect for an INT score greater than or equal to 12, say, that would be easy. But what if we want a different effect for each score - zero bonuses at INT=12, and six bonuses for INT=18? The "greater-than-or-equal" relation doesn't work well here, we just want a simple "=" relation. So we'll have to add our own.
    APPEND ~splprot.2da~ ~D5_INT_EQ%TAB%38%TAB%-1%TAB%1~
    I add a new line with four columns: a simple identifier (prefaced with my modding prefix, for safety), then "38" in the STAT cloumn (the line # in STATS.ids for INT), then "-1" in the VALUE column (-1 means, read the value from parameter1 of your 326 effect), then "1" in the RELATION column (1 means "equal" - read more about the RELATION values here). I separate them by the Weidu variable %TAB% so that they make nice neat columns in the .2da file.

    Now I have a "INT=" line in SPLPROT.2da, so I am ready to give INT-based bonuses, right? Not so fast. I have my "INT=" line in the .2da file, but I have no way, in advance of the mod installation, to make a spell with a 326 effect that can reference that line. So I have to build it in Weidu.

    3. Now, make your opcode 326 spell with dummy values. I make a spell with multiple effects. Each of these effects uses opcode 326. In the "parameter2" field (labeled "creature type" in Near Infinity) I'll choose a pre-existing one... let's use that "STAT INT >= value" that I mentioned earlier. We will change it later. But this lets me put a value into the parameter1 field (labeled "creature value"). (Remember, our new SPLPROT.2da entry has "-1" for VALUE so it will get the information from whet we put here.) I'll put a different INT score in parameter1 in each 326 effect. If I want a bonus for every point above 12, then I'll make six effects and populate parameter1 with 13, 14, 15, 16, 17, and 18. (or you could make 13 effects, and go all the way up to 25. The point is, since we're looking at a "=" relation, we need a separate 326 effect for each score.

    Put this .spl file into your mod folder - let's call it "d5intspl.spl" - and add a COPY line to your .tp2 file.
    COPY ~IntMod/files/d5intspl.spl~ ~override~
    4. Now you need to know how to find the line you APPENDed to SPLPROT.2da. I don't know what this file looks like; each player might have used many other mods that might have changed the file. So I have to find the line I added to it, at install-time. This is kind of the point of this thread: here is some code that you can adapt pretty easily to your own mod:
    COPY_EXISTING ~splprot.2da~ ~override~
    COUNT_2DA_COLS cols // amount of columns
    READ_2DA_ENTRIES_NOW rows cols // read all file into memory
    FOR (row = 1; row < rows; ++row) BEGIN // iterate over rows
    READ_2DA_ENTRY_FORMER rows row 0 ~stat~ // read column value
    PATCH_IF ~%stat%~ STRING_EQUAL_CASE ~D5_INT_EQ~ BEGIN
    SET int_eq_row = %row%
    END
    END
    BUT_ONLY
    This reads every entry in the first column ("column 0"), in every row in SPLPROT.2da, assigning what it reads there to the variable %stat%. If and when %stat% matches the string "D5_INT_EQ" (that's the first entry we APPENDed up in step 2) then it sets that row number into the variable %int_eq_row% for later use. Put this before the COPY commands so that the variable is ready to be used by them.

    5. Now insert that variable into your 326 spell. Add this under the COPY line for the 326 spell:
      LPF ALTER_EFFECT INT_VAR match_opcode = 326 parameter2 = %int_eq_row% END
    Remember I originally used a dummy value in parameter2 of the 326 spell, well now, at install-time, I am changing it to refer to the new row of SPLPROT.2da that I added.

    6. Finally, let's add this to the Trueclass fighter CLAB table, to give them a bit of a boost over their superior kits:
    APPEND ~clabfi01.2da~ ~ABILITY    AP_D5INTSPL ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****  ~
    So the complete code in Weidu looks like this:
    APPEND ~splprot.2da~ ~D5_INT_EQ%TAB%38%TAB%-1%TAB%1~

    COPY_EXISTING ~splprot.2da~ ~override~
    COUNT_2DA_COLS cols // amount of columns
    READ_2DA_ENTRIES_NOW rows cols // read all file into memory
    FOR (row = 1; row < rows; ++row) BEGIN // iterate over rows
    READ_2DA_ENTRY_FORMER rows row 0 ~stat~ // read column value
    PATCH_IF ~%stat%~ STRING_EQUAL_CASE ~D5_INT_EQ~ BEGIN
    SET int_eq_row = %row%
    END
    END
    BUT_ONLY

    COPY ~IntMod/files/d5LSprof.spl~ ~override~
    COPY ~IntMod/files/d5intspl.spl~ ~override~
    LPF ALTER_EFFECT INT_VAR match_opcode = 326 parameter2 = %int_eq_row% END

    APPEND ~clabfi01.2da~ ~AP_D5INTSPL **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ~
    You'll need to make the spell files yourself, but this can be adapted pretty easily to all sort of stuff. You can check any stat in STATS.ids, so ability scores, proficiency levels, saving throws, thief skills, spell effects, etc. You would only need to change that "38" to some other value in the APPEND line for SPLPROT.2da.

    Okay that's it for now. Hopefully someday in the future I'll talk about how to make these effects dynamic (it involves what I call "auras," i.e. repeating self-cancelling effects).
  • SystemSystem Administrator Posts: 199
    edited March 2020
    Next up: HOW TO GIVE KIT EFFECTS TO ALL KITS (including mod-added kits)

    Okay. Now we have applied a spell to a trueclass fighter that gives him or her some bonus based on INT score. What if we want this to apply to ALL fighters, of any kit? Not just the four vanilla kits, but all fighter kits from any source? The tricky thing is that we cannot control how each player mods their game. Some might stick with the four vanilla fighter kits but others might install tons of kits. How do we cover all bases?

    We do that with the help of an associative array. My current method for this involving using arrays in a way that "they are not really meant to be used," according to one elder statesman of the modding scene. But it works! So to heck with it. Let's begin.

    1. First, you make an array containing every kit and linking it to its base class. We will populate the array with information from kitlist.2da.
    COPY_EXISTING ~kitlist.2da~ ~override~
    COUNT_2DA_COLS cols
    COUNT_2DA_ROWS cols rows
    FOR ( row = 1 ; row < rows ; row = row + 1 ) BEGIN
    READ_2DA_ENTRY %row% 5 10 clab
    READ_2DA_ENTRY %row% 8 10 class
    DEFINE_ASSOCIATIVE_ARRAY d5_kit_clabs BEGIN "%clab%" => "%class%" END
    END
    BUT_ONLY
    This creates an array in memory that consists of a simple list of the clab table of every kit in kitlist.2da, linked to that kit's class number. (Mage = 1, fighter = 2, cleric = 3, thief = 4, paladin = 6, ranger = 12, etc.) The array is called d5_kit_clabs.

    I never totally understood how arrays work, especially because it is not something that you can seen in front of your eyes. But all you need to know is what I just said: we have now linked each kit's clab table with its underlying class, in a way that Weidu can read and act upon, using ACTION_PHP_EACH.

    2. Read and act upon the array using ACTION_PHP_EACH. Now the task is rather simple: tell Weidu to do something to every clab table that belongs to a fighter kit. First, we need to tell Weidu to read the array. (We are doing this as a fresh command, so it will be an ACTION operation; but you can also use PATCH_PHP_EACH if you want to do stuff in the middle of a PATCH operation.)
    ACTION_PHP_EACH d5_kit_clabs AS yoo => hoo BEGIN
    "Yoo" and "hoo" are meaningless; they are just terms to help Weidu read the array. Remember above when we did DEFINE_ASSOCIATIVE_ARRAY we defined it as "clab => class." So now, "Yoo" equals clab, and "hoo" equals class. Now we will have Weidu do a command, but only for kits in the fighter class:
    	ACTION_IF (%hoo% = 2) AND (FILE_EXISTS_IN_GAME ~%yoo%.2da~) BEGIN
    The FILE_EXISTS check is just for safety's sake, to make sure the clab file listed in kitlist.2da hasn't disappeared somehow. If it has, this operation will gracefully skip over it and keep going.
    		APPEND ~%yoo%.2da~ ~ABILITY    AP_D5INTSPL ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****        ****  ~
    This is simply the patch we did above to the trueclass fighter clab table; only now instead of patching just the one table, I am patching every table that equates to the %yoo%.2da variable - i.e. every fighter kit.

    Well, every fighter kit EXCEPT the trueclass - trueclass kits aren't listed in kitlist.2da. So we will keep the original APPEND line as well. Now we can put all that together, and we can combine it with the 326 code I posted above:
    APPEND ~splprot.2da~ ~D5_INT_EQ%TAB%38%TAB%-1%TAB%1~

    COPY_EXISTING ~splprot.2da~ ~override~
    COUNT_2DA_COLS cols // amount of columns
    READ_2DA_ENTRIES_NOW rows cols // read all file into memory
    FOR (row = 1; row < rows; ++row) BEGIN // iterate over rows
    READ_2DA_ENTRY_FORMER rows row 0 ~stat~ // read column value
    PATCH_IF ~%stat%~ STRING_EQUAL_CASE ~D5_INT_EQ~ BEGIN
    SET int_eq_row = %row%
    END
    END
    BUT_ONLY

    COPY ~IntMod/files/d5LSprof.spl~ ~override~
    COPY ~IntMod/files/d5intspl.spl~ ~override~
    LPF ALTER_EFFECT INT_VAR match_opcode = 326 parameter2 = %int_eq_row% END

    COPY_EXISTING ~kitlist.2da~ ~override~
    COUNT_2DA_COLS cols
    COUNT_2DA_ROWS cols rows
    FOR ( row = 1 ; row < rows ; row = row + 1 ) BEGIN
    READ_2DA_ENTRY %row% 5 10 clab
    READ_2DA_ENTRY %row% 8 10 class
    DEFINE_ASSOCIATIVE_ARRAY d5_kit_clabs BEGIN "%clab%" => "%class%" END
    END
    BUT_ONLY
    ACTION_PHP_EACH d5_kit_clabs AS yoo => hoo BEGIN
    ACTION_IF (%hoo% = 2) AND (FILE_EXISTS_IN_GAME ~%yoo%.2da~) BEGIN
    APPEND ~%yoo%.2da~ ~ABILITY AP_D5INTSPL **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ~
    END
    END
    APPEND ~clabfi01.2da~ ~ABILITY AP_D5INTSPL **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** ~
    Again, you can pull out this bit of code (everything from the COPY_EXISTING ~kitlist and below) and adapt it for all sorts of uses. I use this to give my "Quickstride" increased movement rate ability to all rangers. The sky is the limit.

    BUT: install order matters. Like I said, this will patch every fighter kit's clab table, including those added by other mods... but ONLY if this is installed after those other mods. (Naturally, those mod kits can only be patched if they exists in your game at the time this patch is installed.) So this wants to be installed late in the install order. But so many mods want to be installed late in the order! How to deal with it?

    My simple rule of thumb for install order, is this:
    - Ascension
    - quests
    - NPCs
    - items
    - spells
    - kits
    - tweaks
    - SCS

    This sort of thing - patching abilities or effects into kits - is very much a tweak, so your mod should advertise it as such. Just tell players that it must be installed after all other mods that add kits to the game. Six or twelve different mods can do this sort of thing, and as long as they are all installed after all kit mods, they should work fine together.

    Finally, PLEASE NOTE: there are better ways to do this. I mean, all of the info we put in the array (clab table and associated class number) is already right there in kitlist.2da, already associated with each other. We could forget the array and instead adapt the method from the post just above this one: read through each row of kitlist, noting the value in column 8 (class), check for a match against "2," and then note the row number, then read the value in column 5 in that row (clab table), then perform some action on that .2da file (using INNER_ACTION). Those skilled with Weidu will find a way to do this elegantly. But for enthusiastic amateurs like me, here's the important thing: the array method works, reliably. Variations of that code appear probably 30 or 40 times in my mods. So if you don't want to mess around with the code, but just want something to drop into your mod so you can focus on the creative decisions, this is for you. :wink:
  • SystemSystem Administrator Posts: 199
    edited March 2020
    HOW TO TARGET YOUR MOD KIT WITH UNIQUE EFFECTS

    Let's say you are making a kit mod, and you want to target your kit with opcode 177 "use .eff" effects, or opcode 326 "apply effects list" effects. Here's an example:

    Say you make a sorcerer kit, and the theme is that it channels magical energy better than most sorcerers. Call it a "Channeler." Of course you will have read the excellent tutorial on creating KIT mods, so you know the first line of your ADD_KIT routine will look like this:
    ADD_KIT ~D5_CHANNELER~
    That name is how the engine recognizes your kit... sometimes. Other times, it refers to the kit's value in the KIT.IDS file.

    Say you want to add a special disadvantage, that every time a Channeler is struck by Magic Missile, they take an extra 2d4 magic damage. Because magic just flows through them too easily. The way to do this is to add an effect to the Magic Missile, using opcode 177 and targeting your kit, and making an .eff file that applies the damage. Opcode 177 uses the kit's value in KIT.IDS. For vanilla kits this is easy, they are listed in KIT.IDS and you can look up their value there and plug it into the 177 effect.

    But mod-added kits are added to KIT.IDS sequentially, and you have no idea how many kit mods a player might install, or in what order. So how do you add that 177 effect to Magic Missile?

    Well, each kit is listed in KITLIST.2DA, with its name and .2da clab table and description strings, etc. And in the EEs there is an extra column that contains the kit's IDS value. So with this file we can link the kit's name (which you will know, because you named it) to the kit's IDS value (which you will never know ahead of time. The following code will read the contents of that .2da file, find the line with your kit's name, and spit out the associated IDS value as a variable that you can use elsewhere.
    COPY_EXISTING ~kit.ids~ ~override~
    COUNT_2DA_COLS cols
    READ_2DA_ENTRIES_NOW rows cols
    FOR (row = 1; row < rows; ++row) BEGIN
    READ_2DA_ENTRY_FORMER rows row 1 ~this_kit~
    PATCH_IF ~%this_kit%~ STRING_EQUAL_CASE ~D5_CHANNELER~ BEGIN
    SET this_row = %row%
    READ_2DA_ENTRY_FORMER rows this_row 0 channeler_code
    END
    END
    BUT_ONLY
    That is a bit hard to digest; I find the READ_2DA_FORMER/NOW stuff difficult to understand. But the nice thing is, there is no need to actually understand this. You can copy that and drop it directly into your own .tp2 code. The only thing you need to worry about is where it says: "...STRING_EQUAL_CASE ~D5_CHANNELER~..." J
    just put your own kit's name between those two tildes: ~...~. The IDS value for your kit will be encoded into the %channeler_code% variable at the end there. (You can rename that variable if you like.)

    Now, armed with that variable, we can edit Magic Missile:
    COPY_EXISTING ~spwi112.spl~ ~override~
    LPF ADD_SPELL_EFFECT INT_VAR opcode = 177 parameter1 = %channeler_code% STR_VAR resource = ~D5_MDMG~ END
    (Where "D5_MDMG.EFF" is the name of the .eff file you created that does the extra magic damage.)

    You could also edit items to have unique characteristics with your kit, using ADD_ITEM_EFFECT or ADD_ITEM_EQEFFECT. Maybe the Staff of Power's thunderbolt ability does extra damage when used by a Channneler. Maybe a fleet-of-foot thief kit gets 2 extra APR when using Belm, instead of just one. The sky is the limit; you just need to know your kit's IDS value in order to make effects like that, and this code gives you that.
  • SystemSystem Administrator Posts: 199
    edited March 2020
    HOW TO ALTER CLASS/KIT DESCRIPTIONS AND NOT WORRY ABOUT STRING REFERENCES

    Okay, let's say you're into tweak mods. Like mine. I have a mod that slightly changes the Swashbuckler: it takes traps away (I can't really see Swashbucklers patiently laying traps) but gives them a (reduced) backstab multiplier. Then I add a different kit, the Scout, which has traps but no backstabs like the vanilla Swashbuckler.

    So, I want to change the Swashbuckler's description in-game so that the player will read and understand the kit's new abilities and restrictions. But where is the text I have to change? I could search for it and find the string reference with Near Infinity... but that's a pain. Plus there are many different games with different versions of dialog.tlk (TOB, BGT, BGEE, SoD, BG2EE, IWDEE, EET) and some of those have doubles or even triples of the kit description text. Dealing with all those variations is a minor nightmare. So what do we do?

    Ignore the string reference. Here's how:

    The strings for all kit names and descriptions are listed in KITLIST.2DA in columns 3, 4, and 5 (lower-case name, mixed-case name, and description, respectively). If your game has the files, the kit descriptions and the class descriptions are also in CLASTEXT.2DA and SODCLTXT.2DA, in columns 3, 4, and 5 (lower, description, and mixed, respectively - note the different order!). So to find and alter the strings, we can read those files. Here's example code that is extremely easy to adapt to your mod:
    ACTION_IF (FILE_EXISTS_IN_GAME ~clastext.2da~) BEGIN
    COPY_EXISTING ~clastext.2da~ ~override~
    COUNT_2DA_COLS cols
    READ_2DA_ENTRIES_NOW rows cols
    FOR (row = 1; row < rows; ++row) BEGIN
    READ_2DA_ENTRY_FORMER rows row 0 ~kit_name~
    PATCH_IF ~%kit_name%~ STRING_EQUAL_CASE ~SWASHBUCKLER~ BEGIN
    SET patch_row = %row%
    END
    END
    SET_2DA_ENTRY %patch_row% 3 cols RESOLVE_STR_REF (@20001)
    SET_2DA_ENTRY %patch_row% 4 cols RESOLVE_STR_REF (@20003)
    SET_2DA_ENTRY %patch_row% 5 cols RESOLVE_STR_REF (@20002)
    BUT_ONLY
    END
    ACTION_IF (FILE_EXISTS_IN_GAME ~sodcltxt.2da~) BEGIN
    COPY_EXISTING ~sodcltxt.2da~ ~override~
    COUNT_2DA_COLS cols
    READ_2DA_ENTRIES_NOW rows cols
    FOR (row = 1; row < rows; ++row) BEGIN
    READ_2DA_ENTRY_FORMER rows row 0 ~kit_name~
    PATCH_IF ~%kit_name%~ STRING_EQUAL_CASE ~SWASHBUCKLER~ BEGIN
    SET patch_row = %row%
    END
    END
    SET_2DA_ENTRY %patch_row% 3 cols RESOLVE_STR_REF (@20001)
    SET_2DA_ENTRY %patch_row% 4 cols RESOLVE_STR_REF (@20003)
    SET_2DA_ENTRY %patch_row% 5 cols RESOLVE_STR_REF (@20002)
    BUT_ONLY
    END
    ACTION_IF (FILE_EXISTS_IN_GAME ~kitlist.2da~) BEGIN
    COPY_EXISTING ~kitlist.2da~ ~override~
    COUNT_2DA_COLS cols
    READ_2DA_ENTRIES_NOW rows cols
    FOR (row = 1; row < rows; ++row) BEGIN
    READ_2DA_ENTRY_FORMER rows row 1 ~kit_name~
    PATCH_IF ~%kit_name%~ STRING_EQUAL_CASE ~SWASHBUCKLER~ BEGIN
    SET patch_row = %row%
    END
    END
    SET_2DA_ENTRY %patch_row% 2 cols RESOLVE_STR_REF (@20001)
    SET_2DA_ENTRY %patch_row% 3 cols RESOLVE_STR_REF (@20002)
    SET_2DA_ENTRY %patch_row% 4 cols RESOLVE_STR_REF (@20003)
    BUT_ONLY
    END
    You can copy and paste this into your mod, all you have to change is the kit name in the "PATCH_IF ~%kit_name%~ STRING_EQUAL_CASE" lines, and change the @_____ tra references to your own strings. Just, remember that the order is different between CLASTEXT and KITLIST!

    If you want to get more advanced you can do more complicated things. Instead of using SET_2DA ENTRY to replace the whole string with a new one, you could READ_2DA_ENTRY to get the string reference into a variable, and then edit the original string with a more fine-grained method.

    The key thing here, though, is that the above code works on every version of the games, at least going back to BG2/TOB. Players will be able to install your mod on SoD, BG2EE, or IWDEE and your code doesn't even have to know which game is being played.

    @BCaesar and @agb1 may in particular be interested in this.
  • SystemSystem Administrator Posts: 199
    edited March 2020
    BCaesar said:

    The part I don't understand is, "change the @_____ tra references to your own strings"

    So I need to create a .tra file and put my new class description text in there? What is a .tra file and how do I create one? Sorry for the really basic questions.

    No worries! First, I don't believe you need to use a .tra file... you can just put a string in quotes/tildes/delimiters there, so it could look like this (I think):
        SET_2DA_ENTRY %patch_row% 5 cols RESOLVE_STR_REF (~Your text here!~)
    I've been using .tra files for a while... it's just a text file, like the .tp2. It has a list of "@" references like this:
    @1  = ~text~
    @2 = ~other text~
    @4 = ~et cetera~
    See, connected to each "@number" is a string that looks just like you have in your mod. You move all the strings out to en external document and put matching "@number" references into your .tp2 file. This way, if you want to add support for other languages to your mod, a translator only has to translate the .tra file, put the translated version into a different language directory, and your .tp2 file can use it automatically, by adding something like this in the front:
    LANGUAGE
    ~English~
    ~english~
    ~scales_of_balance/language/en_US/setup.tra~
    LANGUAGE
    ~Polski (Translation by etamin)~
    ~polish~
    ~scales_of_balance/language/en_US/setup.tra~
    ~scales_of_balance/language/pl_PL/setup.tra~
    Otherwise, to get a translation of the mod, you would have to make a translated duplicate of the whole .tp2 file. And then what if you want to change something later? You would have to meticulously keep all versions of the .tp2 file in sync... it would be a nightmare.
    BCaesar said:

    Also while I'm asking questions, if I have a mod that is only for Baldur's Gate 1:EE version 2.0 and later without SoD, so I am fine with editing a single string of dialog.tlk how to I do that?

    Not sure exactly what you mean by this. If you know a particular string reference (but remember, they are different in each game!), you can replace that string using SET_STRING.
    BCaesar said:

    Also what's the easiest way to edit a single line of a file? For example with my monk mod I change HPCLASS.2DA and change only monks to HBBARB and leave the rest intact. I could create a whole new file with Near Infinity (that's what I'm doing now) but then that creates compatibility issues with other mods. I'd prefer just to edit one line and I'm assuming there's an easy code to do that in my TP2 file in WeiDU and then I wouldn't have to overwrite the whole HPCLASS.2DA file.

    This depends. For any given file, there may or may not be a good way to do something like this. But specifically for .2da files, which are always sort of arranged like a spreadsheet, Weidu has nice tools to analyze and edit them. Some of which I've used in the posts above.

    For your edit to HPCLASS.2DA, it is a simple matter: you wan to use SET_2DA_ENTRY:
    COPY_EXISTING ~hpclass.2da~ ~override~
    SET_2DA_ENTRY 44 1 2 ~HPBARB~
    SET_2DA_ENTRY 45 1 2 ~HPBARB~
    SET_2DA_ENTRY 46 1 2 ~HPBARB~
    That will change the entries for Monk, Sun Soul, and Dark Moon. (Which are in the 44th, 45th, and 46th rows of that file that have at least two colunms. That explains the 1st and 3rd numbers in those lines. The 2nd number, "1," is slightly trickier: it tells Weidu to edit the entry in the second column... because for whatever reason, in this instance, it starts counting at zero.)
  • SystemSystem Administrator Posts: 199
    edited March 2020
    @BCaesar There's no shorter way to deal with weapprof.2da. One of my mods affects every class and kit, it has like 800 lines of SET_2DA_ENTRY's. It's insane.

    The #3 number is the "minimum column count." So when you say row # whatever, if that row has fewer columns than the number in #3, it will be ignored. WHat this really means is that there are only two things you should put here: 1, or the actual column count of the 2da table. For a file like weapprof.2da, just put 1. The only issue this causes is that some rows, like the very first one with some garbage text, get counted in your row count - because that garbage is considered a column. All this means is that your row number might be different. But that doesn't matter because you just put whatever row number works.

    If you use 1 in #3 with weapprof, I believe row 11 is bastard sword, and row 34 is dual-wielding, and everything else you could possibly want to change is between those two rows. (I think those are the numbers you would use in #1... easy enough to double-check.)
  • SystemSystem Administrator Posts: 199
    edited March 2020

    I'm having trouble figuring out how to give effects to creatures in WeiDU. For example, I want to give the level 6 Minsc file "MINSC6" a minimum damage effect (opcode 250) and set the first parameter to 20. What would be the code for that?

    Something like
    COPY_EXISTING ~minsc6.cre~ ~override~
    LPF ADD_CRE_EFFECT INT_VAR opcode=250 target=1 timing=9 parameter1=20 resist_dispel=0 END
    BUT_ONLY
    I didn't test that, but it should work.
  • SystemSystem Administrator Posts: 199
    edited March 2020
    parameter1 = (0 - 50)

    But be aware, negative values do not work in all of these functions. I *think* it works in this one, but it does not work in ALTER_EFFECT or CLONE_EFFECT.
  • Jaguar_KnightJaguar_Knight Member Posts: 8
    Hey there, I've been creating an NPC mod for personally use and I am on the last bit of it. But I keep running into the problem of the .TP2 file. All the mod making guides I've read have been vague on this aspect, and so I'm wondering since it allows the Weidu to script, what the heck do I put in it?
  • SkitiaSkitia Member Posts: 1,054
    edited May 2020
    What do you have in it so far? It would be easier to answer with a bit of knowledge.

    To give a really general example for an NPC Mod without addressing any tips for compatibility with EET or such (Especially since this is for personal use anyway), they all start like:

    BACKUP: ~Where the backup folder is created. Generally something like ~ModFolderName/Backup~
    AUTHOR: ~Your name here. Or Website. Or some people put the support file name. But this is personal use so...your name here.~
    VERSION ~1.0, or whatever version number you are using to help keep track of what change/version your mod is at.~

    AUTO_TRA ~%MOD_FOLDER%/tra/%s~ // Sets the directory of the language files.



    LANGUAGE: Sets the language. Generally it will look like:

    ~English~
    ~English~
    ~%MOD_FOLDER%/tra/english/setup.tra~ , or ~French~ ~French~, ~Directory to set up file~ etc, etc.

    BEGIN ~Mod name, can be anything. This is just a display string~

    Let me know if I"m on the right track in regards to what you are looking for in an answer, then I'll spell out the rest of things.

    StummvonBordwehr
  • Jaguar_KnightJaguar_Knight Member Posts: 8
    rhsrnfoccqfy.png

    After adding your suggestions in, this is what I got. I tried to mirror what the Branwen NPC tutorial showed me on it's .TP2 file prior to this, but due to the fact I don't have audio as well as other features, it fell flat in what I could mimic in that case.

    My mod has a Backup folder, a Character folder, a Dialogue folder, an English folder, and a Scripts folder. I hope that can more or less shed some light on what I'm working with.
  • GwendolyneGwendolyne Member Posts: 461
    edited May 2020
    line #9
    LANGUAGE ~English~ ...
    
    should solve the issue. ;)
  • Jaguar_KnightJaguar_Knight Member Posts: 8
    Oh my god, that did it. Thank you, thank both of you. This has been driving me crazy for days. ;.;
  • SkitiaSkitia Member Posts: 1,054
    edited May 2020
    Okay, now that I know I'm on the right track, I'll make a full guide.

    Your LANGUAGE: line isn't parsing because it should be LANGUAGE with no colon.

    After Begin, it should start looking like this:

    // Adds custom IsValidForPartyDialogue state used throughout
    APPEND ~STATE.IDS~ // adds custom IsValidForPartyDialogue state
    ~0x80101FEF CD_STATE_NOTVALID~
    UNLESS ~CD_STATE_NOTVALID~

    IF and ONLY IF you use CD_STATE_NOTVALID, you can go ahead and include the above. Else it's wasted lines of copying. For BG:EE and BG2:EE, IsValidForPartyDialogue("Creature") works just fine and is much better than the group use of InParty("Creature") InMyArea("Creature") !StateCheck("Creature",CD_STATE_NOTVALID) that was standard use in older mods for interject. You only need it if you want to be compatible with older BG2 and BGT.

    Next you can start copying the creature and lines over, this is a snippet, but since you've seen Branwen, you probably know what the full group is supposed to look like. Make sure to have an instance for ToB and/or SoD if you're using them in those expansions and want them to appear for people who are just starting those games out and not importing a save.
    tgtrh4funz7b.png

    This will set up your Joined party, banter lines, and post party lines. The D after X3Emi (X3Emi is my character's creature code) is any lines that run after the rest party is clicked, a pre-rest talk with the protagonist.

    86pdqj19q4r7.png

    If you have custom portraits, just include their path in a COPY command.
    0s0jrvw2id4g.png

    A small note while we are at creatures, non-joinable creatures don't need the lengthy set up, just these few lines will do.

    rsb4w6f9jr5b.png

    Then you just set up the creature/dialogue/script files. Note for area files you use the EXTEND_TOP or EXTEND_BOTTOM. I tend to use EXTEND_TOP if it's noticeable that an NPC will just suddenly "appear" because its taking the game so long to get to the end of the area script, or there's a script preventing mine from firing. Otherwise EXTEND_BOTTOM works just fine.

    Then make sure dialogue/script files start with COMPILE EVALUATE BUFFER

    1o0wsrskhc5h.png

    Let me know if that helps. If you get any other errors, just copy screenshots here again and I can help you.
  • Jaguar_KnightJaguar_Knight Member Posts: 8
    edited May 2020
    h0pml0i1tbbz.png

    This very much helps, thank you. But now I'm getting the cre error I was getting beforehand, despite the fact I labeled everything accordingly as shown. Unless there's something I'm missing or just not seeing.

    EDIT: Actually, found and fixed that problem. But hold a moment.
  • Jaguar_KnightJaguar_Knight Member Posts: 8
    ic2qqdthq4hy.png

    Yeah, now something in the scripting is acting up. Don't exactly know what, but I have just about the full script showing in the screenshot in case it can be caught.
  • SkitiaSkitia Member Posts: 1,054
    Hard to tell to be honest. It could be a pathing or directory issue, and I don't think it actually is an issue with the script. Attach the script file here and I can know for sure. Is this from GoG, Beamdog, or Steam?
Sign In or Register to comment.