/*
marry.t -- Inter-character marriage for TADS games.
Copyright (c) 1997 by Christopher Nebel
This code may be freely included in any TADS game, commercial
or otherwise, but is not in the Public Domain. Please send
bugs and comments to <
[email protected]>.
INTRODUCTION:
Ever wanted to write a more mannerly interactive fiction game?
An adaptation of "Pride and Prejudice," perhaps? Well, here's
a small library to help. Using it, you can allow the player
to marry other NPCs and even arrange marriages between NPCs.
INSTRUCTIONS:
This code was written to work with TADS 2.2 using adv.t, though
with minor modifications it could work with WorldClass as well.
Write your actors as usual, include "marry.t", then start
overriding these two methods:
- verMarry(d) : A marriage has been proposed between <self>
and <d>. Speak now, or forever hold your piece.
- saywillmarry(d) : Performs the actual marriage.
There's also one useful property, "betrothed". If a character has
agreed to marry someone, this property points to the character they're
married (or at least engaged) to. If they're single, it will be nil.
There are several other methods that are defined for internal use:
verDoMarry(actor), doMarry(actor), marry(d), and saybetrothed. In
general, you shouldn't override these, though you might use them
for special effects.
MORE DETAILED INSTRUCTIONS:
- verMarry(d): This is where you determine who will agree to marry whom.
It covers not only cases where the player is proposing (e.g., "marry Jane"
or "Jane, marry me"), but also NPCs that you're ordering to marry to each
other (e.g., "Wickham, marry Lydia.")
verMarry works like a normal verXoVerb handler (though it isn't really one).
If there is any output, the proposal is considered to be rejected. If
there is no output, program flow continues on to check the other partner
and then to the "saywillmarry" method.
By default, no one will agree to marry anyone, the anti-social wretches.
To change this, override verMarry. Here's a simple example:
Jane: Actor
verMarry(d) = {
if (d != Bingley)
"\"But I love Mr.\ Bingley!\" ";
}
;
Now Jane will agree to marry Bingley, but no one else. However, Bingley
has his own say in the matter, so for the marriage to work, we have to
override his verMarry as well:
Bingley: Actor
verMarry(d) = {
if (d != Jane)
"Mr.\ Bingley seems uninterested in marrying <<d.thedesc>>. ";
}
;
Of course, you are free to represent much more complicated relationships.
The one caveat is that you should not alter the game state in verMarry,
since like a verXoVerb method, you will be called invisibly at times.
Here's a more complex example:
Elizabeth: Actor
verMarry(d) = {
if (d == Darcy) {
if (not darcyletter.isknownto(self))
"\"I think not -- a more conceited, arrogant man I've never met.\" ";
else
; // Thinks he's ok, don't object.
}
else if (d == Wickham) {
if (Wickham.betrothed)
"\"But Mr. Wickham is already married!\" ";
else {
if (darcyletter.isknownto(self))
"\"What an idea!\" she replies in a scathing tone. ";
else
"\"What an idea!\" she smiles. ";
}
}
else if (d == Collins) {
"Elizabeth rolls her eyes slightly. ";
}
}
;
- saywillmarry(d): Performs the actual marriage. Standard behavior is
provided by an internal method "marry", so there's no need to call the
inherited "saywillmarry." The default version simply prints "<<self>>
consents to marry <<d>>"; you'll probably want to override this with
something more elaborate.
If you order two NPCs to marry, the system calls "saywillmarry" such that
"self" is the proposing actor and "d" is the proposee; e.g., the command
"Collins, marry Charlotte", would call "Collins.saywillmarry(Charlotte)."
If you propose (successfully) to an NPC, either by saying "marry Jane" or
"Jane, marry me," it will call Jane.saywillmarry(Me). This is admittedly
backwards from the other case, but helps keep the code associated with an
actor all in one place.
WHO GETS CALLED WHEN:
This gets a little complicated, so pay attention. Marriage commands come
in three possible forms:
1. "marry X."
2. "X, marry me."
3. "X, marry Y."
Cases 1 and 2 are handled identically, though they're different to the
parser. First it calls X.verMarry(Me) to give the proposee a chance to
protest, then it calls Me.verMarry(X) to give the player the same chance.
For Me.verMarry(X), it's actually more that the player might not be
allowed to marry -- presumably they want to, or they wouldn't have
proposed in the first place. Finally, if no one complains, it calls
X.saywillmarry(Me).
In case 3, the player is ordering two NPCs to marry. First the system
calls X.verMarry(Y) -- X might not want to be pushed around by the player,
in addition to not wanting to marry Y. Then it calls Y.verMarry(X) to
see if Y will accept X's proposal.
To sum up:
"marry Kitty" or "Kitty, marry me."
1. Kitty.verMarry(Me) -- does Kitty want to marry you?
2. Me.verMarry(Kitty) -- can you marry Kitty?
If no output results,
3. Kitty.saywillmarry(Me)
"Wickham, marry Lydia."
1. Wickham.verMarry(Lydia) -- will Wickham propose to Lydia in the first place?
2. Lydia.verMarry(Wickham) -- will Lydia accept?
If no output results,
3. Wickham.saywillmarry(Lydia)
*/
#pragma C+
marryVersion: versionTag
id="$Id: marry.t 1997/12/25 03:48:00 cdn Exp cdn $\n"
author='Christopher Nebel'
func='support for inter-character marriage'
;
marryVerb: deepverb
verb = 'marry' 'wed'
sdesc = "marry"
doAction = 'Marry'
validDoList(actor, prep, iobj) =
(inherited.validDoList(actor, prep, iobj) + visibleList(Me))
validDo(actor, obj, seqno) =
(obj.isVisible(actor))
;
modify thing
verMarry(obj) =
"You have a very fertile imagination. "
saybetrothed = {
/* Necessary because adv.t doesn't have a sufficiently
detailed grasp of grammatical cases. This could be
simplified under WorldClass. */
if (self == Me)
"You are already spoken for. ";
else
"\^<<self.thedesc>> is already spoken for. ";
}
verDoMarry(actor) = {
/* Make sure they're not trying to marry themselves and
that both parties are unmarried. */
if (actor == self)
"That would be awfully narcissistic. ";
else if (self.betrothed)
self.saybetrothed;
else if (actor.betrothed)
actor.saybetrothed;
}
doMarry(actor) = {
/*
- "marry X" or "X, marry me."
X gets to object first, then Me, then call X.marry(Me).
- "X, marry Y."
X gets to object first, then Y, then call X.marry(Y).
*/
local h, A, B;
if (actor == Me)
A = self, B = actor;
else
A = actor, B = self;
h = outhide(true);
A.verMarry(B);
if (outhide(h)) {
/* Output resulted, which means there's an objection;
call it again and do no more. */
A.verMarry(B);
}
else {
h = outhide(true);
B.verMarry(A);
if (outhide(h)) {
/* Same drill as before. */
B.verMarry(A);
}
else
A.marry(B);
}
}
marry(d) = {
self.betrothed = d;
d.betrothed = self;
self.saywillmarry(d);
}
saywillmarry(d) = {
/* Again, could be simplified under WorldClass. */
if (d == Me)
"\^<<self.thedesc>> consents to marry you. ";
else {
"\^<<self.thedesc>> consents to ";
if ((d.isHim and self.isHim) or (d.isHer and self.isHer))
"enter into a domestic partnership with ";
else "marry ";
"<<d.thedesc>>. ";
}
}
;
modify movableActor
verMarry(d) = {
"\^<<self.thedesc>> shows no interest in marriage. ";
}
actorAction(v, d, p, i) = {
if (v == marryVerb)
/* Let 'em try... */;
else
pass actorAction;
}
;