Jump to content

Newbie Modding Questions


Twani

Recommended Posts

This is obvious stuff that I'm sure is explained somewhere on one of the three main modding boards, but I can't find it and I'm feeling stupid. I'll probably be asking a lot of questions like this, so I figured I'd open a thread for it.

 

Basically, I use CHAIN when I want to have other characters besides just my NPC and <CHARNAME> interject, and then SAY if I just want it to be my NPC and <CHARNAME>, right? I think I've got that.

 

Can I link back and forth between the two? Let's say (because it's true) that my first meeting joining dialog is a CHAIN because I want two NPC's to interject if they're there, but my 'have already met but not currently in the party' joining dialog is a SAY because it's just three lines and no one cares. Can I link back to the CHAIN's 'join my party!' and 'don't join my party!' responses so I don't have to write them out again? Can I do the opposite? Let's say my first friendship dialog is a SAY, but I have a later friendship dialog that has interjections in it and is a CHAIN. Can I link back to my first friendship dialog's 'I don't want to talk right now' generic response?

 

I know when going to CHAIN to SAY I have to APPEND. Is there anything I have to do when going from SAY to CHAIN?

Link to comment
Is there anything I have to do when going from SAY to CHAIN?
No, nothing. Other than END an APPEND, if there was one before the CHAIN, of course.

 

so I don't have to write them out again
Never, ever do something double if you already have it in one place. This goes for dialogue states (if in the same .d, you can link to it from any other state). This also goes for text lines, especially journal entries: In case you need one in several .d files, put the relevant text line into one separate .tra that you load with the setup.tra. [sorry for telling things you didn't ask, but it's something I learned painfully and it's important for the BG:EE journal entry handling, too.]
Link to comment
Basically, I use CHAIN when I want to have other characters besides just my NPC and <CHARNAME> interject [...]

Basically, CHAIN was made for dialogs in which Charname doesn't participate (that is, there are no replies)

Otherwise, using CHAIN isn't the best choice (IIRC, it adds dead ends to the .dlg file when replies are used in a CHAIN)

But of course going from SAY to CHAIN and back is perfectly OK

Link to comment
(IIRC, it adds dead ends to the .dlg file when replies are used in a CHAIN)
What are you referring to? Reply options or other transactions are perfectly fine after a CHAIN:

 

CHAIN
IF ~~ dlgname statename
~bla~
END
++ ~reply1~ EXTERN dlgnameX state_1

 

That's the way to add reply options to a CHAIN.

Link to comment

Adding replies to a CHAIN without ENDing it is wrong syntax. Considering every reply option lead to a new dialogue state it is kind of logical imho that the CHAIN is cut off and the dialogue continues with (an)other(s). I still didn't get what you meant with "dead ends". Maybe I didn't get your meaning but your post reads as if using CHAINs somehow excludes the possibility of reply options, or that it leads to compile errors, or that it is bad in some other way. which is not true. It is perfectly all right to use CHAIN, with or without reply options that lead to new dialogue states (that can be coded as CHAINs again). But, yes, the relevant CHAIN has to be ENDed for the reply options to be put in, and the dialogue then has to continue in another dialogue state or CHAIN, coding wise.

Link to comment

Okay, now I'm confused. I have for instance this as part of the joining dialog:

 

CHAIN M3ALT greetintro

~I am a Windwalker. Altan is my name. My usual duty is guarding caravans, but... without caravans, there's no one to guard. So I'm looking to sign on with an Adventuring Company and find out why that is. And to explore places and generally adventure and all that. And you seem to be an Adventuring Company, of sorts.

== %JAHERIA_JOINED% IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~He seems a bit naive, but Windwalkers are well thought of by certain organizations that do right by this world. I wouldn't tell you how to form your party, <CHARNAME>, but he may be worth considering.~

== %VICONIA_JOINED% IF ~InParty(“Viconia”) InMyArea(“Viconia”) !StateCheck(“Viconia”,CD_STATE_NOTVALID)~ THEN ~A weak male for a weaker god. We have no need of him.~

== M3ALT ~I know my way around the Sword Coast well, and if you need a guide to get somewhere, I can probably help you. I'm a skilled tracker, and a decent cook. And I know it's not a bow, but I have a pretty mean shot with a sling.~

END

++ ~I'm <CHARNAME>. What exactly is a Windwalker?~ EXTERN greetwind

++ ~I think I could make use of you. I'm <CHARNAME>. Welcome to the party.~ EXTERN greetjoin

++ ~I'll give you my name- <CHARNAME>- but I want nothing to do with a coddled child like you. Off with you.~ EXTERN greethellno

 

Greetwind, greetjoin, greethellno all lead to more CHAIN's. Is this okay and will compile nicely without explosions and chaos? I thought replies were fine in chains.

 

 

 

Another question, and this might be harder. About BGTutu/BGT/BGEE compatability doom.

 

I'm about to start work on interjections, and how they work cross compability is confusing me. I've checked out Gavin, Isra, and Valerie, and- taking the first example from Gavin- he does an interjection with Dawn Priest Blane. The code is like this:

I_C_T ~%tutu_var%BLANE~ 0 BGavinBlane

== ~B!GAVINJ~ IF ~InParty("B!GAVIN") InMyArea("B!GAVIN") !StateCheck("B!GAVIN",CD_STATE_NOTVALID) %BGT_VAR%~ THEN @4

== ~%tutu_var%BLANE~ IF ~InParty("B!GAVIN") InMyArea("B!GAVIN") !StateCheck("B!GAVIN",CD_STATE_NOTVALID) %BGT_VAR%~ THEN @5

END

 

Likewise, Isra's first interjection is with Tranzig, and the code goes like this:

 

I_C_T ~%tutu_var%TRANZI~ 7 rh#int.tranzig

== RH#ISRAJ IF ~InParty("rh#Isra") InMyArea("rh#Isra") !StateCheck("rh#Isra",CD_STATE_NOTVALID)~ THEN

~I have no wish to murder a man who has surrendered, <CHARNAME>, granted he can be trusted not to return to his former masters.~

DO ~SetGlobal("rh#IsraTranzigSpared","GLOBAL",1)~

== ~%tutu_var%TRANZI~ ~I swear it! He'd kill me himself if I tried!~

END

 

I understand the I_C_T, the needing to name each interjection individually, the need to check for in the party-ness and the need to set globals if this is an interaction that can be repeated so you don't see the interjection a million times. What I don't get is stuff like %tutu_var%TRANZI. How does that help BGT (and BGEE) find that person for interjection? I didn't see anything in the lib files about people you interject with, just area and creature codes. Is that something that is coded in WEDIU (which I'm avoiding at the moment- I'll save that for last, as it confuses me even more then scripting)? Or does WEIDU automatically understand that %tutu_var%TRANZI is _Tranzi in Tutu, Tranzi in BGEE, and whatever it is in BGT? I'm a bit lost on this. I assume I make my interjections by copying how Gavin, Isra, Valerie, Finch, Indi, and the BG1NPC project do it, but I figure it's better for me to know what exactly I'm doing then just copy without knowledge.

 

Then there's the '%BGT_VAR%' in Gavin's dialog. Is that required? What does it do exactly? Isra doesn't have it, and I gather she works on BGT, but I don't want to be making mistakes.

 

 

Also, just a... general question. Why do most interjections in BG1 have a response from the person being interjected with immediately after it? I've noticed that for all NPCs, as a general rule, when someone interjects, the writer has the interjectory (...) respond rather then simply ending it with the interjection. That's not true in BGII modding. Does that help cross-compatibility? Just a quirk of the modding scene? Is it something one should generally do if at all possible?

 

 

...Thank you so much for answering all my stupid questions. This board is so friendly. :)

