Jump to content

Recommended Posts

DisplayStringHead()

or, classic commentary that sneaks past conversation

 

In all of the i.e. engine games, there is a "shortcut" to side commentary - stuff that is either sotto voce or minor sidebar commentary not really worth a full interruption of the action for a full dialog treatment. This shortcut is displaying a short string, very short, over the head of the speaker, for example the *groan* and *gasp* comments in the healer's hut at the beginning of IWD2, or in its most direct usage, Lilacor's occassional comments (though that actually uses a related command, not DSH(), but you get the point. Now, at one time in i.e. moding history, everyone seemed to be in love with this usage, especially with items - a talking item, way cool! But, as things have gone on, this kind of thing in BG2 has been only used occasionally, and with some pretty specific intent. Let's look at it, though, because it could help out with some side comments and take a burden off of building a tone of little two-liner interchanges. As always, we can always turn it off via setting or unsetting a blocking variable, so players who hate this can drop the content, and folks who like it can add it in.

 

 

When too Much Is Too Much

[ARAN] Hey, I just saw a vampire. Cool.

[MIRIAM] So what am I, chopped liver?

[ARAN] I wish.

[MIRIAM] Come closer and say that, little lamb...

 

Perhaps this might make it into banter territory - short and sweet. But does the party really needs to stop and hear all that? there is not much point to it, and it is scenery dialog. But this one really, really cannot be worth a single dialog box popping...

[ARAN] *phew*

[ARAN] Somethin' died in here, eh...

 

or even

[ARAN] Bugger all - we'd better rest.

 

Now, most modders don't add this stuff much - except for some cutscenes work, hardly ever. A little goes a long, long way, and frankly the game uses the same vehicle for "out-of-character pointers", so it can be distracting. Lilacor is a PITA I seldom enjoy for long, even though he is an interesting personality... or the first 5 playthroughs...

 

So who has used this and how can we see what it is all about?

 

BioWare™ BG2 Usage

 

Surprisingly, according to a search of all decompiled .bcs shipped with BGII-SoA and updated to ToB,

 

1,398 times in .bcs.

 

Wow.

 

OK, there are alot of BG files included in that number, but still - a pretty darned high incidence of usage for something that is not particularly noticeable. Most of the usage is simple stuff, scenery stuff, but here are two quick samples:

 

usage as stage direction or hint for the player

This example is how the dividing troll, well, "divides".

file BGII - SoA\bg2_bcs\TROLUO01.BAF

IF
HPLT(Myself,10)
THEN
RESPONSE #100
	DisplayStringHead(Myself,49970) // To your horror the troll's corpse heaves, and with a violent splash two smaller trolls emerge from the body.
	SmallWait(1)
	CreateVisualEffectObject("ICCSWOUI",Myself)
	Wait(1)
	CreateCreatureObject("trollsm2",Myself,0,0,0) // Troll
	CreateCreatureObject("trollsm2",Myself,0,0,0) // Troll
	CreateVisualEffectObject("ICCSWOUI",Myself)
	DestroySelf()
END

 

usage as scenery dialog not worthy of a conversation

Here, the Beastmaster in the Gladiator pits bemoans the loss of his companion, without pausing to interrupt the combat with a long banter and digressive diatribe about the fundamental unfairness of clobbering an animal with an automatic rifle instead of using nature's equipment and taking her on with just your own bare hands, followed by a small eulogy, while for some reason all combat ceases and people chat about waiting for the fight to restart:

 

file BGII - SoA\bg2_bcs\BEAST.BAF

IF
See([PC])
Dead("Tabitha")
!StateCheck(Myself,STATE_CHARMED)
Global("cry","LOCALS",0)
THEN
RESPONSE #100
	DisplayStringHead(Myself,2544) // My Tabitha...loyal to the end.  Your death I shall avenge, on that I swear.
	Enemy()
	SetGlobal("cry","LOCALS",1)
END

 

and of course, the usage for our favorite talking sword, in baldur.bcs

 

 

NOTE: [DON'T DO THIS EVAR EVAR EVVVVARRRRRR!!!! You had better know your crap thoroughly before you mess with the master script, or you risk really messing up the game for EVERYONE... way not cool... and it runs all the time, and a big baldur.bcs slows everything down, so even if you don't screw it up, you slow down everyone else whether your mod is active or not, or the player is using your content or not - you basically just added a permanent ankle weight to the whole game, so it had better be absolutely necesssary and bloody well worth it, too. Use multiple area scripts with checks for your content being active. Use your NPC script. Heck, use whatever you can figure, and if you can't figure it out, ask every modder you have ever heard of. Seriously. Even if you weight it correctly, and set an immediate blocking variable like InParty("myNPC"). Sorry, rant over. ]

 

file BGII - SoA\bg2_bcs\BALDUR.BAF, the related "DisplayStringHeadOwner()", so that if an item is equipped it will DSH() on the actor...

IF
Delay(600)
CombatCounter(0)
OR(6)
	HasItemEquipedReal("sw2h14",Player1) // Lilarcor
	HasItemEquipedReal("sw2h14",Player2) // Lilarcor
	HasItemEquipedReal("sw2h14",Player3) // Lilarcor
	HasItemEquipedReal("sw2h14",Player4) // Lilarcor
	HasItemEquipedReal("sw2h14",Player5) // Lilarcor
	HasItemEquipedReal("sw2h14",Player6) // Lilarcor
THEN
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",20580) // I may be an intelligent sword, but I've had no formal edumication.
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",20779) // Can we go kill something now, huh?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",20780) // How about now?  No?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",20956) // Come on let's kill something NOW!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",24939) // mmmm.... now?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",25349) // What about now?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31258) // Now?  Please?  Pretty please?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31259) // I don't know what you were expecting, but as a sword I'm pretty one-dimensional in what I want.
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31260) // Can we go whack something now?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31638) // Let's whack something eeeeevvvvillllll....
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31639) // Why don't we go kill that over there?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31640) // You know, I was a Moonblade once.
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31641) // You really need to clean me.  I like to shine!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31646) // Are we going to kill something now, maybe?  Huh?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31649) // You know, my last owner always said I was sharp and edgy.  He was such an ass.
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31651) // I don't chop wood.  I am not an axe.
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31652) // Now!  Now!  Kill something now!!  Yeah!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31654) // Booooo-ring!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31655) // (sigh)
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31656) // (double sigh)
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",6433) // Wanna go kill that over there? C'mon, let's kill somthin'!
END

