/*
	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 <c.nebel@apple.com>.
	
	
	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;
	}
;