Link to comment

I think everyone is right here - in general, don't use a nuclear warhead to kill a fly is a good choice!

Here is the original way we had to create banter/dialog between NPCs.

 

Form tashia, Bri and lord Ernie cleaning up the original by Laufey:

BEGIN taarilis

IF ~Global("TashiaArilistan","GLOBAL",2)
   Dead("taevil")~ THEN BEGIN 23
 SAY @0
 IF ~~ THEN DO ~SetGlobal("TashiaArilistan","GLOBAL",3)
			 ChangeAIScript("kensai",CLASS)
			 Enemy()
			 Attack(Player1)~ EXIT
END

IF ~Global("TashiaArilistan","GLOBAL",0)~ THEN BEGIN 0
 SAY @1
 IF ~~ THEN DO ~SetGlobal("TashiaArilistan","GLOBAL",1)~ EXTERN tashiaj c1
END

APPEND tashiaj
 IF ~~ THEN BEGIN c1
   SAY @2
   IF ~~ THEN EXTERN taarilis c2
 END
END

APPEND taarilis
IF ~~ THEN BEGIN c2
 SAY @3
 IF ~~ THEN EXTERN tashiaj c3
END
END

APPEND tashiaj
 IF ~~ THEN BEGIN c3
   SAY @4
   IF ~~ THEN EXTERN taarilis c4
 END
END
//etc., etc.

 