IF
Delay(125)
!CombatCounter(0)
OR(6)
	HasItemEquipedReal("sw2h14",Player1) // Lilarcor
	HasItemEquipedReal("sw2h14",Player2) // Lilarcor
	HasItemEquipedReal("sw2h14",Player3) // Lilarcor
	HasItemEquipedReal("sw2h14",Player4) // Lilarcor
	HasItemEquipedReal("sw2h14",Player5) // Lilarcor
	HasItemEquipedReal("sw2h14",Player6) // Lilarcor
THEN
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",839) // You deal, I'll cut!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",844) // Let's see what's inside this one!  Yeah!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",849) // Come get some!  Boo-yah!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",869) // Choke up, dolt, your grip is all wrong!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",2308) // Hands up, kiddies, who wants to die?!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",2389) // Mmmm... tastes like chicken!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",4393) // Sissy fighter!  You grab, I'll scratch!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31659) // Muwahahaha-ha-ha!!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31660) // You can't be serious!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",7908) // Ooo, that'll leave a mark!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",8480) // Murder!  Death!!  KILL!!!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",9687) // Who's your daddy!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",9800) // We got a gusher!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",10725) // Are YOU talking to ME?!!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",11255) // Some of my finest work!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",12671) // I'm the best at what I do, and what I do ain't pretty!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31662) // Yeah!  Hit it!  Hit it again!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31663) // I am invincible!  Invincible, I say!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",32426) // Wouldn't it be cool if you could dual-wield me?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",19304) // YOINK!  Got yer nose!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",19441) // My brother is a +12 Hackmaster!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",19638) // I love the smell of daisies in the morning!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",20059) // Swing harder!  Swing harder!!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",20396) // Bring 'em on!  I ain't done!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",20457) // Oh yeah!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",31658) // Let's dance!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",34689) // Kill it!  Kill it quick before they're all gone!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",36145) // Kill kill kill!  Yeah!  Cool!!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",41815) // ...and this one's for grandma, who said I'd never amount to anything more than a butterknife!!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",6434) // Hot butta!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",6435) // You feel lucky, punk?
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",6441) // Oooh, I'm shaking! Haha!
RESPONSE #10
	DisplayStringHeadOwner("sw2h14",6442) // Oooh, throw a coin in that fountain! Hahaha!
END

 

 

Well, ok, what about mods? One of my favorite ones uses it in a way that I would not consider - I would rather some of Tashia's stuff was actually set up as dialog or banters, but some of them are pretty enjoyable as throw-away lines:

 

I like her flirting, with some cool one-liner put-downs, using a random response and resetting the LOCALS value to zero for a new cycle - pretty darned cool, since they are one-liners, and don't need a bunch of responses:

