//
// += 3: A Logical Adventure
//
// Concept by Carl de Marcken and Dave Baggett.
// Coding by Dave Baggett.
//
// Created 15-Nov-94.
// Made easier 19-Nov-94 (v1.1)
// Fixed bug (things given to troll don't disappear) (v1.2)
//
// This source requires WorldClass, a free TADS class library available
// from ftp.gmd.de: if-archive/programming/tads/worldclass/
//
#include <world.t>

modify global
       playtesting = nil
       turns = 1587
       score = 99
;
modify putVerb
       doDefault(actor, prep, io) = {
               return dropVerb.doDefault(actor, prep, io);
       }
;
modify dropVerb
       doDefault(actor, prep, io) = {
               local   l, r, i;

               l := actor.itemcontents(actor, nil);
               r := [];
               for (i := 1; i <= length(l); i++)
                       if (not l[i].isworn)
                               r += l[i];

               return r;
       }
;

replace intro: function
{

       I(); "Wow!  This sure has been one tough game so far.  But
       you're almost there -- 99 points out of 100 and what looks to
       be a run-of-the-mill troll on the bridge puzzle.  Should be
       trivial for an adventure game god like you.  And besides,
       any puzzle with a logical solution can't be *too* hard to
       solve.  It's about time you got busy and finished the last
       puzzle and wrote up a walkthrough for...";

       "\b"; version.sdesc; "\b";
}

replace version: object
       name = {
               "\(+=\ 3: A Controversial but Nevertheless Logical Adventure\)\n
                Version 1.2";
       }

       sdesc = {
               self.name; "\n";
               "Copyright (C) 1994 David M.\ Baggett\n
               All rights reserved.\n
               Developed with TADS, the Text Adventure Development System.\n";
               classlibrary.info; "\n";
               "Difficulty Rating: Probably Requires Random Search
               (10 out of 10)\b";

               "***"; P();

               I(); "For instructions, type \"instructions\"."; P();

               I(); "Read footnotes "; note(self); " with the note command;
               e.g., type \"note 1.\""; P();

               I(); "Type \"credits\" for more information about the
                    game."; P();

               "***"; P();
       }

       footnote = {
               "Footnote markers are numbers enclosed in square brackets.";
       }
;

replace userpreinit: function
{
       local   v;

       for (v := firstobj(Verb); v <> nil; v := nextobj(v, Verb))
               v.allok := nil;
}

replace userinit: function
{
       if (global.restarting = nil) {
               "\b\b\b\b\b\b\b\b";
               intro();
       }
       global.lastactor := Me;
       Me.location.enter(Me);
       score_statusline();
}
creditsVerb: Soloverb
       verb = 'credits' 'acknowledgements'
       sdesc = "list credits for"
       soloaction(actor) = {
               I(); "Carl de Marcken and Dave Baggett designed this game.
               Dave Baggett coded."; P();

               I(); "Russ Bryan asked for it."; P();

               I(); "\"You know, it looks to me like the real message
               of the game is that common-sense puzzles are a bad idea.\""; P();

               "\t\t\t -- Felix Lee\n";
       }
;
instructVerb: Soloverb
       verb = 'instructions' 'help' 'hint'
       sdesc = "HELP!"
       soloaction(help) = {
               I(); "This game is not impossible, but it is very
               difficult.  In fact, the authors suspect that few (if
               any) will be able to solve it the direct way; i.e., by
               using the clues in the game and common sense to figure
               out how to solve the puzzles."; P();
       }
;

Me: Player
       location = bridge
       noun = 'me' 'self' 'myself'
       ldesc = {
               "You're the adventurer in \(Zork\) who was too polite
               to open someone else's mailbox.";
       }
       isnoticeable(actor) = { return nil; }
       smelldesc = "You smell inextinguishable."
       listendesc = "You sound like a colorless green idea."

       starvationcheck = nil
       dehydrationcheck = nil
       sleepcheck = nil
;
bridge: Room
       tdesc = "On the Three Troll Bridge"
       ldesc = {
               I(); "You are standing on a rickety wooden bridge. ";

               if (troll.givencount < 3) {
                       "A burly Three Troll blocks your passage
                       north, across the bridge.";
               }
       }
       sdesc = "<<self.tdesc>>"

       verGoSouth(actor) = {
               "Sorry, you've already explored that area and
               gotten all the points.";
       }
       verGoNorth(actor) = {
               if (troll.givencount < 3)
                       "The troll won't let you pass.";
       }
       goNorth(actor) = {
               "You stride confidently past the troll and
               onto a glorious but drafty victory.";

               incscore(1);
               end();
       }

       verGoDown(actor) = {
               "There's no way to get down there short of jumping,
               which seems like a bad idea indeed.";
       }
       verJump(actor) = { return self.verGoDown(actor); }
;
bridgedecoration: Qover
       location = bridge
       noun = 'bridge'
       adjective = 'troll' 'three' 'rickety' 'wooden'
       sdesc = "rickety wooden bridge"
       ldesc = "It's just a typical rickety adventure game bridge."
       acceptsput(actor, loctype) = { "You can't reach."; }
