/* 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 . 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 and . 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 <>. "; } ; 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 "<> consents to marry <>"; 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 "\^<> 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) "\^<> consents to marry you. "; else { "\^<> consents to "; if ((d.isHim and self.isHim) or (d.isHer and self.isHer)) "enter into a domestic partnership with "; else "marry "; "<>. "; } } ; modify movableActor verMarry(d) = { "\^<> shows no interest in marriage. "; } actorAction(v, d, p, i) = { if (v == marryVerb) /* Let 'em try... */; else pass actorAction; } ;