Jump to content

Crossing the Great Divide


Recommended Posts

Crossing the Great Divide: Single-source modding for Tutu, BGT, and Beyond

A Beginner's Introduction to Coding for both Tutu and BGT

We have two solid, viable approaches to playing Baldurs Gate using the BG2 engine. Currently, it is common practice to build your mod for one or the other, and then convert the program (either manually, or by asking Ascension64 to assist). This is great for the community, allowing both audiences the content of your mod. It also leaves you with a challenge; maintaing two sets of code, one of which you may not quite understand. After all, someone else converted it!

 

Luckily for us, only three obstacles fall in the path of writing just one code to cover both platforms; resource/file names, chapter numbers, and actual state numbers. The vast majority of coding can be used on both Tutu and BGT. Baldurs Gate (BG1) is a different matter, as the scripting actions and triggers available differ, so for now we will deal with just Tutu and BGT).

 

The ideas used in this tutorial are currently utilized in The BG1 NPC Project internal versions. The ideas are compiled from many different modders in both the BGT and Tutu modding circles, and represent one way of consolidating some of the best ideas from the IE Modding community. It assumes the following:

  1. It seems easier for folks to read/check plain language long names than to remember area numbers or script/dialogue names.
  2. It seems easier to code using one file and "transparently" adapt to different installs on install.
  3. It appears either quicker or the same to use a single EVALUATE_BUFFER then it is to process multiple platform pairings of copy/patch actions on any computer capable of running BG2.
  4. It is easiest to code your ideas when you have had almost all the legwork done for you in a template, so you can copy/paste and concentrate on the important stuff... writing your story, for others to enjoy.

Part 1. An Introduction to The Magic of Variables

For us non-codewarriors, OUTER_SPRINT might as well be Swahili. Using variable substitution looks like magic. Here is the good news; variables are just cool ways of swapping out one thing for another. A good example is making a good salad. We can create one using lettuce, nuts, and fruit. To make things more specific, we can use lettuce, walnuts, and apples; or we can use lettuce, hazelnuts, and oranges. The placeholders "fruit" and "nuts" can be defined many different ways.

We can do this using WeiDU relatively easily. Let's start with an example, a check to see if your actor is in a specific area.

In your myMod.BAF file, you might have the code (simplifed for examples)

IF
AreaCheck("FW1900")
InParty("cmorgan")
THEN
RESPONSE #100
SetGlobal("CmorganInBanditCamp","GLOBAL",1)
END

In Tutu, areas are named differently from BGT, so the Bandit Camp in Tutu is FW1900, while in BGT it is AR8700. Wouldn't it be nice if we could just tell the darned mod that we want "BanditCamp" as the area? Then we have a nice, readable name. So let's use WeiDU to make this happen.

We can declare BanditCamp a variable, by putting it in %'s: %BanditCamp%. So far, so good. Now we just write our code,

IF
AreaCheck("%BanditCamp%")
InParty("cmorgan")
THEN
RESPONSE #100
SetGlobal("CmorganInBanditCamp","GLOBAL",1)
END

"Whooot!", you say,"wicked easy! I can do that!" except... we need to tell WeiDU what possible values there are for %BanditCamp%. Right now, there is nothing there. You have said "fruit" without defining when you want "fruit" to be "apple", and when you want it to be "orange".

So back to WeiDU. The first step is to tell the player's machine that we want to substitute things in the tp2.

ACTION_IF FILE_EXISTS_IN_GAME ~FW0100.ARE~ THEN BEGIN

tells WeiDu to check to see if the player has the file FW0100.are in their install. Since this is only on Tutu installs, we can now say "ok, we want fruit=apple":

OUTER_SPRINT "BanditCamp" "FW1900"

Now we have something! On a Tutu install, WeiDU will see %BanditCamp%, and will understand it as FW1900. But we still need to help out the BGT side:

END ELSE BEGIN

tells WeiDU to stop the section where the Tutu file exists. If it didn't exist, then it is ok to go ahead and use the BGT value:

OUTER_SPRINT "BanditCamp" "AR8700"

After we close this action, the resulting code looks like this:

ACTION_IF FILE_EXISTS_IN_GAME ~FW0100.ARE~ THEN BEGIN
 OUTER_SPRINT "BanditCamp" "FW1900"
END ELSE BEGIN
 OUTER_SPRINT "BanditCamp" "AR8700"
END

And voila - you have now told WeiDU "If Tutu is the install, say FW1900 for %BanditCamp%; if it is not Tutu, say AR8700 for %BanditCamp%".

 