IF
Global("DoFlirt","LOCALS",5)
THEN
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@280) // Excusez-moi, je... sans vouloir vous offenser... mais vous êtes un de ces étrangers dont tout le monde parle, n'est-ce pas ? Un aventurier venu du nord ?
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@281) // Le parchemin de Helm dispara”t avec la destruction de l'avatar de Démogorgon.
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Myself,@282) // P-par pitié, ne me faites pas de mal ! Je... je suis venu vous voir parce que j'ai entendu parler de votre grand pouvoir, étranger. Vous... vous êtes bien un aventurier venu du nord, n'est-ce pas ?
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@283) //
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@284) //
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@285) // Mais oui, bien sûr. Tout le monde peut voir que vous êtes un homme extraordinaire, pardonnez-moi.
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@286) // Et toi, tu dois être celui dont parlait le garçon près du cimetière.
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@287) // On vous a parlé de moi ? Oui, c'est vrai que c'est une petite ville. Et à l'écart de tout, c'est-ce que j'ai pensé... suffisamment pour que personne ne me trouve ici. Quelle grossière erreur !
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@288) // C'est une aubaine que quelqu'un d'aussi puissant que vous soit venu dans ce coin perdu. Je pensais qu'Amkethran serait suffisamment loin de tout pour que personne ne m'y trouve, mais je me trompais !
RESPONSE #10
	SetGlobal("DoFlirt","LOCALS",0)
	DisplayStringHead(Player1,@289) // Je ne veux pas vous importuner, étranger, mais je cours un très grave danger ! J'ai besoin de votre aide ! J'implore de vous une faveur, messire, sinon ma fille et moi allons sûrement mourir !
END

 

Where I disagree with the usage is when there are several lines passed back and forth. Not the ones that might be mini-banters, like this funny little jibing of Jaheira's snoring:

IF
InParty(Myself)
PartyRested()
AreaType(DUNGEON)
See("Jaheira")
InParty("Jaheira")
!Global("SnoreJaheira","GLOBAL",1)
THEN
RESPONSE #100
	SetGlobal("SnoreJaheira","GLOBAL",1)
	DisplayStringHead(Myself,@123) // No such index
	Wait(3)
	DisplayStringHead("Jaheira",@124) // No such index
	Wait(3)
	DisplayStringHead(Myself,@125) // No such index
	Wait(3)
	DisplayStringHead("Jaheira",@126) // No such index
	Wait(3)
	DisplayStringHead(Myself,@127) // No such index
END

but the ones where Player1 is scripted the response. I hate that. Even for one liners, if there is going to be a reply, unless Player1 has been brainsucked and dominated, there really is no reason I can think of to not give the player some choice. I like this sequence in-game, but then, I like Tashia and I like those responses. But I play certain types of characters. I would rather have choices to match more roleplaying options.

 

One I would rewrite as a banter:

IF
Global("SleepComment","LOCALS",3)
THEN
RESPONSE #100
	SetGlobal("SleepComment","LOCALS",0)
	SetGlobal("PillowTalk","LOCALS",1)
	StartCutSceneMode()
	MoveViewObject("Tashia",INSTANT)
	FaceObject(Player1)
	DisplayStringHead(Myself,@77) // No such index
	Wait(3)
	DisplayStringHead(Myself,@78) // No such index
	Wait(2)
	DisplayStringHead(Player1,@79) // No such index
	Wait(2)
	DisplayStringHead(Myself,@80) // No such index
	Wait(2)
	DisplayStringHead(Player1,@81) // No such index
	Wait(2)
	DisplayStringHead(Myself,@82) // No such index
	Wait(3)
	DisplayStringHead(Myself,@83) // No such index
	EndCutSceneMode()
END

 

The most common mod usage is for combat script, like this snippet of Amber that gives a potion to a fellow player if the conditions are right (Comments by Darios):

// **********************************************************************
// *		   Segment Name: dai_AmberHealLIPotions.baf
// **********************************************************************
//Pass a potion to the Love Interest - this may not always work due to IE limitations
//This is triggered by a 2001call from DPLAYER3.BCS or from gs_2001Call.baf
//Works for both PCS and non-PCS parties

//If Amber has a potion..... problem is, this will make her pass all potions of type
//This is an IE limitation: GiveItem always gives all items of the specified type

//Superior healing
IF
ActionListEmpty()
!CombatCounter(0)
Heard(Player1,2001)
Global("M#AmberRomanceActive","GLOBAL",2)
Global("M#AmberMatch","GLOBAL",1)
!StateCheck(Player1,STATE_OUT_OF_ACTION)
!HasItem("potn08",Player1)
!HasItem("potn52",Player1)
!HasItem("potn55",Player1)
HasItem("potn55",Myself)
THEN
 RESPONSE #100
  GiveItem("potn55",Player1)
  DisplayStringHead(Myself,@58) // Quickly, my love! Drink this!
END

 

All these can get the job done written into the .baf files. Just check which versionn of WeiDU you are using - up until recently, you *had* to add USING to your traification stuff with compiling .baf files, even if you used AUTO_TRA. I am not sure if it is necesary now, but I will have to wait a bit to test or get comments, so it is probably safest to use COMPILE ~mybaf.baf~ USING ~mybaf.tra~

 

DisplayStringHead(Myself,~They at least no is wuss around here.~)

DisplayStringHead(Myself,%They at least no is wuss around here.%)

