1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "glk/alan3/main.h"
24 #include "glk/alan3/alan_version.h"
25 #include "glk/alan3/class.h"
26 #include "glk/alan3/compatibility.h"
27 #include "glk/alan3/container.h"
28 #include "glk/alan3/current.h"
29 #include "glk/alan3/debug.h"
30 #include "glk/alan3/decode.h"
31 #include "glk/alan3/dictionary.h"
32 #include "glk/alan3/event.h"
33 #include "glk/alan3/exe.h"
34 #include "glk/alan3/glkio.h"
35 #include "glk/alan3/instance.h"
36 #include "glk/alan3/inter.h"
37 #include "glk/alan3/jumps.h"
38 #include "glk/alan3/lists.h"
39 #include "glk/alan3/literal.h"
40 #include "glk/alan3/location.h"
41 #include "glk/alan3/memory.h"
42 #include "glk/alan3/msg.h"
43 #include "glk/alan3/options.h"
44 #include "glk/alan3/output.h"
45 #include "glk/alan3/parse.h"
46 #include "glk/alan3/reverse.h"
47 #include "glk/alan3/rules.h"
48 #include "glk/alan3/scan.h"
49 #include "glk/alan3/score.h"
50 #include "glk/alan3/state.h"
51 #include "glk/alan3/syserr.h"
52 #include "glk/alan3/syntax.h"
53 #include "glk/alan3/utils.h"
54 
55 namespace Glk {
56 namespace Alan3 {
57 
58 /* PUBLIC DATA */
59 
60 /* Amachine structures - Static */
61 VerbEntry *vrbs;        /* Verb table pointer */
62 
63 
64 /* PRIVATE DATA */
65 #define STACKSIZE 100
66 
67 /*----------------------------------------------------------------------*
68  *
69  * Event Handling
70  *
71  *----------------------------------------------------------------------*/
72 
73 /*----------------------------------------------------------------------*/
eventName(int event)74 static char *eventName(int event) {
75 	return stringAt(events[event].id);
76 }
77 
78 
79 /*----------------------------------------------------------------------*/
runPendingEvents(CONTEXT)80 static void runPendingEvents(CONTEXT) {
81 	int i;
82 
83 	resetRules();
84 	while (eventQueueTop != 0 && eventQueue[eventQueueTop - 1].after == 0) {
85 		eventQueueTop--;
86 		if (isALocation(eventQueue[eventQueueTop].where))
87 			current.location = eventQueue[eventQueueTop].where;
88 		else
89 			current.location = where(eventQueue[eventQueueTop].where, TRANSITIVE);
90 		if (traceSectionOption) {
91 			printf("\n<EVENT %s[%d] (at ", eventName(eventQueue[eventQueueTop].event),
92 			       eventQueue[eventQueueTop].event);
93 			CALL1(traceSay, current.location)
94 			printf(" [%d]):>\n", current.location);
95 		}
96 		CALL1(interpret, events[eventQueue[eventQueueTop].event].code)
97 		CALL1(evaluateRules, rules)
98 	}
99 
100 	for (i = 0; i < eventQueueTop; i++)
101 		eventQueue[i].after--;
102 }
103 
104 
105 /*----------------------------------------------------------------------*\
106 
107   Main program and initialisation
108 
109 \*----------------------------------------------------------------------*/
110 
111 Common::SeekableReadStream *codfil;
112 
113 /*----------------------------------------------------------------------
114   Calculate where to start calculating the CRC. Is different for
115   different versions. CRC is calculated from pre-beta2 memory start to
116   be compatible.  If header size changes this should return beta2
117   header size for later versions.
118 */
crcStart(const byte version[4])119 static int crcStart(const byte version[4]) {
120 	/* Some earlier versions had a shorter header */
121 	if (isPreAlpha5(version))
122 		return sizeof(Pre3_0alpha5Header) / sizeof(Aword);
123 	else if (isPreBeta2(version))
124 		return sizeof(Pre3_0beta2Header) / sizeof(Aword);
125 	else
126 		return sizeof(ACodeHeader) / sizeof(Aword);
127 }
128 
129 
130 /*----------------------------------------------------------------------*/
readTemporaryHeader(CONTEXT,ACodeHeader * tmphdr)131 static void readTemporaryHeader(CONTEXT, ACodeHeader *tmphdr) {
132 	codfil->seek(0);
133 	if (codfil->read(&tmphdr->tag[0], sizeof(ACodeHeader)) != sizeof(ACodeHeader) ||
134 			strncmp((char *)tmphdr, "ALAN", 4) != 0)
135 		playererr(context, "Not an Alan game file, does not start with \"ALAN\"");
136 }
137 
138 
139 /*----------------------------------------------------------------------*/
140 #ifdef SCUMM_LITTLE_ENDIAN
reverseMemory()141 static void reverseMemory() {
142 	if (debugOption || traceSectionOption || traceInstructionOption)
143 		output("<Hmm, this is a little-endian machine, fixing byte ordering....");
144 	reverseACD();           /* Reverse content of the ACD file */
145 	if (debugOption || traceSectionOption || traceInstructionOption)
146 		output("OK.>$n");
147 }
148 #endif
149 
150 /*----------------------------------------------------------------------*/
setupHeader(ACodeHeader tmphdr)151 static void setupHeader(ACodeHeader tmphdr) {
152 	if (isPreBeta2(tmphdr.version)) {
153 		header = (ACodeHeader *)duplicate(&memory[0], sizeof(ACodeHeader));
154 		if (isPreAlpha5(tmphdr.version)) {
155 			header->ifids = 0;
156 		}
157 		header->prompt = 0;
158 	} else if (isPreBeta3(tmphdr.version)) {
159 		header = (ACodeHeader *)pointerTo(0);
160 	} else {
161 		header = (ACodeHeader *)pointerTo(0);
162 	}
163 }
164 
165 
166 /*----------------------------------------------------------------------*/
loadAndCheckMemory(ACodeHeader tmphdr,Aword crc,char err[])167 static void loadAndCheckMemory(ACodeHeader tmphdr, Aword crc, char err[]) {
168 	int i;
169 	/* No memory allocated yet? */
170 	if (memory == NULL) {
171 		memory = (Aword *)allocate(tmphdr.size * sizeof(Aword));
172 	}
173 
174 	memTop = tmphdr.size;
175 	codfil->seek(0);
176 	if (codfil->read(memory, sizeof(Aword) * memTop) != (sizeof(Aword) * memTop))
177 		syserr("Could not read all ACD code.");
178 
179 	/* Calculate checksum */
180 	for (i = crcStart(tmphdr.version); i < memTop; i++) {
181 		crc += memory[i] & 0xff;
182 		crc += (memory[i] >> 8) & 0xff;
183 		crc += (memory[i] >> 16) & 0xff;
184 		crc += (memory[i] >> 24) & 0xff;
185 	}
186 	if (crc != tmphdr.acdcrc) {
187 		sprintf(err, "Checksum error in Acode (.a3c) file (0x%lx instead of 0x%lx).",
188 		        (unsigned long) crc, (unsigned long) tmphdr.acdcrc);
189 		if (!ignoreErrorOption)
190 			syserr(err);
191 		else {
192 			output("<WARNING! $$");
193 			output(err);
194 			output("$$ Ignored, proceed at your own risk.>$n");
195 		}
196 	}
197 }
198 
199 
200 /*----------------------------------------------------------------------*/
decodeState(int c)201 static const char *decodeState(int c) {
202 	static char state[3] = "\0\0";
203 	switch (c) {
204 	case 0:
205 		return ".";
206 	case 'd':
207 		return "dev";
208 	case 'a':
209 		return "alpha";
210 	case 'b':
211 		return "beta";
212 	default:
213 		state[0] = header->version[3];
214 		return state;
215 	}
216 }
217 
218 /*======================================================================*/
decodedGameVersion(const byte version[])219 char *decodedGameVersion(const byte version[]) {
220 	static char str[100];
221 	sprintf(str, "%d.%d%s%d",
222 	        (int)version[3],
223 	        (int)version[2],
224 	        decodeState(version[0]),
225 	        (int)version[1]);
226 	return str;
227 }
228 
229 /*----------------------------------------------------------------------*/
incompatibleDevelopmentVersion(ACodeHeader * hdr)230 static void incompatibleDevelopmentVersion(ACodeHeader *hdr) {
231 	Common::String msg = Common::String::format("Incompatible version of ACODE program. "
232 		"Development versions always require exact match. Game is %ld.%ld%s%ld, interpreter %ld.%ld%s%ld!",
233 	        (long)(hdr->version[0]),
234 	        (long)(hdr->version[1]),
235 	        decodeState(hdr->version[3]),
236 	        (long)(hdr->version[2]),
237 	        (long)alan.version.version,
238 	        (long)alan.version.revision,
239 	        alan.version.state,
240 	        (long)alan.version.correction);
241 	apperr(msg.c_str());
242 }
243 
244 
245 /*----------------------------------------------------------------------*/
incompatibleVersion(ACodeHeader * hdr)246 static void incompatibleVersion(ACodeHeader *hdr) {
247 	Common::String msg = Common::String::format("Incompatible version of ACODE program. Game is %ld.%ld, interpreter %ld.%ld.",
248 	        (long)(hdr->version[0]),
249 	        (long)(hdr->version[1]),
250 	        (long)alan.version.version,
251 	        (long)alan.version.revision);
252 	apperr(msg.c_str());
253 }
254 
255 
256 /*----------------------------------------------------------------------*/
alphaRunningLaterGame(char gameState)257 static void alphaRunningLaterGame(char gameState) {
258 	output("<WARNING! You are running an alpha interpreter, but the game is generated by a");
259 	if (gameState == 'b')
260 		output("beta");
261 	else
262 		output("release");
263 	output("state compiler which was released later. This might cause the game to not work fully as intended. Look for an upgraded game file.>\n");
264 }
265 
266 /*----------------------------------------------------------------------*/
nonDevelopmentRunningDevelopmentStateGame(const byte version[])267 static void nonDevelopmentRunningDevelopmentStateGame(const byte version[]) {
268 	char errorMessage[200];
269 	char versionString[100];
270 
271 	strcpy(errorMessage, "Games generated by a development state compiler");
272 	sprintf(versionString, "(this game is v%d.%d.%d%s)", version[0], version[1],
273 	        version[2], decodeState(version[3]));
274 	strcat(errorMessage, versionString);
275 	strcat(errorMessage, "can only be run with a matching interpreter. Look for a game file generated with an alpha, beta or release state compiler.>\n");
276 	apperr(errorMessage);
277 }
278 
279 
280 /*======================================================================*/
checkVersion(ACodeHeader * hdr)281 void checkVersion(ACodeHeader *hdr) {
282 	/* Strategy for version matching is:
283 	   1) Development interpreters/games require exact match
284 	   2) Alpha, Beta and Release interpreters will not run development games
285 	   3) Alpha interpreters must warn if they run beta or release games
286 	   4) Beta interpreters may introduce changes which are not alpha compatible,
287 	   if the change is a strict addition (i.e. if not used will not affect
288 	   alpha interpreters, example is introduction of a new opcode if it is
289 	   done at the end of the list)
290 	   5) Release interpreters should run alpha and beta games without problems
291 
292 	   NOTE that we are working with a non-reversed version string/word here.
293 	*/
294 
295 	char interpreterVersion[4];
296 	bool developmentVersion;
297 	bool alphaVersion;
298 	int compareLength;
299 	char gameState = hdr->version[3];
300 
301 	/* Construct our own version */
302 	interpreterVersion[0] = alan.version.version;
303 	interpreterVersion[1] = alan.version.revision;
304 	interpreterVersion[2] = alan.version.correction;
305 	interpreterVersion[3] = alan.version.state[0];
306 
307 	/* Check version of .ACD file */
308 	if (debugOption && !regressionTestOption) {
309 		printf("<Version of '%s' is %d.%d%s%d!>\n",
310 		       g_vm->getFilename().c_str(),
311 		       (int)hdr->version[0],
312 		       (int)hdr->version[1],
313 		       decodeState(hdr->version[3]),
314 		       (int)hdr->version[2]);
315 		newline();
316 	}
317 
318 	/* Development version require exact match, else only 2 digit match */
319 	developmentVersion = (strcmp(alan.version.state, "dev") == 0);
320 	alphaVersion = (strcmp(alan.version.state, "alpha") == 0);
321 	compareLength = (developmentVersion ? 3 : 2);
322 
323 	if (gameState == 'd' && !developmentVersion)
324 		/* Development state game requires development state interpreter... */
325 		nonDevelopmentRunningDevelopmentStateGame(hdr->version);
326 	else {
327 		/* Compatible if version, revision (and correction if dev state) match... */
328 		if (memcmp(hdr->version, interpreterVersion, compareLength) != 0) {
329 			/* Mismatch! */
330 			if (!ignoreErrorOption) {
331 				if (developmentVersion)
332 					incompatibleDevelopmentVersion(hdr);
333 				else
334 					incompatibleVersion(hdr);
335 			} else
336 				output("<WARNING! Incompatible version of ACODE program.>\n");
337 		} else if (developmentVersion && gameState != 'd')
338 			/* ... unless interpreter is development and game not */
339 			incompatibleDevelopmentVersion(hdr);
340 		else if (alphaVersion && gameState != 'a') {
341 			/* If interpreter is alpha version and the game is later, warn! */
342 			alphaRunningLaterGame(gameState);
343 		}
344 	}
345 }
346 
347 /*----------------------------------------------------------------------*/
load(CONTEXT)348 static void load(CONTEXT) {
349 	ACodeHeader tmphdr;
350 	Aword crc = 0;
351 	char err[100];
352 
353 	CALL1(readTemporaryHeader, &tmphdr)
354 	checkVersion(&tmphdr);
355 
356 	/* Allocate and load memory */
357 #ifdef SCUMM_LITTLE_ENDIAN
358 	reverseHdr(&tmphdr);
359 #endif
360 
361 	if (tmphdr.size <= sizeof(ACodeHeader) / sizeof(Aword))
362 		syserr("Malformed game file. Too small.");
363 
364 	loadAndCheckMemory(tmphdr, crc, err);
365 
366 #ifdef SCUMM_LITTLE_ENDIAN
367 	reverseMemory();
368 #endif
369 	setupHeader(tmphdr);
370 }
371 
372 
373 /*----------------------------------------------------------------------*/
checkDebug(CONTEXT)374 static void checkDebug(CONTEXT) {
375 	/* Make sure he can't debug if not allowed! */
376 	if (!header->debug) {
377 		if (debugOption | traceSectionOption | traceInstructionOption) {
378 			printf("<Sorry, '%s' is not compiled for debug! Exiting.>\n", g_vm->getFilename().c_str());
379 			CALL1(terminate, 0)
380 		}
381 		para();
382 		debugOption = FALSE;
383 		traceSectionOption = FALSE;
384 		traceInstructionOption = FALSE;
385 		tracePushOption = FALSE;
386 	}
387 
388 	// If debugging, use no randomization
389 	if (debugOption || regressionTestOption)
390 		g_vm->setRandomNumberSeed(1);
391 }
392 
393 
394 /*----------------------------------------------------------------------*/
initStaticData(void)395 static void initStaticData(void) {
396 	/* Dictionary */
397 	dictionary = (DictionaryEntry *) pointerTo(header->dictionary);
398 	/* Find out number of entries in dictionary */
399 	for (dictionarySize = 0; !isEndOfArray(&dictionary[dictionarySize]); dictionarySize++);
400 
401 	/* Scores */
402 
403 
404 	/* All addresses to tables indexed by ids are converted to pointers,
405 	   then adjusted to point to the (imaginary) element before the
406 	   actual table so that [0] does not exist. Instead indices goes
407 	   from 1 and we can use [1]. */
408 
409 	if (header->instanceTableAddress == 0)
410 		syserr("Instance table pointer == 0");
411 	instances = (InstanceEntry *) pointerTo(header->instanceTableAddress);
412 	instances--;            /* Back up one so that first is no. 1 */
413 
414 
415 	if (header->classTableAddress == 0)
416 		syserr("Class table pointer == 0");
417 	classes = (ClassEntry *) pointerTo(header->classTableAddress);
418 	classes--;          /* Back up one so that first is no. 1 */
419 
420 	if (header->containerTableAddress != 0) {
421 		containers = (ContainerEntry *) pointerTo(header->containerTableAddress);
422 		containers--;
423 	}
424 
425 	if (header->eventTableAddress != 0) {
426 		events = (EventEntry *) pointerTo(header->eventTableAddress);
427 		events--;
428 	}
429 
430 	/* Scores, if already allocated, copy initial data */
431 	if (scores == NULL)
432 		scores = (Aword *)duplicate((Aword *) pointerTo(header->scores), header->scoreCount * sizeof(Aword));
433 	else
434 		memcpy(scores, pointerTo(header->scores), header->scoreCount * sizeof(Aword));
435 
436 	if (literals == NULL)
437 		literals = (LiteralEntry *)allocate(sizeof(Aword) * (MAXPARAMS + 1));
438 
439 	stxs = (SyntaxEntry *) pointerTo(header->syntaxTableAddress);
440 	vrbs = (VerbEntry *) pointerTo(header->verbTableAddress);
441 	msgs = (MessageEntry *) pointerTo(header->messageTableAddress);
442 	initRules(header->ruleTableAddress);
443 
444 	if (header->pack)
445 		freq = (Aword *) pointerTo(header->freq);
446 }
447 
448 
449 /*----------------------------------------------------------------------*/
initStrings(void)450 static void initStrings(void) {
451 	StringInitEntry *init;
452 
453 	for (init = (StringInitEntry *) pointerTo(header->stringInitTable); !isEndOfArray(init); init++)
454 		setInstanceAttribute(init->instanceCode, init->attributeCode, toAptr(getStringFromFile(init->fpos, init->len)));
455 }
456 
457 /*----------------------------------------------------------------------*/
sizeOfAttributeData(void)458 static Aint sizeOfAttributeData(void) {
459 	uint i;
460 	int size = 0;
461 
462 	for (i = 1; i <= header->instanceMax; i++) {
463 		AttributeEntry *attribute = (AttributeEntry *)pointerTo(instances[i].initialAttributes);
464 		while (!isEndOfArray(attribute)) {
465 			size += AwordSizeOf(AttributeEntry);
466 			attribute++;
467 		}
468 		size += 1;          /* For EOD */
469 	}
470 
471 	if (size != header->attributesAreaSize
472 	        && (sizeof(AttributeHeaderEntry) == sizeof(AttributeEntry)))
473 		syserr("Attribute area size calculated wrong.");
474 	return size;
475 }
476 
477 
478 /*----------------------------------------------------------------------*/
initializeAttributes(int awordSize)479 static AttributeEntry *initializeAttributes(int awordSize) {
480 	Aword *attributeArea = (Aword *)allocate(awordSize * sizeof(Aword));
481 	Aword *currentAttributeArea = attributeArea;
482 	uint i;
483 
484 	for (i = 1; i <= header->instanceMax; i++) {
485 		AttributeHeaderEntry *originalAttribute = (AttributeHeaderEntry *)pointerTo(instances[i].initialAttributes);
486 		admin[i].attributes = (AttributeEntry *)currentAttributeArea;
487 		while (!isEndOfArray(originalAttribute)) {
488 			((AttributeEntry *)currentAttributeArea)->code = originalAttribute->code;
489 			((AttributeEntry *)currentAttributeArea)->value = originalAttribute->value;
490 			((AttributeEntry *)currentAttributeArea)->id = originalAttribute->id;
491 			currentAttributeArea += AwordSizeOf(AttributeEntry);
492 			originalAttribute++;
493 		}
494 		*((Aword *)currentAttributeArea) = EOD;
495 		currentAttributeArea += 1;
496 	}
497 
498 	return (AttributeEntry *)attributeArea;
499 }
500 
501 
502 
503 
504 /*----------------------------------------------------------------------*/
initDynamicData(void)505 static void initDynamicData(void) {
506 	uint instanceId;
507 
508 	/* Allocate for administrative table */
509 	admin = (AdminEntry *)allocate((header->instanceMax + 1) * sizeof(AdminEntry));
510 
511 	/* Create game state copy of attributes */
512 	attributes = initializeAttributes(sizeOfAttributeData());
513 
514 	/* Initialise string & set attributes */
515 	initStrings();
516 	initSets((SetInitEntry *)pointerTo(header->setInitTable));
517 
518 	/* Set initial locations */
519 	for (instanceId = 1; instanceId <= header->instanceMax; instanceId++)
520 		admin[instanceId].location = instances[instanceId].initialLocation;
521 }
522 
523 
524 /*----------------------------------------------------------------------*/
runInheritedInitialize(CONTEXT,Aint theClass)525 static void runInheritedInitialize(CONTEXT, Aint theClass) {
526 	if (theClass == 0) return;
527 	CALL1(runInheritedInitialize, classes[theClass].parent)
528 
529 	if (classes[theClass].initialize)
530 		interpret(context, classes[theClass].initialize);
531 }
532 
533 
534 /*----------------------------------------------------------------------*/
runInitialize(CONTEXT,Aint theInstance)535 static void runInitialize(CONTEXT, Aint theInstance) {
536 	CALL1(runInheritedInitialize, instances[theInstance].parent)
537 
538 	if (instances[theInstance].initialize != 0)
539 		interpret(context, instances[theInstance].initialize);
540 }
541 
542 
543 /*----------------------------------------------------------------------*/
initializeInstances(CONTEXT)544 static void initializeInstances(CONTEXT) {
545 	uint instanceId;
546 
547 	/* Set initial locations */
548 	for (instanceId = 1; instanceId <= header->instanceMax; instanceId++) {
549 		current.instance = instanceId;
550 		CALL1(runInitialize, instanceId)
551 	}
552 }
553 
554 
555 /*----------------------------------------------------------------------*/
start(CONTEXT)556 static void start(CONTEXT) {
557 	int startloc;
558 
559 	current.tick = 0;
560 	current.location = startloc = where(HERO, TRANSITIVE);
561 	current.actor = HERO;
562 	current.score = 0;
563 
564 	CALL0(initializeInstances)
565 
566 	if (traceSectionOption)
567 		printf("\n<START:>\n");
568 	CALL1(interpret, header->start)
569 	para();
570 
571 	if (where(HERO, TRANSITIVE) == startloc) {
572 		if (traceSectionOption)
573 			printf("<CURRENT LOCATION:>");
574 		CALL0(look)
575 	}
576 
577 	resetAndEvaluateRules(context, rules, header->version);
578 }
579 
580 
581 /*----------------------------------------------------------------------*/
openFiles(void)582 static void openFiles(void) {
583 	/* If logging open log file */
584 	if (transcriptOption || logOption) {
585 		startTranscript();
586 	}
587 }
588 
589 
590 /*----------------------------------------------------------------------*/
init(CONTEXT)591 static void init(CONTEXT) {
592 	int i;
593 
594 	/* Initialise some status */
595 	eventQueueTop = 0;          /* No pending events */
596 	initStaticData();
597 	initDynamicData();
598 	initParsing();
599 	CALL0(checkDebug)
600 
601 	getPageSize();
602 
603 	/* Find first conjunction and use that for ',' handling */
604 	for (i = 0; i < dictionarySize; i++)
605 		if (isConjunction(i)) {
606 			conjWord = i;
607 			break;
608 		}
609 
610 	/* Start the adventure */
611 	if (debugOption) {
612 		CALL3(debug, FALSE, 0, 0)
613 	} else {
614 		clear();
615 	}
616 
617 	start(context);
618 }
619 
620 
621 
622 /*----------------------------------------------------------------------*/
traceActor(CONTEXT,int theActor)623 static bool traceActor(CONTEXT, int theActor) {
624 	if (traceSectionOption) {
625 		printf("\n<ACTOR ");
626 		R0CALL1(traceSay, theActor)
627 		printf("[%d]", theActor);
628 		if (current.location != 0) {
629 			printf(" (at ");
630 			R0CALL1(traceSay, current.location)
631 		} else
632 			printf(" (nowhere");
633 		printf("[%d])", current.location);
634 	}
635 	return traceSectionOption;
636 }
637 
638 
639 /*----------------------------------------------------------------------*/
scriptName(int theActor,int theScript)640 static char *scriptName(int theActor, int theScript) {
641 	ScriptEntry *scriptEntry = (ScriptEntry *)pointerTo(header->scriptTableAddress);
642 
643 	while (theScript > 1) {
644 		scriptEntry++;
645 		theScript--;
646 	}
647 	return (char *)pointerTo(scriptEntry->id);
648 }
649 
650 
651 /*----------------------------------------------------------------------*/
moveActor(CONTEXT,int theActor)652 static void moveActor(CONTEXT, int theActor) {
653 	ScriptEntry *scr;
654 	StepEntry *step;
655 	Aint previousInstance = current.instance;
656 	bool flag;
657 
658 	if (context._break) {
659 		// forfeit setjmp replacement destination
660 		assert(context._label == "forfeit");
661 		context.clear();
662 		current.instance = previousInstance;
663 		return;
664 	}
665 
666 	current.actor = theActor;
667 	current.instance = theActor;
668 	current.location = where(theActor, TRANSITIVE);
669 
670 	if (theActor == (int)HERO) {
671 		// Ask him!
672 		CALL0(parse)
673 		capitalize = TRUE;
674 		fail = FALSE;           // fail only aborts one actor
675 
676 	} else if (admin[theActor].script != 0) {
677 		for (scr = (ScriptEntry *) pointerTo(header->scriptTableAddress); !isEndOfArray(scr); scr++) {
678 			if (scr->code == admin[theActor].script) {
679 				/* Find correct step in the list by indexing */
680 				step = (StepEntry *) pointerTo(scr->steps);
681 				step = (StepEntry *) &step[admin[theActor].step];
682 				/* Now execute it, maybe. First check wait count */
683 				if (admin[theActor].waitCount > 0) { /* Wait some more ? */
684 					FUNC1(traceActor, flag, theActor)
685 					if (flag)
686 						printf(", SCRIPT %s[%ld], STEP %ld, Waiting another %ld turns>\n",
687 						       scriptName(theActor, admin[theActor].script),
688 						       (long)admin[theActor].script, (long)admin[theActor].step + 1,
689 						       (long)admin[theActor].waitCount);
690 
691 					admin[theActor].waitCount--;
692 					break;
693 				}
694 				/* Then check possible expression to wait for */
695 				if (step->exp != 0) {
696 					FUNC1(traceActor, flag, theActor)
697 					if (flag)
698 							printf(", SCRIPT %s[%ld], STEP %ld, Evaluating:>\n",
699 						       scriptName(theActor, admin[theActor].script),
700 						       (long)admin[theActor].script, (long)admin[theActor].step + 1);
701 					FUNC1(evaluate, flag, step->exp)
702 					if (!flag)
703 						break;      /* Break loop, don't execute step*/
704 				}
705 				/* OK, so finally let him do his thing */
706 				admin[theActor].step++;     /* Increment step number before executing... */
707 				if (!isEndOfArray(step + 1) && (step + 1)->after != 0) {
708 					FUNC1(evaluate, admin[theActor].waitCount, (step + 1)->after)
709 				}
710 
711 				FUNC1(traceActor, flag, theActor)
712 				if (flag)
713 					printf(", SCRIPT %s[%ld], STEP %ld, Executing:>\n",
714 					       scriptName(theActor, admin[theActor].script),
715 					       (long)admin[theActor].script,
716 					       (long)admin[theActor].step);
717 				CALL1(interpret, step->stms)
718 				step++;
719 				/* ... so that we can see if he failed or is USEing another script now */
720 				if (fail || (admin[theActor].step != 0 && isEndOfArray(step)))
721 					/* No more steps in this script, so stop him */
722 					admin[theActor].script = 0;
723 				fail = FALSE;           /* fail only aborts one actor */
724 				break;          /* We have executed a script so leave loop */
725 			}
726 		}
727 		if (isEndOfArray(scr))
728 			syserr("Unknown actor script.");
729 	} else {
730 		FUNC1(traceActor, flag, theActor)
731 		if (flag) {
732 			printf(", Idle>\n");
733 		}
734 	}
735 
736 	current.instance = previousInstance;
737 }
738 
739 /*======================================================================*/
run(void)740 void run(void) {
741 	Stack theStack = NULL;
742 	Context ctx;
743 
744 	openFiles();
745 	load(ctx);			// Load program
746 
747 	do {
748 		ctx.clear();
749 		if (ctx._break)
750 			break;
751 
752 		if (theStack)
753 			deleteStack(theStack);
754 
755 		theStack = createStack(STACKSIZE);
756 		setInterpreterStack(theStack);
757 
758 		initStateStack();
759 
760 		// Initialise and start the adventure
761 		init(ctx);
762 
763 		while (!g_vm->shouldQuit()) {
764 			if (!(ctx._break && ctx._label == "forfeit")) {
765 				if (ctx._break) {
766 					assert(ctx._label.hasPrefix("return"));
767 
768 					if (ctx._label == "returnError") {
769 						forgetGameState();
770 						forceNewPlayerInput();
771 					} else if (ctx._label == "returnUndo") {
772 						forceNewPlayerInput();
773 					}
774 
775 					ctx.clear();
776 				} else {
777 					if (debugOption)
778 						debug(ctx, FALSE, 0, 0);
779 
780 					if (!ctx._break) {
781 						if (stackDepth(theStack) != 0)
782 							syserr("Stack is not empty in main loop");
783 
784 						if (!current.meta)
785 							runPendingEvents(ctx);
786 					}
787 				}
788 
789 				recursionDepth = 0;
790 
791 				// Move all characters, hero first
792 				rememberGameState();
793 				current.meta = FALSE;
794 			}
795 
796 			moveActor(ctx, header->theHero);
797 
798 			if (!ctx._break) {
799 				if (gameStateChanged)
800 					rememberCommands();
801 				else
802 					forgetGameState();
803 
804 				if (!current.meta) {
805 					current.tick++;
806 
807 					// Remove this call? Since Eval is done up there after each event...
808 					resetAndEvaluateRules(ctx, rules, header->version);
809 
810 					if (!ctx._break) {
811 						// Then all the other actors...
812 						for (uint i = 1; i <= header->instanceMax; i++) {
813 							if (i != header->theHero && isAActor(i)) {
814 								moveActor(ctx, i);
815 								if (ctx._break)
816 									break;
817 
818 								resetAndEvaluateRules(ctx, rules, header->version);
819 								if (ctx._break)
820 									break;
821 							}
822 						}
823 					}
824 				}
825 			}
826 
827 			if (ctx._break && ctx._label == "restart")
828 				break;
829 		}
830 	} while (!g_vm->shouldQuit() && ctx._label == "restart");
831 }
832 
833 } // End of namespace Alan3
834 } // End of namespace Glk
835