Part 2. WeiDU's Magic SaladSpinner

If you are with me so far, there is really only one more step to making the variables work. You have to tell WeiDU to actually use the definitions for the variables. You have fruit=apple or fruit=orange, but you haven't actually put them in the salad.

The easiest way of doing this is to use EVALUATE_BUFFER. We do this:

ACTION_IF FILE_EXISTS_IN_GAME ~FW0100.ARE~ THEN BEGIN
 OUTER_SPRINT "BanditCamp" "FW1900"
END ELSE BEGIN
 OUTER_SPRINT "BanditCamp" "AR8700"
END

COMPILE EVALUATE_BUFFER  ~myMod/BAF/myBAF.BAF~

EVALUATE_BUFFER is taking your original file and running it through WeiDU's SaladSpinner. WeiDU compiles the file and, well, "evaluates the buffer". Basically, it creates a new file, translated into whatever the player's install type is, based on what you have defined. Remember, while myDialogue.D is able to use AUTO_TRA, myBaf.BAFs are not, so if you had text to display you would add the command USING:

ACTION_IF FILE_EXISTS_IN_GAME ~FW0100.ARE~ THEN BEGIN
 OUTER_SPRINT "BanditCamp" "FW1900"
END ELSE BEGIN
 OUTER_SPRINT "BanditCamp" "AR8700"
END

COMPILE EVALUATE_BUFFER ~myMod/PLATFORM/myBAF.BAF~
 USING ~myMod/TRA/myBAF.tra

For a list of values to declare, and a copy of an operational ALWAYS section of a tp2 that uses this method set up for your Copy & Paste (or study and change) pleasure, follow this link to the G3 Development Wikki for OUTER_SPRINT Tutu and BGT values. OK, so that is pretty straightforward... now how about myMod.D files? After all, those resources are different. What do we do here?

Well, let's start backwards. You can use the single line COMPILE EVALUATE_BUFFER for both .D and .BAF files:

ACTION_IF FILE_EXISTS_IN_GAME ~FW0100.ARE~ THEN BEGIN
 OUTER_SPRINT "myVariable" "TutuValue"
END ELSE BEGIN
 OUTER_SPRINT "myVariable" "BGTValue"
END

COMPILE EVALUATE_BUFFER  ~myMod/DLG/myDialogueFile.D~

You can extend the variable substitution pretty much as far as you want. For example, there are different assigned NPC Banter files between versions. Easy - just declare what you want them to be up front. You declare any and all things that you want to change between the two versions.

In the file myMod.tp2,

ACTION_IF FILE_EXISTS_IN_GAME ~FW0100.ARE~ THEN BEGIN
/* so if WeiDU sees one it doesn't 'hiccup' */
OUTER_SPRINT "percentage_sign" "%"
/* BGT-only shutdown of D and BAF after BG1 content */
/* note the alternate ~, so we can use " in our variable */
OUTER_SPRINT ~BGT_VAR~ ~~
/* DVs are the same for Tutu/BGT, except for Imoen */
OUTER_SPRINT "IMOEN_DV" "imoen"
/* Set Tutu BanterFiles */
OUTER_SPRINT "SAFANA_BANTER" "_BSAFAN"
END ELSE BEGIN
/* so if WeiDU sees one it doesn't 'hiccup' */
OUTER_SPRINT "percentage_sign" "%"
/* BGT-only shutdown of D and BAF after BG1 content */
/* note the alternate ~, so we can use " in our variable */
OUTER_SPRINT ~BGT_VAR~ ~!Global("ENDOFBG!","GLOBAL",2)~
/* DVs are the same for Tutu/BGT, except for Imoen */
OUTER_SPRINT "IMOEN_DV" "imoen2"
/* Set Tutu BanterFiles */
OUTER_SPRINT "SAFANA_BANTER" "BSAFAN"
END

By declaring anything that changes between the two mods as a variable, we can set up both BAF and D files for single-file cross-platform usage.

Using the variables declared above, we can do some interesting things. The most entertaining is a full Global check for a trigger that only needs to show up on one side. Tutu folks don't want to add unnessesary Global chacks, but BGT folks need BG1 content to shut down and not clutter up their BGT game. Irreconcileable differences? Divorce? Alimony? I say verily unto thee *NO*!

IF %BGT_VAR%
Global("EdwinGetsFleas","GLOBAL",2)
InParty("edwin")

compiles as

IF
Global("EdwinGetsFleas","GLOBAL",2)
InParty("edwin")