DisplayStringHead(Myself,@247)

/* or, if there already is a string reference to use, */
DisplayStringHead(Myself,46150) // quaffs a potion

 

You can also call an entire conversation this way, back and forth. Take a look at these two cool blocks from Zrayen's "Beyond The Law".

 

This one kicks the party hard (though safer action is to kick them out of the party and then set them as enemies) if the script sees the listed conditions:

// If the PC attacks Brega or Bylanna or Prelate Radiant Heart

IF 	OR(2)
	InParty("Kiyone")
	InParty("Kova")
OR(8)
	Allegiance("habrega",ENEMY)
	Allegiance("bylanna",ENEMY)
	Allegiance("hprelate",ENEMY)
	Allegiance("Z#ARDEL",ENEMY)
	Allegiance("Z#Baev",ENEMY)
	Dead("hprelate")
	Dead("bylanna")
	Dead("habrega")
THEN
RESPONSE #100
DisplayStringHead("Kiyone", @804)
DisplayStringHead("Kova", @805)
ActionOverride("Kiyone", Enemy())
ActionOverride("Kova", Enemy())
END

 

and this one does a randomly different statement when it is run:

IF	GlobalGT("GovtMeetGuards","GLOBAL",3)
THEN
RESPONSE #10
SetGlobal("GovtMeetGuards","GLOBAL",2)
DisplayStringHead("Kiyone", @810)
ReputationInc(-1)
RESPONSE #10
SetGlobal("GovtMeetGuards","GLOBAL",2)
DisplayStringHead("Kiyone", @811)
ReputationInc(-1)
RESPONSE #10
SetGlobal("GovtMeetGuards","GLOBAL",2)
DisplayStringHead("Kiyone", @812)
ReputationInc(-1)
END

 

Chloe uses it to inform the player that they have Transgressed Against The Will Of God (Or At Least The Modder) by trying to use Chloe's special item:

// FIRE FIRE FIRE!! Hehehehe, FIRE, yeah FRY 'EM!

// SW 1

IF
  !HasItemEquiped("CHLOSW1","Chloe")
  HasItemEquiped("CHLOSW1",Player1)
THEN
  RESPONSE #100
  DisplayStringHead(Player1,~Only a chosen of Akadia can wield this weapon. You have commited sacriledge~)
  CreateVisualEffectObject("SPSCHGI",Player1)
  CreateVisualEffectObject("SPHOLYWD",Player1)
  CreateVisualEffectObject("SPHOLYMT",Player1)
  CreateVisualEffectObject("SPGENHLA",Player1)
  CreateVisualEffectObject("SKYBOLT",Player1)
  CreateVisualEffectObject("SPFIREPI",Player1)
  CreateVisualEffectObject("SPFIRSDI",Player1)
  ActionOverride(Player1,ReallyForceSpell(Player1,WIZARD_FIREBALL))
  Kill(Player1)
END