;
water: Qcontainer
       sdesc = "the water"
       isdetermined = true
       ldesc = "There's nothing special about the water."
       location = bridgedecoration
       locationtype = 'under'
       noun = 'water'
       verIoPutin(actor) = {}
       ioPutin(actor, dobj) = {
               local   r;

               "Splash.  ";

               r := rand(4);
               if (r = 1)
                       "The fish jumps.";
               else if (r = 2)
                       "The fish jumps high in the air, executes a
                       flawless double twist, and then splashes back
                       into the water.";
               else if (r = 3)
                       "The fish jumps high in the air -- almost
                       as high as the bridge.";
               else if (r = 4)
                       "The fish jumps over the bridge and back
                       into the water, startling the troll!";

               dobj.movein(nil);
       }

       passgen(actor, obj, loctype, passmethod) = {
               // If not "in" containment or nil, call our parent's method.
               if (loctype <> nil and loctype <> 'in')
                       return inherited.(passmethod)(actor, obj, loctype);

               "You can't reach the water from here.";

               return nil;
       }
       passcantouchin(actor, obj, loctype) = {
               return self.passgen(actor, obj, loctype, &passcantouch);
       }
       passcantakein(actor, obj, loctype) = {
               return self.passgen(actor, obj, loctype, &passcantake);
       }
       passcansmellin(actor, obj, loctype) = {
               return self.passgen(actor, obj, loctype, &passcansmell);
       }
;
redthing: Decoration
       location = water
       locationtype = 'in'
       sdesc = "red thing"
       ldesc = "It seems to be swimming around."
       noun = 'thing' 'fish' 'herring'
       adjective = 'red'
       verDoTake(actor) = { "There is no \(obvious\) way to get at it."; }
;
troll: Male, Actor, Listablesound
       givencount = 0
       sdesc = "burly Three Troll"
       ldesc = {
               if (self.givencount < 3)
                       "He holds his hand out expectantly.";
               else
                       "He seems to be ignoring you.";
       }
       noun = 'troll'
       adjective = 'burly'
       location = bridge
       actordesc = {}
       islistable(actor) = { return nil; }
       verIoGiveto(actor) = {}
       ioGiveto(actor, dobj) = {
               if (self.givencount = 3) {
                       "The troll ignores you.";
               }
               else {
                       dobj.movein(nil);
                       self.givencount++;
                       "\^\"<<saynum(self.givencount)>>!\" he grunts.";

                       if (self.givencount = 3)
                               " The troll now seems less overbearing.";
               }
       }
       listlistendesc = "is ticking."
       listendesc = "The troll, oddly enough, seems to be ticking."
       smelldesc = "The troll smells lemony fresh."
;
trollhand: Part
       partof = troll
       sdesc = "troll's hand"
       ldesc = {
               if (troll.givencount < 3)
                       "It's being held out by its owner, the troll,
                       expectantly.";
               else
                       "It looks like an ordinary troll hand.";
       }
       noun = 'hand'
       adjective = 'troll\'s' 'troll'
       acceptsput(actor, loctype) = { return loctype = 'in' ? true : nil; }
       verIoPutin(actor) = { troll.verIoPutin(actor); }
       ioPutin(actor, dobj) = { troll.ioPutin(actor, dobj); }
;

class myclothes: Clothing
       ldesc = "There's nothing special about <<self.objthedesc(nil)>>."
       isdetermined = true
       adjective = 'my'
       location = Me
       isnoticeable(actor) = {
               if (self.isin(Me) and self.isworn)
                       return nil;
               else
                       return true;
       }
       isworn = true
;
shirt: myclothes
       sdesc = "your shirt"
       noun = 'shirt'
;
pants: myclothes
       isplural = true
       sdesc = "your pants"
       noun = 'pants'
;
shoes: myclothes
       isplural = true
       sdesc = "your shoes"
       noun = 'shoes'
;
socks: myclothes
       isplural = true
       sdesc = "your socks"
       noun = 'socks'
;
glasses: myclothes
       isplural = true
       sdesc = "your glasses"
       noun = 'glasses' 'spectacles' 'specs'
;
underwear: myclothes
       sdesc = "your underwear (yuck)"
       noun = 'underwear'
;
clothes: Decoration
       noun = 'clothes' 'clothing'
       adjective = 'my'
       location = bridge
       sdesc = "your clothes"
       isplural = true
       isdetermined = true
       ldesc = {
               if (troll.givencount = 0)
                       "There's nothing unusual about your clothes.";
               else
                       "There's nothing unusual about the clothing that
                       you still have.";
       }
       verDoTake(actor) = { "You'll need to be more specific."; }
;