on Tutu, and

IF
!Global("ENDOFBG1","GLOBAL",2)
Global("EdwinGetsFleas","GLOBAL",2)
InParty("edwin")

on BGT.

Imoen is the only different dv between platforms, but that doesn't stop us using only one file:

== ~%IMOEN_JOINED%~ IF ~InParty("%IMOEN_DV%") InMyArea("%IMOEN_DV%") !StateCheck("%IMOEN_DV%",CD_STATE_NOTVALID)~ THEN ~Plus, folks can just copy and paste this code.~

becomes Tutu's

== ~_IMOEN2~ IF ~InParty("imoen") InMyArea("imoen") !StateCheck("imoen",CD_STATE_NOTVALID)~ THEN ~Plus, folks can just copy and paste this code.~

and BGT's

== ~IMOEN2~ IF ~InParty("imoen2") InMyArea("imoen2") !StateCheck("imoen2",CD_STATE_NOTVALID)~ THEN ~Plus, folks can just copy and paste this code.~

(((Advanced note: while we could just declare the underscore blank for BGT and _ for Tutu and use this everywhere, we don't want to do this with resources that we want to be able to easily read and troubleshoot, especially when some require major modification. This idea means the big consistent items are fully declared, like %VICONIA_BCS%.bcs)))

 

Part 3. Translating Translation Files

OK, well, what about my Translation files?

Well, other than sound references and your actual tp2 if you are reassigning sounds or using percent signs (%), .tra files do not need manipulation. If you have AUTO_TRA set, your COMPILE EVALUATE_BUFFER will happily chug away, and WeiDU will use the correct .tra references.

The main exception is if you are calling existing sound references from BG1. Mod-added sounds and BG2 sounds will reference directly without manipulation, but a line that calls on existing BG1 sound references looks like this on Tutu

@204  = ~[ZOMBIE 03]~ [_ZOMBI03]

and this on BGT

 @204  = ~[ZOMBIE 03]~ [ZOMBI03]

If you use BG2 resources, you do not need to evaluate the .tra file. If you want to create this, though,

@204  = ~[ZOMBIE 03]~ [%tutu_var%ZOMBI03]

you will also need to set any item descriptions that use things like "+10% Electrical Resistance", so that WeiDU will not start looking on the wrong side of the percent sign, and happily create all your creatures with corrupted sound references of %TUTU_VA (the first eight places of the variable). If you need to evaluate your .tra file(s) for your target platform, you need an extra manipulaton.

The first step here is to understand that WeiDU needs a variable-free zone to start up. For that, we separate the initial .tra into a setup.tra and a myMOD.tra. In setup.tra we put all the strings that have to do with component names, error messages, etc., etc., and we have no variables at all.

Here is a sample of a setup.tra:

@1000  = ~Tutu detected: support at www.gibberlings3.net.~
@1001  = ~BGT detected: support at www.spellholdstudios.net.~
@1002  = ~This mod should be installed in your BG2, Tutu, EasyTutu, or BGT folder, after Tutu/BGT conversion.~
@1003  = ~Please remember to start a new game to access the contents of this component.~
@1004  = ~BG1 NPC Required Changes component is not installed.~
@1005  = ~The BG1 NPC Project: Required Modifications for v12 Beta4, March 10, 2007~
@1006  = ~The BG1 NPC Project: Banters, Quests, and Interjections~

In myMod_tmp.tra, we put item descriptions, creature .tra references, and anything we want to have use variables. We can then evaluate this secondary file on install, renaming it myMod.tra so that AUTO_TRA can do its job. Sample from myMod_tmp.tra:

@77   = ~This is a plain looking short spear with a leaf-shaped point. It was balanced for a slender elven hand. Mage Thalantyr enchanted the weapon for Kivan of Shilmista.

STATISTICS:

Combat Abilities:
10%percent% chance with every hit that opponent is entangled for 24 seconds, no save
THAC0: +2 bonus
Damage:  1D6 +2
Damage type:  piercing
Weight: 3
Speed Factor: 4
Proficiency Type: Spear
Type:  2-handed
Requires: 5 Strength
Only Usable By: Elves
Not Usable By:
Cleric
Mage~
@93   = ~  Prepare to meet your DOOOOM!  heh...~ [JANJAN11]
@253  = ~[WOLF, DIRE 03]~ [%tutu_var%DWOLF03]
@346  = ~Flaming Fist Officer~

Here's a breakdown of the code to use the above .tra files. In the ALWAYS section of the .tp2,

  /* prep tras for sound references */
 COPY ~BG1NPC/TRA/%LANGUAGE%/BG1NPC_tmp.tra~ ~BG1NPC/TRA/%LANGUAGE%/BG1NPC.tra~
   EVALUATE_BUFFER
 LOAD_TRA ~BG1NPC/TRA/%LANGUAGE%/BG1NPC.tra~

Here we copy an unevaluated temporary file with variables to a new file where the variables have all been evaluated for the player's platform. We do this so that we do not overwrite the original file, and so that the file ends up named the same as the .tp2 for AUTO_TRA.

In the language declaration section,

/* Language Settings */
AUTO_TRA ~BG1NPC/TRA/%s~
LANGUAGE ~English~ ~english~ ~BG1NPC/TRA/english/setup.tra~

This tells WeiDU that the "clean" file is called "setup.tra", and that it should start with setup.tra, then follow on with the evaluated myMod.tra file that we just created. The final code would look like this:

/* Backup folder */
BACKUP ~BG1NPC/backup~
/* Author */
AUTHOR ~The BG1 NPC Project Team~

ALWAYS
 ACTION_IF FILE_EXISTS_IN_GAME ~FW0100.ARE~ THEN BEGIN
OUTER_SPRINT "BanditCamp" "FW1900"
 END ELSE BEGIN
OUTER_SPRINT "BanditCamp" "AR8700"
 END

 /* prep tras for sound references */
 COPY ~BG1NPC/TRA/%LANGUAGE%/BG1NPC_tmp.tra~ ~BG1NPC/TRA/%LANGUAGE%/BG1NPC.tra~
   EVALUATE_BUFFER
 LOAD_TRA ~BG1NPC/TRA/%LANGUAGE%/BG1NPC.tra~

 /* launch the ReadMe file on exit from install */
 AT_INTERACTIVE_EXIT ~VIEW BG1NPC/BG1NPCReadMe.html~
END

/* Language Settings */
AUTO_TRA ~BG1NPC/TRA/%s~
LANGUAGE ~English~ ~english~ ~BG1NPC/TRA/english/setup.tra~

Some coding notes; we need to reload the .tra after evaluating it, so that WeiDU knows that changes have been made. We use the ALWAYS section because we want this run even if the player only decides to use Component #750, or comes back and reruns the installer and modifies the install. The AT_INTERACTIVE_EXIT waits until the mod has finished its business and then launches the ReadMe for the user to ignore :).

 

Part 4. Give Me the Code, and I'll Change The (Fantasy) World.

Let's see some examples of this in practice. The following code samples are based on The BG1 NPC Project files, and represent an extreme usage of this idea. For the setup of variables, and plenty of data to use for cut and paste into your own mod, materials on the G3 Development Wikki provide the values for the next block of code.

tp2 setting flags: example of usage for area variables

/* Area Flagging */
/* OUTDOOR ONLY: Tutu and BGT */
COPY_EXISTING ~%GnollStronghold%.are~ ~override~
		  ~%NashkelMines%.are~ ~override~
		  ~%FriendlyArmInn%.are~ ~override~
		  ~%Temple%.are~ ~override~
		  ~%NashkelCarnival%.are~ ~override~
 READ_BYTE  "0x48" "flags"
 WRITE_BYTE "0x48" ("%flags%" BOR "0b00000001")
 BUT_ONLY_IF_IT_CHANGES

For an expanded sample set of code for patching all areas, please follow this link to the G3 Development Wikki showing actual code in use.

Sample Banter CHAIN using this idea

In this next example, we have set everything between to % signs at the top of the tp2. The values used here were set in the ALWAYS section described here.

In myMod.tp2,

 COMPILE EVALUATE_BUFFER ~myMod\DLG\AddBanterToImoen.D~

in AddBanterToImoen.D

CHAIN 
IF WEIGHT #-1 ~%BGT_VAR% Global("UseNewCrossmodVariables","GLOBAL",0) 
GlobalGT("Chapter","GLOBAL",%tutu_chapter_3%) 
InParty("%IMOEN_DV%")
InMyArea("%IMOEN_DV%")
!StateCheck("%IMOEN_DV%",CD_STATE_NOTVALID)
InParty("alora")
InMyArea("alora")
!StateCheck("alora",CD_STATE_NOTVALID)~ ~%IMOEN_BANTER~ RandomlyCalledBanterFileEntry1
~I am going to try that new variable substitution in a random banter, Alora.~ 
== ~%ALORA_BANTER%~ IF ~InParty("alora") InMyArea("alora") !StateCheck("alora",CD_STATE_NOTVALID)~ THEN ~I want to interject too!~
== ~%IMOEN_BANTER%~ IF ~InParty("%IMOEN_DV%") InMyArea("%IMOEN_DV%") !StateCheck("%IMOEN_DV%",CD_STATE_NOTVALID)~ THEN ~Here I respond again!~
== ~%ELDOTH_BANTER%~ IF ~InParty("eldoth") InMyArea("eldoth") !StateCheck("eldoth",CD_STATE_NOTVALID)~ THEN ~Idiots.~
== ~%XAN_BANTER%~ IF ~InParty("xan") InMyArea("xan") !StateCheck("xan",CD_STATE_NOTVALID)~ THEN ~We are all doomed.~
== ~%MINSC_BANTER%~ IF ~InParty("minsc") InMyArea("minsc") !StateCheck("minsc",CD_STATE_NOTVALID)~ THEN ~Boo want's to interject too!~
== ~%VICONIA_BANTER%~ IF ~InParty("viconia") InMyArea("viconia") !StateCheck("viconia",CD_STATE_NOTVALID)~ THEN ~Stupid surface-dwellers.~
END
++ ~There, that wasn't so bad, and you can just copy and paste!~ DO ~SetGlobal("UseNewCrossmodVariables","GLOBAL",1)~ EXIT
++ ~I dunno about this...~ DO ~SetGlobal("UseNewCrossmodVariables","GLOBAL",1)~ EXTERN ~%EDWIN_BANTER%~ Naysayers1
++ ~I think I need a second opinion.~ DO ~SetGlobal("UseNewCrossmodVariables","GLOBAL",1)~ EXTERN ~%DYNAHEIR_BANTER%~ Yeasayers1

CHAIN ~%EDWIN_BANTER%~ Naysayers1
~This is beneath even you, <CHARNAME>. (Simians. When I learned coding, we still had to write all strings hardcoded in ASCII and insert them using a hex editor!).~
== ~%DYNAHEIR_BANTER%~ IF ~InParty("dynaheir") InMyArea("dynaheir") !StateCheck("dynaheir",CD_STATE_NOTVALID)~ THEN ~*casts Silence, 10' radius*~
== ~%EDWIN_BANTER%~ IF ~InParty("dynaheir") InMyArea("dynaheir") !StateCheck("dynaheir",CD_STATE_NOTVALID)~ THEN ~...~
END
IF ~~ THEN JOURNAL ~Banters down, now Called States from Joined Dialogue File and BCS.~ EXIT

"HEY!", you say, "Wait a minute!". There was an odd looking variable back there -

%tutu_chapter_3%

"What the heck is *that*?" Well, take a look at the end of the discussion, under Advanced Considerations, and I will tell you. But for now, let's keep on task.

For a fully coded example using the values declared in the sample OUTER_SPRINT section, ready for cut and paste for all BG1 NPCs,follow this link to the G3 Development Wikki.

Sample Called Dialogue from BCS and D using this idea

Again, this sample uses the OUTER_SPRINT values set by the sample section.

In the file myMod.tp2

EXTEND_BOTTOM ~%IMOEN_BCS%.bcs~ ~myMod\BAF\AddToImoenJ.baf~
 EVALUATE_BUFFER

COMPILE EVALUATE_BUFFER ~myMod\DLG\AddToImoenJ.D~

in the file AddToImoenJ.baf

/* activate joined file dialogue */
IF
%BGT_VAR% //this will only result in anything showing on his line if it is BGT
GlobalGT("Chapter","GLOBAL",%tutu_chapter_3%) // 3 for Tutu, 4 for BGT
Global("UseNewCrossmodVariables","GLOBAL",0)
AreaCheck("%CloakwoodWyverns_WyvernCave%")
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
InParty("alora")
InMyArea("alora")
!StateCheck("alora",CD_STATE_NOTVALID)
InMyArea(Player1) 
!StateCheck(Player1,CD_STATE_NOTVALID)
THEN
RESPONSE #100
SetGlobal("UseNewCrossmodVariables","GLOBAL",1)
END

/* initiate joined file dialogue */
IF %BGT_VAR%
GlobalGT("Chapter","GLOBAL",%tutu_chapter_3%) // 3 for Tutu, 4 for BGT
Global("UseNewCrossmodVariables","GLOBAL",1)
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
InMyArea(Player1) 
!StateCheck(Player1,CD_STATE_NOTVALID)
InParty("alora")
InMyArea("alora")
!StateCheck("alora",CD_STATE_NOTVALID)
CombatCounter(0)
!See([ENEMY])
THEN
RESPONSE #100
StartDialogueNoSet("alora")
END

In the file AddtoImoen.D

CHAIN 
IF WEIGHT #-2 ~%BGT_VAR% Global("UseNewCrossmodVariables","GLOBAL",1)~ ~%IMOEN_JOINED~ SpecificallyCalledBanterFileEntry1
~I am going to try that new variable substitution on the J file, Alora.~ 
== ~%ALORA_JOINED%~ IF ~InParty("alora") InMyArea("alora") !StateCheck("alora",CD_STATE_NOTVALID)~ THEN ~Wheee! This is just as easy as using the old system!~
== ~%IMOEN_JOINED%~ IF ~InParty("%IMOEN_DV%") InMyArea("%IMOEN_DV%") !StateCheck("%IMOEN_DV%",CD_STATE_NOTVALID)~ THEN ~Plus, folks can just copy and patse cmorgan's code.~
== ~%SAFANA_JOINED%~ IF ~InParty("safana") InMyArea("safana") !StateCheck("safana",CD_STATE_NOTVALID)~ THEN ~Of course, they will want to edit out the parts they don't want, daaaahling.~
END
++ ~There, that wasn't so bad, and you can just copy and paste!~ DO ~SetGlobal("UseNewCrossmodVariables","GLOBAL",1)~ EXIT
++ ~I dunno about this...~ DO ~SetGlobal("UseNewCrossmodVariables","GLOBAL",2)~ EXTERN ~%EDWIN_JOINED%~ Naysayers1
++ ~I think I need a second opinion.~ DO ~SetGlobal("UseNewCrossmodVariables","GLOBAL",2)~ EXTERN ~%DYNAHEIR_JOINED%~ YeaSayers1

For a full treatment of this BAF/J-file sample code ready for cut and paste, please follow this link to the G3 Development Wikki.

EXTEND_* versus COMPILE EVALUATE_BUFFER For those of you who notcied something different about the EXTEND_BOTTOM coding, yes, there is a different setup in the tp2 for actions in the EXTEND_* family. The usage is just like the COPY usage found in the .tra examples. While we can say

COMPILE EVALUATE_BUFFER ~myMod\DLG\myDialogue.D~

or

COMPILE EVALUATE_BUFFER ~myMod\BAF\myBAF.BAF~

we need to say

EXTEND_BOTTOM ~targetToChange.bcs~ ~myMod\BAF\myBAF.BAF~
 EVALUATE_BUFFER

or

EXTEND_TOP ~targetToChange.bcs~ ~myMod\BAF\myBAF.BAF~
 EVALUATE_BUFFER

For most mods, the usages presented here will be enough to get most, if not all, of the work done for a single-source install. As you go, you may run into exceptions, which is why at the end of this tutorial you will find the section Advanced Considerations.

 

Part 5. Straw-Man Questions (Real ones are too hard to answer :love:

General Notes

  1. Q: Won't doing this slow things down? A: In current testing, so far, no. With a huge, overblown, way-too-many variables set install running in an Always section, an archaeic P4 1.7 with 762 MB operating RAM compiles the code as quickly as a straight copy of two sets of files. BG1 NPC is a hugely singular case, as it interjects into thousands (yep, I counted) of existing states, requiring hundreds of variables to operate completely (at least until we learn what we can pare down and not delare!). The average mod would need far less, and produce far less load on any machine.
  2. Q: Isn't this hard to remember stuff, all this %THIS% and %THAT%? A: Well, if you can remember that _CORANP is Coran's Post-joining dialogue and that area FW3499 is the Sekreet Samurai Stronghold of Doom, then no. After all, while there is a set of variables available for copy/paste on the Development Wikki, and a set of materials in Phase2 of this tutorial, the good news is you could name the variables anything you want! (My favorite is %*****% which is not printable by the filters here and probably should not be used in polite company. I just cannot stand Skie's snivelling ???.)
  3. Q: But I don't know what changes between Tutu and BGT!!! A: Which is why we have a community. This tutorial has links to the G3 Development Wikki where many basic lists of differences are already worked out. Some searching, a little copy/paste, and you are in business. For more advanced materials, if you are a BGT modder you can contact a Tutu modder and ask, and vice versa - just because we have our own personal preferences does not preclude sharing ideas. For die-hard modders willing to throw themselves into the task, you can do the unthinkable... put both installs on your machine, and compare the differences yourself. (Most folks would prefer not to do this last, which is why contacting a fellow modder across the fence is probably a good idea.)
  4. Q: But %MYFavoritePLATFORM% Sucks and %MYhatedPLATFORM% Rocks - why would I bother with any of this? A: Well, why are you reading this, then! :) Seriously, we write for an audience. If we want the widest possible audience, we write for as many implementations as we can. This method is designed to make it easy for folks to be able to do that. We can all stick to our own choices, but stories are much bigger than code. If you have written it, why not let the widest audience possible enjoy it?
  5. Q: Hey - you said there were three obstacles - resources, chapters, and statenames. I don't see all of those represented here. What gives? A: Aaaahhhh.... the answers to these and further questions follow in...

Part 6. Advanced Considerations

Resource/File Names

We have discussed that there are different sound resource names, Banter/BCS/Joined/Post names, etc. The big standard NPCs should be easy to read and troubleshoot, so we go ahead and set these as "_VICONI" vs "BGVICNIA". The innumerable lesser actors, like Red Shirt/uard #475, _RONLIT vs IRONLIT, may need just a "tutu_scriptI" = "_" vs "I".

While the vast majority of these are a difference of one simple underscore, there are exceptions. For a list of ones we have identified, and to contribute more differences, please join us [iNSERT DEV WIKKI LINK]. Many of these can be completely ignored!. Unless your mod does a good bit of I_C_T or manipulation of existing in-game actors, you may not need to deal with a single one of these. The modding way around even having to deal with this is to simply create your own cast of characters for the player to interact with - which is what many mods do already.

Chapter Numbers

The concern here is that Tutu and BGT treat the Prologue differently. Tutu uses 0 (null, unused, no reference),1,2,3,4,5,6,7. BGT uses 1,2,3,4,5,6,7,8. This is quickly accomplished in chapter checks by declaring and using "tutu_chapter_3" as "3" on Tutu and "4" on BGT.

State Numbers

State names are a little tougher, and may require either research or a check to see if someone has helped out on the [iNSERT DEV WIKKI LINK]. BGT adds the BG1 strings to any NPC that is set to travel on into BG2 with you. That means that (for instance) if you need to manipulate Edwin's dialogue by adding a new EXTEND_BOTTOM, you will need to look up the differences and declare them: in a .D file set up to modify Edwin,

 EXTEND_BOTTOM ~%tutu_var%EDWIN~ %EdwinUnjoined77%
IF ~~ THEN REPLY @0 + X#EdwinJoinsAlone
END

Here, we have found that Tutu has Edwin's dialogue state 0, which is BGT's state 77 in the same file.

If your mod deals with Edwin Jaheira's unjoined dialogue or some other NPC that carries directly forward in BGT, then it is probably wise to do some research and make sure that a person more familiar with the platform you do not use takes a look at the state numbers and makes sure that you re adjusting the state you really want. The OUTER_SPRINT, EVALUATE_BUFFER, and you are good to go for both platforms.

Edited by cmorgan
Link to comment
Does Weidu Mac offer the same functionality? The mac version usually follows the PC updates.

Yes, all versions of WeiDU are compiled from the same source code (well, unless devSin has some diffs that haven't been merged in).

 

cmorgan: you don't need to COPY EVAL_BUFFER when you're compiling a BAF, COMPILE EVAL_BUFFER works both for BAF and D.

After checking the source, I found out that you can put arbitrary patches after an EXTEND_*, so you can use

EXTEND_TOP ~something.bcs~ ~my/mod/something.baf~
 EVALUATE_BUFFER

as opposed to

EXTEND_TOP EVALUATE_BUFFER ~something.bcs~ ~my/mod/something.baf~

Link to comment

Question: rather than using variables like %FishingVillage% for the areas, why not use the original BG designations like %ar0100%? With a quick copy and paste, you could make a full set of the variables (BGT has a doc with the mappings, for Tutu you just sub FW for AR) and then drop it in as a library as needed.

Link to comment

@ the bigg - I was having some trouble with those EXTEND TOP/BAF usages, but I bet it was me... I will go test it out on my install, and update the tutorial. Thank you!

 

@CamDawg - as berelinde commented, for the tutorial purposes, it seemed easier to do the english equivalents (easier for folks who haven't lived with the code awhile to see "BanditCamp"). For someone who has the basic idea down, I agree it would be much easier to produce a list using your idea (in fact, I bet Ascension64's cool rebuild tool uses something similar, or a 2da lookup.). For a new person trying out things, though, since I built the references using Miloch's area list, it seemed easiest to set up a "copy/paste" structure folks could use wholesale (or retail) and then skip the whole step of learning area references. I just need to put the link in to the actual code on the Wikki, as I seem to keep running into the post size limit here. You are absolutely on target as to a library structure, but before folks use a huge library of references that they don't need (which we are right now) I figured it was an opportunity to get across the basic idea in a friendly manner.

 

We could extend the "Advanced" tutporial with these ideas, including both the library usage and the ALWAYS usage. We also need to include the darned AUTO_TRA manipulations and oddities with people using single delimeters throwing the variable evaluation off. (I am still trying to rewrite it, as I can't seem to get the right balance for new folks - gotta find ways to slow it down and break it down step by step.). Any comments on ways of making this more tutorial more complete and (preferably) more simple/step by step? I don't know if I broke it down far enough, or too far. After all, I teach middle-schoolers, non-abstract thinkers all.

 

p.s. I forgot the area script naming differences - not sure if that is a good extension of this idea or not, though. I guess if we use %JAHEIRA_BCS%.bcs and %FishingVillage%.are, we might as well set %FishingVillage_BCS%.bcs, too. Currently we stick to the standard method, naming/extending scripts with platform-specific files.

Edited by cmorgan
Link to comment

Too long examples at the end, you're losing people there. Pare them down a little? You don't need an example with all sixteen npcs or twenty areas to show the technique.

 

Apart from that, understandable tutorial for a not-quite-newbie-anymore.

Link to comment

Understood. I prefer learning the techniques and extending them myself, rather than doing cargo-cult programming, but to each their own... :)

 

(and since you don't actually define the variables anywhere, I'd think it of limited use, and hurtful for readability)

Link to comment

Actually, that is a good idea - since I can't get it all on the post, I will reduce the "example" code to make it pretty simple, but them right after it link to the Wikki entries with something like [Full Code for Copy/Paste Here]. I had better get that link up for the demo "ALWAYS" too... you are right, erik, it is of no real use without reference to the actual OUTER_SPRINT settings used.

Link to comment

Good stuff, Captain Morgan.

 

Wasn't there a reason to use REPLACE_TEXTUALLY [EXACT_MATCH] instead of EVALUATE_BUFFER, apart from trying to evaluate the odd % as a variable?

 

I'll admit I prefer stupidly short (but unique) variables to long, descriptive ones (particularly in scripts, where it might make a difference in runtimes, or so I've read). But I guess everyone will have there personal preference there, and it probably makes little difference, unless we're really going to have some sort of community standards.

Link to comment

The only problem we ran into (requiring EXACT_MATCH and REPLACE_TEXTUALLY) was in evaluating .tra files. I finally tracked down one place where " was used singly, and followed Nythrun's suggestion of declaring "precent_sign", so we still could use +10% and such in the ,tra file. That's why we need the advanced tutorial section to get into the details of tra,AUTO_TRA, and file manipulation.

 

I am not sure it needs to be a community standard thing for the actual variables, any more than folks do now with regular patching; my bet is only a few folks will ever really just cut & paste code (I will, but that is because I set it up :) ). The biggest hurdle for me was understanding what most of you folks seem to already know somehow; abstract manipulation of placeholders (yeah, I know it is just fancy ways of doing algebra, but it didn't translate well for my brain!) For people who only rreluctantly deal with code, either from lack of time or from really just wanting to write stories, it is there for the copy/paste. When I am testing stuff out, I shamelessly use %tsu% or whoever I am learning from at the moment. You should have seen the tp2 when I was cribbing from Nythrun, CamDawg, Ascension64, Grim Squeaker, and pro5 all at the same time!

Link to comment

I have 2 choices when it comes to deciding how to spend my precious modding time. I can write or I can learn weidu-fu. There are people who will always be better than me at coding *anything*. I'll leave them to it.

 

I see how it all works, and what needs to happen for this all to work out. It only took me 30 seconds to figure out how the %tutu_var% worked, once I understood the basic concept, so I can do it on the fly if I have to. Buy why? Left to my own devices, I'd just go and generate the same list all over again. and copy and paste from that. I may as well just let someone else do the typing.

 

I'm a chemist by trade. I've got a dozen template lab reports for the testing I do. Sure, I could generate the same report over and over, but then my boss would be paying me to type. My boss seems to feel that would be a waste of money, so I spend most of my day in the lab, and use the templates.

Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...