(Hey, put a half-crazy god-child in your party and take her stuff, and I guess you really get what you deserve, even if it is a game killing TKO... I reallyy hope you saved. You did save, didn't you...)

 

Opportunities for Aran

 

Well, there are some things that really don't need much. I have some odd things here and there for fun, like this one, which could be dropped from a single line called in dialog to a simple one liner DSH():

 

in .baf

/* Shade Lord (Darios)  */
IF
Killed([0.UNDEAD.SHADOW.SHADOW.0.FEMALE]) // Shade Lord
Global("c-silencearan","GLOBAL",0)
Global("c-aranshadelord","LOCALS",0)
OR(2)
  AreaCheck("AR1400") // Temple ruins
  AreaCheck("AR1404") // Temple ruins restored
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
!StateCheck(Player1,CD_STATE_NOTVALID)
THEN
RESPONSE #100
	SetGlobal("c-aranshadelord","LOCALS",1)
END

 

in .d

 /* Shade Lord (Darious)  */
IF ~Global("c-aranshadelord","LOCALS",1) Global("c-silencearan","GLOBAL",0)~ THEN BEGIN c-aranshade1
SAY ~[ARAN] Ah, light! Lathandar's Luminated Lamp, that's a right fine thing to see. I was beginnin' to think we'd never see naught but shadow, darkness, an' death.~
IF ~~ THEN DO ~SetGlobal("c-aranshadelord","LOCALS",2) SetGlobalTimer("c-aransmalltalk","GLOBAL",300)~ EXIT
END

 

becomes

/* Shade Lord (Darios)  */
IF
Killed([0.UNDEAD.SHADOW.SHADOW.0.FEMALE]) // Shade Lord
Global("c-silencearan","GLOBAL",0)
Global("c-aranshadelord","LOCALS",0)
OR(2)
  AreaCheck("AR1400") // Temple ruins
  AreaCheck("AR1404") // Temple ruins restored
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
!StateCheck(Player1,CD_STATE_NOTVALID)
THEN
RESPONSE #100
	DisplayStringHead(Myself,~Ah, light! Lathandar's Luminated Lamp, that's a right fine thing to see. I was beginnin' to think we'd never see naught but shadow, darkness, an' death.~)
	SetGlobal("c-aranshadelord","LOCALS",1)
	SetGlobalTimer("c-aransmalltalk","GLOBAL",300)
END

 

Or what about exchanges that are too short for dialog?

 

/* Korgan Doppleganger  */
IF
See([0.0.DOPPLEGANGER])
Global("c-silencearan","GLOBAL",0)
Global("c-arandopple","LOCALS",0)
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
!StateCheck(Player1,CD_STATE_NOTVALID)
InParty("korgan")
!StateCheck("korgan",CD_STATE_NOTVALID)
!StateCheck("korgan",CD_STATE_NOTVALID)
THEN
RESPONSE #100
	DisplayStringHead("korgan",~That be one ugly bastard.~)
	Wait(2)
	DisplayStringHead(Myself,~Hey! He looks just like me!~)
	Wait(2)
	DisplayStringHead("korgan",~That's what I said.~)
	Wait(2)
	SetGlobal("c-aranarandopple","LOCALS",1)
	SetGlobalTimer("c-aransmalltalk","GLOBAL",300)
END

 

Or perhaps something for the ladies in service...

 

/* ..And Your Beady Little Eyes on the Road Ahead (10 points for song reference)  */
IF
CombatCounter(0)
Global("c-silencearan","GLOBAL",0)
See("kpmaid01")
Global("c-aranchanelle","LOCALS",0)
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
!StateCheck(Player1,CD_STATE_NOTVALID)
THEN
RESPONSE #100
	DisplayStringHead(Myself,~Well, now, you are a pretty lass...~)
	Wait(2)
	DisplayStringHead("kpmaid01",~Watch those hands, sirrah.~)
	Wait(2)
	SetGlobal("c-aranchanelle","LOCALS",1)
	SetGlobalTimer("c-aransmalltalk","GLOBAL",300)
END

 

Or even a minor interlude with a friend...

 

/* Childish Jokes Are Almost Always Funny  */
IF
Global("c-silencearan","GLOBAL",0)
OR(2)
	GlobalGT("c-arananomen","LOCALS",0) // banter fired, needs G<>L check
	GlobalGT("c-anomenaran","LOCALS",0) // banter fired, needs G<>L check
Global("c-arananomenf","LOCALS",0)
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
!StateCheck(Player1,CD_STATE_NOTVALID)
InParty("anomen")
!StateCheck("anomen",CD_STATE_NOTVALID)
!StateCheck("anomen",CD_STATE_NOTVALID)
THEN
RESPONSE #100
	DisplayStringHead(Myself,~*BUUURRPPPP*~)
	Wait(2)
	DisplayStringHead("anomen",~Control yourself, Whitehand. That is churlish behavior.~)
	Wait(2)
	DisplayStringHead(Myself,~Sir, Yes Sir. No more loud burpin', Sir.~)
	Wait(3)
	DisplayStringHead(Myself,~*fffbbbbbt*~)
	Wait(2)
	SetGlobal("c-arananomenc","LOCALS",1)
	SetGlobalTimer("c-aransmalltalk","GLOBAL",300)
END

 

This just might have some possibilities.

Edited by cmorgan

Share this post


Link to post
/* Childish Jokes Are Almost Always Funny */

BWAHAHAHAHAHAHAHhahahahahah!

 

That was funny.

Share this post


Link to post

Just wanted to say thanks for the idea. IWD however requires the use of FloatMessage. Here's a working example...

IF
 ActionListEmpty()
 Global("ab_heal_at_rest","GLOBAL",1)
 HPPercentLT(MostDamagedOf(GroupOf(Myself)),100)
 HaveSpell(PALADIN_LAY_ON_HANDS)
 GlobalTimerExpired("ab_rest_healing","GLOBAL")
THEN
 RESPONSE #100
SetGlobalTimer("ab_rest_healing","GLOBAL",6)
Spell(MostDamagedOf(GroupOf(Myself)),PALADIN_LAY_ON_HANDS)
FloatMessage(Myself,@7)
Wait(3)
FloatMessage(MostDamagedOf(GroupOf(Myself)),@8)
END

Just so you know the text is as follows:

Spell caster says: ~Did ya feel the power?

I laid my hands on you.~

The one healed says: ~I feel dirty now...~

Share this post


Link to post

I like it!

 

ActionListEmpty()

 

Spell(MostDamagedOf(GroupOf(Myself)),PALADIN_LAY_ON_HANDS)

 

I am going to go look at some of that in BG2 engine - using this stuff as Combat AI only is where most folks are now, it seems, but I like the idea.

Share this post


Link to post
I like it!

 

ActionListEmpty()

 

Spell(MostDamagedOf(GroupOf(Myself)),PALADIN_LAY_ON_HANDS)

 

I am going to go look at some of that in BG2 engine - using this stuff as Combat AI only is where most folks are now, it seems, but I like the idea.

I've got a couple more uses of it in my IWD mod Rest For 8 Hours. If you want to look at them, the link to the mod is in my signature...

Share this post


Link to post

I only know that text that pops up somewhere on the screen makes me very nervous, because I have the impression I am missing something. Having my eyes somewhere else (guaranteed), I'll panicky pause the game and scroll through the text box. I like to see everything in a way it can't slip by.

This doesn't mean I don't like the idea, though. Probably if it's comments that may repeat or come in similar places, so I'd now it's "one of his comments".

Share this post


Link to post

DisplayStringHead() wasn't supported in BG/TotSC, so those 1,398 hits should all be unique to BG2 if you searched for "Head."

 

I'm not in favor of using it as a substitute for dialogue outside cutscene mode. Tabitha is pushing the limits of where I think it's safe to use; a dynamic scene like the genie in Ust Natha is a place where I think it's particularly effective. To me, DisplayString is really more like feedback than interaction. Short exchanges between NPCs (like the guards and commoners in Amkethran) or if plainab's block is for an NPC are good examples for stuffing more fun in an otherwise bland and un-dialogue-able routine, I think.

 

I am going to go look at some of that in BG2 engine - using this stuff as Combat AI only is where most folks are now, it seems, but I like the idea.
ActionListEmpty() is good, but it's hard to find general uses for it. It's also not the most pleasant since it takes extra thought to really figure out beforehand when the action list really will be empty (for PC AI, it's useful to not preempt the player's "manual" actions with dumb script actions).

 

GroupOf() won't return anything useful in BG2. MostDamagedOf() will only return the most damaged party member (regardless of where it's called from) in BG and BG2.

Edited by devSin

Share this post


Link to post

Cool, thanks - and thanks for the information on the stats return, too, since they are related.

 

 

I agree on your points regarding the usage. There might be some fun one-liner things that can fit into this, but both Jastey's comments and BioWare's usage shows DSH() is most useful as direct feedback or "extras" commenting - unless there is some specific usage that needs non-interruptible dialog during combat, which is the *least* likely place for that to be read, especially .

 

The use of it as trap and static object warnings, and things like the "you look into the pools and see..." usage in the initial dungeon works well, and its use in AI scripts for feedback, that seems to be where the vast majority of folks have used it (IWD, on the other hand, seems to be more liberal).

 

The most interesting useage I can think of was Domi's BG1NPC spell sequence in Dynaheir's (and Minsc's) attempted Abduction by Winski. It was fun learning how to do this for her, and fits the "fun idea", but it means a nice little poem actually never gets seen - especially by the players who will appreciate it most, the ones who want Dy to stick around and finish the game.

 

Winski takes off, and leaves an imp behind who begins "casting a spell" in player terms, but actually it is his combat script. All he does is speak verses and spout casting sounds - if the script runs to the end without the imp being killed (thus stopping the script from running), the last block of the script takes Dy and Minsc away.

 

IF
 True()
 Global("X#DImpSpell","LOCALS",0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",1)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@0)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",1)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",2)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@1)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",2)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",3)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@2)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",3)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",4)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@3)
PlaySound("%tutu_var%EFF_P24")
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",4)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",5)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@4)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",5)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",6)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@5)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",6)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",7)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@6)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",7)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",8)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@7)
PlaySound("%tutu_var%EFF_P24")
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",8)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",9)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@8)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",9)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",10)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@9)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",10)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",11)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@10)
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",11)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
StartTimer(0,5)
SetGlobal("X#DImpSpell","LOCALS",12)
PlaySound("IMPPP04")
DisplayStringHead("Ichthraa",@11)
CreateCreatureObjectOffset("X#MEPHT2",Player1,[60.60])
CreateCreatureObjectOffset("X#MEPHT1",Player1,[70.100])
PlaySound("%tutu_var%EFF_P24")
Continue()
END

