//
// += 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;
	}
;