Then the magic of Weimer and The Bigg made it possible to "shortcut" this, as if you look at the decompiled files from vanilla BG2, you can see how crazy it gets trying to write for multiple discussion folks - miles and miles of "if she is present then extern to her file, if not then extern to his file, else goto another option" statements that quickly clobber everyone's brain. So I_C_T[2,3,4] and eventually CHAIN:

 

Rhaella's Adrian:

CHAIN IF WEIGHT #-1 ~Global("rh#AdrianTalks","GLOBAL",12)~ THEN RH#ADRJ rh#talk6
~Dammit. I should be glad that she's more interested in profit than blood, but it's only a matter of time before she changes her mind.~
== JAHEIRAJ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~And now you will demand protection, no doubt. You are lucky that <CHARNAME> did not simply hand you over to the Cyricist.~
== RH#ADRJ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~And here I always thought your kin enjoyed rescuing people from the Zhentarim.~
== JAHEIRAJ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~You are no victim, Adrian.~
== RH#ADRJ IF ~InParty("Jaheira") InMyArea("Jaheira") !StateCheck("Jaheira",CD_STATE_NOTVALID)~ THEN ~Of course not. Hells, Harper. Could this please wait until later? I'm slightly more worried about Tanya right now.~
== RH#ADRJ ~As I recall, she was always too organized for her own good. She tended to keep written records of her affairs -- a terrible habit, but then I've never expected much competence from a Cyricist.~
= ~If we're very lucky, she may even keep notes on any associates of hers. If we can figure out where she's staying, identify and hunt down whatever contacts she has in the city, this problem should solve itself. I hope. <CHARNAME>?~
DO ~IncrementGlobal("rh#AdrianTalks","GLOBAL",1)~
END
   ++ ~Explain. Now.~ + rh#talk6_explanation
    ++ ~You should have told me about this earlier.~ + rh#talk6_explanation
    ++ ~I hope I won't have to worry about more of your old friends dropping by.~ + rh#talk6_friends
    ++ ~I may have given you a head start on your old friends, but don't mistake that for tolerance. Get lost. Now.~ + rh#talk6_getlost

 

But now we get into the point of contention - Seb and some serious modders fall in the camp of "don't abuse CHAIN". And Zrayan and some other folks currently modding say "I'll do what I want and do things like this, because it works":

 

Kulyok's tutorial Branwen:

// Spellhold, right after the player loses his or her soul.

INTERJECT Player1 3 O#BranSpellholdDizzy0
== O#BRANJ IF ~InParty("O#Bran") Range("O#Bran",15) !StateCheck("O#Bran",CD_STATE_NOTVALID)~ THEN
~Are you all right? What has Irenicus done to you? I swear, I'll kill him!~
END
++ ~I'm all right. Don't worry.~ EXTERN O#BRANJ pl1.1
++ ~I felt strange, like I wasn't in control.~ EXTERN O#BRANJ pl1.2
++ ~Don't coddle me!~ EXTERN O#BRANJ pl1.1

CHAIN O#BRANJ pl1.1
~All right. But be wary. No one wants to lose you.~
EXIT

CHAIN O#BRANJ pl1.2
~Really? That's disturbing. But I'm here, <CHARNAME>. All your friends are with you.~
EXIT

 

OK.... usually you would do

// Spellhold, right after the player loses his or her soul.

INTERJECT Player1 3 O#BranSpellholdDizzy0
== O#BRANJ IF ~InParty("O#Bran") Range("O#Bran",15) !StateCheck("O#Bran",CD_STATE_NOTVALID)~ THEN
~Are you all right? What has Irenicus done to you? I swear, I'll kill him!~
END
++ ~I'm all right. Don't worry.~ EXTERN O#BRANJ pl1.1
++ ~I felt strange, like I wasn't in control.~ EXTERN O#BRANJ pl1.2
++ ~Don't coddle me!~ EXTERN O#BRANJ pl1.1

APPEND O#BRANJ

IF ~~ pl1.1
 SAY ~All right. But be wary. No one wants to lose you.~
 IF ~~ THEN EXIT
END

IF ~~ pl1.2
 SAY ~Really? That's disturbing. But I'm here, <CHARNAME>. All your friends are with you.~
 IF ~~ THEN EXIT
END

END // of APPEND

 

... but in this case, Branwen is not close to an APPEND block, so using CHAIN like this means that the non-traified code is easily readable. So the "abuse" of CHAIN to add one state makes WeiDU process some stuff differently... it doesn't really make any discernable difference.

 

Now, if you are a nut and go about doing everything with CHAIN and *really* abuse it, it can lead to all sorts of problems - because WEIGHT and processing order for the engine is easier to determine when you are working within an APPEND block. First in = highest weight, unless you do something special and actually set the weighted order of dialogs...

 

