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:
- It seems easier for folks to read/check plain language long names than to remember area numbers or script/dialogue names.
- It seems easier to code using one file and "transparently" adapt to different installs on install.
- 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.
- 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.
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) ENDIn 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 BEGINtells 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 BEGINtells 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" ENDAnd 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.traFor 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" ENDBy 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_CHANGESFor 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.
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 -
"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") ENDIn 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%~ YeaSayers1For 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_BUFFERor
EXTEND_TOP ~targetToChange.bcs~ ~myMod\BAF\myBAF.BAF~ EVALUATE_BUFFERFor 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
- 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.
- 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 .)
- 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.)
- 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?
- 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...
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.
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 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 ENDHere, 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, 05 April 2007 - 01:38 PM.