IF
 Global("X#DImpSpell","LOCALS",12)
 TimerExpired(0)
 !Dead("Ichthraa")  // Ichthraa
THEN
 RESPONSE #100
SetGlobal("X#DImpSpell","LOCALS",12)
PlaySound("%tutu_var%EFF_P18")
SetGlobal("X#WinskiTakeDyna","GLOBAL",1)
SetGlobal("X#DynaheirRomanceInactive","GLOBAL",1)
ActionOverride("dynaheir",LeaveParty())
ActionOverride("dynaheir",ChangeAIScript("",DEFAULT))
ReallyForceSpell("dynaheir",DRYAD_TELEPORT)
ActionOverride("minsc",LeaveParty())
ActionOverride("minsc",ChangeAIScript("",DEFAULT))
ReallyForceSpell("minsc",DRYAD_TELEPORT)
ReallyForceSpell("Ichthraa",DRYAD_TELEPORT)
END

 

the related .tra, Domi's casting poem,

@0	= ~All mortal men must die~
@1	= ~And mortal women do too~
@2	= ~Run, snow wolf, run~
@3	= ~Dragons are coming for you.~
@4	= ~The lions have choked~
@5	= ~On the dark rose hips~
@6	= ~And wolves that won~
@7	= ~Went with the wind~
@8	= ~Twists'n'scream bare squid~
@9	= ~Stag has fled to the wall~
@10   = ~You are coming with me~
@11   = ~It is now your turn~

 

