Jump to content

reading kitlist.2da to identify mod kits & edit clabs


subtledoctor

Recommended Posts

Posted

Everyone is so great around here, I'm just going to continue posting questions until you kick me off the boards :p

 

I'd like to craft a function to do the following:

- 1) read kitlist.2da and look for any mod kits (i.e. any rows after the number of rows in the base game)

- 2) for each such kit, identify its CLAB file

- 3) for each such kit, identify its base class

- 4) COPY_EXISTING / APPEND_FILE for each such CLAB file, using different text files according to the kit's base class

 

I can already do 2), and given enough time I could figure out 1). But 3) is, for my current meager skills, a stumper. And even if I figured out 3), I think getting everything to work properly in 4) would take me a long time to figure out too.

Posted

Go look at the XP cap remover from Tweaks. It reads in the clabs off kitlist and extends them to 50 columns (if they aren't already).

Posted

So, I'm finally tackling this. (It's just about the last thing to learn and implement in my mod.) I'm trying to understand associative arrays, but I'm being tripped up a bit by the fact that the BG2tweaks component only takes one variable - the CLAB name - from each row in kitlist.2da, while I need 2: the CLAB name and the class number. (The values from column 5 and column 8, in other words.) I've gotten this far:

   COPY_EXISTING ~kitlist.2da~ ~override~
      COUNT_2DA_ROWS ~9~ "rows"
      FOR ( index = 38 ; index < rows ; index = index + 1 ) BEGIN
         READ_2DA_ENTRY %index% 5 10 modclab
         READ_2DA_ENTRY %index% 8 10 modclass
         DEFINE_ASSOCIATIVE_ARRAY mod_kit_clabs BEGIN "%modclab%" => %modclass% END
      END

Now, when I

   ACTION_PHP_EACH mod_kit_clabs AS foo => moo BEGIN
      PRINT ~%foo%~
   END

...it prints the CLAB names of any installed mod kits. Which is great, because if I can PRINT it then I can do other tp2 actions to it. But when I

     PRINT ~%moo%~

...it just spits out "modclass" a few times, rather than returning the variables I defined earlier. Which makes me think that my associative array did not successfully associate %modclab% with %modclass%.

 

I suppose I could 2 arrays, one for %modclab% and one for %modclass%, but then I don't know how I can get to my end result, which is (conceptually):

 

 

   PATCH_IF modclass = ~1~ BEGIN
     COPY_EXISTING ~%modclab%.2DA~
         APPEND_FILE ~SoB/profs/Pwizar.txt~
   END
   PATCH_IF modclass = ~2~ BEGIN
      COPY_EXISTING ~%modclab%.2DA~
         APPEND_FILE ~SoB/profs/Pfight.txt~
   END
   PATCH_IF modclass = ~3~ BEGIN
      COPY_EXISTING ~%modclab%.2DA
         APPEND_FILE ~SoB/profs/Pcleri.txt~
   END
   PATCH_IF modclass = ~4~ BEGIN
      COPY_EXISTING ~%modclab%.2DA~
         APPEND_FILE ~SoB/profs/Pthief.txt~
etc.

 

 

 

Any thoughts?

Posted

%modclass% is equivalent to ~modclass~ and "modclass", so WeiDU is doing exactly what you are telling it to do: associating the variable %modclab% with the string %modclass%. Unless you actually intend to use % as a string delimiter, it is always a mistake to use % without an additional pair of string delimiters. Additionally, wrapping integers in variable delimiters is always wholly redundant.

Posted

Ah, from my observations I had thought ~_~ and "_" denote strings, while %_% denotes the string represented by a given variable.

 

But that's not really the issue here. I have this, right:

READ_2DA_ENTRY %index% 5 10 modclab
READ_2DA_ENTRY %index% 8 10 modclass
When I PRINT %foo% as above, after installing some kits from Song & Silence, it returns

A!chori

A!sharp

A!adven

 

But when I PRINT %moo% it returns

modclass

modclass

modclass

 

I could make two arrays, one full of CLAB names and one full of class numbers... but then how would I associate each with the other?

 

Am I going down the wrong path? I can find all of the CLAB names for any installed mod kits; but how do I tell Weidu "if this kit is a fighter kit then do x, but if this kit is a thief kit then do y" ?

Posted