so if someone starts doing stuff like

 

CHAIN O#BRANJ pl1.1
~All right. But be wary. No one wants to lose you.~
END
++ ~Oh, sure. I am actually trying to get lost.~ EXTERN O#BRANJ pl1.2
++ ~I want to be lost. I am done with you FOREVAR.~ EXTERN O#BRANJ pl1.2

CHAIN O#BRANJ pl1.2
~Really? That's disturbing. But I'm here, <CHARNAME>. All your friends are with you.~
EXIT

CHAIN IF ~Global("Jaheiratalks","GLOBAL",14)~ THEN JAHEIRJ JaheiraTalks1
~Branwen,I am talking to you out of the J file..~
DO ~SetGlobal("Jaheiratalks","GLOBAL",15)~
EXIT

CHAIN IF ~Global("Jaheiratalks","GLOBAL",16)~ THEN BJAHEIR JaheiraTalks2
~Branwen,I am talking to you out of the B file..~
DO ~SetGlobal("Jaheiratalks","GLOBAL",17)~
EXIT

 

then we have a real mess - and folks will never understand where they are actually putting things; finding them could be a hassle, weights are all over the map, mass hysteria, dogs and cats living together...

 

..and some dlialog gurus (I think Seb over at SHS, but it could also have been JCompton) early on made a big post and tutorial about how it was far more efficient to code traditionally and only use CHAIN for the specific instance where you want only NPC stuff to take place.

Link to comment

You are looking for this, I think:

 

https://github.com/cmorganbg/BG1NPC/tree/master/bg1npc/lib

 

%tutu_var%TRANZI evaluates to TRANZI on BGT, so WeiDU looks for the correct file and adds your stuff.

 

%tutu_var%TRANZI evaluates to _TRANZI on Tutu, so WeiDU looks for the correct file and adds your stuff.

 

The %BGT_VAR% evaluates to absolutely nothing in Tutu, so the condition does not exist on Tutu scripting blocks and dialogs, but evaluates to !Global("endofbg1","GLOBAL",2) on BGT - so that on BGT, Jaheira doesn't run BG content when she is in BG2 content.

Link to comment
Why do most interjections in BG1 have a response from the person being interjected with immediately after it?

 

"passback", the references are here:

 

http://forums.pocketplane.net/index.php?topic=24398.20;wap2

 

