subtledoctor Posted September 30, 2014 Posted September 30, 2014 Everyone is so great around here, I'm just going to continue posting questions until you kick me off the boards 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.
CamDawg Posted September 30, 2014 Posted September 30, 2014 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).
subtledoctor Posted October 18, 2014 Author Posted October 18, 2014 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?
Wisp Posted October 18, 2014 Posted October 18, 2014 %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.
subtledoctor Posted October 18, 2014 Author Posted October 18, 2014 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 modclassWhen I PRINT %foo% as above, after installing some kits from Song & Silence, it returnsA!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" ?
subtledoctor Posted October 18, 2014 Author Posted October 18, 2014 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?
CrevsDaak Posted October 19, 2014 Posted October 19, 2014 I think Wisp was telling you to put "%modclass%" instead of just %modclass% 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.
subtledoctor Posted October 19, 2014 Author Posted October 19, 2014 I think Wisp was telling you to put "%modclass%" instead of just %modclass% 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.)
Miloch Posted October 19, 2014 Posted October 19, 2014 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.
subtledoctor Posted October 19, 2014 Author Posted October 19, 2014 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.)
subtledoctor Posted October 19, 2014 Author Posted October 19, 2014 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.)
Mike1072 Posted October 19, 2014 Posted October 19, 2014 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
subtledoctor Posted October 19, 2014 Author Posted October 19, 2014 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.
subtledoctor Posted March 14, 2015 Author Posted March 14, 2015 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.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.