Maybe I could move the modclass variable down into the ACTION_PHP_EACH block. Do something like (again, conceptually):

   COPY_EXISTING ~kitlist.2da~ ~override~
      COUNT_2DA_ROWS ~9~ "rows"
      FOR ( index = 38 ; index < rows ; index = index + 1 ) BEGIN
         READ_2DA_ENTRY %index% 5 10 modclab
         DEFINE_ASSOCIATIVE_ARRAY mod_kit_clabs BEGIN "%modclab%" => 0 END
      END

   ACTION_PHP_EACH mod_kit_clabs AS foo => moo BEGIN
      COPY_EXISTING ~kitlist.2da~ ~override~
         [set row # of %foo% to modrow]
         READ_2DA_ENTRY %modrow% 8 10 modclass
      COPY_EXISTING ~%foo%.2da~ ~override~
         PATCH_IF modclass = 2 BEGIN
            APPEND_FILE ~mymod/fighter.txt~
         END
         PATCH_IF modclass = 3 BEGIN
         [etc.]
   END

Is there a way for Weidu to search a 2da file for a string and return the row # that it is sitting in?

Posted

I think Wisp was telling you to put "%modclass%" instead of just %modclass% :p

 

   PATCH_IF modclass = ~1~ BEGIN
     COPY_EXISTING ~%modclab%.2DA~
         APPEND_FILE ~SoB/profs/Pwizar.txt~
   END
   PATCH_IF modclass = ~2~ BEGIN
      COPY_EXISTING ~%modclab%.2DA~
         APPEND_FILE ~SoB/profs/Pfight.txt~
   END
   PATCH_IF modclass = ~3~ BEGIN
      COPY_EXISTING ~%modclab%.2DA
         APPEND_FILE ~SoB/profs/Pcleri.txt~
   END
   PATCH_IF modclass = ~4~ BEGIN
      COPY_EXISTING ~%modclab%.2DA~
         APPEND_FILE ~SoB/profs/Pthief.txt~
etc.

Any thoughts?

 

I think you should use PATCH_MATCH instead of many PATCH_IFs, but that's not relevant anyway.
Posted

I think Wisp was telling you to put "%modclass%" instead of just %modclass% :p

I just went back and read what I wrote, and then read what wisp wrote, and then read what you wrote... and I'm still confused. You mean in the DEFINE_ASSOCIATIVE_ARRAY line?

 

Wait - I just read it all again, and I get it now. You *do* mean in the associative array line! Thanks! (And thanks wisp!)

 

As for making the code more efficient... I want to make the code *work* first. But I'll get there eventually. (No joke, in the last few days I cut 11,000 lines from my .tp2, without changing the functionality.)

Posted

Level 1 NPCs does something like what you want too, during kit selection (I guess around line 5300 in the tp2) but don't look there for optimized code. In fact, don't look at the code at all if you want to stay sane.

Posted

I looked at the L1NPCs tp2 a few weeks ago, and just a glance did indeed nearly drive me insane. But, I have learned a lot since then, so maybe I can make some sense of it now...

 

So I'm getting closer, thanks to wisp and crevsdaak. My latest code looks like this:

 

 

COPY_EXISTING ~kitlist.2da~ ~override~
    COUNT_2DA_ROWS ~9~ "rows"
    FOR ( index = 38 ; index < rows ; index = index + 1 ) BEGIN
        READ_2DA_ENTRY %index% 5 10 modclab
        READ_2DA_ENTRY %index% 8 10 modclass
        DEFINE_ASSOCIATIVE_ARRAY mod_kit_clabs BEGIN "%modclab%" => "%modclass%" END
    END
    BUT_ONLY
ACTION_PHP_EACH mod_kit_clabs AS foo => moo BEGIN
    ACTION_IF %modclass% = 1 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Pwizar.txt~
            BUT_ONLY
    END
    ACTION_IF %modclass% = 2 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Pfight.txt~
            BUT_ONLY
    END
    ACTION_IF %modclass% = 3 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Pcleri.txt~
            BUT_ONLY    
    END
    ACTION_IF %modclass% = 4 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Pthief.txt~
            BUT_ONLY
    END
    ACTION_IF %modclass% = 5 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Pbard.txt~
            BUT_ONLY
    END
    ACTION_IF %modclass% = 6 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Ppalad.txt~
            BUT_ONLY
    END
    ACTION_IF %modclass% = 11 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Pdruid.txt~
            BUT_ONLY
    END
    ACTION_IF %modclass% = 12 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Prange.txt~
            BUT_ONLY
    END
    ACTION_IF %modclass% = 19 THEN BEGIN
        COPY_EXISTING ~%modclab%.2DA~ ~override~
            APPEND_FILE ~SoB/profs/Pwizar.txt~
            BUT_ONLY
    END
END

 

Weidu threw up parse error with PATCH_IF, seems to prefer ACTION_IF here. But, it's not quite there. I tested with 3 bard kits and a thief kit from S&S. PRINT %foo% correctly gave this output:

 

A!ACRO
A!DIRGE
A!GYP
A!SOUL

...and PRINT %moo% correctly gave this output:

 

5
5
5
4

...so it looks like the array is correctly formed. And A!SOUL.2da does get the thief .txt file appended to it. But it gets the text appended 4 times, and the bard kits are not getting patched. It's as if the ACTION_PHP_EACH block, having identified 4 extra kits, is correctly running through its loop 4 times. But it is only applying the change from the last entries in the array, and applying it 4 times to the last added kit, instead of once each.

 

I very much assume this is my own fault. Any ideas *how* it's my fault? :)

 

(ps. on the bright side this did identify a very small bug in S&S which I'll report over on its forums.)

Posted

AH! Stupid me. Reading my own post I spotted the problem: just need to swap out %modclab% and %modclass% for %foo% and %moo%. Works fine now! (Except for the fact that S&S adds an extra newline to the bottom of its CLAB files and thus screws me over. Sigh.)

Posted

Your usage of DEFINE_ASSOCIATIVE_ARRAY threw me for a bit there. It looks like it works fine, but I probably would have used this myself:

SET $mod_kit_clabs(~%modclab%~) = modclass

A more traditional usage of the associative array could help to simplify the rest of your code:

ACTION_DEFINE_ASSOCIATIVE_ARRAY clab_additions BEGIN
  1  => Pwizar
  2  => Pfight
  3  => Pcleri
  4  => Pthief
  5  => Pbard
  6  => Ppalad
  11 => Pdruid
  12 => Prange
  19 => Pwizar
END

ACTION_PHP_EACH mod_kit_clabs AS clab => class BEGIN
  ACTION_IF (VARIABLE_IS_SET $clab_additions(~%class%~)) BEGIN
    OUTER_TEXT_SPRINT clab_addition $clab_additions(~%class%~)
    COPY_EXISTING ~%clab%.2da~ ~override~
      APPEND_FILE ~SoB/profs/%clab_addition%.txt~
      BUT_ONLY
  END
END
Posted

Oooo... that's *much* prettier than my code. But, probably the reason I didn't do that is, I have no idea that first line was something that could be done - or even what it actually does!

 

Anyway, at least I've got things working now. Like I say above, first I get it to work, then in the next go-round I'll try to make the code better and more efficient.

Posted

Okay I am semi-necroing this thread. I left it aside before, because my code seemed to be working.

 

But my code is not working. Not perfectly, anyway. Here's my code:

 

 

 

ACTION_IF GAME_IS ~bgee~ THEN BEGIN
    COPY_EXISTING ~kitlist.2da~ ~override~
        COUNT_2DA_ROWS ~10~ "rows"
        PATCH_IF ( rows > 37 ) BEGIN
            FOR ( index = 38 ; index < rows ; index = index + 1 ) BEGIN
                READ_2DA_ENTRY %index% 5 10 modclab
                READ_2DA_ENTRY %index% 8 10 modclass
                DEFINE_ASSOCIATIVE_ARRAY mod_kit_clabs BEGIN "%modclab%" => "%modclass%" END
            END
        END
        BUT_ONLY
    ACTION_PHP_EACH mod_kit_clabs AS foo => zoo BEGIN
        ACTION_IF (%zoo% = 12) AND (FILE_EXISTS_IN_GAME ~%foo%.2da~) THEN BEGIN
            COPY_EXISTING ~%foo%.2da~ ~override~
                LPM remove_blank_lines
                APPEND_FILE ~sob/profs/prange.txt~
                BUT_ONLY
        END
    END
END

 

 

 

What it does is, go through kitlist.2da looking at kits' CLAB files, and associate each CLAB file with its relevant class. Then, based on the class each kit belongs to, it appends a line of text to that CLAB file. Crucially, in BGEE, it begins at line 38 of kitlist.2da. This code gets repeated for each game since kitlist has a different number of rows in each game.

 

Why it does that: this lets me arbitrarily add effects and abilities to any mod kits, dynamically, without knowing beforehand which mods are installed in the game. E.g. my mod gives a "Quickstride" ability to rangers, allowing them to move as fast as barbarians. After adding the ability to the vanilla ranger kits, I throw this code in there, and now my mod can successfully patch the ability into any new ranger kits added to the game, be they created years after I have left the scene. Compare, for example, aTweaks' PnP Paladin Disease Immunity, which patches kits like this:

 

 

ACTION_FOR_EACH ~file~ IN
          ~clabpa01~                     // True Paladin
          ~clabpa02~                     // Cavalier
          ~clabpa03~                     // Inquisitor
          ~clabpa04~                     // Undead Hunter
          ~KishHL~                        // Holy Liberator (from Oversight)
          ~tcselune~                      // Paladin of Selune (from Classic Adventures)
BEGIN
...

 

 

 

aTweaks obviously will not patch any number of great new paladin kit mods that have been released lately. And if it's not being maintained or updated, it may never work with new kit mods. But with a technique like mine (or an even better one, if and when I integrate Mike's suggestions) aTweaks would continue working no matter what new paladin kits are introduced.

 

ANYWAY: here's the problem. The code works great to patch all kits with the proper abilities. BUT it doesn't start from line 38; it is starting at line 1 of kitlist.2da. This line:

    FOR ( index = 38 ; index < rows ; index = index + 1 ) BEGIN

...doesn't seem to be doing what it's supposed to be doing. If I individually patch the Stalker CLAB with Pranger.txt, and then use this code to patch any mod kits with Qranger.txt, what's happening is, the Stalker's CLAB is being patch with *both* Pranger.txt *and* Qranger.txt.

 

The associatiove array shouldn't contain the Stalker CLAB; that FOR line is meant to exclude it. But it is failing at that job. Can anyone around here see why?

 

Thanks all.

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...