/*	$NetBSD: main.c,v 1.22 2021/05/02 12:50:43 rillig Exp $	*/

/*-
 * Copyright (c) 1991, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * The game adventure was originally written in Fortran by Will Crowther
 * and Don Woods.  It was later translated to C and enhanced by Jim
 * Gillogly.  This code is derived from software contributed to Berkeley
 * by Jim Gillogly at The Rand Corporation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
 The Regents of the University of California.  All rights reserved.");
#endif /* not lint */

#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/2/93";
#else
__RCSID("$NetBSD: main.c,v 1.22 2021/05/02 12:50:43 rillig Exp $");
#endif
#endif /* not lint */

/*      Re-coding of advent in C: main program */

#include <sys/file.h>
#include <err.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "hdr.h"
#include "extern.h"

int
main(int argc, char **argv)
{
	int     i;
	int     rval, ll;
	struct text *kk;

	/* revoke setgid privileges from dm */
	setgid(getgid());

	init();		/* Initialize everything */
	signal(SIGINT, trapdel);

	if (argc > 1) {		/* Restore file specified */
				/* Restart is label 8305 (Fortran) */
		i = restore(argv[1]);	/* See what we've got */
		switch (i) {
		case 0:	/* The restore worked fine */
			yea = Start();
			k = null;
			unlink(argv[1]);	/* Don't re-use the save */
			goto l8;		/* Get where we're going */
		case 1:				/* Couldn't open it */
			errx(1,"can't open file");	/* So give up */
		case 2:				/* Oops -- file was altered */
			rspeak(202);		/* You dissolve */
			exit(1);	/* File could be non-adventure */
		}			/* So don't unlink it. */
	}
	startup();			/* prepare for a user */

	for (;;) {			/* main command loop (label 2) */
		if (newloc < 9 && newloc != 0 && isclosing) {
			rspeak(130);	/* if closing leave only by */
			newloc = loc;	/* main office */
			if (!panic)
				clock2 = 15;
			panic = TRUE;
		}
		rval = fdwarf();	/* dwarf stuff */
		if (rval == 99)
			die(99);

l2000:		if (loc == 0)
			die(99);	/* label 2000 */
		kk = &stext[loc];
		if ((abb[loc] % abbnum) == 0 || kk->seekadr == 0)
			kk = &ltext[loc];
		if (!forced(loc) && dark()) {
			if (wasdark && pct(35)) {
				die(90);
				goto l2000;
			}
			kk = &rtext[16];
		}
#if 0
l2001:
#endif
		if (toting(bear))
			rspeak(141);	/* 2001 */
		speak(kk);
		k = 1;
		if (forced(loc))
			goto l8;
		if (loc == 33 && pct(25) && !isclosing)
			rspeak(8);
		if (!dark()) {
			abb[loc]++;
			for (i = atloc[loc]; i != 0; i = links[i]) { /* 2004 */
				obj = i;
				if (obj > 100)
					obj -= 100;
				if (obj == steps && toting(nugget))
					continue;
				if (prop[obj] < 0) {
					if (closed)
						continue;
					prop[obj] = 0;
					if (obj == rug || obj == chain)
						prop[obj] = 1;
					tally--;
					if (tally == tally2 && tally != 0)
						if (limit > 35)
							limit = 35;
				}
				ll = prop[obj];	/* 2006 */
				if (obj == steps && loc == fixed[steps])
					ll = 1;
				pspeak(obj, ll);
			}	/* 2008 */
			goto l2012;
	l2009:		k = 54;	/* 2009 */
	l2010:		spk = k;
	l2011:		rspeak(spk);
		}
l2012:		verb = 0;	/* 2012 */
		obj = 0;
l2600:		checkhints();	/* to 2600-2602 */
		if (closed) {
			if (prop[oyster] < 0 && toting(oyster))
				pspeak(oyster, 1);
			for (i = 1; i < 100; i++)
				if (toting(i) && prop[i] < 0)	/* 2604 */
					prop[i] = -1 - prop[i];
		}
		wasdark = dark();	/* 2605 */
		if (knfloc > 0 && knfloc != loc)
			knfloc = 1;
		getin(&wd1, &wd2);
		if (delhit) {	/* user typed a DEL */
			delhit = 0;	/* reset counter */
			copystr("quit", wd1);	/* pretend he's quitting */
			*wd2 = 0;
		}
l2608:		if ((foobar = -foobar) > 0)
			foobar = 0;	/* 2608 */
		/* should check here for "magic mode" */
		turns++;
		if (demo && turns >= SHORT)
			done(1);	/* to 13000 */

		if (verb == say && *wd2 != 0)
			verb = 0;
		if (verb == say)
			goto l4090;
		if (tally == 0 && loc >= 15 && loc != 33)
			clock1--;
		if (clock1 == 0) {
			closing();	/* to 10000 */
			goto l19999;
		}
		if (clock1 < 0)
			clock2--;
		if (clock2 == 0) {
			caveclose();	/* to 11000 */
			continue;	/* back to 2 */
		}
		if (prop[lamp] == 1)
			limit--;
		if (limit <= 30 && here(batter) && prop[batter] == 0
		    && here(lamp)) {
			rspeak(188);	/* 12000 */
			prop[batter] = 1;
			if (toting(batter))
				drop(batter, loc);
			limit = limit + 2500;
			lmwarn = FALSE;
			goto l19999;
		}
		if (limit == 0) {
			limit = -1;	/* 12400 */
			prop[lamp] = 0;
			rspeak(184);
			goto l19999;
		}
		if (limit < 0 && loc <= 8) {
			rspeak(185);	/* 12600 */
			gaveup = TRUE;
			done(2);	/* to 20000 */
		}
		if (limit <= 30) {
			if (lmwarn || !here(lamp))
				goto l19999;	/* 12200 */
			lmwarn = TRUE;
			spk = 187;
			if (place[batter] == 0)
				spk = 183;
			if (prop[batter] == 1)
				spk = 189;
			rspeak(spk);
		}
l19999:	k = 43;
		if (liqloc(loc) == water)
			k = 70;
		if (weq(wd1, "enter") &&
		    (weq(wd2, "strea") || weq(wd2, "water")))
			goto l2010;
		if (weq(wd1, "enter") && *wd2 != 0)
			goto l2800;
		if ((!weq(wd1, "water") && !weq(wd1, "oil"))
		    || (!weq(wd2, "plant") && !weq(wd2, "door")))
			goto l2610;
		if (at(vocab(wd2, 1, 0)))
			copystr("pour", wd2);

l2610:		if (weq(wd1, "west"))
			if (++iwest == 10)
				rspeak(17);
l2630:		i = vocab(wd1, -1, 0);
		if (i == -1) {
			spk = 60;	/* 3000 */
			if (pct(20))
				spk = 61;
			if (pct(20))
				spk = 13;
			rspeak(spk);
			goto l2600;
		}
		k = i % 1000;
		kq = i / 1000 + 1;
		switch (kq) {
		case 1:
			goto l8;
		case 2:
			goto l5000;
		case 3:
			goto l4000;
		case 4:
			goto l2010;
		default:
			bug(22);
		}

l8:
		switch (march()) {
		case 2:
			continue;	/* i.e. goto l2 */
		case 99:
			die(99);
			goto l2000;
		default:
			bug(110);
		}

l2800:		copystr(wd2, wd1);
		*wd2 = 0;
		goto l2610;

l4000:		verb = k;
		spk = actspeak[verb];
		if (*wd2 != 0 && verb != say)
			goto l2800;
		if (verb == say)
			obj = *wd2;
		if (obj != 0)
			goto l4090;
#if 0
l4080:
#endif
		switch (verb) {
		case 1:	/* take = 8010 */
			if (atloc[loc] == 0 || links[atloc[loc]] != 0)
				goto l8000;
			for (i = 1; i <= 5; i++)
				if (dloc[i] == loc && dflag >= 2)
					goto l8000;
			obj = atloc[loc];
			goto l9010;
		case 2:
		case 3:
		case 9:	/* 8000 : drop,say,wave */
		case 10:
		case 16:
		case 17:	/* calm,rub,toss */
		case 19:
		case 21:
		case 28:	/* find,feed,break */
		case 29:	/* wake */
	l8000:		printf("%s what?\n", wd1);
			obj = 0;
			goto l2600;
		case 4:
		case 6:	/* 8040 open,lock */
			spk = 28;
			if (here(clam))
				obj = clam;
			if (here(oyster))
				obj = oyster;
			if (at(door))
				obj = door;
			if (at(grate))
				obj = grate;
			if (obj != 0 && here(chain))
				goto l8000;
			if (here(chain))
				obj = chain;
			if (obj == 0)
				goto l2011;
			goto l9040;
		case 5:
			goto l2009;	/* nothing */
		case 7:
			goto l9070;	/* on */
		case 8:
			goto l9080;	/* off */
		case 11:
			goto l8000;	/* walk */
		case 12:
			goto l9120;	/* kill */
		case 13:
			goto l9130;	/* pour */
		case 14:		/* eat: 8140 */
			if (!here(food))
				goto l8000;
	l8142:		destroy(food);
			spk = 72;
			goto l2011;
		case 15:
			goto l9150;	/* drink */
		case 18:		/* quit: 8180 */
			gaveup = yes(22, 54, 54);
			if (gaveup)
				done(2);	/* 8185 */
			goto l2012;
		case 20:	/* invent=8200 */
			spk = 98;
			for (i = 1; i <= 100; i++) {
				if (i != bear && toting(i)) {
					if (spk == 98)
						rspeak(99);
					blklin = FALSE;
					pspeak(i, -1);
					blklin = TRUE;
					spk = 0;
				}
			}
			if (toting(bear))
				spk = 141;
			goto l2011;
		case 22:
			goto l9220;	/* fill */
		case 23:
			goto l9230;	/* blast */
		case 24:		/* score: 8240 */
			scoring = TRUE;
			printf("If you were to quit now, you would score");
			printf(" %d out of a possible ", score());
			printf("%d.", maxscore);
			scoring = FALSE;
			gaveup = yes(143, 54, 54);
			if (gaveup)
				done(2);
			goto l2012;
		case 25:	/* foo: 8250 */
			k = vocab(wd1, 3, 0);
			spk = 42;
			if (foobar == 1 - k)
				goto l8252;
			if (foobar != 0)
				spk = 151;
			goto l2011;
	l8252:		foobar = k;
			if (k != 4)
				goto l2009;
			foobar = 0;
			if (place[eggs] == plac[eggs]
			    || (toting(eggs) && loc == plac[eggs]))
				goto l2011;
			if (place[eggs] == 0 && place[troll] == 0 &&
			    prop[troll] == 0)
				prop[troll] = 1;
			k = 2;
			if (here(eggs))
				k = 1;
			if (loc == plac[eggs])
				k = 0;
			move(eggs, plac[eggs]);
			pspeak(eggs, k);
			goto l2012;
		case 26:	/* brief=8260 */
			spk = 156;
			abbnum = 10000;
			detail = 3;
			goto l2011;
		case 27:	/* read=8270 */
			if (here(magazine))
				obj = magazine;
			if (here(tablet))
				obj = obj * 100 + tablet;
			if (here(message))
				obj = obj * 100 + message;
			if (closed && toting(oyster))
				obj = oyster;
			if (obj > 100 || obj == 0 || dark())
				goto l8000;
			goto l9270;
		case 30:	/* suspend=8300 */
			spk = 201;
			if (demo)
				goto l2011;
			printf("I can suspend your adventure for you so");
			printf(" you can resume later, but\n");
			printf("you will have to wait at least");
			printf(" %d minutes before continuing.", latency);
			if (!yes(200, 54, 54))
				goto l2012;
			datime(&saveday, &savet);
			ciao();	/* Do we quit? */
			continue;	/* Maybe not */
		case 31:	/* hours=8310 */
			printf("Colossal cave is closed 9am-5pm Mon ");
			printf("through Fri except holidays.\n");
			goto l2012;
		default:
			bug(23);
		}

l4090:
		switch (verb) {
		case 1:	/* take = 9010 */
	l9010:		switch (trtake()) {
			case 2011:
				goto l2011;
			case 9220:
				goto l9220;
			case 2009:
				goto l2009;
			case 2012:
				goto l2012;
			default:
				bug(102);
			}
		l9020: case 2:	/* drop = 9020 */
			switch (trdrop()) {
			case 2011:
				goto l2011;
			case 19000:
				done(3);
			case 2012:
				goto l2012;
			default:
				bug(105);
			}
#if 0
	l9030:
#endif
		case 3:
			switch (trsay()) {
			case 2012:
				goto l2012;
			case 2630:
				goto l2630;
			default:
				bug(107);
			}
		l9040: case 4:
		case 6:	/* open, close */
			switch (tropen()) {
			case 2011:
				goto l2011;
			case 2010:
				goto l2010;
			default:
				bug(106);
			}
		case 5:
			goto l2009;	/* nothing */
		case 7:			/* on   9070 */
	l9070:		if (!here(lamp))
				goto l2011;
			spk = 184;
			if (limit < 0)
				goto l2011;
			prop[lamp] = 1;
			rspeak(39);
			if (wasdark)
				goto l2000;
			goto l2012;

		case 8:		/* off */
	l9080:		if (!here(lamp))
				goto l2011;
			prop[lamp] = 0;
			rspeak(40);
			if (dark())
				rspeak(16);
			goto l2012;

		case 9:	/* wave */
			if ((!toting(obj)) && (obj != rod || !toting(rod2)))
				spk = 29;
			if (obj != rod || !at(fissure) || !toting(obj) || isclosing)
				goto l2011;
			prop[fissure] = 1 - prop[fissure];
			pspeak(fissure, 2 - prop[fissure]);
			goto l2012;
		case 10:
		case 11:
		case 18:	/* calm, walk, quit */
		case 24:
		case 25:
		case 26:	/* score, foo, brief */
		case 30:
		case 31:	/* suspend, hours */
			goto l2011;
		l9120: case 12:/* kill */
			switch (trkill()) {
			case 8000:
				goto l8000;
			case 8:
				goto l8;
			case 2011:
				goto l2011;
			case 2608:
				goto l2608;
			case 19000:
				done(3);
			default:
				bug(112);
			}
		l9130: case 13:/* pour */
			if (obj == bottle || obj == 0)
				obj = liq();
			if (obj == 0)
				goto l8000;
			if (!toting(obj))
				goto l2011;
			spk = 78;
			if (obj != oil && obj != water)
				goto l2011;
			prop[bottle] = 1;
			place[obj] = 0;
			spk = 77;
			if (!(at(plant) || at(door)))
				goto l2011;
			if (at(door)) {
				prop[door] = 0;	/* 9132 */
				if (obj == oil)
					prop[door] = 1;
				spk = 113 + prop[door];
				goto l2011;
			}
			spk = 112;
			if (obj != water)
				goto l2011;
			pspeak(plant, prop[plant] + 1);
			prop[plant] = (prop[plant] + 2) % 6;
			prop[plant2] = prop[plant] / 2;
			k = null;
			goto l8;
		case 14:	/* 9140 - eat */
			if (obj == food)
				goto l8142;
			if (obj == bird || obj == snake || obj == clam
			    || obj == oyster || obj == dwarf || obj == dragon
			    || obj == troll || obj == bear)
				spk = 71;
			goto l2011;
		l9150: case 15:/* 9150 - drink */
			if (obj == 0 && liqloc(loc) != water && (liq() != water
			    || !here(bottle)))
				goto l8000;
			if (obj != 0 && obj != water)
				spk = 110;
			if (spk == 110 || liq() != water || !here(bottle))
				goto l2011;
			prop[bottle] = 1;
			place[water] = 0;
			spk = 74;
			goto l2011;
		case 16:	/* 9160: rub */
			if (obj != lamp)
				spk = 76;
			goto l2011;
		case 17:	/* 9170: throw */
			switch (trtoss()) {
			case 2011:
				goto l2011;
			case 9020:
				goto l9020;
			case 9120:
				goto l9120;
			case 8:
				goto l8;
			case 9210:
				goto l9210;
			default:
				bug(113);
			}
		case 19:
		case 20:	/* 9190: find, invent */
			if (at(obj) || (liq() == obj && at(bottle))
			    || k == liqloc(loc))
				spk = 94;
			for (i = 1; i <= 5; i++)
				if (dloc[i] == loc && dflag >= 2
				    && obj == dwarf)
					spk = 94;
			if (closed)
				spk = 138;
			if (toting(obj))
				spk = 24;
			goto l2011;
		l9210: case 21:/* feed */
			switch (trfeed()) {
			case 2011:
				goto l2011;
			default:
				bug(114);
			}
		l9220: case 22:/* fill */
			switch (trfill()) {
			case 2011:
				goto l2011;
			case 8000:
				goto l8000;
			case 9020:
				goto l9020;
			default:
				bug(115);
			}
		l9230: case 23:/* blast */
			if (prop[rod2] < 0 || !closed)
				goto l2011;
			bonus = 133;
			if (loc == 115)
				bonus = 134;
			if (here(rod2))
				bonus = 135;
			rspeak(bonus);
			done(2);
		l9270: case 27:/* read */
			if (dark())
				goto l5190;
			if (obj == magazine)
				spk = 190;
			if (obj == tablet)
				spk = 196;
			if (obj == message)
				spk = 191;
			if (obj == oyster && hinted[2] && toting(oyster))
				spk = 194;
			if (obj != oyster || hinted[2] || !toting(oyster)
			    || !closed)
				goto l2011;
			hinted[2] = yes(192, 193, 54);
			goto l2012;
#if 0
	l9280:
#endif
		case 28:	/* break */
			if (obj == mirror)
				spk = 148;
			if (obj == vase && prop[vase] == 0) {
				spk = 198;
				if (toting(vase))
					drop(vase, loc);
				prop[vase] = 2;
				fixed[vase] = -1;
				goto l2011;
			}
			if (obj != mirror || !closed)
				goto l2011;
			rspeak(197);
			done(3);
#if 0
	l9290:
#endif
		case 29:	/* wake */
			if (obj != dwarf || !closed)
				goto l2011;
			rspeak(199);
			done(3);

		default:
			bug(24);
		}

l5000:
		obj = k;
		if (fixed[k] != loc && !here(k))
			goto l5100;
l5010:		if (*wd2 != 0)
			goto l2800;
		if (verb != 0)
			goto l4090;
		printf("What do you want to do with the %s?\n", wd1);
		goto l2600;
l5100:		if (k != grate)
			goto l5110;
		if (loc == 1 || loc == 4 || loc == 7)
			k = depression;
		if (loc > 9 && loc < 15)
			k = entrance;
		if (k != grate)
			goto l8;
l5110:		if (k != dwarf)
			goto l5120;
		for (i = 1; i <= 5; i++)
			if (dloc[i] == loc && dflag >= 2)
				goto l5010;
l5120:		if ((liq() == k && here(bottle)) || k == liqloc(loc))
			goto l5010;
		if (obj != plant || !at(plant2) || prop[plant2] == 0)
			goto l5130;
		obj = plant2;
		goto l5010;
l5130:		if (obj != knife || knfloc != loc)
			goto l5140;
		knfloc = -1;
		spk = 116;
		goto l2011;
l5140:		if (obj != rod || !here(rod2))
			goto l5190;
		obj = rod2;
		goto l5010;
l5190:		if ((verb == find || verb == invent) && *wd2 == 0)
			goto l5010;
		printf("I see no %s here\n", wd1);
		goto l2012;
	}
}