Basically, in order to make sure you end up with the original actor doing whatever it is they do, you create a "passback" and use I_C_T. There are other solutions to this, too; one is to not interject into the same state with multiple files within the same mod (something we couldn't avoid in BG1NPC). But to make sure you never actually hijack the original actions onto your interjecting speaker, using a passback is the simplest solution.

Link to comment
I thought replies were fine in chains.
They are and that's why I posted several posts above, to set Lu_'s vaguely phrased comments right before more confusion is spreading. Your CHAIN looks like correct syntax.

 

stuff like %tutu_var%TRANZI. How does that help BGT (and BGEE) find that person for interjection? I didn't see anything in the lib files about people you interject with, just area and creature codes. Is that something that is coded in WEDIU (which I'm avoiding at the moment- I'll save that for last, as it confuses me even more then scripting)? Or does WEIDU automatically understand that %tutu_var%TRANZI is _Tranzi in Tutu, Tranzi in BGEE, and whatever it is in BGT?
The games are identified and the right names are inserted upon install, if you include the libs I think cmorgan linked to. Have a look at the BG1NPC-setup.tp2 and look at the "INCLUDE .... .lib" lines executed in the ALWAYS block at the beginning.

 

'%BGT_VAR%' in Gavin's dialog. Is that required? What does it do exactly?
I think cmorgan already explained it but this variable (the one it compiles to) is only needed for BGT to distinguish between "before Sarevok end fight" and "after", to make sure no BG1 stuff happens in the BGII part of the game. It is not needed if the script / NPC is not present in BGII, obviously.

 

The passback-line just makes sure the actions stay with the original speaker. Very important for things like EscapeArea() or Enemy() - without the passback line it will be the last NPC talking who performs the actions (be assured I had several NPCs vanish and turning hostile because I didn't consider this in time. Ahem.) Since you never know what other mod will add to the actions of the state you are I_C_T into,. it is always safer to always include a passback line. It does lengthen the dialogue considerably, though, if every mod NPC that is interjecting adds another line to the original speaker, so it's a question of optimizing compatibility / dialogue flow. (Only an option for those cases where the actions do not include things that can only be executed by the original speaker but are safe for everyone, like e.g. SetGlobal, SetTimer, ActionOverride(anything) etc., of course).

 

And finally a general "yay!" to crossplatform coding! I honor your will to be compatible with all the BG1-enhanced platforms. (Original BG1 is such a hassle due to restrictions of the engine it is a separate thing, although I still try to keep BG1 compatibility for my mods, too. If you have any ambitions concerning this I will suggest strongly against it feel free to ask.)

Link to comment

Having a tutorial would certainly be great. What the Weidu readme covers in 7.2 is far from comprehensive (just inherited from the earliest version, I gather)

 

@Jastey

Sorry for the vague wording, let me explain it then

I was referring to the posibility of putting reply options strictly INSIDE a CHAIN, -- i.e, no END ( or EXTERN or whatever else ends it) between CHAIN (the beginning of it) and replies

Once, -- years and years ago, -- I read a discussion on the subject (one of those that Cmorgan meant, perhaps), and from that I tried it myself. So here's what I got

The purpose was to get kinda

IF ~~ THEN BEGIN A

SAY ~Blah blah~

IF ~~ THEN REPLY ~Blah blah~ GOTO B1

IF ~~ THEN REPLY ~Blah blah~ GOTO B2

...

END

 

But using reply options inside the CHAIN resulted in something like

IF ~~ THEN BEGIN A

SAY ~Blah blah~

IF ~~ THEN EXIT

IF ~~ THEN REPLY ~Blah blah~ GOTO B1

IF ~~ THEN REPLY ~Blah blah~ GOTO B2

...

END

This totally useless 'IF ~~ THEN EXIT' is what I meant mentioning dead ends

Link to comment

I made it down to the 'K's' in interjections. Reading all the dialog in the game is hard... ;_; Not to mention I haven't even looked at BGEE and it's new NPCs and quests yet. My NPC should have a few things to say during Rashaad's whole conflict with the Shar monks, if nothing else... but that's just me moaning and complaining.

 

I think I understand the passback. Basically, if the NPC is doing anything that affects the NPC (escaping, turning hostile), I need to give them back control of the dialog. If they're not doing anything or making generic actions (such as setting globals), I can just do an interjection without passback, right? If I'm correct, I think Jatsey's post is a good enough tutorial on that on it's own. Explains things nicely.

 

I'm not quite sure I understand how %tutu_var%TRANZI links up to BGT/BGEE Tranzi, but as long as it works (if I have the lib folder and such), I guess that's good enough for me. :) I know to use the %Banter Files/Area Locations% and how they work, at least.

 

I'm a long way from needing this- I'm still dithering back and forth on whether I want to write a romance and fully shaping the personality- but how does crossmod work with BG1 NPCs? I see in the forum description for the crossmod banter pack, it says for BGTutu as well, but as far as I can tell, no BG1 content is included in it. Is BG1 crossmod generally included inside the mod, then? That's how it seems to work with Gavin and Isra, but I figured I'd ask here.

 

I'm sure I'll be back with more stupid questions soon enough. Thank you, all. :)

Link to comment

Crossmod: If it's an BG resource (i.e., dialogue file of the BioWare / Overhaul NPCs) you include interactions into your mod.

 

If it is something mod added (e.g. Isra's or Gavin's dialogue file) the problem is the following: If these mods are not installed on the player's account upon installing your mod, any reference to the (then not present) dialogue file would lead to an install error.

 

There is no BG1 Crossmod Banter Pack yet, but it was always discussed as "we can make one if the need is there". Solution until then: Specify an install order in the readme (i.e. your mod to be installed after Isra and Gavin), include a check for the dialogue files (so the installer can skip it if they are not present) and live with people complaining about no interactions between the NPCs because they did the wrong install order (because no one reads readmes). :)

 

The %tutu_var% gets compiled the same as the %area_reference% thingies. For a more "use-but-not-necessary-understood" approach (no offence meant) it's just important to always COMPILE EVALUATE_BUFFER if you have a script or dialogue file using the OUTER_SPRINT variables, and the installer puts in the right variable values from the libs (if they are INCLUDed, of course).

 

Lu_: Sorry for sounding really arrogant, but the examples you posted are normal dialogue states, so they do not enlighten me. I kind of can't get my brains around what exactly you meant by including reply options into the CHAIN (was one reply option supposed to continue the CHAIN? Otherwise, I really don't understand it).

 

Maybe best we agree that the CHAIN's correct synatx consists of: 1. as many NPC to-and-fro as one wants including DOs for everyone; 2. END /EXIT 3. transactions or reply options leading to other dialogue states, and therefore reply options can be added to a CHAIN, but since they work as transitions, they will always lead to a separately scripted dialogue state.

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...