Shorter is better, and less is more - wow, all sorts of truisms to toss about her, I guess :)

 

So DSH() and DSHO() is like very strong cayenne - to be used sparingly, and in only the right dishes!

Share this post


Link to post

Fun with standing around doing nothing... since these fire off 1 per minute, it pretty much is just for me to have some fun while testing various things, because few or no folks are actually going to hang around in the virtual bar. Fun with cyclical but randomized bloack!

 

/* area script for C-AR01, The Broken Sword */

/* create Aran, cue up scenery dialogs */
IF
 Global("c-aranspawn","C-AR01",0)
 !Exists("c-aran")
THEN
RESPONSE #100
 CreateCreature("c-aran7",[976.306],6)
 SetGlobal("c-aranspawn","C-AR01",1)
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
END

/* Barfight, started from PID choice */
IF
 Global("c-arantoran","GLOBAL",1)
 Global("c-arantoranfight","C-AR01",0)
THEN RESPONSE #100
 SetGlobal("c-arantoranfight","C-AR01",1)
 ActionOverride("c-toran",StartDialogNoSet(Player1))
END

/*  smalltalk, randomized blocks, cyclical */ 
IF
 RealGlobalTimerExpired("c-scenery","GLOBAL")
 Global("c-smalltalk","C-AR01",0)
THEN
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",1)
 Wait(2)
 DisplayStringHead("C-AW01W1",~I heard you, I heard you.~)
 Wait(2)
 DisplayStringHead("C-TORAN",~No rush. Just letting you know I need more ale.~)
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",1)
 Wait(2)
 DisplayStringHead("C-AW01W1",~Orrin, whose orders are these?~)
 Wait(2)
 DisplayStringHead("C-AW01TK",~I have no idea.~)
 Wait(2)
 DisplayStringHead("C-AW01W1",~Oh.~)
END

IF
 RealGlobalTimerExpired("c-scenery","GLOBAL")
 Global("c-smalltalk","C-AR01",1)
