Skip to content

[Project] A new language for writing mods

I have started to implement a new way of writing mods, using an existing programming language instead of WeiDU.

Here is the repository and here is the documentation.

The language is Julia; this is portable to at least as many platforms as EE games, while offering all the required syntactic sugar and being reasonably efficient. Short teaser:
# Let's create a big sword!

bigsword = Longsword(_"Really Big Sword", +1, weight = 200,
  description = _"A sword so big that it does crushing-type damage!")
bigsword.abilities[1].damage = Crushing(2d6+1)

# Translations are handled by `.po` files, no need to bother
# with @XXX strings.

# Keevor is a bit protective about Imoen:
from("imoen", 1)
actor("reevor") interject(_"Hey, you! Be gentle with Imoen!")

I am perfectly aware that WeiDU exists and of the huge codebase that it has collected over the last 20 years. However, I also think that this tool starts to show its age, and hope that InfinityEngine games (and mods) will remain alive for at least the next 20 years, so it is not too late to try and write something even better than WeiDU. Moreover, distant development goals include some level of compatibility with WeiDU
as well as semi-automatic translation (e.g. this should be possible at least for .d/.tra dialogue files).

The repository's README (linked above) contains a longer discussion of all the possible advantages
which such a tool could eventually offer relatively to WeiDU. These importantly include gains in robustness (e.g. no mod crash because of missing tildes in .tra file) and portability (no need to include shell code in mod tp2, Julia makes everything portable by default). I also hope that a more accessible syntax, making life easier for mod authors and translators, would leave them more energy for writing many good mods.

This is not usable yet. I only post the link here because the project is now advanced enough to start discussing it in public. Although most core concepts are mostly implemented, for now applications are strictly limited to editing items and dialogs.

So: I am now welcoming any form of constructive input about this tool, be it about design (which is not closed yet), testing, or even (for the brave) help in developing.

Final remark: I am not a mod author, but I did play all the IE games since the very first CD-ROM editions and Weimer's first mods. Since however I can program a bit, think of this project as an eventual “thank you” to all the people who can write good mods.

