G3

A course on WEIDU - chapter 1: Introductory WEIDU

By DavidW - V1.1 12/14/2023

This chapter covers the rudiments of WEIDU: you'll learn how to set it up and how to write a basic mod that installs files you've already created in an editor.

1.1 Setting up WEIDU

WEIDU (created by Wesley Weimer, heavily developed by Valerio Biggiani ("TheBigg") and maintained currently by Wisp) is the standard modding tool for writing and installing IE mods. To set it up:

  • Download the latest version of WEIDU. The latest version (v249 at time of writing) is here.
  • Unzip the download and extract weidu.exe to the folder in which your IE game is installed. (I’ll be assuming this is BG2 for the most part, but WEIDU works for any of the Infinity Engine games.)
  • Pick a name for your mod. By tradition, I’ll use ‘mymod’ for that name, but you should use something unique. The normal convention is to pick a couple of letters or numbers that no-one else has used and to start all your names with those letters; I use ‘dw’, for instance, so I might choose ‘mymod’ to be ‘dwnewmod’.
  • Make a copy of weidu.exe and call it ‘setup-mymod.exe’ (where again ‘mymod’ stands in for your mod’s name – I won’t keep saying this).
  • Create a new folder, "mymod", in your BG2 directory. In that folder, create a new text file and call it "mymod.tp2".
  • Open up "mymod.tp2" in a text editor (Notepad is fine; Context or Notepad++ is better; lots of others exist and everyone has their own favourites). Enter the following text (it doesn’t matter exactly how long the lines of //////// are, or even if you put them in at all; they’re just there for readability):

BACKUP "weidu_external/backup/mymod"
AUTHOR "Myname (my email address)"
AUTO_EVAL_STRINGS

/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN "Boring component" DESIGNATED 100
/////////////////////////////////////////////////////////////////////////////////////////////////////
OUTER_SPRINT boring "This is a boring string"
PRINT "The value of the boring string is ‘%boring%’"

//////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN "Even more boring component" DESIGNATED 200
//////////////////////////////////////////////////////////////////////////////////////////////////////
PRINT "Here is some text"

If you now double-click on setup-mymod.exe, you will be offered the choice of installing the two boring components. If you do, you should see some text displayed.

Let’s look at the basic structure of the file. It starts with a block called the preamble, which specifies some stuff relevant to all components of the mod. In this case, the only information in the preamble is the folder used to back up the mod, the information to display to the user if the mod fails to install, and a somewhat gnomic command, ‘AUTO_EVAL_STRINGS’, that specifies the version of WEIDU we’re using. (If you want to use this guide, do not remove the AUTO_EVAL_STRINGS command: the guide assumes it in many places.)

After that is a list of components, each starting with a BEGIN ~My component name~ (and each being ended, implicitly, either by the next BEGIN line or the end of the file). The BEGIN line also includes a ‘DESIGNATED’ line that assigns a unique number to each component: you can pick these numbers, but it’s a good idea to make them increase by a reasonably large value (10 or 100) between each component. (You can skip the DESIGNATED if you like, and WEIDU will assign a number automatically, but I don’t recommend it.)

In the text following the BEGIN line you put the instructions required to install the component. In this case, the instructions don’t do anything very interesting. All the first component is doing is defining a variable (‘boring’), specifying what the value of that variable is, and then printing it. It’s boring because it isn’t actually doing anything to Baldur’s Gate at all (and if you just want to program without any IE-specific applications, WEIDU is a poor choice). The second component is even worse.

WEIDU comes equipped with a huge range of commands that could be put into the text of the component instead. They are exhaustively detailed in the WEIDU readme. In programming terms the standard WEIDU commands are mostly "low level" – they let you insert or modify bytes in the files on the basis of how far into the file they occur, without much engagement with the high-level interpretation of a given file as (say) a spell or creature.

(Incidentally, the particular choice of backup folder here (weidu_external/backup/mymod) stores the backup information as a subfolder of a folder (“weidu_external”) common to several of my mods and which is shareable with others. A more traditional alternative would be to choose mymod/backup, which stores the backup information as a subfolder of your own mod folder. I am inclined to think that it is better not to do this as (among other reasons) it makes it easy to accidentally distribute a (potentially large) backup folder when you publish the mod, but it’s up to you.)

1.2 Copying Files

Let’s do something a bit more interesting with WEIDU. The simplest sort of Baldur’s Gate mod is one where you’ve built a bunch of files using a graphical editor and you just want to install them in the game. For instance, maybe you’ve edited the Fireball and Lightning Bolt spells to do 1d6 damage per level all the way up to level 20. If so, you’ve got a couple of files, ‘SPWI304.spl’ (Fireball) and ‘SPWI308.spl’ (Lightning Bolt), and all you want to do is install them. It’s easy enough to do this. Put the spells into your mod’s folder (‘mymod’ in my example). And put the following code into one of the components of your TP2:
COPY "%MOD_FOLDER%/SPWI304.spl" override
COPY "%MOD_FOLDER%/SPWI308.spl" override

Let’s break this up.

  • 'COPY’ is an instruction to WEIDU: take an existing file, copy it to another location. COPY takes two arguments: you write ‘COPY this that’, and it copies this to that.
  • 'this’ (the first argument) is the location of the first thing you want to copy. ‘%MOD_FOLDER%’ is a variable (more on them later) that just stores the name of your mod’s main folder. So you could have replaced it with ‘mymod’, but it’s better practice to use the variable, so that if you ever decide to change your mod’s name you don’t need to edit your code.
  • ‘that’ (the second argument) is where you want to copy it to. 99% of the time, this will be ‘override’, the override folder of the main game (files in this space override files in the main game data files).
So the first line copies the file ‘SPWI304.spl’, which is in your ‘mymod’ folder, into override. And the second line copies ‘SPWI308.spl’ to the same place. Next time you play, you’ll get overpowered fireballs and lightning bolts.

Before continuing, let’s ask why you’d want to code this super-minimal mod in WEIDU instead of just distributing the files for people to drop into their override manually. The answer is that if you uninstall this change, WEIDU will just roll back the changes and restore the previous versions of Fireball and Lightning Bolt. That matters in particular in case some other mod you installed earlier has also altered those spells: if so, uninstalling this component will restore the other mod’s version of the spells, not the unmodded game’s version.

(To be truthful, with something this simple it doesn’t matter all that much, but it quickly starts to as the mod gets more complicated.)

There are a few variations of the COPY command worth knowing. Firstly, you can list lots of ‘this’ … ‘that’ pairs at once – you don’t need to repeat COPY each time. The following works just as well as our previous code:

COPY
	"%MOD_FOLDER%/SPWI304.spl" override
	"%MOD_FOLDER%/SPWI308.spl" override
(WEIDU does not care about spacing and line returns; the tab in the above code is just for readability.)

Secondly, if you want to change the name of the file, you can do so. Maybe you decided to store the modified spells with easy-to-memorize names? Then you’d do this:

COPY
	"%MOD_FOLDER%/fireball.spl" "override/spwi304.spl"
	"%MOD_FOLDER%/lightning_bolt.spl" "override/spwi308.spl"
(When do you put things in quote marks? Basically, whenever there are symbols other than letters and numbers involved. There’s a bit more to it than that, but you won’t go wrong with that rule.)

Thirdly, you can copy a whole directory at once. Let’s suppose you’ve decided to keep your mod folder tidy by creating a subfolder, overpowered_spells, in which you’ve placed your two spells. (This is generally good practice.) Then you can do the following to copy everything in that folder into the override:

COPY "%MOD_FOLDER%/overpowered_spells" "override"
(I actually don’t recommend you do this: it can end up copying things you don’t intend to copy, and there are more controlled ways to copy lots of files. But lots of people disagree.)

1.3 Compiling and extending scripts and dialogs

Scripts (suffix .bcs) are files that tell creatures (or occasionally objects, areas, or the whole game) what to do. For instance, WTASIGHT.BCS says ‘attack the nearest enemy’ and is used by lots of monsters. Dialogs (suffix.dlg) are files that tell creatures (or occasionally other things) what to say when you talk to them. The format of either file is beyond the scope of this course, but what matters here is that both scripts and dialogs are usually written in a human-readable form and then compiled into the form that the game uses. Scripts are stored as .baf files; dialogs are stored as .d files.

(The .baf -> .bcs compilation is built into the core game. The .d -> .dlg compilation is a creation of WEIDU. And d files are much more powerful than baf files, and can encode edits to existing dialogs or create multiple dialogs at once.)

This means that your mod will normally store dialog and script files in uncompiled form. You’ll compile them when you install the mod, like this:

COMPILE 
	"%MOD_FOLDER%/mybaf.baf"
	"%MOD_FOLDER%/mydlg.d"
Running this will take the ‘mybaf.baf’ file in your mod directory, compile it into mybaf.bcs, and dump it into the override directory; then it will compile ‘mydlg.d’ into ‘mydlg.dlg’ and again dump it into the override.

(You can in principle compile a whole directory, like with COPY. I recommend against this: you should have tighter control of what you’re compiling.)

Often you’ll want not to create an entire new script, but just to add a bit of code onto an existing script. That’s easy to do in WEIDU. This code adds ‘mybaf.baf’ to the top of the existing script ‘wtasight.bcs’:

EXTEND_TOP "wtasight.bcs" "%MOD_FOLDER%/mybaf.baf"

If you want to put your new code at the bottom instead, use EXTEND_BOTTOM.

1.4 Editing existing files

Sometimes your mod might want to alter an existing file rather than overwriting with a new one. (More sophisticated mods do this almost exclusively.) For instance, maybe you want Minsc to be a fighter with the Berserker kit, not a Ranger. For this, we need the COPY_EXISTING command. Here’s some code that does this (in BG1):

COPY_EXISTING 
	"minsc.cre" override
	"minsc2.cre" override
	"minsc4.cre" override
	"minsc6.cre" override
	"minsc7.cre" override
		WRITE_BYTE 0x273 1
		WRITE_LONG 0x244 0x4001
BUT_ONLY
IF_EXISTS
This is starting to look a bit more complicated; let’s break it down.

Firstly, we’re COPYing some EXISTING files: the four creature files minsc.cre, minsc2.cre, minsc4.cre and minsc6.cre that specify Minsc’s stats in BG1. (Which one is used depends on your own level when you meet him.) We’re not copying over our own new files this time; we’re copying existing game files.

Secondly, we’re giving WEIDU some instructions as to what to do to the file when we copy it. The WRITE_BYTE and WRITE_LONG commands alter Minsc’s stats to something new.

Thirdly, we’re telling WEIDU that it should only make the copy if something has actually changed. (‘BUT_ONLY’ is short for ‘BUT_ONLY_IF_IT_CHANGES’).

Fourthly, we're telling WEIDU that it should only carry out the copy if the file exists. ('IF_EXISTS' is short for 'BUT_ONLY_IF_IT_EXISTS'). Without this command, if the file isn't present then WEIDU will give an error message instead of installing.

So the overall form of the command is

COPY_EXISTING 
	file1 override
	file2 override
	…
		[patch commands]
BUT_ONLY
IF_EXISTS
The BUT_ONLY is optional, but it’s usually good form to leave it in. Whether you leave the IF_EXISTS or not depends on whether you actually want WEIDU to fail if it can't find a file. In the example above, 'minsc7.cre' exists in Siege of Dragonspear but not in BGEE without Siege of Dragonspear, so the IF_EXISTS conveniently lets this code work on both versions of BGEE. But if your mod actually needs a file to exist - or if you're confident it exists - it's usually better to leave out the IF_EXISTS, because then the mod will visibly fail to work rather than silently not working.

You can also use this syntax with ordinary COPY, incidentally, in case you want to alter the file you’re copying over from your own mod. (The BUT_ONLY and IF_EXISTS flags aren't necessary in this case.) Normally you’ll do this if you want its contents to depend on what other mods are installed.

How do the [patch commands] work? By default, WEIDU treats anything it’s copying just as a binary file. Files like this are lists of numbers, each in the 0-255 range, each with an ‘offset’ – how far through the file it is. The first number has offset 0, the second has offset 1, and so on. WEIDU’s basic patch commands just say: `go to offset this-offset and replace the number at that offset with this-number’.

By convention, in WEIDU we specify offsets, and often numbers, in hexadecimal: so the basic numbers are in the 0x00-0xff range. We do this because we want to deter newbs because the way files are organized makes hexadecimal offset easier to read and manipulate. (But you can skip this if you like and just use decimal: 0x273, for instance, is 627 in decimal.)

There are then four basic patch commands:

  • WRITE_BYTE [ind] [number] puts [number] (in the 0-255 range) into offset [ind]
  • a SHORT is an integer in the (0-255)2 range (or: two integers in the 0-255 range sequentially); WRITE_SHORT [ind] [number] puts [number] into the two slots following offset [ind]
  • a LONG is an integer in the (0-255)4 range (or: four integers in the 0-255 range sequentially); WRITE_LONG [ind] [number] puts [number] into the two slots following offset [ind]
  • an ASCII is a string of letters, numbers and other sequences; WRITE_ASCII [ind] ["string"] writes that string at offset ind, converting letters to their code numbers in the process.
(There are variants of these that apply if you want to write negative integers: WRITE_SBYTE, WRITE_SSHORT and WRITE_SLONG.)

In the example, the BYTE at 0x273 stores the creature’s class; setting it to 1 makes Minsc a fighter. The LONG at 0x244 stores the creature’s kit; setting it to 0x4001 makes Minsc a berserker. (You can look these up in Near Infinity or in the IESDP).

There are some subtleties about WRITE_ASCII that arise because a string might be of any length (whereas BYTEs, SHORTs and LONGs are of fixed length). Suppose, for instance, I want to swap Jaheir’s dialog file for a new file, ‘dwjah’, of my own devising. The dialog file lives in the sequence of 8 bytes at offset 0x2cc, so your natural guess as to how to do this might be

COPY_EXISTING 
	"jaheir.cre" override
		WRITE_ASCII 0x2cc "dwjah"
BUT_ONLY

The problem with this is that ‘dwjah’ only has five characters, so WEIDU only writes ‘dwjah’ over those five characters. But a dialog file name can be up to eight characters, and indeed Jaheira’s default dialog file is ‘jaheir’, which has six characters. So if you tried this code, Jaheira’s new script would be ‘dwjahr’ – the last character of the old script is still there. The solution is to specify the length of the ASCII write explicitly, like this:

COPY_EXISTING
	"jaheir.cre" override
		WRITE_ASCII 0x2cc "dwjah" (8)
BUT_ONLY
WEIDU now knows that you’re overwriting an 8-byte ASCII entry, and so it fills any remaining spaces with blanks.

Two more things about patching files before we move on. Firstly, WEIDU has quite a lot of offsets for the main file type pre-memorized (there’s a full list in section 15 of the main WEIDU readme). For instance, it knows the location of the dialog file is 0x2cc. When you’re writing to one of these offsets, you can use WEIDU’s pre-stored value of the offset instead of entering it manually, like this:

COPY_EXISTING 
	"jaheir.cre" override
		WRITE_ASCII DIALOG "dwjah" (8)
BUT_ONLY
This makes your code easier to read; it also makes it less error-prone. If you mistype the dialog offset as ‘0x2c’, WEIDU will happily patch the file, but it will be patched in the wrong place and will probably crash the game. If you mistype WEIDU’s name for it as ‘DIALOGUE’, your mod won’t install in the first place. (‘Install-time’ errors like this are much better than ‘run-time errors’ like the game crashing, because you can spot them much more easily when you test your mod.)

Secondly: you can also clone existing files to make new files. For instance, this code makes a copy of the Baldur’s gate basic hobgoblin with a different combat script.

COPY_EXISTING "hobgob.cre" "override/dwhobgob.cre"
	WRITE_ASCII SCRIPT_OVERRIDE "dwscript" (8)

1.5 Text and the dialog file

Let’s talk about altering in-game text: the names of characters and items, the descriptions of items and spells, and so forth. Suppose you want to alter Minsc’s name to ‘Minsc the Awesome’, for instance.

‘Minsc the awesome’ is a string, so you might guess that you need to do a WRITE_ASCII to minsc.cre. That’s not how it works. Text isn’t stored in individual files; it’s stored in a huge table called a dialog file. When the game wants to display Minsc’s name, it looks in the ‘name’ offset of minsc.cre and finds a LONG value, 9501. Then it goes to the dialog file, finds the entry labelled ‘9501’, and sees that it’s ‘Minsc’. There are a bunch of reasons the game works this way, but one main reason is that it makes translations into other languages easier. If you want a sword to be called ‘epee’ in French, you don’t need to alter the sword file itself, you just alter the text in the French version of the dialog file.

(The other main reason is that Minsc’s name might be arbitrarily long, so that if it was stored directly in his CRE file, that file would have to cope with variable-length fields. As it is, the NAME field can be fixed to be four bytes long.)

What all this means is that we need to get ‘Minsc the Awesome’ into the dialog file with a new number, get that number, and then put the number into the right offset in minsc.cre. Fortunately, WEIDU makes this pretty simple: you just do this:

COPY_EXISTING
	"minsc.cre" override
	"minsc2.cre" override
	"minsc4.cre" override
	"minsc6.cre" override
		SAY NAME1 "Minsc the Awesome"
		SAY NAME2 "Minsc the Awesome"
BUT_ONLY

This ‘SAY’ command has the general form ‘SAY [offset] [string]’ (here we’re using WEIDU’s prememorized offsets for the two ‘name’ fields in a .cre file). When you use it, WEIDU looks in the dialog file for "Minsc the Awesome". If it finds it, it writes the number of that string into [offset]. If it doesn’t find it, it adds "Minsc the Awesome" to the dialog file with a new number, and then writes that number into [offset]. In this case, we’re using the same string twice. The first time, it gets added to the dialog file; the second time, it’s already there, so we just reuse the first value.

(Editing the dialog file in a friendly way was the original selling point of WEIDU, 20 years ago. Before WEIDU, mods had to distribute their own copies of the dialog file, which meant that no two mods could both change in-game text.)

1.6 Translation files

Actually, the simple method of entering in-game text mostly isn’t used by well-designed mods. The reason is, again, translation. If you write "Minsc the awesome" into your mod directly, translating your mod into another language means distributing a new version of the mod. It’s better instead to take a leaf out of Baldur’s Gate’s book and use your own version of a dialog file.

Here’s how this works. Firstly, you need to create a file called a ‘tra’ file for each language you’re using. Unless you’re multilingual, probably you’ll only create a tra file for one language; I’ll assume it’s English. The tra file should have a name like ‘setup.tra’, can be created in a text editor, and is going to look like this:

@1="Minsc the Awesome"
@2="Rename Minsc so he’s awesome"
@3="A third string that we don’t need"

Secondly, you need to put this tra file into your mod. There are fairly specific rules as to where to put this file. You should:

  • Create a folder inside your mod folder with a name like ‘tra’, ‘lang’, or ‘languages’. (I’ll use ‘lang’ in this course.)
  • Create a folder inside ‘lang’ named for your language, in this case English.
  • Put your tra file inside that folder.

Thirdly, you need to alter your tp2 file to tell WEIDU where the tra file is. Because this applies for the whole mod, it’s done in the preamble, not in a component. (Everything else we’ve done so far is inside a component.) Here’s how we’ll do it:

BACKUP "weidu_external/mymod/backup"
AUTHOR "Myname (my email address)"
AUTO_EVAL_STRINGS

/// Language options
LANGUAGE 
"English"  
"english" 
"mymod/lang/english/setup.tra"

/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN "the first component" DESIGNATED 100 
/////////////////////////////////////////////////////////////////////////////////////////////////////
…

The line under ‘LANGUAGE’ has three parts to it. The first is how the language is described to the person installing the mod. The second is the name of the folder in which you’re storing your tra files. The third is the path to your tra file.

(By the way, you can’t (safely) use %MOD_FOLDER% in these LANGUAGE commands, due to a glitch in WEIDU (see here for more). You have to enter ‘mymod’ manually.)

Since there’s only one LANGUAGE command entered here, WEIDU will just automatically pick English when you install the mod. But you can now refer to strings in the tra file in your components, like this:

COPY_EXISTING 
	"minsc.cre" override
	"minsc2.cre" override
	"minsc4.cre" override
	"minsc6.cre" override
		SAY NAME1 @1
		SAY NAME2 @1
BUT_ONLY

When you write @1 WEIDU looks up the first string in your tra file and uses it. So now you’ve moved the string out of your main code and into the tra file. The power of this now comes when someone translates your mod into (say) French. They’ll create their own setup.tra and send it to you, and you’ll put it in a ‘french’ subfolder of the ‘lang’ folder; it will look something like

@1="Minsc le genial"
@2= "renommer Minsc tellement il est genial"

(I don't actually speak French, and these are from Google Translate, so don't take them too seriously!)

Then you’ll expand your LANGUAGE declaration to look like this:

/// Language options
LANGUAGE 
"English"  
"english" 
"mymod/lang/english/setup.tra"
LANGUAGE
"French (translation by Google Translate)"
"french"
"mymod/lang/english/setup.tra" "mymod/lang/french/setup.tra"

Now we have a second LANGUAGE block that defines French. It includes the text to display to the player, the variable to set, and the path to the French translation. Perhaps surprisingly, it also contains a second path, to the English tra file. This is a backup: in case your translator has missed a line, the English translation gets used instead. (For large mods, or mods that are updated frequently, sometime the translation can get out of sync.) The English backup is listed first, because WEIDU loads tra files in order and overwrites earlier ones with later ones.

Now if someone installs your mod, they’ll be offered the choice at the start of English or French. And WEIDU will use the tra file appropriate to their language.

You can put @ commands into your .d and .baf files, and WEIDU will slot in the correct strings when you compile those files. You can also use @ commands in the names of your components, so that they also get translated. Here’s the complete ‘awesome Minsc’ mod, making this change too:

BACKUP "weidu_external/mymod/backup"
AUTHOR "Myname (my email address)"
AUTO_EVAL_STRINGS

/// Language options
LANGUAGE 
"English"  
"english" 
"mymod/lang/english/setup.tra"
LANGUAGE
"French (translation by Helen)"
"french"
"mymod/lang/english/setup.tra" "mymod/lang/french/setup.tra"


/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN @2 DESIGNATED 100  // Make Minsc awesome
/////////////////////////////////////////////////////////////////////////////////////////////////////

COPY_EXISTING 
	"minsc.cre" override
	"minsc2.cre" override
	"minsc4.cre" override
	"minsc6.cre" override
		SAY NAME1 @1
		SAY NAME2 @1
BUT_ONLY

Problems with charsets

One nasty problem in working with multiple languages – or indeed, working with any language that has accents, umlauts, or non-Latin characters, i.e. most languages other than English – is that there are different encoding conventions for how these languages are stored in text files. The Enhanced edition of Baldur’s Gate uses a UTF-8 convention; the original one uses (I think) ISO-8859.

If you are working with only one version of the game (probably the Enhanced Edition) this isn’t too difficult to handle: just make sure your tra files are in that game’s encoding, probably UTF-8. (Your text editor program will have some option to set this.) If you want to make your mod compatible with old and new versions of the game it’s quite a bit more complicated; see here.

1.7 Using multiple translation files

Especially as your mod gets more complicated, you may want to break your tra file into multiple components. In particular, it’s common practice for each dialog file to have its own associated tra file.

USING commands

If you’re compiling or extending dialogs or scripts, this is pretty easy: you just specify the tra file you want to use using a ‘USING’ command, like this:

COMPILE "%mymod%/mydlg.d" USING "%MOD_FOLDER%/english/mymod.tra"

When you run this bit of code, WEIDU loads the mymod.tra tra file from mymod/English, and uses those strings in preference to any tra file you’ve already loaded. You can put a USING command at the end of an EXTEND_TOP or EXTEND_BOTTOM too.

You may have noticed a limitation here: by specifying the whole path to the tra file we’ve hardcoded English as our preferred language. That’s easy to work around: just do this:

COMPILE "%mymod%/mydlg.d" USING "%MOD_FOLDER%/%s/mymod.tra"
WEIDU replaces ‘%s% with the correct language folder.

AUTO_TRA

There is a systematic shortcut specifically for dialog files. If you put ‘AUTO_TRA "[path to your language directory]’ in the preamble of your mod, like this:

BACKUP "weidu_external/mymod/backup"
AUTHOR "Myname (my email address)"
AUTO_EVAL_STRINGS
AUTO_TRA "%MOD_FOLDER%/lang/%s"
Then every dialog file will automatically load a tra file matching its own name from the directory specified by AUTO_TRA. If you are using AUTO_TRA, then when you compile ‘this_dlg.d’ then WEIDU will check for ‘this_dlg.tra’ without you having to specify a USING command manually. Note that you can again use the '%s' shortcut to point to the language directory of your chosen lagnuage.

More advanced dialog loading

You can also load a dialog file manually. The following code loads ‘awesome.tra’ from your language directory, and also (as a backup) from the English language directory:

WITH_TRA
 "%MOD_FOLDER%/english/awesome.tra" 
"%MOD_FOLDER%/%LANGUAGE%/awesome.tra"
BEGIN
.. some comands
END

awesome.tra is forgotten as soon as you get to the ‘END’ command. If you want to load it permanently, do this instead:

LOAD_TRA
 "%MOD_FOLDER%/english/awesome.tra" 
"%MOD_FOLDER%/%LANGUAGE%/awesome.tra"
(In my view, it’s tidier and safer to only load tra files as long as you need them, so I normally use WITH_TRA, but different people have different preferred styles.)

1.8 More on editing existing files: WEIDU’s built-in file-editing tools

The basic editing tools – WRITE_LONG, WRITE_ASCII, SAY, etc – are pretty limited in what they let you do, basically because they only work if you know in advance exactly which offset to edit. That’s fine for fields like names, creature scripts, or soundsets, which always occur at the same offset. But most of the data stored in game files might be stored in different offsets for different files of the same type. For instance, a store can hold arbitrarily many items, so there can’t just be a fixed offset for, say, the 10th item in the store. That means that if, say, you want to add a new item to a store, WRITE_LONG and friends aren’t up to the job.

Systematically learning how to edit these features of game files requires more advanced WEIDU than we’re covering in this chapter. But WEIDU has built-in tools to do many of the most common edits. For instance, adding that item to a store is done like this:

COPY_EXISTING sto4803.sto override
	ADD_STORE_ITEM "dw_wnd01" #10 #0 #0 IDENTIFIED #3
BUT_ONLY

This adds 3 copies of ‘dw_wnd01’ to the store (it’s the Nashkel store, as it happens), each with 10 charges. See the main WEIDU readme for full documentation.

There are lots of these built-in tools. As of WEIDU v249, here’s the list (most have self-explanatory names):

  • ARE files
    • ADD_MAP_NOTE
  • CRE files
    • ADD_KNOWN_SPELL
    • ADD_MEMORIZED_SPELL
    • REMOVE_KNOWN_SPELL
    • REMOVE_KNOWN_SPELLS (removes all known spells)
    • REMOVE_MEMORIZED_SPELL
    • REMOVE_MEMORIZED_SPELLS (removes all memorized spells)
    • SET_BG2_PROFICIENCY
    • ADD_CRE_ITEM
    • REPLACE_CRE_ITEM
    • REMOVE_CRE_ITEM
    • REMOVE_CRE_ITEMS (removes all items)
  • STO files
    • ADD_STORE_ITEM
    • REMOVE_STORE_ITEM
You can find instructions on all of them in the main WEIDU documentation.

You can go vastly beyond the built-in tools by using the range of functions that ship with WEIDU, but that’s for a later chapter.

1.9 Other useful tricks

Comments

Any text following two or more ‘/’ is ignored. So is any text between ‘/*’ and ‘*/’. You can use this to comment your code and make it easier to read. For instance

/* 
this code
will make Minsc
into ‘Minsc the Awesome’
*/
COPY_EXISTING "minsc.cre" // need to add minsc2, etc, later
	// here’s Minsc’s first name entry
	SAY NAME1 @1
	// here’s Minsc’s second name entry
	SAY NAME2 @1
BUT_ONLY

Inlining files

Sometimes it’s convenient not to have to put text (e.g., a script) into a separate file, but instead to include it in your main TP2. (That’s mostly the case for very short bits of text.) You can do this through ‘inlined files’, basically files that are included in your tp2 but which WEIDU treats as actual files. Here’s an example:

<<<<<<<<.../mymod-inlined/minsc_add.baf
IF
	See(NearestEnemyOf(Myself))
Delay(10)
THEN
	RESPONSE #100
		DisplayStringHead(Myself,@1) // ‘I’m AWESOME!’
END
>>>>>>>>
(That’s eight ‘<’ at the start, and eight ‘>’ at the end.) The file name, here ‘…/mymod-inlined/minsc_add.baf’, can be anything you like, but it needs to be unique – you shouldn’t use it elsewhere yourself, and you should be sure no-one else will use it. Hence the usual convention (used here) is to call it ‘.../[my mod name]-inlined/[file name].

Once the inlined file is defined, you can use it at any later point in your code, such as:
EXTEND_TOP "minsc.bcs" ".../mymod-inlined/minsc_add.baf"

Breaking up your code with INCLUDE

It can get messy putting all of your code into one very long TP2. To make it more manageable, you can put some bits of your code in separate files. (Normal convention is to have them end in ‘.tph’ or ‘tpa’ but you can do whatever you like.) You can then use ‘INCLUDE [file-path]’ in your main tp2 and WEIDU will just insert the code and treat it as if it was just part of the original tp2.

Here’s an example of a mod where all the content has been moved into INCLUDEd files like this. (That’s my own preferred way of writing mods.)

BACKUP "weidu_external/mymod/backup"
AUTHOR "Myname (my email address)"
AUTO_EVAL_STRINGS

/// Language options
LANGUAGE 
"English"  
"english" 
"mymod/lang/english/setup.tra"

/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN @2 DESIGNATED 100  // Make minsc awesome
/////////////////////////////////////////////////////////////////////////////////////////////////////

INCLUDE "%MOD_FOLDER%/lib/awesome_minsc.tph" 

/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN @3 DESIGNATED 200  // Make tiax less annoying
/////////////////////////////////////////////////////////////////////////////////////////////////////

INCLUDE "%MOD_FOLDER%/lib/less_annoying_tiax.tph" 

Quote marks

I have been using " for quotations in examples so far. But WEIDU is just as happy using ~ or % to begin and end quotations, which can be useful if you want to include an actual " sign in a string:

~I said, "Minsc is awesome!"~
%Two of the three WEIDU quote marks are ~ and ". %

Very occasionally even that doesn’t work, in which case you can use five consecutive tildes, ~~~~~, as a quote mark:

~~~~~The three basic quote marks in WEIDU are ~, " and %. ~~~~~ 

1.10 Putting it all together

Here’s an example of a mod that uses most of these techniques:

BACKUP "weidu_external/dw_awesome/backup"
AUTHOR "DavidW (my email address)"
AUTO_EVAL_STRINGS

/// Language options
LANGUAGE 
"English"  
"english" 
"dw_awesome/lang/english/setup.tra"
LANGUAGE
"French (translation by Google Translate)"
"french"
"dw_awesome/lang/english/setup.tra" "dw_awesome/lang/french/setup.tra"


/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN @1 DESIGNATED 100  // Rename Minsc to be awesome and make him a berserker
/////////////////////////////////////////////////////////////////////////////////////////////////////

WITH_TRA
	"%MOD_FOLDER%/dw_awesome/english/awesome_name.tra"
	"%MOD_FOLDER%/dw_awesome/%LANGUAGE%/awesome_name.tra"
BEGIN

	COPY_EXISTING 
		"minsc.cre" override
		"minsc2.cre" override
		"minsc4.cre" override
		"minsc6.cre" override
			SAY NAME1 @1
			SAY NAME2 @1
			WRITE_BYTE 0x273 1 // class=fighter
			WRITE_LONG 0x244 0x4001 // kit=berserker			
	BUT_ONLY
END // end of the WITH_TRA command

/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN @2 DESIGNATED 200  // give Minsc an awesome battle cry
/////////////////////////////////////////////////////////////////////////////////////////////////////

<<<<<<<<.../dw_awesome-inlined/minsc_add.baf
IF
	See(NearestEnemyOf(Myself))
	Delay(10)
THEN
	RESPONSE #100
		DisplayStringHead(Myself,@1) // ‘I’m AWESOME!’
END
>>>>>>>>

EXTEND_TOP "minsc.bcs" ".../dw_awesome-inlined/minsc_add.baf" 
	USING "%MOD_FOLDER%/%s/awesome_cry.tra"

/////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN @3 DESIGNATED 300  // give Minsc an awesome new sword
/////////////////////////////////////////////////////////////////////////////////////////////////////

WITH_TRA
	"%MOD_FOLDER%/dw_awesome/english/awesome_sword.tra"
	"%MOD_FOLDER%/dw_awesome/%LANGUAGE%/awesome_sword.tra"
BEGIN
	// make the sword
	COPY_EXISTING "sw1h06.itm" "override/dw_swda.itm" // just a copy of Varscona, renamed
		SAY NAME2 @1
		SAY IDENTIFIED_DESC @2

END // end of the WITH_TRA command

	// give it to Minsc

COPY_EXISTING 
	"minsc.cre" override
	"minsc2.cre" override
	"minsc4.cre" override
	"minsc6.cre" override
		ADD_CRE_ITEM "dw_swda" #0 #0 #0 IDENTIFIED WEAPON EQUIP	
BUT_ONLY