Author Topic: Let's Abuse CHAIN Together  (Read 4806 times)

0 Members and 1 Guest are viewing this topic.

Offline Zyraen

  • Level 2
  • **
  • Posts: 818
  • Karma: +0/-0
    • MSN Messenger - zyraen@hotmail.com
    • View Profile
Let's Abuse CHAIN Together
« on: September 12, 2005, 07:25:45 AM »
One of my friends is trying to bug me to show him how to code Dialogues and stuff, lol, so I decided to do it here. One of the odd things though, about my coding style is that I almost "abuse" CHAINs. ;)

They make things a lot easier, not having to keep to the body of a BEGIN xxxx, allow for better organisation, viewing a banter in a single continuous flow, autonavigation of Options and so on ;) In any case, here's a little tidbit for those who are very new, and maybe for those who are struggling with the irritating irrationalities of linking different D file contents, crossreferencing and all that.

For those of you who are wondering, I think it should be possible to mod a fully-functional NPC without using ANY other blocks in your .D code other than BEGIN (filename), INTERJECT_COPY_TRANS2 and CHAINs ;) and maybe an odd EXTEND_BOTTOM here and there...

Here's the basics of a CHAIN structure

CHAIN
IF (weights, if any)
~(conditions if any)~
THEN (DLG name, let's call it A) (name for this segment)
~line 1~
= ~line 2~
== (another DLG name, call B) IF ~(conditions for B)~ THEN
~line that B says if conditions for B to talk are met~
DO ~(stuff that B executes if conditions for B to talk are met)~
EXIT (or other endings, see below)

I'm sure most of that might not make sense to at least a few of you, so here's some stuff for elaboration.

============

BASIC - A really basic one would be

CHAIN
IF ~~ THEN ARAN hidude
~Hi Dude. Chilling good?~
== DUDEJ ~Swell as hell. Stay cool!~
= ~You need a better hairdo.~
DO ~DisplayStringHead(Myself, @809)~
== ARAN ~You think so?~
= ~Well, what you should really learn is never to insult a Shadowmaster in his lair...~
= ~DIE!~
DO ~Enemy()~
== DUDEJ ~Woah no gotta run for it!~
EXIT

This one is a fairly basic one, between Aran and Dude. Notice that the Enemy() command is executed by Aran yet the DisplayStringHead is executed by Dude. There are no condition checks here, it's fairly straightforward. This little CHAIN, if done without CHAIN, as you can imagine, would be at least 3 calls from DUDEJ.DLG to ARAN.DLG back and forth - nicely caught in a single block here.

Things to note about a basic CHAIN though, is that the DLGs MUST exist BEFORE this CHAIN is compiled. So, if we do not have a BEGIN DUDEJ somewhere in one of the files that have been installed, this basic CHAIN wouldn't be able to execute, as it has no DUDEJ.DLG to point to.

==============

FOR TRANSITIONS - because CHAINs are not contained in a BEGIN body, it is often strange to be unable to do some things...

CHAIN
IF WEIGHT #-1 ~NumTimesTalkedTo(0)
InParty("dude") InMyArea("dude")~ THEN ARAN hi1
~This is a special hi I'm going to say because you have the cool NPC Dude in your party, but after this I'm going to go back and say my usual beginning stuff, so yeah, chill.~
GOTO 0

This, to my knowledge, generates an error, because the program has no idea what "GOTO 0" points to, even though for most it would simply be the 0 in the ARAN file. To get around this, simply replace "GOTO 0" with "EXTERN ARAN 0". Yes it's odd that you have "extern" to the same DLG file you already have, but that's the way things go with CHAIN.

Notice also that, unlike normal IF ~~ THEN BEGIN blocks, you don't have to END a CHAIN.

==============

PLAYER CHOICES - Creating a CHAIN that allows you to program in player responses. Interestingly, this is the one place I seem to be able to use GOTO, but I'm not going to say how to use it...

CHAIN
IF WEIGHT #-1 ~InParty("dude") InMyArea("dude")~ THEN ARAN dudehichoices
~Hey <CHARNAME>! This is so cool you've got Dude with you! Where did you pick him up?~
= ~Wait, actually I don't give a crap about that. Actually I want him dead, mind giving his head to me for some gold?~
== DUDEJ ~Wait, just wait a minute, I swear I didn't know nothing about this!~
== ARAN ~No big deal, it's for <CHARNAME> to decide now, haha! You'll find out what I want with you if he agrees to hand you over for say.. hmm... ten thousand gold should be reasonable.~
= ~So, what say you, <CHARNAME> ? ~
END
IF ~~ THEN REPLY ~That's a really cool amount, Aran. Take this dude from me, and don't forget the gold~ EXTERN ARAN takedude
IF ~CheckStatGT(Player1,15,CHR)~ THEN REPLY ~I don't want nothing of this dude, but the gold's too little. Maybe if you pay me more?~ EXTERN ARAN bargaintakedude
IF ~!CheckStatGT(Player1,15,CHR)~ THEN REPLY ~I don't want nothing of this dude, but the gold's too little. Maybe if you pay me more?~ EXTERN ARAN nottakedude
IF ~~ THEN REPLY ~Dude isn't so bad, I'll keep him a bit longer. If I change my mind we'll drop by to deliver him back to you.~ EXTERN ARAN nottakedude
IF ~~ THEN REPLY ~Screw you, I want Dude for myself.~ EXTERN ARAN fighttotakedude

Notice this bit actually has an END before the beginning of the choices, and there is NO "END" after the last of the options.

==============

COMPLEX - However, a concrete example that comes close to adequately demonstrating the usefulness of CHAIN would be

CHAIN
IF WEIGHT #-1~InParty("dude") InMyArea("dude")~
THEN ARAN hidude
~Hi Dude.~
= ~How you chilling?~
== DUDEJ IF ~HPPercentGT("dude",50)~ THEN
~Chilling right cool, man!~
== DUDEJ IF ~!HPPercentGT("dude",50)~ THEN
~Slightly bummered, a healing potion would be nice...~
== DUDEJ IF ~!HPPercentGT("dude",50)  HasItem("potn52", "dude")~ THEN
~Hey what do you know? I've got one! This is swell, here's a swig to <CHARNAME>!~
DO ~UseItem("potn52",Myself)~
== ARAN IF ~!HPPercentGT("dude",50)  !HasItem("potn52", "dude")~ THEN
~Hmm, been using you like packmules eh? <CHARNAME> isn't as cool as I thought.~
== DUDEJ IF ~!HPPercentGT("dude",50)  !HasItem("potn52", "dude")~ THEN
~Yeah man, major bummer for Dude.~
= ~Hey, you got one of those healing potions around you? Think I could buy one off you?~
== ARAN IF ~!HPPercentGT("dude",50)  !HasItem("potn52", "dude")~ THEN
~No worries, man! On the den... I mean house, that is. Here you go - enjoy!~
DO ~GiveItemCreate("potn52","dude",1,0,0)
ActionOverride("dude", UseItem("potn52",Myself) )
ActionOverride("dude", SetGlobal("GotPotionFromAran","LOCALS",1) )~
== DUDEJ IF ~Global("GotPotionFromAran","LOCALS",1)~ THEN
~All right! You so rock, man! Damned, when I'm through with <CHARNAME> I've gotta join you and buy you a few rounds.~
== ARAN ~Heh, glad to see you're getting by, Dude. Stay cool.~
== DUDEJ ~Right, you are man. Stay un-bummered.~
EXIT

This single piece of writing above has a great amount of versatility and condition checks that can be viewed continuously, and is a lot easier in a CHAIN than scripting to and fro between files, which would require a LOT more work. However, in effect it is many different conversations all lumped into a single block - a very powerful and handy thing, I think. It also, very niftily, is actually able to check for LOCALS variables, something which cannot be done properly from a non-CRE-specific script (don't bother if you don't understand this last line).

If Dude has more than 50% of his life, the conversation would be
Aran ~Hi Dude.~
Aran ~How you chilling?~
Dude ~Chilling right cool, man!~
Aran ~Heh, glad to see you're getting by, Dude. Stay cool.~
Dude ~Right, you are man. Stay un-bummered.~

If Dude has less than 50% of his life and has potn52.
Aran ~Hi Dude.~
Aran ~How you chilling?~
Dude ~Slightly bummered, a healing potion would be nice...~
Dude ~Hey what do you know? I've got one! This is swell, here's a swig to <CHARNAME>!~ (drinks potn52)
Aran ~Heh, glad to see you're getting by, Dude. Stay cool.~
Dude ~Right, you are man. Stay un-bummered.~

(I'm sure you can figure out other cases yourself)

However, there are things to take note of.

- In most DLGs that pauses the game, the action only occurs in an instant, but there are DLGs which do not pause the game, and might cause the speaker to be performing an action while talking. For eg, in the above if Dude drinks the potion, his HP might not have registered an increase yet, just paused at the "glowy effect" of drinking the potion.

- The order of the above placements are important, especially because Dude executes his actions which MAY affect the conditions. For example, if Dude has exactly ONE potn52, after saying "Hey what do you know? I've got one! This is swell, here's a swig to <CHARNAME>!", he might have none left and STILL have less than half his HitPoints. This would cause Aran to comment that <CHARNAME> isn't cool, which is a contradiction and probably not the intent of the writer.

A simple way to fix this would simply be to reorder the condition checks, so that it FIRST checks that Dude has no Potion, and finishes the whole sequence about him drinking the potion Aran provided him, BEFORE making the check for him already having a potion.

So, we move the troublesome code segment to near the bottom so that the code now reads.

(etc)
ActionOverride("dude", SetGlobal("GotPotionFromAran","LOCALS",1) )~

// following 3 lines cut from above and inserted here.
== DUDEJ IF ~!HPPercentGT("dude",50)  HasItem("potn52", "dude")~ THEN
~Hey what do you know? I've got one! This is swell, here's a swig to <CHARNAME>!~
DO ~UseItem("potn52",Myself)~

// back to the default code
== DUDEJ IF ~Global("GotPotionFromAran","LOCALS",1)~ THEN
(etc)

There's probably other things to watch out for, but they've slipped my mind for now.

============

Hope that keeps you guys tuned on the usefulness of CHAIN :) I'm not sure if there's more, hopefully if more comes to mind I'll try to put it somewhere...
SoAVer
Love between a Law Enforcer and a Fugitive - can such a thing even happen?
SoA Release - Overview / Download Links

Zyraen's Miscellaneous Mods - Ust Natha Accelerator, item tweaks, XP caps and redistribution, and more.

Offline Zyraen

  • Level 2
  • **
  • Posts: 818
  • Karma: +0/-0
    • MSN Messenger - zyraen@hotmail.com
    • View Profile
Let's Abuse CHAIN Together
« Reply #1 on: September 23, 2005, 01:50:38 AM »
Edited to clarify the last part somewhat :) On shifting the potentially troublesome code down.
SoAVer
Love between a Law Enforcer and a Fugitive - can such a thing even happen?
SoA Release - Overview / Download Links

Zyraen's Miscellaneous Mods - Ust Natha Accelerator, item tweaks, XP caps and redistribution, and more.