Comments

  • ahungryahungry Member Posts: 29
    Cool idea - I was just thinking along the same lines recently when mulling over the idea of benchmarking a custom C or Rust program for patching 15k files (and getting timing in how that may compare with weidu).

    This looks like it has more of a focus on readability from the author POV.

    To paraphrase some thoughts I recently had in the g3 discord:

    What if a new tool kept weidu/weinstall compatability for the rollback (--uninstall) operation?

    Then you'd just need weidu/weinstall to have a small switch as it reads a file - if it sees tp2, it runs weinstall as it currently does. If it sees a new file suffix intended for your program, it'd run that one instead.

    That may allow seamless integration into weidu setups (as long as the various weidu side-effects were mirrored - writing to weidu.log, creating the backup/ files in a way weidu proper can use them).

    It might actually greatly open up the novel tooling space (I could write some weird installer, and have it play nicely with yours and weidu).

  • ahungryahungry Member Posts: 29
    edited September 2022
    Another idea may be doing something akin to Typescript - transpile to the "common" language (weidu).

    I think a simple JSON -> weidu transpiler might be very valuable as well - I would have a much simpler time writing custom tooling around BG items if they were represented as basic JSON or xml data.

    So instead of:
    bigsword = Longsword(_"Really Big Sword", +1, weight = 200,
      description = _"A sword so big that it does crushing-type damage!")
    bigsword.abilities[1].damage = Crushing(2d6+1)
    

    You may have (using xml here, slightly more readable than JSON on a forum):
    <items>
      <item 
        name="BigSword" 
        type="longsword" 
        desc="Really Big Sword" 
        damage="2d6 + 1"
        weight=200 
        enchantment=1>
        <abilities>(whatever custom effects)</abilities>
      </item>
      ....(all the other package specific items)....
    </items>
    
  • CirconflexeCirconflexe Member Posts: 6
    For compatibility it is even simpler: we only need to have *either* (a) a new tool able to install/uninstall WeiDU mods, *or* (b) tell WeiDU how to manage mods written with the new tools. Both possibilities are relatively straightforward: (a) means a mod manager (I happen to already have this, and use it, although it is not documented enough to be releasable), and (b) means to write, for mods written with the new tool, a trivial .tp2 file which in turn launches the new tool (this is close to the solution you mention but does not even require patching WeiDU).
  • GraionDilachGraionDilach Member Posts: 589
    edited September 2022
    Please explain why one shouldn't see this as an attempt of "I don't like/understand your fringe language, so I propose to use my fringe language".

    WeiDU started out to edit the dialogues and everything else just grew on top of it. Yes, it's syntax is weird and uncommon. On the other hand, it allows to do everything and half of the shipped internal functions are written in WeiDU inside it. This is important, because in the older days, lowlevel stuff and direct byte manipulation were more common, and while I get this one tries to abstract away the things, abstraction without explanations is bad and shouldn't be the default.

    WeiDU's evolution was that it started from the lowest level. The teaser already implies this goes another way, opting for internal magic numbers, looks restrictive from the get-go and has way too many assumptions on stuff it shouldn't assume about (a great example is the 2.6 soundset additions - if a mod wants to use those, WeiDU doesn't offer a constant, but you can just go with the classic byte offset manipulation and call it a day, while this teaser implies me that ahwell, tough spot). This isn't robustness, this is a case of "I don't understand the needs of my target audience".

    On the other hand, the B solution with a TP2 wrapper is doable and there are mods doing it - The Horde is written in Java and does exactly this, the tp2 calls the Java executable. (This also means The Horde's bugs can't be fixed at all, because the Java executable lacks source code and one needs to reverse-engineer it outright to fix the issues and yes, the mod is buggy). In fact, The Horde is outright the reason why I wouldn't even support a language which needs a compiler. I also participated in a modding community for a decade where there were actual effort wasted to introduce obfuscators in the scene, preventing modders to learn from each other due to asset protection. I've seen the toxicity that can lead to and having a compiler in the ecosystem provides a massive starting point for this mindset.

    Note that WeiDU offers everything for a mod manager running on top of it, as the BWS proved, and PI/subtledoctor's Mac toolkit proves as well. There is room for another one in this layer though, since PI's mindset isn't novice-friendly - but it should really follow PI's metadata format proposal as a standard.

    There's already SCS's SSL as an alternative option which is somewhat based on Perl's syntax and invokes that, but since it still keeps everything on the interpreter stage, this allows other modders to learn and pick it up and incorporate into their mods, like how Made in Heaven did.

    Also see https://www.gibberlings3.net/forums/topic/32890-a-turing-machine-in-weidu/ and https://www.gibberlings3.net/forums/topic/32862-alternatives-to-weidu-or-how-to-write-a-smarter-sound-set-installer/ which also covers this topic. Although the latter one was atleast using a language I wouldn't consider fringe outright.
  • CirconflexeCirconflexe Member Posts: 6
    edited September 2022
    Please explain why one shouldn't see this as an attempt of "I don't like/understand your fringe language, so I propose to use my fringe language".

    Please see the discussion linked above, but here are some examples:

    1. .po files the industry standard for translations, whereas .tra files are quite brittle (e.g. any translation missing even one string crashes the mod). Also, the current quality of mod translations is often quite poor, because .tra strings are translated without context; e.g. translators see only "Slow" and don't know whether this is an adjective or a verb, and despite their best efforts this produces nonsensical translations. This is basically impossible to fix without changing the language.

    2. Right now a lot of mods invoke shell scripts or batch scripts depending on OS. This forces the authors to write (and maintain) several sets of functions while often being able to validate only one of them. This is of course a great source of bugs. Hence I suggest a solution which totally dispenses with shell scripts and makes everything portable by default, by running on a platform which is already as portable as the game itself. Again, this could be fixed by implementing a few shell functions (cp, mv, rm) inside WeiDU, but at this point we are already converting WeiDU into a new tool aren't we?

    2.5 While we are on portability: WeiDU is quite bad with case-sensitive filesystems (so that e.g. installing mods on a Linux install requires mounting a separate ad-hoc ciopfs, which significantly slows down the game). I am trying to write something which works natively with any filesystem and (this is important) without requiring any extra effort from mod authors.

    3. (A more minor point) This module seems (for now; tests are obviously not complete) to be running circles around WeiDU or InfinityExplorer when it comes to speed (on my ordinary laptop it loads the whole game database in < 5 milliseconds, and this is not a SSD) — this becomes significant when some mods litterally take hours to install (SCS...) and one may need to reinstall the whole stack a few times to tweak some installation options.

    4. Any existing language is, by definition, strictly less obscure than WeiDU. I won't discuss style here (although WeiDU would lose, even without mentioning OCaml or SCS's Perl) but the exact choice of a non-WeiDU language does not matter much, as long as it is easy to learn. In this respect most modern script-like languages are very much alike: had I used (say) Lua or Python instead of Julia, the teaser above would still have looked almost exactly the same. (But if you want to write a Lua variant of my project, please do, and I will probably even join you — this could possibly have been an even better choice, although the task of writing all of this in a very minimal language looks a bit daunting to me).

    5. About magic numbers: what exactly makes you believe that it is not possible to assign a value at a given offset with this program? This would actually be a quite simple feature to implement. However, I believe that this is would be a *bad* feature, because abstracting the format of the game resource database from mod authors is extremely useful. Here is a little thought experiment to support this: imagine that in some future version the binary format of ITM file changes. Now all .tp2 files which use magic offset constants need to be rewritten. On the other hand, the InfinityEngine module just needs a simple patch to learn about (and detect) the new binary format and any code written by mod authors then remains valid automatically. (Right now the module only knows one version of game resource database, but extending to several versions is in the pipes to support other games than BGEE. Future changes like in the thought experiment would naturally hook into this mechanism and be very straightforward to write).

    Oh and by the way, of course this does not need a compiler for individual mods: compilation is JIT so that this is used exactly as if it were a scripting language. The intended development cycle is exactly the same as that of WeiDU mods. And the goal here is to make mod source less obfuscated; this should be obvious when comparing the nonsensical example above with its WeiDU equivalent.


    I am perfectly aware of WeiDU's “organic” growth, and I believe that all of the disadvantages of WeiDU listed above are artifacts of its growth, since it originated as a single-OS, single-author, single-language, (almost) single-mod tool.
    Now we have the advantage of hindsight: while Westley Weimer had to invent everything from scratch, we know which features are actually used by mod authors and how to smooth everything, and this requires re-thinking the toolset globally. For one more example, mod stack management is more of an afterthought for WeiDU: claiming that WeiDU offers “everything needed” is a bit exaggerated when even language codes are not standardized between mods, components options are passed through terminal interactions, and mod stack managers tend to work despite WeiDU's conception. Making a WeiDU mod BWS (etc.)-friendly brings even more constraints on its author.

    Besides, the fact that a mod manager is even needed at all is one more deficiency of WeiDU that I intend to remedy (and mod managers themselves are not portable — I never succedded running PI on Linux and I was not even aware of Mac-specific solutions). I had to write my own mod manager, some code of which will probably be reused in this project.
  • CirconflexeCirconflexe Member Posts: 6
    edited September 2022
    Your question is perfectly valid and I realize that the sample above does not represent the best advantages of this module. However, in case you did not read the discussion linked above, here are a few reasons why I think a new tool is needed.

    1. Translations. ".po" files are the industry standard for localization. In comparison, ".tra" files are extremely brittle: for example, a single missing string crashes the mod on install (this can easily happen when translations are not updated as fast as the mod's core).

    Moreover, the quality of mod translations is currently sometimes quite poor, and this is not the translators' fault: ".tra" files offer absolutely no context for translated strings. When a translator sees, say, "Slow", they don't know whether this is a verb or an adjective, and this does lead quite often to nonsensical translations. This is basically impossible to fix in WeiDU as it is now. On the other hand, I already have some quite simple code for providing translation contexts.

    2. Portability. A lot of mods use OS functions for moving files around, which requires writing the same function several times in various languages (shell script/batch). Of course most authors only use *one* of those languages, so the other ones become obsolete very fast: this is one more great source for bugs.

    It would naturally be possible to fix this by including e.g. "mv", "cp" functions in WeiDU (but this already counts as “a new modding language”).

    3. Portability/performance. WeiDU is notoriously bad with case-sensitive filesystems, to the point when running it on Linux requires mounting an ad-hoc ciopfs. This significantly slows down the game. Again, since file names are determined by mod authors, this would be very hard to fix from within WeiDU.

    On the other hand, I am writing something which completely abstracts the file names from mod authors and natively solves this problem.

    4. Magic numbers. What makes you believe that this tool cannot support writing offsets by hand? This would actually be a quite simple feature to write. But I believe that going down in abstraction would be a very bad idea, much in the same way as replacing a C struct by a char[] of the same size and assigning pointers by hand, and not only for convenience reasons.

    Here is a little thought experiment in support of this: imagine that in some future release, the binary format of ITM files is modified. Now mods using magic offset numbers need to be completely rewritten, and this is very brittle (every single use of magic offsets need to be trakced down, etc.). On the other hand, if the modding language offers an abstraction for items, then only the language itself needs to be aware of the new format. This is actually something that is eventually going to be present in the InfinityEngine module anyway, since various games use different resource formats, so adding just one more format can plug into
    this system.

    (On a side note: I play without sound, so I am totally unaware of those 2.6 soundsets. Do you have a pointer to this?).

    5. Mod stack management. The fact that an external tool is even needed at all is already a disadvantage of WeiDU. Moreover, modding tools tend to work *despite* WeiDU's conception and not with it: even something as simple as language codes is not standardized across mods; component options are passed by simulating terminal IO; mod metadata was added as an afterthought; mod conflicts are left to be guessed; obtaining the mod README is hard (for my own mod manager I needed to patch a "--list-readme" option into WeiDU) and component READMEs are impossible, etc.

    Moreover, mod tools tend to be not portable (I was unable to run PI under Linux and you also mention a Mac-only tool), to the point where I needed to write my own mod manager to install a big WeiDU stack on Linux. (I expect to reuse some of that code in this new project).

    6. Speed. This is a more minor point, but still significant since some mods (SCS) can require a few hours to install, and with WeiDU's model tweaking a few options may need to reinstall the whole stack. Of course the benchmarks are not definitive yet, but on my (non-gamer, not SSD) laptop my module can load all game resources in less than 5 milliseconds.


    I am fully aware of WeiDU's history (as said above, I used it from the very beginning): it began as a single-author, single-OS, single-language, and (almost) single-mod tool. Again, I am not saying anything bad about WW's work: he started everything and we are all grateful to him for this. But now we happen to have the benefit of hindsight; we know which features are used by mod authors, we know how many mods (and of which kinds) compose a typical installation, we know how to make everything robust, so we can try and design something better from start.


    Note that none of the points above is about syntax. But now that I have established why a new tool can be an improvement, we might just as well try and make life easier for mod authors. In this respect, almost any existing language is by definition less obscure than TP2 (even LISP :smile:); however, most modern “script-like” languages are very much alike in syntax. The short teaser above could be rewritten in Lua or Python and look almost the same. I simply chose Julia because it offers a lot of useful features (for example, I use introspection to generate translated strings, and this is a fast language). However, while I leave “fringe” to your taste, importantly enough this is not my own language but a pre-existing one which is at least as portable as the
    game itself and with an easy learning curve (I believe most people would indeed find it easier than TP2, WeiDU's OCaml, or SCS's Perl — and I say this while generally being a defender of OCaml or Perl).

    I am not married to the Julia language (or to anyone named Julia for that matter). If by chance you happen to prefer, say, Lua, then feel free to re-use my work to write a Lua modding library -- I might even join you on that project (I believe Lua could be another interesting choice for the final product, but writing all of this in such a minimal language is a bit too intimidating for me alone).

    Last note: I fully agree with your remark on compiled and obfuscated mods. Note however that this exactly not what I am suggesting; Julia is JIT-compiled, so that in practice it behaves as a scripting language, and the development process for mods in this system would be almost exactly the same as with WeiDU (with maybe minor changes in the translation process, to the advantage of translators). On the contrary, I try very hard to make the syntax as simple as possible, not only to help write good mods, but also to help maintain them.
    Post edited by Circonflexe on
  • GraionDilachGraionDilach Member Posts: 589
    edited September 2022
    I don't have time to respond on the rest but 2 is nonsense, WeiDU is cross-platform, the ciopfs issues are needed because the internals of the Infinity Engine are case-sensitive and while classic used lowercase internally (while shipping uppercase files), Beamdog started using uppercase resource names internally as well.
  • suysuy Member Posts: 30
    edited September 2022
    I don't have time to respond on the rest but 2 is nonsense, WeiDU is cross-platform, the ciopfs issues are needed because the internals of the Infinity Engine are case-sensitive and while classic used lowercase internally (while shipping uppercase files), Beamdog started using uppercase resource names internally as well.

    I would not be so sure about that (but I'm not claiming to be 100% sure on what I say next either). The unmodded EE game works without a case insensitive file system. Then, I've modded stuff manually and with NearInfinity, and the game did not require it either. Even when changing the case of file names inside "override" on purpose. Then added changes via WeiDU, and suddenly the game needs it to run. More: you just need the case insensitive file system to _start_ running WeiDU, because is unable to locate the dialog.tlk file. Maybe this is fixable in WeiDU, I don't know, but I think WeiDU is part of the problem.
    Post edited by suy on
  • OlvynChuruOlvynChuru Member Posts: 3,079
    @Circonflexe

    This is an interesting project, definitely worth pursuing. Though you do have your work cut out for you. Your program is going to need to re-implement several of WeiDU's features before it can replace WeiDU. You've likely solved some of these already, but it's worth checking:

    1. You'll need to implement ways of modifying 2DA and IDS files. Mods will occasionally have to read or write values in these files, or add or remove rows.

    2. There should be some way of matching and replacing text in files (akin to WeiDU's REPLACE_TEXTUALLY and REPLACE_EVALUATE). These functions can be used to dynamically modify BAF files, the BAF chunks in DLG files, UI.MENU, the INI files used for animations, as well as LUA files. This also requires you to implement some way of decompiling and compiling the BCS files (modifying the BAF chunks in DLG files also requires you to implement some way of decompiling and compiling the DLG files, as WeiDU is already capable of doing).

    3. Replacing the system of writing at offsets for editing fields with an object-oriented system is okay, but make sure your program has a comprehensive list of variable names for every field in ARE, CHR, CHU, CRE, DLG, EFF, ITM, PRO, SPL, STO, VVC, WED, and WMP files. Otherwise, I might run into situations where I want to modify a field that you forgot to include a variable for. I remember this was a big problem when I was making mods for Skyrim; the in-game functions don't let you modify all the fields in spell files, so I had to use a third-party modding utility to modify those things.

    4. Even if specifying offsets to write at like in WeiDU isn't the primary way of editing files, it should still be an option, just in case someone wants to edit a file type you didn't plan for. In the process of developing Icewind Dale 2: Enhanced Edition, for example, I had to modify BMP files with WeiDU at one point (this was specifically to modify search maps, which have gameplay implications).

    5. Make sure that you have ways of adding new data blocks to all file types that have those (e.g. new headers to items and spells, new effects to item and spell headers, new actors, containers, doors, regions, etc. to areas, new items to stores), as well as ways of removing them.

    6. Also, just checking: does your program have a way to make copies of existing files and modify the copies, like WeiDU does? This is generally a much better idea than trying to make a new sword item file from scratch.

    7. Does your program have a way to copy all the new files from the mod folder into the override folder with a single line of code? WeiDU can do this. My bigger mods typically have a line of code that says this:

    COPY ~%mod_folder%/Allfiles~ ~override~

    It would be good to have some equivalent of that.

    8. Does your program have some equivalent to COPY_EXISTING_REGEXP that lets you modify all files in BIF and override that match a specific regexp?

    9. Can a mod coded using your program be uninstalled, undoing the changes of that mod but not the changes of mods installed before that one?

    10. Can a mod coded using your program have multiple components (potentially with subcomponents), with some way of allowing the user to choose which components or subcomponents they want to install?

    11. You also might need to add equivalents of WeiDU's various functions that do special or complex things (e.g. ADD_KIT, ADD_PROJECTILE, BUT_ONLY_IF_IT_CHANGES, IF_EVAL).
  • suysuy Member Posts: 30
    I have a few things that I would like to say (my attempt at constructive feedback, don't fear :-) ), but on the topic of the language, known that I think a big deal on the lack of actual improvements on WeIDU, is mostly that it's written in a non-mainstream language. If it were written in even plain old and crappy C, I imagine someone would have proposed a patch where you just write BEGINLUA /* actual Lua code here*/ ENDLUA, and there you go, backwards compatibility and an option for people who want a regular programming language with proper abstractions. That, or something similar, I mean.

    I know close to nothing about Julia, and I don't feel quite motivated to learn it, but certainly the availability of a tool to make modding easier could make me think about it. Some other scripting language could be much better, though.

    My "plan" (more like a pipe dream, to be honest) was to complete the support for IE file formats in the library of my application, Moebius Toolkit. I've been progressing very little on it, but I plan a more aggressive strategy for the next release, as I want to have basic browsing in the application. For that, I would only need read support, but write will be a bit simpler, I think, as the main deal has been me being very panicky about breaking compatibility, and having unit tests and the like.

    The next step was making a toy mod, for my own use, in C++ (the language in which the app and library are written), then add scripting support for it. Lua is the first on the list, as it seems the most appropriate (simple, popular in games, used in EEex and the InfinityEngine console, etc.). JavaScript was also on the options because popularity and availability.

    I think scripting is better for this kind of project (mods), but I surely don't have a strong opinion. I don't see the problem with compiled languages given that WeiDU, EEex, BG2RadarOverlay or NearInfinity are all compiled (and open source or at least have source available). The only problem with opaque binaries is that they can do shady things. My answer to that would be to skip this mods entirely. :(
  • EndarireEndarire Member Posts: 1,519
    @Circonflexe
    How does your proposed alternative interact with GemRB, a revised Infinity Engine, and EEex, a default Infinity Engine extender?
  • CirconflexeCirconflexe Member Posts: 6
    OlvynChuru wrote: »
    @Circonflexe

    This is an interesting project, definitely worth pursuing. Though you do have your work cut out for you. Your program is going to need to re-implement several of WeiDU's features before it can replace WeiDU. You've likely solved some of these already, but it's worth checking:

    1. You'll need to implement ways of modifying 2DA and IDS files. Mods will occasionally have to read or write values in these files, or add or remove rows.

    As I said, I focused first, as proofs-of-concept, on items (code written here will be reusable for many resource types) and on dialogs (efining and editing state machines needs special syntax). I do have some code for reading 2da and ids (not writing them though, but this will be the easy part, just use printf). I will also need some way of using IDs in-script (this will be quite easy, the language has dictionaries).
    2. There should be some way of matching and replacing text in files

    This is actually one of the reasons behind the language choice, since Julia has native regular expressions, whereas Lua does not.
    replace(string, "pattern" => "substitution") is native Julia syntax.
    3. Replacing the system of writing at offsets for editing fields with an object-oriented system is okay, but make sure your program has a comprehensive list of variable names for every field in ARE, CHR, CHU, CRE, DLG, EFF, ITM, PRO, SPL, STO, VVC, WED, and WMP files.

    By construction it does; for an example, you can look in the git repository (file src/InfinityEngine.jl) how "struct Item" is defined.

    About BMP files: this module does not yet handle binary resources. I thought that the most we needed to do with them was copying and renaming files; your example does show that there may be a few more needs. However, this is (again) one of the joys of using an actual existing language: of course it already has features for editing a binary file and it won't be much work to use that.
    5. Make sure that you have ways of adding new data blocks to all file types that have those (e.g. new headers to items and spells, new effects to item and spell headers, new actors, containers, doors, regions, etc. to areas, new items to stores), as well as ways of removing them.
    This is already the case (well, for those resources which are already implemented, namely actors and items): adding new effects and abilities to items are trivial since these have the API of a Vector (a native construct in the language), we can simply push onto the list etc.
    6. Also, just checking: does your program have a way to make copies of existing files and modify the copies, like WeiDU does? This is generally a much better idea than trying to make a new sword item file from scratch.

    Of course it does, and this is actually shown in the example above: Longsword() is really shorthand for cloning the basic long sword item; the actual function definition is (almost verbatim) Longsword(args...) = copy("sw1h04.itm", args...), and we can use just any item name in there.
    7. Does your program have a way to copy all the new files from the mod folder into the override folder with a single line of code?

    Not yet (although it would be straightforward to implement since the language natively contains "cp") but the goal is to have something slightly different, and (intended as) more author-friendly:
    - game resources are identified by any author-chosen string and (semi-)automatically namespaced to prevent name collision (rendering the 2-byte prefixes useless and names more explicit) (however nothing prevents author from still choosing 2+6-byte names if they really want to).
    - I suggest defining resources from within the script instead on from an external file (having a text version is more edit-friendly and even more maintenance-friendly: it can be versioned, diff-ed, etc.). I think of this as having access to the source code of resources vs. only a compiled form (even though “decompiling” is here quite simple).

    Given all of this it is still possible to have a one-line copy, of course.
    8. Does your program have some equivalent to COPY_EXISTING_REGEXP that lets you modify all files in BIF and override that match a specific regexp?

    Just like above: scripts are not yet a handled resource type, but the Julia language has very easy access to regexps, so this will be very simple to implement.
    10. Can a mod coded using your program be uninstalled, undoing the changes of that mod but not the changes of mods installed before that one?

    This is definitely on the TODO list, and one of the points which I think deserves discussion, hence my post here. I think that this is actually the single hardest remaining problem. WeiDU's stack-based concept has the advantage of simplicity but is not too efficient; when you want to tweak an option deep in the stack and you need to uninstall + reinstall everything (including taking ages to reinstall SCS) you regret it.

    Ideally I would like to have some system where each game resource is “owned” by either the base game or a mod: this would prevent mod conflict, help sort out the “mod install order” problem, and make uninstall trivial (just restore the original resource). However the needed granularity could be very fine (e.g. must each single cell in a 2da file have an owner?). I must test how this works in practice (e.g. using data compression I could probably store the (mod) -> (set of owned resources) map) before committing to a particular solution.
    11. Can a mod coded using your program have multiple components (potentially with subcomponents), with some way of allowing the user to choose which components or subcomponents they want to install?

    Same answer as 10. Moreover, what I have now is not yet a proper modding system (“WeiDU”), but an Infinity Engine-access interface (“InfinityExplorer”): the way to define actual mods is not defined yet.
    12. You also might need to add equivalents of WeiDU's various functions that do special or complex things (e.g. ADD_KIT, ADD_PROJECTILE, BUT_ONLY_IF_IT_CHANGES, IF_EVAL).

    This is for me one of the greatest advantages of using a “real” programming language: once we have basic access to resources, implementing that kind of bigger changes becomes very simple (just write a function in that language). Of course there will eventually be some form of ADD_KIT etc., but that is the easy part.

    @GraionDilach : I maintain my point 2 and your answer is quite obviously nonsense since the InfinityEngine *does* run on a case-sensitive filesystem. The problem is not with the game engine but with mods. With the tool I am developing, I did succeed in modding a few resources without ciopfs and having them recognized with the game. My experiments actually suggest something very close to @suy 's answer: I am under the impression that the game engine does ignore case when opening resources and that the problem lies entirely within WeiDU's ability to open files (and author's ability to use case-consistent filenames, which is quite poor in practice).
  • CirconflexeCirconflexe Member Posts: 6
    One last comment about language choice: my main goal is not to defend a particular language but to show which features could be added to a modding tool. The small example in the first post is supposed to show that learning full Julia is not needed to write mod: a very small subset suffices, and this subset happens to be (almost) the same in most modern programming languages. Again, feel free to improve on my work and write something using another back-end, and I will likely contribute to it!

    I selected this language because it has useful features (regular expressions, introspection, somewhat extensible syntax) and probably decent staying power. Obviously, knowing more about the Julia language would of course be needed to maintain the tool itself. (However, this is still an improvement over WeiDU).
  • GraionDilachGraionDilach Member Posts: 589
    edited September 2022
    On the EEs, in order to use the "separate portrait files for separate sizes" custom portrait feature (aka the S/M/L size suffix), one needs to use 7.3 filenames with the size suffix explicitly defined as uppercase, otherwise the file won't be loaded and the portrait will be garbled. (8.3 with a size suffix doesn't get loaded either, 8.3 without size suffix works as a generic portrait.)

    Yes, using a lowercase size suffix will not work on Windows. That feature is picky enough that in all my setups where I am using it, I explicitly opt for mixed cases, with everything else excluding the size suffix being lowercase.

    Doesn't sound like a case insensitive logic to me.

    Also, newsflash: WeiDU has this ownership model. That's what --change-log runs on. Have an example.
    d:\Baldur's Gate - ProjectInfinity\Baldur's Gate II EET>weidu --log nul --change-log BGEE.LUA
    [weidu] WeiDU version 24900
    
    Mods affecting BGEE.LUA:
    00000: /* created or unbiffed */ ~EET\EET.TP2~ 0 0 // EET core (resource importation)V13.4
    00001:  ~IMOEN_FOREVER\IMOEN_FOREVER.TP2~ 0 0 // Imoen 4 Ever in BGII: Imoen Returns after Talking to Gaelan in Chapter 2v10
    00002:  ~C#ENDLESSBG1\C#ENDLESSBG1.TP2~ 0 0 // Endless BG1: Main Component (Required)11
    00003:  ~C#ENDLESSBG1\C#ENDLESSBG1.TP2~ 0 1 // More Flavor to Hero of Baldur's Gate (Includes PC's Residence Inside Palace)11
    00004:  ~C#ENDLESSBG1\C#ENDLESSBG1.TP2~ 0 4 // Sarevok's Sword11
    00005:  ~C#ENDLESSBG1\C#ENDLESSBG1.TP2~ 0 5 // Imoen and Duke Jannath (Imoen Gets Residence Inside Palace)11
    00006:  ~C#ENDLESSBG1\C#ENDLESSBG1.TP2~ 0 8 // Elminster Makes an Appearancejastey's Version11
    00007:  ~C#ENDLESSBG1\C#ENDLESSBG1.TP2~ 0 10 // First Refugees Come to Baldur's Gate11
    00008:  ~TRANSITIONS\TRANSITIONS.TP2~ 0 0 // Main component: Allow continued play after Sarevok and/or Irenicus is defeatedv2.4
    00009:  ~SOTSC\SOTSC.TP2~ 0 0 // Shades of the Sword Coast - Expansion Pack for BGEE7.1
    00010:  ~DSOTSC\DSOTSC.TP2~ 0 0 // Dark Side of the Sword Coast (DSotSC)v4.1
    00011:  ~NTOTSC\NTOTSC.TP2~ 0 0 // Northern Tales of the Sword Coast (NTotSC) for BGT-Weidu, BG:EE, and EET5.0.0
    00012:  ~NTOTSC\NTOTSC.TP2~ 0 2 // Keelor the Dwarf5.0.0
    00013:  ~NTOTSC\NTOTSC.TP2~ 0 3 // Llindellyn's Lucky Arrow5.0.0
    00014:  ~NTOTSC\NTOTSC.TP2~ 0 5 // Pilar and Gheldehar5.0.0
    00015:  ~BG1RE\SETUP-BG1RE.TP2~ 0 4 // Extension of Bjornin Encounter (Personal Wound Treatment), by jastey9.0
    00016:  ~BG1RE\SETUP-BG1RE.TP2~ 0 6 // Duke Eltan's Spare Minute, by jastey9.0
    00017:  ~BG1RE\SETUP-BG1RE.TP2~ 0 9 // Bartus' Seduction, by jastey9.0
    00018:  ~BG1RE\SETUP-BG1RE.TP2~ 0 26 // The Messenger, by Thimblerig9.0
    00019:  ~BG1RE\SETUP-BG1RE.TP2~ 0 29 // The Honest Lies of Two Riversides, By Lava9.0
    00020:  ~BG1RE\SETUP-BG1RE.TP2~ 0 30 // Necromancer's Trouble, by jastey9.0
    00021:  ~BG1RE\SETUP-BG1RE.TP2~ 0 31 // Dinner with Thalantyr, by jastey9.0
    00022:  ~BG1RE\SETUP-BG1RE.TP2~ 0 41 // The Messenger 2: Rain or Snow or Gloom of Night, by Thimblerig and tibicina9.0
    00023:  ~BG1RE\SETUP-BG1RE.TP2~ 0 42 // Camryn and Tamah, by tibicina9.0
    00024:  ~BG1RE\SETUP-BG1RE.TP2~ 0 44 // Cloakwood Lovers, by tibicina9.0
    00025:  ~WHEELS\SETUP-WHEELS.TP2~ 0 0 // The Wheels of Prophecyv8.5
    00026:  ~LONGERROAD\LONGERROAD.TP2~ 0 0 // Longer Road2.0.3
    00027:  ~ARESTORATIONP\ARESTORATIONP.TP2~ 1 1 // Restored Characters and Dialogsv8.4
    00028:  ~ARESTORATIONP\ARESTORATIONP.TP2~ 1 8 // Minor Restorationsv8.4
    00029:  ~BGQE\SETUP-BGQE.TP2~ 0 0 // Slime Questv25.4
    00030:  ~BGQE\SETUP-BGQE.TP2~ 0 1 // Beregost Family Questv25.4
    00031:  ~BGQE\SETUP-BGQE.TP2~ 0 2 // Babysitting Quest, including the Carnival Encounter...v25.4
    00032:  ~BGQE\SETUP-BGQE.TP2~ 0 3 // Nashkel Monster Questv25.4
    00033:  ~BGQE\SETUP-BGQE.TP2~ 0 4 // Fallen Paladin Questv25.4
    00034:  ~BGQE\SETUP-BGQE.TP2~ 0 5 // Undying Love Questv25.4
    00035:  ~BGQE\SETUP-BGQE.TP2~ 0 6 // Lovesick Half-Orcv25.4
    00036:  ~BGQE\SETUP-BGQE.TP2~ 0 7 // Unexpected Help Questv25.4
    00037:  ~BGQE\SETUP-BGQE.TP2~ 0 8 // Many Little Pawsv25.4
    00038:  ~BGQE\SETUP-BGQE.TP2~ 0 9 // Drunk near Beregost Templev25.4
    00039:  ~BGQE\SETUP-BGQE.TP2~ 0 10 // A Warm Place for Nooberv25.4
    00040:  ~BGQE\SETUP-BGQE.TP2~ 0 11 // Brage's Swordv25.4
    00041:  ~BGQE\SETUP-BGQE.TP2~ 0 12 // Legal Sea Charts Sourcesv25.4
    00042:  ~BGQE\SETUP-BGQE.TP2~ 0 14 // A Worried Farmerv25.4
    00043:  ~BGQE\SETUP-BGQE.TP2~ 0 15 // Bodies for a Good Causev25.4
    00044:  ~BGQE\SETUP-BGQE.TP2~ 0 16 // Finish Cordyr's Quest without killing Silv25.4
    00045:  ~C#SODTWEAKS\SETUP-C#SODTWEAKS.TP2~ 0 12 // SoD Ending: jastey's TweaksRevised Full Versionv9.2
    00046:  ~C#SODBOABRI\C#SODBOABRI.TP2~ 0 2 // Bridge Scene has Different Choicesv2
    00047:  ~SKIECOST\SKIECOST.TP2~ 0 0 // Skie: The Cost of One Girl's Soul - New quest for Baldur's Gate 2 EE4.2
    00048:  ~SKIECOST\SKIECOST.TP2~ 0 3 // Skie: The Cost of One Girl's Soul - The Return of Eddard Silvershield (quest & a joinable NPC)4.2
    00049:  ~UB\SETUP-UB.TP2~ 0 0 // The Kidnapping of Boo by Cliffettev28
    00050:  ~UB\SETUP-UB.TP2~ 0 1 // The Suna Seni/Valygar Relationshipv28
    00051:  ~UB\SETUP-UB.TP2~ 0 2 // Kalah and What He Was Promisedv28
    00052:  ~UB\SETUP-UB.TP2~ 0 4 // Gorje Hilldark and the Extended Illithium Questv28
    00053:  ~UB\SETUP-UB.TP2~ 0 5 // The Pai'Na/Spider's Bane Questv28
    00054:  ~UB\SETUP-UB.TP2~ 0 25 // The Murder of Acton Balthis, by Kulyokv28
    00055:  ~BG1NPC\BG1NPC.TP2~ 0 10 // The BG1 NPC Project: Banters, Quests, and Interjectionsv30
    00056:  ~RE\SETUP-RE.TP2~ 0 3 // Anishai's Deft Hands, by cmorganv15
    00057:  ~RE\SETUP-RE.TP2~ 0 37 // Solaufein in the Lust Chambers, by jasteyv15
    00058:  ~EILISTRAEE\SETUP-EILISTRAEE.TP2~ 0 0 // Eilistraee's SongYes, but don't patch the existing save games7.0
    00059:  ~AC_QUEST\AC_QUEST.TP2~ 1 0 // A Job Well-Paid4.0
    00060:  ~AC_QUEST\AC_QUEST.TP2~ 1 1 // A Feast for the Gnolls4.0
    00061:  ~AC_QUEST\AC_QUEST.TP2~ 1 2 // Jumper4.0
    00062:  ~AC_QUEST\AC_QUEST.TP2~ 1 3 // The Lost Son4.0
    00063:  ~AC_QUEST\AC_QUEST.TP2~ 1 4 // Of Wolves and MenQuest uses hut near Thalantyr in High Hedge.4.0
    00064:  ~AC_QUEST\AC_QUEST.TP2~ 1 6 // The Great Carlini4.0
    00065:  ~AC_QUEST\AC_QUEST.TP2~ 1 7 // A Home for the Gibberlings4.0
    00066:  ~AC_QUEST\AC_QUEST.TP2~ 1 9 // The Serpents of Abbathor4.0
    00067:  ~AC_QUEST\AC_QUEST.TP2~ 1 10 // A Halfling among the Eyeless4.0
    00068:  ~BST\SETUP-BST.TP2~ 0 0 // The BS Company presents Balduran's SeatowervEAOB.7
    00069:  ~INNERSHADE\SETUP-INNERSHADE.TP2~ 0 0 // Colours of Infinity: InnershadeYes, but don't patch the existing save games11.0
    00070:  ~OOZE\OOZE.TP2~ 0 0 // Athkatlan Grounds: The Ooze's Lounge - a new area under Athkatlan Slums2.92
    00071:  ~SOUTHERNEDGE\SOUTHERNEDGE.TP2~ 0 0 // Southern Edge: the new district of AthkatlaYes, but don't patch the existing save games4.0
    00072:  ~TOTDG\SETUP-TOTDG.TP2~ 0 0 // Colours of Infinity: Tales of the Deep GardensYes, but don't patch the existing save games12.6
    00073:  ~SOS\SETUP-SOS.TP2~ 0 0 // Shadows Over Soubar1.16
    00074:  ~EMAD\SETUP-EMAD.TP2~ 0 0 // A Z-rated Adventure - an IM4 Non-Entryv11
    00075:  ~EMAD\SETUP-EMAD.TP2~ 0 1 // The Promise of a Trollv11
    00076:  ~EMAD\SETUP-EMAD.TP2~ 0 2 // A Bhaalspawn's Best Friendv11
    00077:  ~TGC1E\SETUP-TGC1E.TP2~ 0 0 // The Grey Clan Episode One: In Candlelight, BGT-WeiDU/EET/BG:EE edition v1.9Normal editionv1.9
    00078:  ~WHITEQUEEN\WHITEQUEEN.TP2~ 0 0 // Colours of Infinity - The White QueenYes, but don't patch the existing save games6.8
    00079:  ~ISNF\ISNF.TP2~ 0 0 // Colours of Infinity: I Shall Never Forget6.1
    00080:  ~SNAKES\SNAKES.TP2~ 0 0 // The Slithering Menace (for BGII:ToB only)v4.0.0
    00081:  ~BACKBRYNNLAW\BACKBRYNNLAW.TP2~ 0 0 // Back to Brynnlaw mod for Baldur's Gate IIv9
    00082:  ~ALTERNATIVES\SETUP-ALTERNATIVES.TP2~ 0 0 // Alternativesv15
    00083:  ~SELLSWORDS\SELLSWORDS.TP2~ 0 0 // The Sellswords mod for Baldur's Gate IIv9.1
    00084:  ~REUNION\REUNION.TP2~ 0 0 // The Reunion mod for Baldur's Gate IIv7
    00085:  ~G3ANNIVERSARY\SETUP-G3ANNIVERSARY.TP2~ 0 0 // The Gibberlings Three Anniversary Modv12
    00086:  ~TANGLEDISLE\TANGLEDISLE.TP2~ 0 0 // Athkatlan Grounds: The Tangled Oak IsleYes, but don't patch existing save gamesv2.26
    00087:  ~COWLEDMENACE\SETUP-COWLEDMENACE.TP2~ 0 1000 // Main Component0.2.1
    00088:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 5 // Additional Shadow Thieves Contentv3.4
    00089:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 6 // Alternative Harper/Xzar Plotv3.4
    00090:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 7 // Extended Reynald Sequencev3.4
    00091:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 8 // Intrigue In The Copper Coronetv3.4
    00092:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 9 // Rahul Kanakia's Potion Questv3.4
    00093:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 10 // Revised Hell Trialsv3.4
    00094:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 13 // Saving Sanik In Brynnlawv3.4
    00095:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 14 // Burglary Of The Bookkeeperv3.4
    00096:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 15 // New Fate For The Dryads' Acornsv3.4
    00097:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 16 // The Tragedy Of Besamenv3.4
    00098:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 17 // Further Slaver Involvementv3.4
    00099:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 18 // Sending The Solamnic Knights Homev3.4
    00100:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 19 // Nazariel The Lichv3.4
    00101:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 20 // Reward Negotiationv3.4
    00102:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 21 // Infernal Thieveryv3.4
    00103:  ~THEVANISHINGOFSKIESILVERSHIELD\THEVANISHINGOFSKIESILVERSHIELD.TP2~ 0 0 // The Vanishing of Skie Silvershield – a new quest for BGEE that lets Eldoth and Skie join your party sooner2.2
    00104:  ~IWDIFICATION\SETUP-IWDIFICATION.TP2~ 0 30 // IWD Arcane Spell Packv5
    00105:  ~IWDIFICATION\SETUP-IWDIFICATION.TP2~ 0 40 // IWD Divine Spell Packv5
    00106:  ~A7-TOTLM-BG2EE\A7-TOTLM-BG2EE.TP2~ 0 0 // Trials of the Luremaster for Baldur's Gate3.0
    00107:  ~CTB\SETUP-CTB.TP2~ 0 0 // Check The Bodies3.0
    00108:  ~CTB\SETUP-CTB.TP2~ 0 1 // Candlekeep Chores3.0
    00109:  ~DW_LANTHORN\DW_LANTHORN.TP2~ 0 20 // Restored Rhynn Lanthorn lens questExpanded Version (adds four new locations where lenses can be found)v2
    00110:  ~BRIDGESBLOCK\BRIDGESBLOCK.TP2~ 0 0 // Athkatlan Grounds: The Bridge's Block1.0
    00111:  ~THECALLING\THECALLING.TP2~ 0 20 // Peaceful Werewolf Isle Resolutionv3
    00112:  ~FADINGPROMISES\SETUP-FADINGPROMISES.TP2~ 0 0 // Fading Promisesv9
    00113:  ~GBTHFKP\GBTHFKP.TP2~ 0 0 // Expanded Thief Strongholdv3.0.0
    00114:  ~A7-TESTYOURMETTLE\A7-TESTYOURMETTLE.TP2~ 0 0 // Test Your Mettle!1.4
    00115:  ~ISRA_BG2\ISRA_BG2.TP2~ 0 0 // Isra for BGIIv3.1
    00116:  ~FADE\SETUP-FADE.TP2~ 0 0 // Fade: An NPC for Baldur's Gate II: SoA and ToB5.6
    00117:  ~EMILY\EMILY.TP2~ 0 0 // Emily NPC for BG1EE1.65
    00118:  ~RECORDER\SETUP-RECORDER.TP2~ 0 0 // UNDEFINED STRING:   @11.5
    00119:  ~FINCHNPC\FINCHNPC.TP2~ 0 0 // Finch NPCv6.0
    00120:  ~VIENXAY\VIENXAY.TP2~ 0 0 // Vienxay NPC for BG1EE1.66
    00121:  ~SKITIANPCS\SETUP-SKITIANPCS.TP2~ 0 0 // UNDEFINED STRING:   @9951.007
    00122:  ~BRANWEN\BRANWEN.TP2~ 0 0 // Branwen BG2 NPC mod for players and moddersv7
    00123:  ~EVANDRA\SETUP-EVANDRA.TP2~ 0 0 // Evandra NPCv2.2
    00124:  ~TYRISFLARE\SETUP-TYRISFLARE.TP2~ 0 0 // Tyris Flare NPCv9
    00125:  ~AJANTISBG2\AJANTISBG2.TP2~ 1 0 // Sir Ajantis NPC for BGII20
    00126:  ~C#SOLAUFEIN\C#SOLAUFEIN.TP2~ 1 0 // Solaufein's Rescue: Jastey's Solaufein NPC for BGII3.2
    00127:  ~ALLTHINGSMAZZY\SETUP-ALLTHINGSMAZZY.TP2~ 0 0 // All Things MazzyVersion 3.07
    00128:  ~HERTHIMONEY\HERTHIMONEY.TP2~ 1 0 // Component 1. Interjections & Mini-quests (by Austin & Arcanecoast Team)4.2.6
    00129:  ~HERTHIMONEY\HERTHIMONEY.TP2~ 1 10 // Component 2. First Calimport Bank Pack (by Scheele & Austin & Arcanecoast Team)4.2.6
    00130:  ~HERTHIMONEY\HERTHIMONEY.TP2~ 1 20 // Component 3. Shadow-Covered Love & Death (by Alisia & Austin)4.2.6
    00131:  ~HERTHIMONEY\HERTHIMONEY.TP2~ 1 30 // Component 4. The Missing Troll Case (by Alisia & Austin)4.2.6
    00132:  ~QUESTPACK\SETUP-QUESTPACK.TP2~ 0 4 // Miscellaneous EnhancementsWith Additional Random Encountersv3.4
    00133:  ~A7-GOLEMCONSTRUCTION\SETUP-A7-GOLEMCONSTRUCTION.TP2~ 0 0 // Golem Construction Ability for Spellcasters6.2
    00134:  ~RR\SETUP-RR.TP2~ 0 11 // Chosen of Cyric encounterv4.92
    00135:  ~MIH_EQ\SETUP-MIH_EQ.TP2~ 0 17 // Enhanced Battles: Zombie Farmv6
    00136:  ~MIH_EQ\SETUP-MIH_EQ.TP2~ 0 19 // The Surgeon's Plightv6
    00137:  ~MIH_EQ\SETUP-MIH_EQ.TP2~ 0 31 // Enhanced Battles: Firkraag's Lairv6
    00138:  ~SODRTD\SODRTD.TP2~ 0 80 // SoD - Stat-based observations and quest options from Lauriel's Themed Tweaks Mod0.7 (Beta)
    00139:  ~SODRTD\SODRTD.TP2~ 0 0 // Main Component: Tracking System0.7 (Beta)
    00140:  ~SODRTD\SODRTD.TP2~ 0 60 // Additional Info Points0.7 (Beta)
    00141:  ~MIH_IP\SETUP-MIH_IP.TP2~ 0 0 // Made in Heaven: Item Packv7
    00142:  ~MIH_FR\SETUP-MIH_FR.TP2~ 0 4 // Spell Restorationsv1
    00143:  ~MIH_SP\SETUP-MIH_SP.TP2~ 0 0 // Made in Heaven: Arcane Spellpackv6
    00144:  ~A7-CHAOSSORCERER\A7-CHAOSSORCERER.TP2~ 0 0 // "Chaos Sorcerer" kit2.7
    00145:  ~RR\SETUP-RR.TP2~ 0 7 // Additional equipment for Thieves and Bardsv4.92
    00146:  ~A7-ACHIEVEMENTS\A7-ACHIEVEMENTS.TP2~ 0 1 // Steam Achievements as Journal EntriesDetailed Statistics2.0
    00147:  ~STRATAGEMS\SETUP-STRATAGEMS.TP2~ 0 5900 // Initialise AI components (required for all tactical and AI components)34.3
    00148:  ~STRATAGEMS\SETUP-STRATAGEMS.TP2~ 0 7040 // Relocated bounty hunters34.3
    00149:  ~STRATAGEMS\SETUP-STRATAGEMS.TP2~ 0 7150 // Improved Carsa/Kahrk interaction34.3
    00150:  ~STRATAGEMS\SETUP-STRATAGEMS.TP2~ 0 8180 // Improved Abazigal's Lair34.3
    
    d:\Baldur's Gate - ProjectInfinity\Baldur's Gate II EET>
    

    EDIT: Come to think of it, it is possible that the case-sensitivity I experienced comes from the Lua sandbox running the UI code (because I know for a fact that the variables inside the Lua code segments are very much case-sensitive there, had to document this within the EE Soundset Tool even).
  • ALIENALIEN Member Posts: 1,271
    @Circonflexe Late to the party, are you still cooking something?
  • Allanon81Allanon81 Member Posts: 342
    One question I have is would this make easier for people to install mods?
Sign In or Register to comment.