Jump to content

cmorgan

Gibberlings
  • Posts

    7,198
  • Joined

  • Last visited

Everything posted by cmorgan

  1. Graoumf, I am looking into it - I can't see anything wrong. The AUTO_TRA ~shardsofice/%s~ should be taking care of this - I rechecked the mod and it looks like everything is in place. i will try an install in french and see if it works.
  2. I have them, thanks! Just to let you know, I haven't abandoned you - I can't access the materials and re-package mods at work, even during downtimes. I work at a school that uses OSX and has a set of blocking software/restrictions that means that just typing this message out right now during school hours is due to the kindness of the tech guys and gals at school. (Luckily, I have several blocks of time during the school day where I can do non-work stuff, like rearrange music parts for kids, reschedule lessons, and such, because some of my work day is before school hours and after school hours, leaving me a little personal time during the day. For parts of the year all of that time is take So when stuff gets updated with Aran, etc., that is all stuff done on thumb drives and posted when I can, but site updates to pages, mod packaging, etc. during the school year has to wait until I get some time with my home computer. Finished taxes yesterdy, and it looks like Friday might just be the day when I have two or three hours of free time, so unles something massive changes things, you can probably expect some action on these tomorrow. Shortened version - even if there are other posts going on, I have not forgotten you (or grogerson!!!) - I just do not have the access to do those tasks at the same moment I have time to do those tasks
  3. Well, if I am writing him reasonably, his language is by choice and custom, rather than by knowledge. He is suposed to be pretty darned smart, bith in street sense and in intelligence, having picked up mathematics, scribing, quill creation, ink creation, vellup and parchament crafting, trading, fighting, multiple languages (spoken and written), and done all this while either ravelling about in a familty Trading Coster wagon or following mercenary adventure. There is alot of sitting-around-timeon guard duty, but ask the dudes and dudettes travelling convoy protection in Iraq right now if they have time ro read on duty - my bet is that watching for the next thing that is going to attack you is a but attention consuming I think you may have identified a weakness in this kind of mod construction, though. I have been writing his character based on a character, not specifically the set of stats - so if someone drops his intelligence to low or escalates it, I have to fall back on "creative adjustment" - in other words, excuses as to why he would react the way he would react, regardless of score. My current "creative readjustment" (bulltookey) is that his class and race and other variable pathways are character driven, from a guy who may or may not be pretty darned smart, but if he is, it has been self-taught and itinerant-scholar taught; a diamond in the rough, uncut and polished. And if the stat is low, well, it is a mirical he is able to do all this. If it is too high, then he has been lazy/preoccupied
  4. Sure thing - please recheck and resend to that same email address, and I can do that as well
  5. ilot, can you please send those translations to cmorganbg at gmail.com? I have the forwarded message from Icelus, but I don't have the others. If you could send them all (including Shards) in a .rar package, I will put them in place and do the updates. I have all 4 mods extracted and set up o my harddrive, ready for the .tra files, and after a quick lowecasing I can toss them out for Linux, too.
  6. Barren Fischa has not been active since June of 2007, but as a retired Gibberling, I suspect Barren would not mind having it kept alive. I'll ask about a more permanent hosting, but until then, Leomar has updated the mod, traified it, and incorporated Yago's German translation. The download link for the time being is [see current release post below]
  7. Thanks for the typo report - will fix! For his class, I am looking at allowing the player to determine what of the 4 base configurations are installed, and he starts as a fighter with those stats. Then the player can dual-class him to whatever they have in mind. Originally, I was going to distribute him SCS-Level0 style, where the .cre is L0 with the right number of XP and the player has complete control over when dualling takes place, but alternatively I can either beg Nythrun to let him into Level1NPCs, or outright borrow her code and run it at the end of the install as a separate component, so folks who want to make him a Kensai or whatever will be able to change class and equipment. The thing I am trying to work through right now with this is: is it better to simply follow traditional approaches, since experienced players will micromanage using things like Ashes of Empire, SCS, BG2 Tweaks, Learn Through Use, etc., or do I go with a customized system that means more install choices and time? My current leaning is to get him into Level1NPCs, with a traditional .cre, becuase so far that gives the players the widest options. Equipment: Since he is a "standard" sellsword mustered out of the Flaming Fist, I figured Flaming Fist gear (long sword and shield) with an appropriate +1 or +2 to the long sword, because he is a seasoned adventurer. He doesn't have any specialized gear or scripts, and his quest is not going to provide anything only usable by him. In fact, the way I am trying to approach him is a twist on Miera and Darious' Amber concept. Basically, if I had a multiplayer game with a friend, and we were working through the game, what would the friend want to say? If he works out reasonably, then he can be the PC's sidekick. Useful, doesn't take over, lots of opportunities for interaction, but still secondary to the main story. Not from me I think the best dudes and dudettes around for that kind of question reside at Sorcerer's Place. Lots of good players over there who can run down the stats and let you know precisely when to dual him from Kensai to Mage to get the most use/powerful build. But since Aran is more of a roleplayer's toy, I haven't gone into that kind of analysis. If the folks at Sorceror's Place lay some knowledge on me, I'll add it into the release documents, with source credit, of course. I am not sure. I like the bg1npc/Gavin approach, with music instead of voicing, because I find the voicings of lines jarring rather than immersive. They also have a functional limitation - the words often don't match the speech (any tokens like <CHARNAME>, <PRO_HIMHER> etc. have to be worked around). The soundset is obligatory, but the voicings in lines mean locking them down 9finding someone to voice is hard enough - matching revoicing is worse). Plus, I want romance folks to be able to place the inflection where they want it inside their mind, as the options usually support all sorts of roleplay. I don't want to script the "insolent-mean" option via sound when someone else might read he same lines as "insolent-teasing". But I haven't made any decisions on it.
  8. Let me check and see if they are posted in the common workroom for folks - I am pretty sure they are. I can try to get a few of these refreshed, most likely early tomorrow afternoon.
  9. I think that was supposed to be me - let me see if I can get that all set up this week.
  10. Icelus' original PPG list is (and I expect will continue to be) the master list across all english-language communities, with a follow-up initiative now being discussed at SHS [working model found here ]. Each one relies on modders (or the community) to update them, as JCompton mentioned, or like the Tutu State of the Union list asks the community for feedback and then periodically a site maintainer comes through and gathers the information and gets it all set up/digested for users. Which is something those of us at G3 don't always remember (like when we do updates, we should probably visit both PPG and that IEMI page, and update them - we have been firing out IE News releases, but not updating materials on either site). I'll try to get time this afternoon and see what we should have updated.
  11. The BG1NPC Project for Tutu, BGT, and BG:EE Available in English, Spanish, French, Polish, and German (partly, missing lines in English). With packages for Windows, OSX, and Linux, this version ships with WeiDU. Banter, Player Initiated Dialogues, Romances, Quests, Tweaks, and Interjections expand your BG game experience when you add this mod to your Tutu, EasyTutu, BGT, BG:EE, or SoD install (no SoD content, though). This project was built over many years by many hands in the i.e. community. For more background, you can visit the Project Page (note: the version number on this page is outdated. Links go to latest release, though.). We hope that you enjoy a great game! Relevant links: Download Forum Project Page Readme - English (for v22) Readme - French (for v22) Get Latest Release/Follow/Contribute on GitHub
  12. OK, v17 is up and running - no translation changes for those folks working on the big tasks for Italian and French communities. Relevant links: Download Forum Project Page Readme Enjoy!
  13. PDIALOG.2DA & INTERDIA.2DA: Non-Standard Mod - Added Joinable NPCs Defining "non-standard" as "currently available and not following standard format for these entries" Azure (Victor) Azure Azurep azurej *** Azurep Azurej *** *** Azurep azurej *uses p and j files for banter* Hessa (llamababe) SUHESSA SUHESSP SUHESSJ SUHES25P SUHES25J SUHES25D SUHES25 | BSUHESS BSUHES25 *entries misaligned due to missing dreamscript entry* Shyhinworunto Chende (MajorTomSawyer) MTS#Shy MTS#ShyE MTS#ShyD MTS#ShyJ MTS#Shy25 Shy25E | *error in interdia.2da, mirrors pdialog.2da entries* Tortured Souls (Vlad & Domi) COPY_EXISTING ~PDIALOG.2da~ ~override/PDIALOG.2da~ REPLACE_TEXTUALLY ~yosh25~ ~yoshimo~ PPBODHI3 PPBODHI3 PPBODHI3 *** PPBODHI3 PPBODHI3 *** *** | *** *** SIME SIMEP SIMEJ SIMED SIME25P SIME25J *** sime25 | BSIME BSIME25 KACHIKO KACHIP KACHIJ KACHID KACHI25P KACHI25J KACHI25D *** | BKACHI BKACHI25 DYNAHEIR DYNAP DYNAJ *** DYNAP DYNA25J *** *** | *** *** CORAN CORANP CORANJ *** CORAN25P CORAN25J *** *** | BCORAN *** Valen (Weimer) Valen ValenP ValenJ ValenD ValenP ValenJ Valen Valen | *no interdia.2da entries * Solaufein (Weimer) SOLA SOLA SOLA SOLA SOLA SOLA SOLA SOLA | *no interdia.2da entries * SOLAUFEIN SOLA SOLA SOLA SOLA SOLA SOLA SOLA | *no interdia.2da entries *
  14. PDIALOG.2DA & INTERDIA.2DA: Standard BG2 Mod - Added Joinable NPCs Defining "standard" as "currently available and following close to standard format for these entries" BG2 pdialog/interdia standard format NPCs DeathVariable SoA-P SoA-J SoA-D ToB-P ToB-J ToB-D ToB-script SoA-B ToB-B Alassa (SimDing0) --- --- --- --- --- --- --- --- D0Alassa D0AlasP D0AlasJ D0AlasD D0Ala25P D0Ala25J D0Ala25D D0Alas25 BD0Alas BD0Ala25 Allison (Rastor) --- --- --- --- --- --- --- --- R#ALLIS R#ALLISP R#ALLISJ R#ALLISD R#ALL25P R#ALLISJ R#ALLISD *** R#ALLISB R#ALLISB Alora (Com_Solaufein) --- --- --- --- --- --- --- --- CMALORA CMALORAP CMALORAJ CMALORAD CMALO25P CMALO25J CMALO25D CMALOR25 BCMALOR BCMALO25 Amber (Miera & Darios) --- --- --- --- --- --- --- --- M#AMBER M#AMBERP M#AMBERJ M#AMBERD M#AMB25P M#AMB25J M#AMB25D m#amb25 BM#AMBER BM#AMB25 Angelo (Sister Vigilante) --- --- --- --- --- --- --- --- ADANGEL ADANGELP ADANGELJ ADANGELD ADANG25P ADANG25J ADANG25D ADANG25 BADANGEL BADANG25
  15. Joined Dialog Files The workhorse of NPCs, both BioWare and Mod-Added, the "J-file" is the storehouse for quest materials, Player-Initiated-Dialogs ("PID"s), friendship talks, and romances. Regardless of how your mod is organized from a file-read-on-install standpoint, these dialog files are not called by the banter engine, so they need to be either a. a conditioned state followed up by directly linked states, either within the same file using GOTO (+) or referencing another available dialog file via EXTERN. or b. a no-conditioned state designed to be linked from either of the above. Often, the Joined Dialog File is referenced via a specific script that you have added to your mod. So, a basic script setup for a friendtalk, added to MyNPC.bcs in your WeiDU command file (myMod.tp2) EXTEND_BOTTOM ~c-aran.bcs~ ~aranw/aransfriendtalks.baf~ And (for conceptualization, a simplified code block in) AransFriendTalks.baf IF Global("MyFriendTalk","GLOBAL",0) THEN RESPONSE #100 SetGlobal("MyFriendTalk","GLOBAL",1) StartDialogNoSet("c-aran") END results in a check of Aran's joined dialog file and a check for the first state which meets all conditions and returns True. If we have a state on C-ARANJ that has this true, then we get a reply: IF ~Global("MyFriendTalk","GLOBAL",1)~ THEN c-aransayhi SAY ~[ARAN] Clangedden's Beard, a FriendTalk!~ IF ~~ THEN DO ~SetGlobal("MyFriendTalk","GLOBAL",1)~ EXIT END If we do not, we get a big problem, as the engine finds nothing true. Player-Initiated-Dialogs take advantage of this behavior by creating an "almost always true" condition, using IsGabber(Player1) or another similar command with no other conditions, so that if the player force-talks the NPC the related dialog file will return one big state with a whole bunch of conditioned replies: IF ~IsGabber(Player1)~ THEN BEGIN c-arantobpid SAY ~You decide to speak to Aran.~ ++ ~There's something wrong with your voice, Aran.~ + c-aranvoicefix /* Inn Flirts */ + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,1) OR(2) AreaCheck("AR5003") AreaCheck("AR5501") ~ + ~ <<TEXT >> ~ + c-aranrom25innA + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,2) OR(2) AreaCheck("AR5003") AreaCheck("AR5501") ~ + ~ <<TEXT >> ~ + c-aranrom25innB + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,3) OR(2) AreaCheck("AR5003") AreaCheck("AR5501") ~ + ~ <<TEXT >> ~ + c-aranrom25innC + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,4) OR(2) AreaCheck("AR5003") AreaCheck("AR5501") ~ + ~ <<TEXT >> ~ + c-aranrom25innD /* Outside Flirts */ + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,1) OR(3) AreaCheck("AR5200") AreaCheck("AR5203") AreaCheck("AR6400") ~ + ~(A sharp pain lances through your ankle, and you lean quickly against a nearby rock)~ + c-aranrom25hikeA + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,2) OR(3) AreaCheck("AR5200") AreaCheck("AR5203") AreaCheck("AR6400") ~ + ~(You poke gently at your meal, but you are unsatisfied. You stand up and walk to the edge of the glade.~ + c-aranrom25campB + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,3) OR(3) AreaCheck("AR5200") AreaCheck("AR5203") AreaCheck("AR6400") TimeoDay(DAY)~ + ~(The swiftly flowing water glistens in the sunlight, and you think you might want to swim.)~ + c-aranrom25swimday + ~Global("c-arantobromance","GLOBAL",2) RandomNum(4,4) OR(3) AreaCheck("AR5200") AreaCheck("AR5203") AreaCheck("AR6400") TimeoDay(NIGHT)~ + ~(The swiftly flowing water glistens in the moonlight, and you think you might want to swim.)~ + c-aranrom25swimnight END /* Voice Fixer Resolved */ IF ~~ c-aranvoicefix << INSERT SOUNDSET FIXER HERE >> END If the player force-talks the NPC and something else returns true, it will fire instead, of course, which means force-talking an NPC is a great way to clear and identify "loopholes" in code or script that have variables hanging open. BioWare sets this up (and gives us a minor headache in the modding world) with a HappinessLT() or BreakingPoint() conditioned dialog, too, so that if an NPC is not happy they will leave instead of continuing their association with the party. If we had a PID like this in place, the game sees "force-talk" and "call from script via Dialog()" as the same thing - so Aran's PID would fire instead of the friend talk we wanted. Technically, any file can actually be used to store directly called states. The engine will happily retrieve the following: CHAIN ~C-ARANJ~ ~[ARAN] Hey, I'm starting in Joined because it is not a Banter, but we could technically switch back and forth...~ == ~CERNDJ~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[CERND] I am talking from my Joined File ~ == ~C-ARANJ~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[ARAN] Oh yeah? ~ == ~BCERND~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[CERND] I am now talking from my Banter File ~ == ~C-ARANB~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[ARAN] Me too! Selune's Silvery Gaze, what tricks can be played.~ EXIT It will also allow you to move freely between banter and joined files once the initial state is called from the correct file, or even create a completely different temporary file, but in practice there are very few examples of this in currently existing mods. Most modders keep joined dialogs together with their reply states, and banter with their banter. Exceptions we can come up with later, in the entries on Items (ITEMDIAL.2da) and Special Topics, like JCompton's use of the "invisible creature trick" to create a temporary shell dialog, applied to the Lilacor/Jaheira/etc. banters. But for standard practice, Joined with Joined, and Banter with Banter. Why not use the Banter Files for more, and just use Interact()? Well, you can, technically. Some mods do - for example, in Taisha Remix, Lord Ernie and Bri follow original modeling after BioWare and put Love Talks on the Banter file, conditioned and weighted: Btashia.d, lines 1005 - 1013 IF ~!Global("TashiaRomanceActive","GLOBAL",3) Global("TashiaMatch","GLOBAL",1) Global("LoveTalk","LOCALS",34) !StateCheck(Player1,STATE_SLEEPING) GlobalGT("TashiaInterestMatch","GLOBAL",2)~ THEN BEGIN 152 // from: SAY ~<CHARNAME>, I have been giving much thought to what happened with Arilistan, and how I feel about him...~ IF ~~ THEN REPLY ~Oh?~ GOTO 154 IF ~~ THEN REPLY ~Not now, Tashia.~ GOTO 153 END The trouble is that using the banter file means you are subjecting your conditioned states to evaluation on a timed script interval (go decode/reverse-engineer JCompton's Banter Accellerator and you will see exactly what scripts where and how the timer evidences). If you are strong enough a coder to figure out how to mess with the weights in the original dialog files and *not* mess up the states that BioWare expected to be availabel in their original ordering and weighting, go for it - but most modders don't even want to open that can of worms. It is much simpler to work from carefully constructed script blocks on the NPC's .bcs (or an area script, or at absolutely last resort and with the knowledge that you are playing with Civil-War Era loaded handguns in the middle of a nuclear reactor chamber covered in C4, on baldur[25].bcs, but don't tell anyone I said anything about that...). The joined file gets called only when the PC is force-talked or specifically instructed by an NPC script. So, the breakdown for the Joined Dialog materials: Joined Dialog File Templates for SoA and ToB Canonical Bioware Characters ////SoA J FILE TEMPLATE//// /////////////////////////////////SoA J FILE TEMPLATE///////////////////////////////// == ~CERNDJ~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[CERND] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~EDWINJ~ IF ~InParty("Edwin") InMyArea("Edwin") !StateCheck("Edwin",CD_STATE_NOTVALID)~ THEN ~[EDWIN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~HAERDAJ~ IF ~InParty("HaerDalis") InMyArea("HaerDalis") !StateCheck("HaerDalis",CD_STATE_NOTVALID)~ THEN ~[HAERDALIS] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~JAHEIRAJ~ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~[JAHEIRA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~JANJ~ IF ~InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID)~ THEN ~[JAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~KELDORJ~ IF ~InParty("Keldorn") InMyArea("Keldorn") !StateCheck("Keldorn",CD_STATE_NOTVALID)~ THEN ~[KELDORN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~KORGANJ~ IF ~InParty("Korgan") InMyArea("Korgan") !StateCheck("Korgan",CD_STATE_NOTVALID)~ THEN ~[KORGAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~MAZZYJ~ IF ~InParty("Mazzy") InMyArea("Mazzy") !StateCheck("Mazzy",CD_STATE_NOTVALID)~ THEN ~[MAZZY] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~MINSCJ~ IF ~InParty("Minsc") InMyArea("Minsc") !StateCheck("Minsc",CD_STATE_NOTVALID)~ THEN ~[MINSC] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~NALIAJ~ IF ~InParty("Nalia") InMyArea("Nalia") !StateCheck("Nalia",CD_STATE_NOTVALID)~ THEN ~[NALIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~VALYGARJ~ IF ~InParty("Valygar") InMyArea("Valygar") !StateCheck("Valygar",CD_STATE_NOTVALID)~ THEN ~[VALYGAR] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~VICONIJ~ IF ~InParty("Viconia") InMyArea("Viconia") !StateCheck("Viconia",CD_STATE_NOTVALID)~ THEN ~[VICONIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~YOSHJ~ IF ~InParty("Yoshimo") InMyArea("Yoshimo") !StateCheck("Yoshimo",CD_STATE_NOTVALID)~ THEN ~[YOSHIMO] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~IMOEN2J~ IF ~InParty("Imoen2") InMyArea("Imoen2") !StateCheck("Imoen2",CD_STATE_NOTVALID)~ THEN ~[IMOEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~AERIEJ~ IF ~InParty("Aerie") InMyArea("Aerie") !StateCheck("Aerie",CD_STATE_NOTVALID)~ THEN ~[AERIE] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~ANOMENJ~ IF ~InParty("Anomen") InMyArea("Anomen") !StateCheck("Anomen",CD_STATE_NOTVALID)~ THEN ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> /////ToB J FILE TEMPLATE///// /////////////////////////////////ToB J FILE TEMPLATE///////////////////////////////// == ~AERIE25J~ IF ~InParty("Aerie") InMyArea("Aerie") !StateCheck("Aerie",CD_STATE_NOTVALID)~ THEN ~[AERIE] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~ANOME25P~ IF ~InParty("Anomen") InMyArea("Anomen") !StateCheck("Anomen",CD_STATE_NOTVALID)~ THEN ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~CERND25J~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[CERND] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~EDWIN25J~ IF ~InParty("Edwin") InMyArea("Edwin") !StateCheck("Edwin",CD_STATE_NOTVALID)~ THEN ~[EDWIN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~HAERD25J~ IF ~InParty("HaerDalis") InMyArea("HaerDalis") !StateCheck("HaerDalis",CD_STATE_NOTVALID)~ THEN ~[HAERDALIS] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~JAHEI25J~ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~[JAHEIRA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~JAN25J~ IF ~InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID)~ THEN ~[JAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~KELDO25J~ IF ~InParty("Keldorn") InMyArea("Keldorn") !StateCheck("Keldorn",CD_STATE_NOTVALID)~ THEN ~[KELDORN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~KORGA25J~ IF ~InParty("Korgan") InMyArea("Korgan") !StateCheck("Korgan",CD_STATE_NOTVALID)~ THEN ~[KORGAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~MAZZY25J~ IF ~InParty("Mazzy") InMyArea("Mazzy") !StateCheck("Mazzy",CD_STATE_NOTVALID)~ THEN ~[MAZZY] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~MINSC25J~ IF ~InParty("Minsc") InMyArea("Minsc") !StateCheck("Minsc",CD_STATE_NOTVALID)~ THEN ~[MINSC] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~NALIA25J~ IF ~InParty("Nalia") InMyArea("Nalia") !StateCheck("Nalia",CD_STATE_NOTVALID)~ THEN ~[NALIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~VALYG25J~ IF ~InParty("Valygar") InMyArea("Valygar") !StateCheck("Valygar",CD_STATE_NOTVALID)~ THEN ~[VALYGAR] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~VICON25J~ IF ~InParty("Viconia") InMyArea("Viconia") !StateCheck("Viconia",CD_STATE_NOTVALID)~ THEN ~[VICONIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~IMOEN25J~ IF ~InParty("Imoen2") InMyArea("Imoen2") !StateCheck("Imoen2",CD_STATE_NOTVALID)~ THEN ~[IMOEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> == ~SAREV25J~ IF ~InParty("Sarevok") InMyArea("Sarevok") !StateCheck("Sarevok",CD_STATE_NOTVALID)~ THEN ~[SAREVOK] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ <<TERMINATION_PLACEHOLDER>> And since we are here, some quick useful templates for "the BioWare NPC is not available, or the BioWare NPC is available, ///// NOT AVAILABLE CONDITIONS ////// // Cernd OR(3) !InParty("Cernd") !InMyArea("Cernd") StateCheck("Cernd",CD_STATE_NOTVALID) //Edwin OR(3) !InParty("Edwin") !InMyArea("Edwin") StateCheck("Edwin",CD_STATE_NOTVALID) // HaerDalis OR(3) !InParty("HaerDalis") !InMyArea("HaerDalis") StateCheck("HaerDalis",CD_STATE_NOTVALID) // Jaheira OR(3) !InParty("Jaheira") !InMyArea("Jaheira") StateCheck("Jaheira",CD_STATE_NOTVALID) // Jan OR(3) !InParty("Jan") !InMyArea("Jan") StateCheck("Jan",CD_STATE_NOTVALID) // Keldorn OR(3) !InParty("Keldorn") !InMyArea("Keldorn") StateCheck("Keldorn",CD_STATE_NOTVALID) // Korgan OR(3) !InParty("Korgan") !InMyArea("Korgan") StateCheck("Korgan",CD_STATE_NOTVALID) // Mazzy OR(3) !InParty("Mazzy") !InMyArea("Mazzy") StateCheck("Mazzy",CD_STATE_NOTVALID) // Minsc OR(3) !InParty("Minsc") !InMyArea("Minsc") StateCheck("Minsc",CD_STATE_NOTVALID) // Nalia OR(3) !InParty("Nalia") !InMyArea("Nalia") StateCheck("Nalia",CD_STATE_NOTVALID) // Valygar OR(3) !InParty("Valygar") !InMyArea("Valygar") StateCheck("Valygar",CD_STATE_NOTVALID) // Viconia OR(3) !InParty("Viconia") !InMyArea("Viconia") StateCheck("Viconia",CD_STATE_NOTVALID) // Yoshimo OR(3) !InParty("Yoshimo") !InMyArea("Yoshimo") StateCheck("Yoshimo",CD_STATE_NOTVALID) // Imoen2 OR(3) !InParty("Imoen2") !InMyArea("Imoen2") StateCheck("Imoen2",CD_STATE_NOTVALID) // Aerie OR(3) !InParty("Aerie") !InMyArea("Aerie") StateCheck("Aerie",CD_STATE_NOTVALID) // Anomen OR(3) !InParty("Anomen") !InMyArea("Anomen") StateCheck("Anomen",CD_STATE_NOTVALID) // MOD ADDED OR(3) !InParty("c-aran") !InMyArea("c-aran") StateCheck("c-aran",CD_STATE_NOTVALID) ////// IN PARTY AND AVAILABLE CONDITIONS ////// // Cernd InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID) //Edwin InParty("Edwin") InMyArea("Edwin") !StateCheck("Edwin",CD_STATE_NOTVALID) // HaerDalis InParty("HaerDalis") InMyArea("HaerDalis") !StateCheck("HaerDalis",CD_STATE_NOTVALID) // Jaheira InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID) // Jan InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID) // Keldorn InParty("Keldorn") InMyArea("Keldorn") !StateCheck("Keldorn",CD_STATE_NOTVALID) // Korgan InParty("Korgan") InMyArea("Korgan") !StateCheck("Korgan",CD_STATE_NOTVALID) // Mazzy InParty("Mazzy") InMyArea("Mazzy") !StateCheck("Mazzy",CD_STATE_NOTVALID) // Minsc InParty("Minsc") InMyArea("Minsc") !StateCheck("Minsc",CD_STATE_NOTVALID) // Nalia InParty("Nalia") InMyArea("Nalia") !StateCheck("Nalia",CD_STATE_NOTVALID) // Valygar InParty("Valygar") InMyArea("Valygar") !StateCheck("Valygar",CD_STATE_NOTVALID) // Viconia InParty("Viconia") InMyArea("Viconia") !StateCheck("Viconia",CD_STATE_NOTVALID) // Yoshimo InParty("Yoshimo") InMyArea("Yoshimo") !StateCheck("Yoshimo",CD_STATE_NOTVALID) // Imoen2 InParty("Imoen2") InMyArea("Imoen2") !StateCheck("Imoen2",CD_STATE_NOTVALID) // Aerie InParty("Aerie") InMyArea("Aerie") !StateCheck("Aerie",CD_STATE_NOTVALID) // Anomen InParty("Anomen") InMyArea("Anomen") !StateCheck("Anomen",CD_STATE_NOTVALID) // MOD ADDED InParty("c-aran") InMyArea("c-aran") !StateCheck("c-aran",CD_STATE_NOTVALID) Again, constructing your own reply, CHAIN, and APPEND templates are just a matter of taking the banter entries found earlier in this tutorial and swapping the resource reference to the ~AERIEJ~/~AERIE25J~ references.
  16. Post Dialog File Next in order of complexity, the set of dialogs called by the regular game scripts, rather than the banter scripts. This is the "land-line", or home telephone call. Here, we find the "POST_DIALOG_FILE" and the "JOIN_DIALOG_FILE" linkages for both SoA and ToB. Called by Dialog(), StartDialogNoSet(), etc. via a character's (or area or the main override) script, we find two (SoA) to four (SoA + ToB) dialog files referenced. The game uses PDIALOG.2DA, a two-dimentional array of dialog files and scripts referenced against the death-variables (script names) of joinable NPCs as a telephone directory: pdialog.2da 2DA V1.0 multig [/td][td]POST_DIALOG_FILE JOIN_DIALOG_FILE DREAM_SCRIPT_FILE 25POST_DIALOG_FILE 25JOIN_DIALOG_FILE 25DREAM_SCRIPT_FILE 25OVERRIDE_SCRIPT_FILE AERIE AERIEP AERIEJ AERIED AERIE25P AERIE25J AERIE25D aeri25 ANOMEN ANOMENP ANOMENJ ANOMEND ANOME25P ANOME25J ANOME25D anom25 CERND CERNDP CERNDJ CERNDD CERND25P CERND25J CERNDD cern25 EDWIN EDWINP EDWINJ EDWIND EDWIN25P EDWIN25J EDWIND edwi25 HAERDALIS HAERDAP HAERDAJ HAERDAD HAERD25P HAERD25J HAERDAD haer25 IMOEN IMOENP IMOENJ IMOEND IMOENP IMOENJ IMOEND imoe25 IMOEN2 IMOEN2P IMOEN2J IMOEN2D IMOEN25P IMOEN25J IMOEN2D imoe25 JAHEIRA JAHEIRAP JAHEIRAJ JAHEIRAD JAHEI25P JAHEI25J JAHEI25D jahe25 JAN JANP JANJ JAND JAN25P JAN25J JAND jan25 KELDORN KELDORP KELDORJ KELDORD KELDO25P KELDO25J KELDORD keld25 KORGAN KORGANP KORGANJ KORGAND KORGA25P KORGA25J KORGAND korg25 MAZZY MAZZYP MAZZYJ MAZZYD MAZZY25P MAZZY25J MAZZYD mazz25 MINSC MINSCP MINSCJ MINSCD MINSC25P MINSC25J MINSCD mins25 NALIA NALIAP NALIAJ NALIAD NALIA25P NALIA25J NALIAD nali25 VALYGAR VALYGARP VALYGARJ VALYGARD VALYG25P VALYG25J VALYGARD valy25 VICONIA VICONIP VICONIJ VICOND VICON25P VICON25J VICON25D vico25 YOSHIMO YOSHP YOSHJ YOSHD YOSHP YOSHJ YOSHD yosh25 TTXAN TTXANP TTXANJ TTXAND TTXANP TTXANJ TTXAND *** TTBRAN TTBRANP TTBRANJ TTBRAND TTBRANP TTBRANJ TTBRAND *** TTIMOEN TTIMOENP TTIMOENJ TTIMOEND TTIMOENP TTIMOENJ TTIMOEND *** TTJAHEIR TTJAHEIP TTJAHEIJ TTJAHEID TTJAHEIP TTJAHEIJ TTJAHEID *** TTMINSC TTMINSCP TTMINSCJ TTMINSCD TTMINSCP TTMINSCJ TTMINSCD *** SAREVOK SAREV25P SAREV25J SAREV25D SAREV25P SAREV25J SAREV25D *** IDIOT01 IDIOTP IDIOTP *** IDIOTP IDIOTP *** *** Referencing this as a chart, we see that Minsc has the dv "MINSC", the POST_DIALOG_FILE entry "MINSCP", the JOIN_DIALOG_FILE entry "MINSCJ", and some other entries. For the ToB entries, he has 25POST_DIALOG_FILE = "MINSC25P" and the 25JOIN_DIALOG_FILE = "MINSC25J". If the game engine is referencing the dialogs in SoA, it will choose MINSCP and MINSCJ files, if in ToB, it will choose the MINSC25P and MINSC25J files. The other entries help the game reference specific scripts, not dialogs. Because this is a primary workhorse of the game, the telephone directory (PDIALOG.2DA) contains other information, including the DREAM_SCRIPT_FILE (a script only run following a call via Rest() or RestParty(), where the "dreams" and "At Rest Talks" are triggered); 25DREAM_SCRIPT_FILE, (the same resource for ToB); and 25OVERRIDE_SCRIPT_FILE (which sets the override file for the NPC in ToB). These entries allow actions and triggers to be tailored to to the specific game and run only there. Adding a Mod NPC to the List Again, without your NPC having a listing here, the game doesn't really know what to do with him or her. So, the blanket "add on" commands in the file myMod.tp2 to add your NPC are APPEND ~pdialog.2da~ ~C-ARAN C-ARANP C-ARANJ C-ARAND C-ARN25P C-ARN25J C-ARN25D C-ARN25~ UNLESS ~C-ARN25~ There is a more detailed way of doing this, detecting differences between SoA installs and ToB installs. This uses the power of UNLESS/IF in WeiDU: /* pdialog SoA style */ APPEND ~pdialog.2da~ ~C-ARAN C-ARANP C-ARANJ C-ARAND ~ UNLESS ~C-ARN25~ UNLESS ~25POST~ /* pdialog ToB style */ APPEND ~pdialog.2da~ ~C-ARAN C-ARANP C-ARANJ C-ARAND C-ARN25P C-ARN25J C-ARN25D C-ARN25~ UNLESS ~C-ARN25~ IF ~25POST~ In these cases, WeiDU looks for the UNLESS string. If it finds it, it does not add the materials - the current PDIALOG.2DA already has been patched to include that NPC. It also looks for the IF string, and if it finds it, adds the materials. Since 25POST only occurs in the ToB pdialog.2da, it serves as a screen to make sure the entries added to SoA are not added ToB. From one of the Grand Master Modders, the original dude, Weimer, we see this setup: Setup-Solaufein.tp2 /* Here we add SOLA to PDIALOG.2DA. We're being extra cautious since this * file changes between SOA and TOB. In SOA it has 4 columns, in TOB it has * more. */ APPEND ~pdialog.2da~ // SOA append ~SOLA SOLA SOLA SOLA SOLAUFEIN SOLA SOLA SOLA~ UNLESS ~SOLA~ // somehow we are already there, skip it UNLESS ~25POST~ // means TOB is installed, skip it APPEND ~pdialog.2da~ // TOB append ~SOLA SOLA SOLA SOLA SOLA SOLA SOLA SOLA SOLAUFEIN SOLA SOLA SOLA SOLA SOLA SOLA SOLA~ UNLESS ~SOLA~ // we are already there, skip it IF ~25POST~ // requires TOB to be installed Here he is adding both "Sola" and "Solaufein". From testing on EasyTutu/Tutu, we found that UNLESS and IF are case sensitive, so you may have to use regular expressions (regexp) to determine case sensitivity. Otherwise, if someone patches in "Sola Sola... etc." and you use UNLESS ~SOLA~ you will get SOLA SOLA SOLA SOLA Sola Sola Sola Luckily, this seems to be a cosmetic error. The game reads through and finds the first one, and uses it without case-sensitivity. It should also be noted that there are several modern mods out there which add ToB - style entries to the pdialog.2da, and skip this cautious check for and they appear to work successfully on SoA installs. The i.e. engine does not care about spacing or having extra columns on the pdialog.2da - SoA seems to ignore them. Post Dialog files are usually short and sweet; for a full line-by line breakdown see Aran's Phat P-File Phun . They are called when an NPC has been in the party and is kicked out or "reformed" out, and either a script call or a player click sends a Dialog() [or within that family of commands] call the NPC's way. While it is possible to code these into CHAIN constructions, it is very seldom done. This is also not usually the place for long discussions. In fact, the only thing usually done to P-files of NPCs (besides creating their own and adding the entries to the PDIALOG.2DA) is the addition of kicked-out dialog that allows an NPC to be moved to a new area to wait for the party later. Most P-files only contain three or four states. The primary usages will be for APPENDing to existing states for specialized responses, but technically if you use a condition you can add CHAIN dialog. To do either, instead of detecting the NPC in question as "in the party" and "in the area" and NOT state=notvalid, you could use a modified NOT inparty IN my area NOT state=notvalid: InParty("c-aran") InMyArea("c-aran") !StateCheck("c-aran",CD_STATE_NOTVALID) ////// NOT IN PARTY BUT AROUND CONDITIONS ////// // Cernd ~!InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ //Edwin ~!InParty("Edwin") InMyArea("Edwin") !StateCheck("Edwin",CD_STATE_NOTVALID)~ // HaerDalis ~!InParty("HaerDalis") InMyArea("HaerDalis") !StateCheck("HaerDalis",CD_STATE_NOTVALID)~ // Jaheira ~!InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ // Jan ~!InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID)~ // Keldorn ~!InParty("Keldorn") InMyArea("Keldorn") !StateCheck("Keldorn",CD_STATE_NOTVALID)~ // Korgan ~!InParty("Korgan") InMyArea("Korgan") !StateCheck("Korgan",CD_STATE_NOTVALID)~ // Mazzy ~!InParty("Mazzy") InMyArea("Mazzy") !StateCheck("Mazzy",CD_STATE_NOTVALID)~ // Minsc ~!InParty("Minsc") InMyArea("Minsc") !StateCheck("Minsc",CD_STATE_NOTVALID)~ // Nalia ~!InParty("Nalia") InMyArea("Nalia") !StateCheck("Nalia",CD_STATE_NOTVALID)~ // Valygar ~!InParty("Valygar") InMyArea("Valygar") !StateCheck("Valygar",CD_STATE_NOTVALID)~ // Viconia ~!InParty("Viconia") InMyArea("Viconia") !StateCheck("Viconia",CD_STATE_NOTVALID)~ // Yoshimo ~!InParty("Yoshimo") InMyArea("Yoshimo") !StateCheck("Yoshimo",CD_STATE_NOTVALID)~ // Imoen2 ~!InParty("Imoen2") InMyArea("Imoen2") !StateCheck("Imoen2",CD_STATE_NOTVALID)~ // Aerie ~!InParty("Aerie") InMyArea("Aerie") !StateCheck("Aerie",CD_STATE_NOTVALID)~ // Anomen ~!InParty("Anomen") InMyArea("Anomen") !StateCheck("Anomen",CD_STATE_NOTVALID)~ // MOD ADDED ~!InParty("c-aran") InMyArea("c-aran") !StateCheck("c-aran",CD_STATE_NOTVALID)~ Next up, Joined dialog files.
  17. To create new states in each Banter file, we can append the new states directly. APPEND construction templates APPEND ~BHAERDA~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[HAERDALIS] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BJAHEIR~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[JAHEIRA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BJAN~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID)~ THEN ~[JAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BKELDOR~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[KELDORN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BKORGAN~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[KORGAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BMAZZY~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[MAZZY] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BMINSC~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[MINSC] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BNALIA~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[NALIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BVALYGA~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[VALYGAR] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BVICONI~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[VICONIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BYOSHIM~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[YOSHIMO] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BIMOEN2~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[IMOEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BCERND~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[CERND] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BEDWIN~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[EDWIN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BAERIE~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[AERIE] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND APPEND ~BANOMEN~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND Adding Aran's template, APPEND ~C-ARANB~ IF ~ <<CONDITION>> ~ THEN BEGIN <<statename>> SAY ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ IF ~~ THEN DO ~ <<CLOSE_CONDITION>> ~ EXIT IF ~~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> IF ~ <<CONDITION>> ~ THEN REPLY ~ <<TEXT>> ~ DO ~ <<CLOSE_CONDITION>> ~ EXTERN <<DIALOG_FILE>> <<statename>> END END // of APPEND Sample usage: HERE and the last permutation initiating a Banter File CHAIN : CHAIN IF ~ <<CONDITION>> ~ THEN ~BAERIE~ << statename>> ~[AERIE] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BANOMEN~ << statename>> ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BCERND~ << statename>> ~[CERND] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BEDWIN~ << statename>> ~[EDWIN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BHAERDA~ << statename>> ~[HAERDALIS] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BIMOEN2~ << statename>> ~[IMOEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BJAHEIR~ << statename>> ~[JAHEIRA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BJAN~ << statename>> ~[JAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BKELDOR~ << statename>> ~[KELDORN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BKORGAN~ << statename>> ~[KORGAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BMAZZY~ << statename>> ~[MAZZY] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BMINSC~ << statename>> ~[MINSC] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BNALIA~ << statename>> ~[NALIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BVALYGA~ << statename>> ~[VALYGAR] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BVICONI~ << statename>> ~[VICONIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END CHAIN IF ~ <<CONDITION>> ~ THEN ~BYOSHIM~ << statename>> ~[YOSHIMO] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == END Sample usage: HERE Now for ToB's banters. BioWare uses a "25" designation for these: /////////////////////////////////ToB B - FILE ///////////////////////////////// == ~BHAERD25~ IF ~InParty("HaerDalis") InMyArea("HaerDalis") !StateCheck("HaerDalis",CD_STATE_NOTVALID)~ THEN ~[HAERDALIS] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ DO ~ <<DO_ACTION>> ~ == ~BJAHEI25~ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~[JAHEIRA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BJAN25~ IF ~InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID)~ THEN ~[JAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BKELDO25~ IF ~InParty("Keldorn") InMyArea("Keldorn") !StateCheck("Keldorn",CD_STATE_NOTVALID)~ THEN ~[KELDORN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BKORGA25~ IF ~InParty("Korgan") InMyArea("Korgan") !StateCheck("Korgan",CD_STATE_NOTVALID)~ THEN ~[KORGAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BMAZZY25~ IF ~InParty("Mazzy") InMyArea("Mazzy") !StateCheck("Mazzy",CD_STATE_NOTVALID)~ THEN ~[MAZZY] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BMINSC25~ IF ~InParty("Minsc") InMyArea("Minsc") !StateCheck("Minsc",CD_STATE_NOTVALID)~ THEN ~[MINSC] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BNALIA25~ IF ~InParty("Nalia") InMyArea("Nalia") !StateCheck("Nalia",CD_STATE_NOTVALID)~ THEN ~[NALIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BVALYG25~ IF ~InParty("Valygar") InMyArea("Valygar") !StateCheck("Valygar",CD_STATE_NOTVALID)~ THEN ~[VALYGAR] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BVICON25~ IF ~InParty("Viconia") InMyArea("Viconia") !StateCheck("Viconia",CD_STATE_NOTVALID)~ THEN ~[VICONIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BYOSHIM~ IF ~InParty("Yoshimo") InMyArea("Yoshimo") !StateCheck("Yoshimo",CD_STATE_NOTVALID)~ THEN ~[YOSHIMO] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BIMOEN25~ IF ~InParty("Imoen2") InMyArea("Imoen2") !StateCheck("Imoen2",CD_STATE_NOTVALID)~ THEN ~[IMOEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BCERND25~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[CERND] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BEDWIN25~ IF ~InParty("Edwin") InMyArea("Edwin") !StateCheck("Edwin",CD_STATE_NOTVALID)~ THEN ~[EDWIN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BAERIE25~ IF ~InParty("Aerie") InMyArea("Aerie") !StateCheck("Aerie",CD_STATE_NOTVALID)~ THEN ~[AERIE] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BANOME25~ IF ~InParty("Anomen") InMyArea("Anomen") !StateCheck("Anomen",CD_STATE_NOTVALID)~ THEN ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BSAREV25~ IF ~InParty("Sarevok") InMyArea("Sarevok") !StateCheck("Sarevok",CD_STATE_NOTVALID)~ THEN ~[SAREVOK] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ Mod-Added Template for ToB B FILE == ~C-ARNB25~ IF ~InParty("c-aran") InMyArea("c-aran") !StateCheck("c-aran",CD_STATE_NOTVALID)~ THEN ~[ARAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ To create the remaining templates in this series, copy and paste the SoA entries, swapping the values present for dialog files in the code above. The only thing that changes is the dialog file designated, as the game indexes the resources on the death variable/script name. The InParty("myDV"), etc. are static across the whole game.
  18. The Heart of the Matter: Dialog Files and How They Are Referenced The question that seems to drive some folks crazy when building an NPC - What tells the engine what pile of states to scan through to find what to present? And what the heck are all these NPC.DLG, JNPC.DLG, BNPC.DLG, etc. that I find lying around the game? OK, easy enough to explain, and it will help me out too, as I like to have quick templates to use for copy/paste. The i.e. engine can see a couple of possibilities for your NPC. It actually sees all calls to the engine equally, processes them in a hierarchical manner, activates and deactivates many different scripts at once, internally subdivides these into several different categories... but that is way DeepCode stuff that really does not concern most modders. If you already know this stuff then you are not here for the tutorial, you are here for the templates. Grab 'em and go, and skip all this talk. But for most of us, we can see the engine as "seeing" two families of dialog states, the Interact() family of called dialog, on the Banter files, and the Dialog() family of called dialog, on the other dialog files. You could use a telephone system analogy here. Each NPC has several different ways of being called, but it all breaks down into the question "cell phone" or "land line". For the purposes of this discussion, Interact() works as dialing a cell phone number, while Dialog() works as a home telephone. Dialog Files and Your NPC The engine can "see" several possible things that you want to do with dialog files assigned to NPCs. a participant NPC exists in the game resources, and is talking primarily with other joined NPCs - called by Interact() in some script, run off of the banter scripting. OR a participant NPC exists in the game resources, and has joined the party, and is no longer in the party. a participant NPC exists in the game resources, and has joined the party, and is talking primarily with the PC. a participant NPC doesn't exist in the game resources. a participant NPC exists in the game resources, and has not joined the party - or is not a joinable NPC at all and will never join the party. Breaking these down: a participant NPC exists and has joined the party, and is talking primarily with other joined NPCs. Here is the "B-File", or "Banter File"; all the materials called for by use of the Interact() set of commands. This is reserved by BioWare primarily for NPC to NPC banter, called through INTERDIA.2DA. More on that below. OR a participant NPC exists and has joined the party, but is no longer in the party. Referenced via PDIALOG.2DA. This, the "P-file", or "Post Dialog File", gives you a dialog file for NPCs who have joined and left (or been kicked out, or been removed via script by the game) and now you are re-encountering them. a participant NPC exists and has joined the party, and is talking primarily with the PC. Referenced via PDIALOG.2DA. This one is the most commonly used, and is called on with commands in the Dialog() and StartDialogNoSet() family. Called the "J-file", or "Joined File", this one is set up for when you click on the joined NPC and force-talk them, and is the home of Love Talks, Friend Talks, and most of the dialog between PC and NPC - with or without other NPCs. It usually contains the most "conditioned" talks. a participant NPC doesn't exist. (You forgot to create the references in PDIALOG.2DA, or the NPC is not installed). Well this one seems just silly - if an NPC doesn't exist in the game, well, duh! Unfortunately, it really isn't silly at all - it is quite common for folks to misunderstand how dialog and dialog files interact in the game. Just because you have built a dialog and compiled it doesn't mean that it exists according to the game. You may have created a dialog file, made sure it includes BEGIN ~MyFile~, added some states, put it into the game, and still the dialog doesn't get called, because there is still a link missing. You haven't told the game how to reference these new structures; you have not added your NPC to the INTERDIA.2DA and PDIALOG.2DA files. More on that later, but basically, you have created an entire new subdivision and forgotten to tell the mapmakers and EMS squad it exists. a participant NPC exists and has not joined the party, or will never join the party... NOT referenced via PDIALOG.2DA The game has a file for all these states, usually named similarly to the NPC's name. Example: AERIE.DLG. These are called all sorts of things, but let's name this the "Pre-Joined Dialog File" for now. When an NPC has not joined the party, this set of states is available to call on. For most NPCs, this is as far as a dialog goes. All those dialog files in NI or DLTCEP or other editors, like BGT's BGWILLA.DLHG, or mod added ones like C-ARAN.DLG, or vanilla ones like JAHEIRA.DLG and such - all of these are simple dialog files for NPCs that are out of the party. All regular non-joinable NPCs work through this dialog file, so we could name it other things, like "standard dialog file" but since we are playing with a specific subset of NPCs (ones that can join the party) let's not. This "Pre-Joined Dialog File" is set up in the .cre file as the primary dialog. For Joinable NPCs, this set of states is designed to be dumped in favor of the J-File when an NPC joins, and the P-File when an NPC is kicked out or leaves the party. OK, let's knock these off one at a time. Before we mess about telling the game new information, we should look at what entries already exist, and how they interact. So, here is the easiest one to work with, the "B-File". Banter, or primarily NPC <-> NPC interaction (whether one, two, or many more NPCs) lives in this set of files. A call via script or through the game's banter script (accellerated if you use JCompton's Banter Accellerator) using Interact("myNPCsDV") references the game's INTERDIA.2DA file. We pick up the cell phone (Interact()) and call our NPC. The game acts as a switchboard, and connects our call using a specific file to look up locations of our NPC's dialog file. For SoA and ToB, we have a two dimentional array of choices for the game, in INTERDIA.2DA: interdia.2da 2DAV1.0 NONE [/td] FILE 25FILE AERIE BAERIE BAERIE25 ANOMEN BANOMEN BANOME25 CERND BCERND BCERND25 EDWIN BEDWIN BEDWIN25 HAERDALIS BHAERDA BHAERD25 JAHEIRA BJAHEIR BJAHEI25 JAN BJAN BJAN25 KELDORN BKELDOR BKELDO25 KORGAN BKORGAN BKORGA25 MAZZY BMAZZY BMAZZY25 MINSC BMINSC BMINSC25 NALIA BNALIA BNALIA25 VALYGAR BVALYGA BVALYG25 VICONIA BVICONI BVICON25 YOSHIMO BYOSHIM BYOSHIM IMOEN2 NONE BIMOEN25 SAREVOK NONE BSAREV25 What this breaks down to is that for death variable "aerie", when processing a call using Interact(), the game will look for the dialog file BAERIE.DLG if it is processing in SoA, and BAERIE25.DLG if it is playing ToB. Notice Sarevok: no entry for the SoA column! Well we know he can't be an NPC in vanilla unmodded SoA. So there is no file assigned. The telephone call cannot be placed, because he doesn't exist as a joinable NPC. The same for Imoen - for some reason, long discussed and buried in ancient forum posts, BioWare decided that Imoen really didn't need banter in SoA. After all, she isn't around for a good chunk of the game. Don't worry: lots of mods fix that situation. But to be very careful, let's see if we can fix that ourselves if it hasn't been fixed yet... Checking and Adding Imoen's Banter File There are several ways of doing this. Here is what Feuille and Miss Sakaki use for The Luxley Family (like most folks, they adapt from the BG2 Fixpack code): //Giving Imoen a banter file if the Fixpack isn't installed ACTION_IF NOT FILE_EXISTS_IN_GAME ~cdbehbla.pro~ //makes sure the fixpack isn't already installed THEN BEGIN ACTION_IF FILE_EXISTS_IN_GAME ~saradush.mve~ THEN BEGIN COPY_EXISTING ~interdia.2da~ ~override~ SET_2DA_ENTRY 17 1 2 ~BIMOEN2~ // fixes ToB version BUT_ONLY_IF_IT_CHANGES END ELSE BEGIN APPEND ~interdia.2da~ ~IMOEN BIMOEN2~ // fixes SoA version UNLESS ~BIMOEN2~ END END side note; the UNLESS is used in the second block to check if BIMOEN2 has already been added to the interdia.2da So for ToB, they look for the movie file for Saradush, and if they find it they read the .2da file and set the specific entry using SET_2DA_ENTRY (follow the link for documentation). If they don't find ToB, it is even easier, as SoA only has a two-column entry; they just add Imoen directly to the bottom of the file. On BG1NPC, CamDawg used regexp instead, after defining some variables so that tabs and/or spaces won't throw off our patching; COPY_EXISTING ~interdia.2da~ ~override~ REPLACE_TEXTUALLY CASE_INSENSITIVE ~IMOEN2[ %whitespace%]+NONE[ %whitespace%]+BIMOEN25~ ~IMOEN2 BIMOEN2 BIMOEN25~ BUT_ONLY_IF_IT_CHANGES For SoA, a regexp example designed to add the BIMOEN2 if it doesn't exist, regardless of case: APPEND ~interdia.2da~ ~IMOEN BIMOEN2~ UNLESS ~_\(BIMOEN2\|bimoen2\)~ A quick reminder, too - the game doesn't care if it is a space, or a tab, or anything dividing up the columns. So "ugly" columns don't matter. The problem comes when you forget to add an entry like "***" or "BLANK" or "NONE" - on ToB, IMOEN2 BIMOEN25 is read not as IMOEN2 {space for blank entry } BIMOEN25 but as /* column 1 */ /* column 2 */ /* column 3 */ IMOEN2 BIMOEN25 That is why you see the "NONE" in the ToB INTERDIA.2DA. Of course, remember the INTERDIA.2DA entries are only for the initial "conditioned" states, called through Interact() - you could *not* patch in and use BIMOEN2 if you wanted, and just store those materials on the J-file, since they are directly called states. More on that when we see jcompton's use of the "invisible creature trick" later. For now, here is what Theaceface does in Sarah to avoid having problems: K#AurenB.d, lines 649 - 664 // AurenImoen CHAIN IF ~Global("AurenImoenBanter1","AR2200",1)~ THEN K#AurenB AI1 ~(Auren speaks softly so that she is not heard by other Drow in the city.)~ DO ~SetGlobal("AurenImoenBanter1","AR2200",2)~ == K#AurenB ~You doing all right, Imoen?~ [K#AureBd] == IMOEN2J ~I...I think so. Thank you for asking...um...~ == K#AurenB ~Auren.~ == IMOEN2J ~Right...sorry.~ == K#AurenB ~So...you're a Child of Bhaal, too?~ == IMOEN2J ~I guess. I'm sort of just in shock over this whole thing. I just hope that when we reach Irenicus and Bodhi that it's not too late.~ == K#AurenB ~Don't worry.~ == K#AurenB ~We'll make it in time.~ == IMOEN2J ~I hope so, Auren.~ EXIT Here, Theaceface has simply assigned all Imoen banter lines to the joined file, IMOEN2J. As long as she avoids starting the banter with Imoen's line form the non-existent SoA B-file via Interact(), she can freely reference other files as storage. Many other mods use this idea; it means Imoen can't initiate a banter, but it also means compatibility protection. So now the modded INTERDIA.2DA says interdia.2da 2DA V1.0 NONE FILE 25FILE AERIE BAERIE BAERIE25 ANOMEN BANOMEN BANOME25 CERND BCERND BCERND25 EDWIN BEDWIN BEDWIN25 HAERDALIS BHAERDA BHAERD25 JAHEIRA BJAHEIR BJAHEI25 JAN BJAN BJAN25 KELDORN BKELDOR BKELDO25 KORGAN BKORGAN BKORGA25 MAZZY BMAZZY BMAZZY25 MINSC BMINSC BMINSC25 NALIA BNALIA BNALIA25 VALYGAR BVALYGA BVALYG25 VICONIA BVICONI BVICON25 YOSHIMO BYOSHIM BYOSHIM IMOEN2 BIMOEN2 BIMOEN25 SAREVOK NONE BSAREV25 This means that any time the game decides it is time for a banter, it goes to it's list of NPC death variables (script names) and can now look up BIMOEN2. Of course, that means we probably should add our own entries for our own NPC, so that banters work. A pretty straightforward additional line in the .tp2 file adds our new entry in: APPEND ~interdia.2da~ ~C-ARAN C-ARANB C-ARNB25~ UNLESS ~C-ARAN~ side note; a quick reminder that while a death variable/script name can be longer than 8 characters, the file references are restricted to 8. So the BioWare designers BAERIE25 is the maximum file resource name. Instead of following BioWare conventions of <<designation>><<name>> and <<designation>><<name>>25, we are using <<community_prefix>><<name>><<designation>>, <<C->> <<ARAN>> <<B>>. The name gets truncated to fit within the 8 character limit for the ToB file, <<community_prefix>><<name>><<designation>>25, or "C- ARN B 25" So now, Aran has his own banter file entry: interdia.2da 2DA V1.0 NONE 25FILE AERIE BAERIE BAERIE25 ANOMEN BANOMEN BANOME25 CERND BCERND BCERND25 EDWIN BEDWIN BEDWIN25 HAERDALIS BHAERDA BHAERD25 JAHEIRA BJAHEIR BJAHEI25 JAN BJAN BJAN25 KELDORN BKELDOR BKELDO25 KORGAN BKORGAN BKORGA25 MAZZY BMAZZY BMAZZY25 MINSC BMINSC BMINSC25 NALIA BNALIA BNALIA25 VALYGAR BVALYGA BVALYG25 VICONIA BVICONI BVICON25 YOSHIMO BYOSHIM BYOSHIM IMOEN2 BIMOEN2 BIMOEN25 SAREVOK NONE BSAREV25 C-ARAN C-ARANB C-ARNB25 We can process this file into a whole set of templates for use in APPEND and CHAIN construction. Templates for Canonical BioWare NPCs Banter File entries /////////////////////////////////SoA B FILE ///////////////////////////////// CHAIN entry construction == ~BAERIE~ IF ~InParty("Aerie") InMyArea("Aerie") !StateCheck("Aerie",CD_STATE_NOTVALID)~ THEN ~[AERIE] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BANOMEN~ IF ~InParty("Anomen") InMyArea("Anomen") !StateCheck("Anomen",CD_STATE_NOTVALID)~ THEN ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BCERND~ IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[CERND] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BEDWIN~ IF ~InParty("Edwin") InMyArea("Edwin") !StateCheck("Edwin",CD_STATE_NOTVALID)~ THEN ~[EDWIN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BHAERDA~ IF ~InParty("HaerDalis") InMyArea("HaerDalis") !StateCheck("HaerDalis",CD_STATE_NOTVALID)~ THEN ~[HAERDALIS] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BIMOEN2~ IF ~InParty("Imoen2") InMyArea("Imoen2") !StateCheck("Imoen2",CD_STATE_NOTVALID)~ THEN ~[IMOEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BJAHEIR~ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~[JAHEIRA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BJAN~ IF ~InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID)~ THEN ~[JAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BKELDOR~ IF ~InParty("Keldorn") InMyArea("Keldorn") !StateCheck("Keldorn",CD_STATE_NOTVALID)~ THEN ~[KELDORN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BKORGAN~ IF ~InParty("Korgan") InMyArea("Korgan") !StateCheck("Korgan",CD_STATE_NOTVALID)~ THEN ~[KORGAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BMAZZY~ IF ~InParty("Mazzy") InMyArea("Mazzy") !StateCheck("Mazzy",CD_STATE_NOTVALID)~ THEN ~[MAZZY] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BMINSC~ IF ~InParty("Minsc") InMyArea("Minsc") !StateCheck("Minsc",CD_STATE_NOTVALID)~ THEN ~[MINSC] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BNALIA~ IF ~InParty("Nalia") InMyArea("Nalia") !StateCheck("Nalia",CD_STATE_NOTVALID)~ THEN ~[NALIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BVALYGA~ IF ~InParty("Valygar") InMyArea("Valygar") !StateCheck("Valygar",CD_STATE_NOTVALID)~ THEN ~[VALYGAR] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DOO ~ <<DO_ACTION>> ~ == ~BVICONI~ IF ~InParty("Viconia") InMyArea("Viconia") !StateCheck("Viconia",CD_STATE_NOTVALID)~ THEN ~[VICONIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ == ~BYOSHIM~ IF ~InParty("Yoshimo") InMyArea("Yoshimo") !StateCheck("Yoshimo",CD_STATE_NOTVALID)~ THEN ~[YOSHIMO] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ and add in Aran's values, Mod-Added Template for SoA B FILE == ~C-ARANB~ IF ~InParty("c-aran") InMyArea("c-aran") !StateCheck("c-aran",CD_STATE_NOTVALID)~ THEN ~[ARAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ //options: DO ~ <<DO_ACTION>> ~ Sample usage: HERE For more traditional coding where you EXTERN directly to another banter file if an NPC is present or to take advantage of the relatively small size of the banter file and toss directly linked states into the banter file, REPLY construction template remember to remove the optional portion, i.e. /* options: DO ~ <<DO_ACTION>> ~ */ IF ~InParty("Aerie") InMyArea("Aerie") !StateCheck("Aerie",CD_STATE_NOTVALID)~ THEN ~[AERIE] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BAERIE~ <<newstate>> IF ~InParty("Anomen") InMyArea("Anomen") !StateCheck("Anomen",CD_STATE_NOTVALID)~ THEN ~[ANOMEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BANOMEN~ <<newstate>> IF ~InParty("Cernd") InMyArea("Cernd") !StateCheck("Cernd",CD_STATE_NOTVALID)~ THEN ~[CERND] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BCERND~ <<newstate>> IF ~InParty("Edwin") InMyArea("Edwin") !StateCheck("Edwin",CD_STATE_NOTVALID)~ THEN ~[EDWIN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BEDWIN~ <<newstate>> IF ~InParty("HaerDalis") InMyArea("HaerDalis") !StateCheck("HaerDalis",CD_STATE_NOTVALID)~ THEN ~[HAERDALIS] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BHAERDA~ <<newstate>> IF ~InParty("Imoen2") InMyArea("Imoen2") !StateCheck("Imoen2",CD_STATE_NOTVALID)~ THEN ~[IMOEN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BIMOEN2~ <<newstate>> IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~[JAHEIRA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BJAHEIR~ <<newstate>> IF ~InParty("Jan") InMyArea("Jan") !StateCheck("Jan",CD_STATE_NOTVALID)~ THEN ~[JAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BJAN~ <<newstate>> IF ~InParty("Keldorn") InMyArea("Keldorn") !StateCheck("Keldorn",CD_STATE_NOTVALID)~ THEN ~[KELDORN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BKELDOR~ <<newstate>> IF ~InParty("Korgan") InMyArea("Korgan") !StateCheck("Korgan",CD_STATE_NOTVALID)~ THEN ~[KORGAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BKORGAN~ <<newstate>> IF ~InParty("Mazzy") InMyArea("Mazzy") !StateCheck("Mazzy",CD_STATE_NOTVALID)~ THEN ~[MAZZY] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BMAZZY~ <<newstate>> IF ~InParty("Minsc") InMyArea("Minsc") !StateCheck("Minsc",CD_STATE_NOTVALID)~ THEN ~[MINSC] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BMINSC~ <<newstate>> IF ~InParty("Nalia") InMyArea("Nalia") !StateCheck("Nalia",CD_STATE_NOTVALID)~ THEN ~[NALIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BNALIA~ <<newstate>> IF ~InParty("Valygar") InMyArea("Valygar") !StateCheck("Valygar",CD_STATE_NOTVALID)~ THEN ~[VALYGAR] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BVALYGA~ <<newstate>> IF ~InParty("Viconia") InMyArea("Viconia") !StateCheck("Viconia",CD_STATE_NOTVALID)~ THEN ~[VICONIA] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BVICONI~ <<newstate>> IF ~InParty("Yoshimo") InMyArea("Yoshimo") !StateCheck("Yoshimo",CD_STATE_NOTVALID)~ THEN ~[YOSHIMO] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~BYOSHIM~ <<newstate>> and add in Aran's values, Mod-Added Template for SoA B FILE IF ~InParty("c-aran") InMyArea("c-aran") !StateCheck("c-aran",CD_STATE_NOTVALID)~ THEN ~[ARAN] <<SPOKEN_TEXT>> ( <<ACTION_TEXT>> ) ~ /* options: DO ~ <<DO_ACTION>> ~ */ EXTERN ~C-ARANB~ Sample usage: HERE
  19. Note: I expect that K'aeloree will create another darned good and simple-to-follow tutorial on this in the relatively near future, correctly outlined, and hopefully he will loot and pillage this attempt in the process. These materials are a consolidation and reference on the subject often passed quickly through on the way to getting dialog in the game. As a side benefit, they provide cut & paste template materials as "code shortcuts". -cmorgan There are many different dialog files the engine calls on when the game is unfolding. There are some great tutorials out there, but since I like to prep stuff beforehand, perhaps this breakdown will be a useful addition and save some folks some work coding their mods. Preparation Tutorial links useful to follow before/while/after reading this investigation of dialog file usage: The Road to Banter - by Blue, the Immortal Bard gives you a clue about some of the dialog files and their use, WeiDU Basics - by Japheth you basic IF THEN END states, a series of short tutorials/examples by Kulyok on PPG and several other sites gives you basic examples, and Definitions, Tools and Resources, NPC Creation Series, part 1, by berelinde and the follow up parts 2 and 3 give you a solid basis for all NPC creation including dialog files. A follow up with Theaceface's Ace's very long NPC creation guide should give you a crosscheck on ideas, so that you can get a handle on much of the syntax. Check out K'aeloree's new materials on SHS as well for follow-up and step-by-step breakdowns on things like "What is CD_STATE_NOTVALID and how do I use it?" or "Coding Interjections" or "Coding Friendships and Romances". If you are looking for item dialogs before I get there, there already is a great tutorial available on that: Easy Item Dialogs, for BG2 SoA and ToB by Smoketest. To organize the basic concepts, check out NPC Dialogue 101 by Ghreyfain, also found in a repost at SHS. This tutorial is an expansion of Ghreyfain's original work. After you have finished this tutorial, I suggest a quick visit to a pair of posts/tutorials, for the folks struggling with the whole "why does the order of states in a file matter" thing (or "why does my dialog not play correctly") which often has to do with the order that the engine 'sees' the various states in order to evaluate whether they are true or false. Weights - State Weights - by Japheth and the follow-up Another look at WEIGHT, by JCompton. So now you have some basics down, let's review again exactly what a state is, and what a dialog file is. Introduction: A review of States and Dialog Files Primary concept: dialog files are lists of states. At the most elementary logic level, a dialog file is no more than a list of possible text lines for the game to present. IF ~some_condition_exists~ THEN PRINT_TO_SCREEN ~some_text_with_or_without_additional_links~ END IF ~some_other_condition_exists~ THEN PRINT_TO_SCREEN ~some_text_with_or_without_additional_links~ END IF ~no_condition~ THEN PRINT_TO_SCREEN ~some_text_with_or_without_additional_links~ END Brought into the game by WeiDU reading in the file myMod.tp2, a dialog state is added when WeiDU compiles an IF THEN END code block through a ".d file" into a new or existing game resource designated by the extension .dlg Examples of usage in myMod.tp2: COMPILE ~myMod/c-aran.d~ COMPILE EVALUATE_BUFFER ~myMod/dlg/AnyNameYouwWant.d~ Reminder: when WeiDU compiles a .d file, it does not automatically add or start or set up references, or create a .dlg file. WeiDU still needs entries in the .tp2 file and .d file to set this into the game. So /* standard .d file with dialog */ COMPILE ~myMod/c-aran.d~ /* "evaluated" .d file with dialog and in-file variables that need to be evaluated before adding strings to the dialog.tlk */ COMPILE EVALUATE_BUFFER ~myMod/dlg/AnyNameYouwWant.d~ does not add the dialog files c-aran.dlg AnyNameYouwWant.dlg it just processes those files to find out what you *do* want added to the game. To add specific dialogs to the game, the .d file needs to have some entries. Why don't we start with adding a .dlg file so that the game will recognize a valid dialog: in myMod.tp2: COMPILE ~myMod/c-aran.d~ in the related c-aran.d: BEGIN ~c-aran~ So that gives the i.e. engine a chance at identifying and reading a new .dlg. Let's go on and add three states to c-aran.d. To keep things separated and simplified, we have begun a .dlg, and now we are going to add states to that .dlg - to "append" new materials to the existing file. BEGIN ~c-aran~ APPEND ~c-aran~ END The APPEND block contains all of the states that relate to a single dialog file, "c-aran". Now we add some actual states: BEGIN ~c-aran~ APPEND ~c-aran~ IF ~NumTimesTalkedTo(0)~ THEN BEGIN c-aranstarts SAY ~Aye, welcome, then. This is a fine day on Trade Way." IF ~~ THEN EXIT END IF ~NumTimesTalkedTo(1)~ THEN BEGIN c-aranagain SAY ~I do remember you - we talked before, didn't we..." IF ~~ THEN GOTO c-aranends END IF ~~ c-aranends SAY ~No matter. Welcome again, then. This is a fine day on Trade Way." IF ~~ THEN EXIT END END The only difference in the above three states is what brings them up to the engine's "use this now" list. While that's a whole other topic, we can shortcut to the following breakdown; When the game engine looks in the .dlg file c-aran, and begins evaluating each state in order. It checks agains State 1, and if it finds the condition NumTimesTalkedTo(0) is true, it fires off State 1 - and in the dialog box in-game, the player sees the text string "Aye, welcome, then. This is a fine day on Trade Way". If it finds State 1 is false (for example, if this is the second time we have called on the dialog file "c-aran.dlg"), then the engine skips State 1 and moves to State 2. It tries again; if it finds " number of times talked to = 1", then state 2 is fired, and the player sees the text string "I do remember you - we talked before, didn't we...". If this is the third time we have talked to the NPC assigned the .dlg "c-aran", then we have a problem. State 1 evaluates false and is skipped, state 2 evaluates false and is skipped, and state 3 has no condition - it literally cannot be evaluated. State 3 can only be linked from another state (in this case it is linked from State 2), so the dialog fails. What happens at this point depends on several factors not for discussion in this tutorial. For now, let's go back and fix this so there is no chance of failure: BEGIN ~c-aran~ APPEND ~c-aran~ IF ~NumTimesTalkedTo(0)~ THEN BEGIN c-aranstarts SAY ~Aye, welcome, then. This is a fine day on Trade Way." IF ~~ THEN EXIT END IF ~NumTimesTalkedToGT(0)~ THEN BEGIN c-aranagain SAY ~I do remember you - we talked before, didn't we..." IF ~~ THEN GOTO c-aranends END IF ~~ c-aranends SAY ~No matter. Welcome again, then. This is a fine day on Trade Way." IF ~~ THEN EXIT END END Now, either State 1 or State 2 will always be true, and we can look at the reply section of State 2. It creates a direct link to State 3. So the game evaluates State 2, then follows the reply, and we get two separate dialog boxes: I do remember you - we talked before, didn't we... No matter. Welcome again, then. This is a fine day on Trade Way. For great information on how to use and manipulate states, there are a large number of in-depth and beginner-friendly tutorials. So let's move on to the subject of this tutorial, which is more about organizing groups of states and forming and manipulating dialog file references. Here, we contextualize states, and break down what .dlg files are - what they do for our NPC.
  20. No problem. It actually is a major oversight on my part, when looking at a "Companion" mod. It fills out the whole "Tinker, Tailor, Soldier, Spy" routine, and makes it a better challenge - what parts of a character define the personality, and how do they need to be adapted to create the immersion? Gives more replayability, and there is good precedent (I like the Harry Turtledove alternate history sci-fi). Those 4 bases cover the dual class/kit combinations that can coexist peacefully [ fighter, fighter/mage, fighter/cleric, fighter/thief ]. Most NPCs are built with a class and alignment defining a good part of how they react to the gameworld, but here we are turning that over on its head, and playing with the idea that a dude or dudette in Faerun can do a job and go to a specific church, have different physical attributes, but still be themselves even if some of that has a mid-career change that really isn't up to them (in this case, the player gets to play god and Aran just goes along for the ride).
  21. Actually, not so dumb. I am keeping out of BG, but really, why not have the reaction thought out even if nothing ever gets crossmodded? It fills out the character.
  22. That's right - hey, they can exist in BG2-land now, too, can't they - heck. This requires some more rereading, and more playing - I blame it all on that crazy rap music. Kids these days - just won't stick to their original game, now, won't they
  23. Thief dual class? Well, sure, why not. I guess if we are playing around from the true "character uuber alles" approach, there really isn't a reason why he couldn't be. Scouting and inteligence gathering is done by both merchants and military, so it could fit his background. Level1 NPCs opens up all sorts of new possibilities, which frees up some traditional D&D ideas. What the heck, let's add it in. See "Survivor" configuration now added above. As for the other NPCs, not sure on the reactions yet - some of those I need a few more playthroughs/studying before I would be able to see his reaction. I don't play many of the evil ones - but I will put them onto my list of "take a look at this".
  24. Aran started as a PBP character in Whisper Company, a short-lived but very fun campaign DM'd by berelinde. The general backstory needed to be adapted to fit better into the BG2 background, though so some of the above "fanfic' like stuff needs re-editing to match his growth. The next chapter is straightforward - he serves in mercenary settings for a few years, going through BG1, then ends up in BG2 ready to parttake in the adventures. It really isn't neccesary to build all this, but it is fun - a game within a game. Some of this can inform the kinds of decisions he would make, and some of it can be built into tall campfire tales - though the whole non-magical bent will have to be editied, and taken in a differet direction. Perhaps different references installed by what class/kit combo he has had chosen for him by the player. Or a re-edit of portions to fit more potential classes.
×
×
  • Create New...