qual_calculator: Item
       sdesc = "qualitative calculator"
       ldesc = {
               I(); "Your parents gave you this for your birthday
               last year.  It's just the sort of thing they'd be
               absolutely wrong about thinking you'd need.  And
               indeed, you've found no use for it to
               date. <<note(self)>>"; P();

               I(); "It has has 9 buttons: ZERO, POSITIVE, NEGATIVE,
               ADD, SUBTRACT, MULTIPLY, DIVIDE, Clear and deClear.
               The readout currently shows <<self.sayreadout>>.";
       }
       noun = 'calculator' 'calc'
       adjective = 'qualitative'
       location = Me

       footnote = { "Respects to Walter Hamscher and Carl de Marcken."; }

       stack = []
       secondstack = []
       saynewreadout = { "\nThe readout now shows <<self.sayreadout>>.\n"; }
       sayreadout = {
               local v;

               if (length(stack) < 1)
                       v := 0;
               else
                       v := stack[1];

               if (v = -1)
                       "[[\ -\ ]]";
               else if (v = 0)
                       "[[\ 0\ ]]";
               else if (v = 1)
                       "[[\ +\ ]]";
               else
                       "[[\ ?\ ]]";
       }
       pop = {
               local v;

               if (length(stack) < 1)
                       v := 0;
               else {
                       v := car(stack);
                       stack := cdr(stack);
               }

               return v;
       }
;

readout: Part
       sdesc = "readout"
       ldesc = { qual_calculator.saynewreadout; }
       partof = qual_calculator
       noun = 'readout'
       adjective = 'calculator'
;

qualbutton: Part, Button
       ldesc = "There is nothing special about <<self.objthedesc(nil)>>."
       partof = qual_calculator
;

clear: qualbutton
       sdesc = "Clear button"
       noun = 'button'
       adjective = 'clear' 'kleer'
       doPush(actor) = {
               qual_calculator.secondstack := qual_calculator.stack;
               qual_calculator.stack := [];
               qual_calculator.saynewreadout;
       }
;

declear: qualbutton
       sdesc = "deClear button"
       noun = 'button'
       adjective = 'declear' 'dekleer'
       doPush(actor) = {
               local tmp;

               tmp := qual_calculator.stack;
               qual_calculator.stack := qual_calculator.secondstack;
               qual_calculator.secondstack := tmp;
               qual_calculator.saynewreadout;
       }
;

zerobutton: qualbutton
       sdesc = "ZERO button"
       noun = 'button'
       adjective = 'zero'
       doPush(actor) = {
               qual_calculator.stack := [ 0 ] + qual_calculator.stack;
               qual_calculator.saynewreadout;
       }
;

positivebutton: qualbutton
       sdesc = "POSITIVE button"
       noun = 'button'
       adjective = 'positive'
       doPush(actor) = {
               qual_calculator.stack := [ 1 ] + qual_calculator.stack;
               qual_calculator.saynewreadout;
       }
;

negativebutton: qualbutton
       sdesc = "NEGATIVE button"
       noun = 'button'
       adjective = 'negative'
       doPush(actor) = {
               qual_calculator.stack := [ -1 ] + qual_calculator.stack;
               qual_calculator.saynewreadout;
       }
;

addbutton: qualbutton
       sdesc = "ADD button"
       noun = 'button'
       adjective = 'add'
       doPush(actor) = {
               local v, v1, v2;
               v1 := qual_calculator.pop;
               v2 := qual_calculator.pop;
               if (v1=2 or v2=2) v := 2;
               else if ((v1=1 and v2=-1) or (v1=-1 and v2=1)) v := 2;
               else if (v1=1 or v2=1) v := 1;
               else if (v1=-1 or v2=-1) v := -1;
               else v := 0;
               qual_calculator.stack := [ v ] + qual_calculator.stack;
               qual_calculator.saynewreadout;
       }
;

subtractbutton: qualbutton
       sdesc = "SUBTRACT button"
       noun = 'button'
       adjective = 'subtract'
       doPush(actor) = {
               local v, v1, v2;
               v1 := qual_calculator.pop;
               v2 := qual_calculator.pop;
               if (v1=2 or v2=2) v := 2;
               else if ((v1=1 and v2=1) or (v1=-1 and v2=-1)) v := 2;
               else if (v2<>0) v := v2;
               else v := -v1;
               qual_calculator.stack := [ v ] + qual_calculator.stack;
               qual_calculator.saynewreadout;
       }
;

multiplybutton: qualbutton
       sdesc = "MULTIPLY button"
       noun = 'button'
       adjective = 'multiply'
       doPush(actor) = {
               local v, v1, v2;
               v1 := qual_calculator.pop;
               v2 := qual_calculator.pop;
               if (v1=2 or v2=2) v := 2;
               else if (v1=0 or v2=0) v:= 0;
               else if (v1=v2) v := 1;
               else v := -1;
               qual_calculator.stack := [ v ] + qual_calculator.stack;
               qual_calculator.saynewreadout;
       }
;

dividebutton: qualbutton
       sdesc = "DIVIDE button"
       noun = 'button'
       adjective = 'divide'
       doPush(actor) = {
               local v, v1, v2;
               v1 := qual_calculator.pop;
               v2 := qual_calculator.pop;
               if (v1=2 or v2=2 or v1=0) v := 2;
               else if (v2=0) v := 0;
               else if (v1=v2) v := 1;
               else v := -1;
               qual_calculator.stack := [ v ] + qual_calculator.stack;
               qual_calculator.saynewreadout;
       }
;