THEN  
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",2)
 Wait(2)
 DisplayStringHead("C-TORAN",~You know, either someone just set this whole place shaking, or I have had too much to drink.~)
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",2)
 Wait(2)
 DisplayStringHead("C-AW01W1",~Orrin, the half orc back there says she wants real ale, not the watered down stuff.~)
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",2)
 Wait(2)
 DisplayStringHead("C-AW01W1",~Orrin, what does "coin-lass" mean?~)
 Wait(2)
 DisplayStringHead("C-AW01TK",~It means you do what Gisele does to make a living.~)
 Wait(2)
 DisplayStringHead("C-AW01W1",~Oh.~)
 Wait(2)
 DisplayStringHead("C-AW01W1",~In that case, make sure the next pint on table twelve makes them sick.~)
 Wait(2)
 DisplayStringHead("C-AW01TK",~So let it be written, so let it be done.~)
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",2)
 Wait(2)
 DisplayStringHead("C-AW01P2",~I wonder if anyone has a game going in the center room.~)
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",2)
 Wait(2)
 DisplayStringHead("C-AW01P1",~You would think this place would have a good spittoon... oh. I'm drinking from it.~)
END

IF
 RealGlobalTimerExpired("c-scenery","GLOBAL")
 Global("c-smalltalk","C-AR01",2) 
THEN  
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",3)
 Wait(2)
 DisplayStringHead("C-AW01TK",~Someone go wake Lani up. She was supposed to be performing tonight, but her harp isn't even unpacked.~)  
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",3)
 Wait(2)
 DisplayStringHead("C-AW01W1",~Can I borrow something pretty from the stock tonight? I have a date....~)
 DisplayStringHead("C-AW01TK",~No.~)
END

IF
 RealGlobalTimerExpired("c-scenery","GLOBAL")
 Global("c-smalltalk","C-AR01",3)
THEN
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",4)
 Wait(2)
 DisplayStringHead("C-AW01TK",~Erika, stop dawdling.~)
 Wait(2)
 DisplayStringHead("C-AW01W1",~I just finished this order. Keep your pants on.~)
 Wait(2)
 DisplayStringHead("C-AW01TK",~Perish the thought.~)
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",4)
 Wait(2)
 DisplayStringHead("C-TORAN",~So Ribald called me a whoreson.~)
 DisplayStringHead("C-AW01TK",~What did you do?~)
 DisplayStringHead("C-TORAN",~Nothing. Can't knock a man for telling the truth.~)
 DisplayStringHead("C-AW01TK",~Cheers to that.~)
END

IF
 RealGlobalTimerExpired("c-scenery","GLOBAL")
 Global("c-smalltalk","C-AR01",4)
THEN  
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",5)
 Wait(2)
 DisplayStringHead("C-AW01TK",~Was that two Tuscan Ales, or two ales for the Tuscans?~)
 Wait(2)
 DisplayStringHead("C-AW01W1",~What is the difference?~)
 Wait(2)
 DisplayStringHead("C-AW01TK",~About 2gp.~)
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",5)
 Wait(2)
 DisplayStringHead("C-TORAN",~Hey, Erika... how about seeing the circus with me?~)
 Wait(2)
 DisplayStringHead("C-AW01W1",~No, thank you. This place is enough of a circus for me.~)
END  

IF
 RealGlobalTimerExpired("c-scenery","GLOBAL")
 Global("c-smalltalk","C-AR01",5)
THEN   
RESPONSE #50
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",6)
 Wait(2)
 DisplayStringHead("C-AW01TK",~You may have had enough, Goodman Toran.~)
 Wait(2)
 DisplayStringHead("C-TORAN",~Hmmm...~)
 Wait(2)
 DisplayStringHead("C-TORAN",~Nope. I can still feel my face. Give me another one.~)
RESPONSE #50
 SetGlobal("c-smalltalk","C-AR01",6)
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 Wait(2)
 DisplayStringHead("C-AW01TK",~What happened? You are blushing.~)
 Wait(2)
 DisplayStringHead("C-AW01W1",~The cleric in the back put his hands someplace he shouldn't.~)
 Wait(2)
 DisplayStringHead("C-AW01TK",~Do I need to do anything?~)  
 Wait(2)
 DisplayStringHead("C-AW01W1",~No. Teldra slapped him and told him to shape up or she would get him in trouble.~)
END  

IF
 RealGlobalTimerExpired("c-scenery","GLOBAL")
 Global("c-smalltalk","C-AR01",5)
THEN   
RESPONSE #20
 SetGlobal("c-smalltalk","C-AR01",0)
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 Wait(2)  
 DisplayStringHead("C-AW01P3",~Oh, the Flaming Fist is a bunch of orc-loving bastards. Speaking of which, I wonder if Cheris is still in her room...~) 
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",0)
 Wait(2)
 DisplayStringHead("C-AW01P2",~I wonder if anyone has a game going in the center room.~)
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",0)
 Wait(2)
 DisplayStringHead("C-AW01P1",~You would think this place would have a good spittoon... oh. I'm drinking from it.~)
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",0)
 Wait(2)
 DisplayStringHead("C-AW01P2",~Anyone want a game of dice? I'll wager clothing.~)
RESPONSE #20
 RealSetGlobalTimer("c-scenery","GLOBAL",60)
 SetGlobal("c-smalltalk","C-AR01",0)
 Wait(2)
 DisplayStringHead("C-AW01P1",~Blighted blue Boars. Think they are all gentlemen.~) 
END

Share this post


Link to post

Just to note, real time is incremented even when the game is paused. So it might look like one per minute, but if you pause the game after the first display, the second could come immediately after when you resume.

Share this post


Link to post

yep - testing this out made it obvious that the timer needs to be longer - or the idea needs to be cut. I could recast it as banters that fire from areascript; for the alph, I am going to leave it in with a two-minute timer and some additions, and see what playtesters like/don't like . For me, it is fun to see, so at leaste for the testing version I'll leave it in place.

Share this post


Link to post

The hugest probability should be assigned to doing nothing. That's the best way to cut down on feedback frenzy; weight it heavier (for your #50s, I'd start with #200, and #100 for the #20s) and have it only set the timer and variables.

 

I seem to remember this is what BioWare did for their feedback (Saradush; Amkethran) in ToB too.

Share this post


Link to post

I think I am misunderstanding the role of #20, #50 weightings in script blocks - for some reason, I seem to have forgotten anything I ever learned about them, and implemented them as if the "weight" was a division of 100%, so

 

#20/#20/#20/#20/#20

 

#50/#50

 

#100

 

I had better go back and relearn this!

Share this post


Link to post

These weights are just of sum. They can add up to anything (well, there is some limit, so don't use too big numbers), and you can calculate general probabilities yourself.

 

#100/#100 = #50/#50 = #1/#1

 

So #20/#20/#20/#20/#20/#400 goes to the last response the majority of the time (80% or something?).

Share this post


Link to post
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

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

×   Your previous content has been restored.   Clear editor

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


×
×
  • Create New...