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  * Based on the original sources
23  *   Faery Tale II -- The Halls of the Dead
24  *   (c) 1993-1996 The Wyrmkeep Entertainment Co.
25  */
26 
27 #include "common/debug.h"
28 
29 #include "saga2/saga2.h"
30 #include "saga2/fta.h"
31 #include "saga2/script.h"
32 #include "saga2/code.h"
33 #include "saga2/tile.h"
34 #include "saga2/mission.h"
35 #include "saga2/hresmgr.h"
36 #include "saga2/saveload.h"
37 #include "saga2/actor.h"
38 
39 namespace Saga2 {
40 
41 #define IMMED_WORD(w)   ((w = *pc++),(w |= (*pc++)<<8)); \
42 	debugC(3, kDebugScripts, "IMMED_WORD(%d 0x%04x)", w, w)
43 #define BRANCH(w)       pc = codeSeg + (w); \
44 	debugC(3, kDebugScripts, "BRANCH(%ld 0x%04lx)", pc - codeSeg, pc - codeSeg)
45 
46 const uint32        sagaID      = MKTAG('S', 'A', 'G', 'A'),
47                     dataSegID   = MKTAG('_', '_', 'D', 'A'),
48                     exportSegID = MKTAG('_', 'E', 'X', 'P');
49 
50 const int           initialStackFrameSize = 10;
51 
52 static bool lookupExport(uint16 entry, uint16 &segNum, uint16 &segOff);
53 uint8 *segmentAddress(uint16 segment, uint16 offset);
54 
55 Thread                  *thisThread;
56 
57 struct ModuleEntry      *moduleList;            // loaded from resource
58 int16                    moduleBaseResource,
59                          moduleCount;
60 
61 uint16                  dataSegIndex;           // saved index of data seg
62 byte                   *dataSegment,            // loaded in data
63                        *exportSegment;          // export table from SAGA
64 
65 int32                   dataSegSize;            // bytes in data segment
66 
67 long                    exportCount;            // number of exported syms
68 
69 //  An extended script is running -- suspend all background processing.
70 int16                   extendedThreadLevel;
71 
72 int16                   lastExport;
73 
74 extern hResource    *scriptResFile;         // script resources
75 hResContext         *scriptRes;             // script resource handle
76 
script_error(const char * msg)77 void script_error(const char *msg) {
78 	thisThread->flags |= Thread::aborted;
79 	WriteStatusF(0, msg);
80 }
81 
seg2str(int16 segment)82 static Common::String seg2str(int16 segment) {
83 	switch (segment) {
84 	case builtinTypeObject:
85 		return "GameObject";
86 
87 	case builtinTypeTAG:
88 		return "TAG";
89 
90 	case builtinAbstract:
91 		return Common::String::format("Abstract%d", segment);
92 
93 	case builtinTypeMission:
94 		return "Mission";
95 
96 	default:
97 		return Common::String::format("%d", segment);
98 	}
99 }
100 
101 //-----------------------------------------------------------------------
102 //	Return the address of a builtin object, such as an Actor or a TAG,
103 //	given a segment number and an index
builtinObjectAddress(int16 segment,uint16 index)104 uint8 *builtinObjectAddress(int16 segment, uint16 index) {
105 	uint16          segNum, segOff;
106 
107 	switch (segment) {
108 	case builtinTypeObject:
109 		return (uint8 *)(&GameObject::objectAddress(index)->_data);
110 
111 	case builtinTypeTAG:
112 		return (uint8 *)(&ActiveItem::activeItemAddress(index)->_data);
113 
114 	case builtinAbstract:
115 		assert(index > 0);
116 		if (lookupExport(index, segNum, segOff) == false)
117 			error("SAGA: Cannot take address of abtract class");
118 
119 		return segmentAddress(segNum, segOff);
120 
121 	case builtinTypeMission:
122 		return (uint8 *)(&ActiveMission::missionAddress(index)->_data);
123 
124 	default:
125 		error("Invalid builtin object segment number: %d\n", segment);
126 	}
127 }
128 
129 //-----------------------------------------------------------------------
130 //	Given the builtin object type (SAGA segment number), and the adress
131 //	from builtinObjectAddress(), return the address of the virtual
132 //	function table for the class associated with this object. Also
133 //	return the address of the C function call table for this builtin
134 //	class.
builtinVTableAddress(int16 btype,uint8 * addr,CallTable ** callTab)135 uint16 *builtinVTableAddress(int16 btype, uint8 *addr, CallTable **callTab) {
136 	GameObject      *obj;
137 	ActiveItem      *aItem;
138 	ActiveMission   *aMission;
139 	uint16          script,
140 	                vtSeg,
141 	                vtOffset;
142 
143 	switch (btype) {
144 	case builtinTypeObject:
145 
146 		//  Get the address of a game object using the ID
147 		obj = ((ObjectData *)addr)->obj;
148 		script = obj->scriptClass();
149 		*callTab = &actorCFuncs;
150 
151 		if (script <= 0)
152 			error("SAGA failure: GameObject %d (%s) has no script.\n", obj->thisID(), obj->proto() ? obj->objName() : "Unknown");
153 
154 		break;
155 
156 	case builtinTypeTAG:
157 		aItem = ((ActiveItemData *)addr)->aItem;
158 		script = aItem->_data.scriptClassID;
159 		*callTab = &tagCFuncs;
160 
161 		if (script <= 0)
162 			error("SAGA failure: TAG has no script.\n");
163 
164 		break;
165 
166 	case builtinTypeMission:
167 		aMission = ((ActiveMissionData *)addr)->aMission;
168 		script = aMission->getScript();
169 		*callTab = &missionCFuncs;
170 
171 		if (script <= 0)
172 			error("SAGA failure: Mission Object has no script.\n");
173 
174 		break;
175 
176 	case builtinAbstract:
177 		*callTab = NULL;
178 
179 		return (uint16 *)addr;
180 
181 	default:
182 		error("SAGA Failure: Attempt to call member function of invalid builtin type.\n");
183 	}
184 
185 	//  Look up the vtable in the export table.
186 	if (script != 0 && lookupExport(script, vtSeg, vtOffset)) {
187 		return (uint16 *)segmentAddress(vtSeg, vtOffset);
188 	} else
189 		return NULL;
190 }
191 
segmentAddress(uint16 segment,uint16 offset)192 uint8 *segmentAddress(uint16 segment, uint16 offset) {
193 	byte  *segHandle = nullptr;
194 
195 	//  A segment number of less than zero means that this is
196 	//  a "builtin" object, in other words the game engine itself
197 	if ((int16)segment < 0)
198 		return builtinObjectAddress(segment, offset);
199 
200 	segHandle = scriptRes->loadIndexResource(segment, "object segment");
201 	if (segHandle == nullptr)
202 		return nullptr;
203 
204 	return segHandle + offset;
205 }
206 
segmentArrayAddress(uint16 segment,uint16 index)207 uint8 *segmentArrayAddress(uint16 segment, uint16 index) {
208 	byte  *segHandle = nullptr;
209 
210 	if ((int16)segment < 0)
211 		return builtinObjectAddress(segment, index);
212 
213 	segHandle = scriptRes->loadIndexResource(segment, "object array segment");
214 	if (segHandle == nullptr)
215 		return nullptr;
216 
217 	return segHandle + sizeof(uint16) + (uint16)(index * READ_LE_INT16(segHandle));
218 }
219 
220 //  Returns the address of a byte given an addressing mode
221 
byteAddress(Thread * th,uint8 ** pcPtr)222 uint8 *byteAddress(Thread *th, uint8 **pcPtr) {
223 	uint8           *pc = *pcPtr,
224 	                 *addr;
225 	uint16          seg,
226 	                offset, offset2,
227 	                index,
228 	                *arg;
229 
230 	switch (*pc++) {
231 	case addr_data:
232 		IMMED_WORD(offset);
233 		debugC(3, kDebugScripts, "byteAddress: data[%d] = %d", offset, dataSegment[offset]);
234 		*pcPtr = pc;
235 		return &dataSegment[offset];
236 
237 	case addr_near:
238 		IMMED_WORD(offset);
239 		debugC(3, kDebugScripts, "byteAddress: near[%d] = %d", offset, th->codeSeg[offset]);
240 		*pcPtr = pc;
241 		return th->codeSeg + offset;
242 
243 	case addr_far:
244 		IMMED_WORD(seg);
245 		IMMED_WORD(offset);
246 		debugC(3, kDebugScripts, "byteAddress: far[%s:%d] = %d", seg2str(seg).c_str(), offset, *segmentAddress(seg, offset));
247 		*pcPtr = pc;
248 
249 		// FIXME: WORKAROUND: Fixes Captain Navis (5299, 17715, 80) in Maldavith not allowing passage to the Tamnath Ruins through sail even if Muybridge is dead.
250 		if (seg == 130 && offset == 2862) {
251 			warning("WORKAROUND: byteAddress: far");
252 			Actor *boss = (Actor *)GameObject::objectAddress(32880);
253 			if (boss->isDead())
254 				return segmentAddress(130, 0);
255 		}
256 
257 		return segmentAddress(seg, offset);
258 
259 	case addr_array:
260 		IMMED_WORD(seg);
261 		IMMED_WORD(offset);
262 		addr = segmentArrayAddress(seg, offset);
263 		IMMED_WORD(offset2);
264 		debugC(3, kDebugScripts, "byteAddress: array[%s:%d:%d] = %d", seg2str(seg).c_str(), offset, offset2, addr[offset2]);
265 		*pcPtr = pc;
266 		return addr + offset2;
267 
268 	case addr_stack:
269 		IMMED_WORD(offset);
270 		debugC(3, kDebugScripts, "byteAddress: stack[%d] = %d", offset, *(th->stackBase + th->framePtr + (int16)offset));
271 		*pcPtr = pc;
272 		return th->stackBase + th->framePtr + (int16)offset;
273 
274 	case addr_thread:
275 		IMMED_WORD(offset);
276 		debugC(3, kDebugScripts, "byteAddress: thread[%d] = %d", offset, *((uint8 *)&th->threadArgs + offset));
277 		*pcPtr = pc;
278 		return (uint8 *)&th->threadArgs + offset;
279 
280 	case addr_this:
281 		IMMED_WORD(offset);
282 		arg = (uint16 *)(th->stackBase + th->framePtr + 8);
283 		*pcPtr = pc;
284 		if (arg[0] == dataSegIndex) {
285 			debugC(3, kDebugScripts, "byteAddress: thisD[%d:%d] = %d", arg[1], offset, dataSegment[arg[1] + offset]);
286 			return &dataSegment[arg[1] + offset];
287 		}
288 		debugC(3, kDebugScripts, "byteAddress: thisS[%s:%d:%d] = %d", seg2str(arg[0]).c_str(), arg[1], offset, *(segmentArrayAddress(arg[0], arg[1]) + offset));
289 		return segmentArrayAddress(arg[0], arg[1]) + offset;
290 
291 	case addr_deref:
292 
293 		//  First, get the address of the reference.
294 		*pcPtr = pc;
295 		addr = byteAddress(th, pcPtr);
296 		pc = *pcPtr;
297 
298 		//  Get the offset from the reference variable.
299 		index = *(uint16 *)addr;
300 
301 		//  Get the segment to dereference from, and the offset
302 		//  within the object.
303 		IMMED_WORD(seg);
304 		IMMED_WORD(offset);
305 		debugC(3, kDebugScripts, "byteAddress: deref[%s:%d:%d] = %d", seg2str(seg).c_str(), index, offset, *(segmentAddress(seg, index) + offset));
306 		*pcPtr = pc;
307 
308 		//  Compute address of object
309 		return segmentAddress(seg, index) + offset;
310 	}
311 
312 	error("byteAddress: Invalid addressing mode: %d.\n", **pcPtr);
313 }
314 
315 //  Returns the address of an object given an addressing mode
316 
objectAddress(Thread * th,uint8 ** pcPtr,uint16 & segNum,uint16 & offs)317 uint8 *objectAddress(
318     Thread          *th,
319     uint8           **pcPtr,
320     uint16          &segNum,                // segment of start of object
321     uint16          &offs) {                // offset of start of object
322 	uint8           *pc = *pcPtr,
323 	                 *addr;
324 	uint16          seg,
325 	                offset = 0,
326 	                index,
327 	                *arg;
328 
329 	switch (*pc++) {
330 	case addr_data:
331 		IMMED_WORD(index);
332 		seg = dataSegIndex;
333 		addr = &dataSegment[index];
334 		debugC(3, kDebugScripts, "objectAddress: data[%s:%d] = %d", seg2str(seg).c_str(), index, *addr);
335 		break;
336 
337 	case addr_far:
338 		IMMED_WORD(seg);
339 		IMMED_WORD(index);
340 		addr = segmentAddress(seg, index);
341 		debugC(3, kDebugScripts, "objectAddress: far[%s:%d] = %d", seg2str(seg).c_str(), index, *addr);
342 		break;
343 
344 	case addr_array:
345 		IMMED_WORD(seg);
346 		IMMED_WORD(index);
347 		IMMED_WORD(offset);
348 		addr = segmentArrayAddress(seg, index) + offset;
349 		debugC(3, kDebugScripts, "objectAddress: array[%s:%d:%d] = %d", seg2str(seg).c_str(), index, offset, *addr);
350 		break;
351 
352 	case addr_this:
353 		IMMED_WORD(offset);
354 		arg = (uint16 *)(th->stackBase + th->framePtr + 8);
355 		seg = arg[0];
356 		index = arg[1];
357 		if (seg == dataSegIndex) {
358 			debugC(3, kDebugScripts, "objectAddress: thisD[%d:%d] = %d", index, offset, dataSegment[index + offset]);
359 			return &dataSegment[index + offset];
360 		}
361 		addr = segmentArrayAddress(seg, index) + offset;
362 			debugC(3, kDebugScripts, "objectAddress: thisS[%s:%d:%d] = %d", seg2str(seg).c_str(), index, offset, *addr);
363 		break;
364 
365 	case addr_deref:
366 
367 		//  First, get the address of the reference.
368 		*pcPtr = pc;
369 		addr = byteAddress(th, pcPtr);
370 		pc = *pcPtr;
371 
372 		//  Get the offset from the reference variable.
373 		index = *(uint16 *)addr;
374 
375 		//  Get the segment to dereference from, and the offset
376 		//  within the object.
377 		IMMED_WORD(seg);
378 		IMMED_WORD(offset);
379 
380 		//  Compute address of object
381 		addr = segmentAddress(seg, index) + offset;
382 		debugC(3, kDebugScripts, "objectAddress: deref[%s:%d:%d] = %d", seg2str(seg).c_str(), index, offset, *addr);
383 		break;
384 
385 	default:
386 		error("objectAddress: Invalid addressing mode: %d.\n", **pcPtr);
387 	}
388 
389 	offs = index;
390 	segNum = seg;
391 	*pcPtr = pc;
392 	return addr;
393 }
394 
395 //  Returns the address and access mask of a bit, given addressing mode
bitAddress(Thread * th,uint8 ** pcPtr,int16 * mask)396 uint8 *bitAddress(Thread *th, uint8 **pcPtr, int16 *mask) {
397 	uint8           *pc = *pcPtr,
398 	                *addr;
399 	uint16          seg,
400 	                offset;
401 
402 	switch (*pc++) {
403 	case addr_data:
404 		IMMED_WORD(offset);
405 		*pcPtr = pc;
406 		*mask = (1 << (offset & 7));
407 		debugC(3, kDebugScripts, "bitAddress: data[%d] = %d", offset, (dataSegment[offset >> 3] & *mask) != 0);
408 		return &dataSegment[(offset >> 3)];
409 
410 	case addr_near:
411 		IMMED_WORD(offset);
412 		*pcPtr = pc;
413 		*mask = (1 << (offset & 7));
414 		debugC(3, kDebugScripts, "bitAddress: near[%d] = %d", offset, (*(th->codeSeg + (offset >> 3)) & *mask) != 0);
415 		return th->codeSeg + (offset >> 3);
416 
417 	case addr_far:
418 		IMMED_WORD(seg);
419 		IMMED_WORD(offset);
420 		*pcPtr = pc;
421 		*mask = (1 << (offset & 7));
422 		debugC(3, kDebugScripts, "bitAddress: far[%s:%d] = %d", seg2str(seg).c_str(), offset, (*segmentAddress(seg, offset >> 3) & *mask) != 0);
423 		return segmentAddress(seg, (offset >> 3));
424 
425 	case addr_array:
426 		IMMED_WORD(seg);
427 		IMMED_WORD(offset);
428 		addr = segmentArrayAddress(seg, offset);
429 		IMMED_WORD(offset);
430 		*pcPtr = pc;
431 		*mask = (1 << (offset & 7));
432 		debugC(3, kDebugScripts, "bitAddress: array[%s:%d:%d] = %d", seg2str(seg).c_str(), offset, offset, (addr[offset >> 3] & *mask) != 0);
433 		return addr + (offset >> 3);
434 
435 	case addr_stack:
436 		IMMED_WORD(offset);
437 		*pcPtr = pc;
438 		*mask = (1 << (offset & 7));
439 		debugC(3, kDebugScripts, "bitAddress: stack[%d] = %d", offset, (*(th->stackBase + th->framePtr + (offset >>3)) & *mask) != 0);
440 		return th->stackBase + th->framePtr + (offset >> 3);
441 
442 	case addr_thread:
443 		IMMED_WORD(offset);
444 		*pcPtr = pc;
445 		*mask = (1 << (offset & 7));
446 		debugC(3, kDebugScripts, "bitAddress: thread[%d] = %d", offset, (*((uint8 *)&th->threadArgs + (offset >> 3)) & *mask) != 0);
447 		return (uint8 *)&th->threadArgs + (offset >> 3);
448 
449 	case addr_this:
450 		error("Addressing relative to 'this' not supported just yet.\n");
451 
452 	}
453 	error("bitAddress: Invalid addressing mode: %d.\n", **pcPtr);
454 }
455 
456 //  Returns the address of a string
457 
strAddress(int strNum)458 uint8 *Thread::strAddress(int strNum) {
459 	uint16 seg    = READ_LE_INT16(codeSeg + 2);
460 	uint16 offset = READ_LE_INT16(codeSeg + 4);
461 	uint8 *strSeg = segmentAddress(seg, offset);
462 
463 	assert(strNum >= 0);
464 	assert(codeSeg);
465 	assert(strSeg);
466 
467 	return strSeg + (uint16)READ_LE_INT16(strSeg + 2 * strNum);
468 }
469 
470 //-----------------------------------------------------------------------
471 //	RandomGenerator class - a random number generator class for function
472 //	objects which each maintain a local seed.
473 class RandomGenerator {
474 	uint32  a;                      //  seed
475 	static const uint32 b;          //  arbitrary constant
476 
477 public:
RandomGenerator(void)478 	RandomGenerator(void) : a(1) {
479 	}
RandomGenerator(uint16 seed)480 	RandomGenerator(uint16 seed) {
481 		a = (uint32)seed << 16;
482 	}
483 
seed(uint16 seed)484 	void seed(uint16 seed) {
485 		a = (uint32)seed << 16;
486 	}
487 
operator ()(void)488 	uint16 operator()(void) {
489 		a = (a * b) + 1;
490 		return a >> 16;
491 	}
492 };
493 
494 const uint32 RandomGenerator::b = 31415821;
495 
496 //-----------------------------------------------------------------------
497 //	A restricted random function
RRandom(int16 c,int16 s,int16 id)498 int16 RRandom(int16 c, int16 s, int16 id) {
499 	//  Create a local random number generator with a seed calculated
500 	//  with a non-deterministic portion generated by the standard
501 	//  library rand() function and a deterministic potion based upon
502 	//  the "id" argument
503 	RandomGenerator rnd(g_vm->_rnd->getRandomNumber(s - 1) + (id * s));
504 	return rnd() % c;
505 }
506 
507 /* ============================================================================ *
508                                 Main interpreter
509  * ============================================================================ */
print_script_name(uint8 * codePtr,const char * descr=NULL)510 void print_script_name(uint8 *codePtr, const char *descr = NULL) {
511 	char    scriptName[32];
512 	uint8   *sym = codePtr - 1;
513 	uint8   length = MIN<uint>(*sym, sizeof scriptName - 1);
514 
515 	memcpy(scriptName, sym - *sym, length);
516 	scriptName[length] = '\0';
517 
518 	if (descr)
519 		debugC(1, kDebugScripts, "Scripts: %d op_enter: [%s].%s ", lastExport, descr, scriptName);
520 	else
521 		debugC(1, kDebugScripts, "Scripts: %d op_enter: ::%s ", lastExport, scriptName);
522 }
523 
objectName(int16 segNum,uint16 segOff)524 const char *objectName(int16 segNum, uint16 segOff) {
525 	//static        nameBuf[64];
526 
527 	if (segNum >= 0)
528 		return "SagaObject";
529 
530 	switch (segNum) {
531 	case builtinTypeObject:
532 		return GameObject::objectAddress(segOff)->objName();
533 
534 	case builtinTypeTAG:
535 		return "Tag";
536 
537 	case builtinAbstract:
538 		return "@";
539 
540 	case builtinTypeMission:
541 		return "Mission";
542 	}
543 	return "???";
544 }
545 
546 #define STACK_PRINT_DEPTH 30
547 
print_stack(int16 * stackBase,int16 * stack)548 static void print_stack(int16 *stackBase, int16 *stack) {
549 	int16 *end = (int16 *)((byte *)stackBase + kStackSize - initialStackFrameSize);
550 	int size = end - stack;
551 
552 	if (size > STACK_PRINT_DEPTH)
553 		end = stack + STACK_PRINT_DEPTH;
554 
555 	debugCN(3, kDebugScripts, "stack size: %d: [", size);
556 	for (int16 *i = stack; i < end; i++)
557 		debugCN(3, kDebugScripts, "%d ", *i);
558 	if (size > STACK_PRINT_DEPTH)
559 		debugCN(3, kDebugScripts, "... ");
560 
561 	debugC(3, kDebugScripts, "]");
562 }
563 
564 #define D_OP(x) debugC(1, kDebugScripts, "[%04ld 0x%04lx]: %s", (pc - codeSeg - 1), (pc - codeSeg - 1), #x)
565 #define D_OP1(x) debugC(1, kDebugScripts, "[%04ld 0x%04lx]: %s = %d", (pc - codeSeg - 1), (pc - codeSeg - 1), #x, *stack)
566 #define D_OP2(x) debugC(1, kDebugScripts, "[%04ld 0x%04lx]: %s [%p] = %d", (pc - codeSeg - 1), (pc - codeSeg - 1), #x, (void *)addr, *stack)
567 #define D_OP3(x) debugC(1, kDebugScripts, "[%04ld 0x%04lx]: %s [%p] %d", (pc - codeSeg - 1), (pc - codeSeg - 1), #x, (void *)addr, *addr)
568 
interpret(void)569 bool Thread::interpret(void) {
570 	uint8               *pc,
571 	                    *addr;
572 	int16               *stack = (int16 *)stackPtr;
573 	int16               instruction_count;
574 	uint8               op;
575 	int16               w,
576 	                    n;
577 	C_Call              *cfunc;
578 
579 	pc = (codeSeg) + programCounter.offset;
580 
581 	thisThread = this;                          // set current thread address
582 
583 	for (instruction_count = 0; instruction_count < maxTimeSlice; instruction_count++) {
584 		print_stack((int16 *)stackBase, stack);
585 
586 		switch (op = *pc++) {
587 		case op_dup:
588 			--stack;
589 			*stack = stack[1];              // duplicate value on stack
590 			D_OP1(op_dup);
591 			break;
592 
593 		case op_drop:                           // drop word on stack
594 			D_OP(op_drop);
595 			stack++;
596 			break;
597 
598 		case op_zero:                           // constant integer of zero
599 			D_OP(op_zero);
600 			*--stack = 0;                       // push integer on stack
601 			break;
602 
603 		case op_one:                            // constant integer of one
604 			D_OP(op_one);
605 			*--stack = 1;                       // push integer on stack
606 			break;
607 
608 		case op_strlit:                         // string literal (also pushes word)
609 		case op_constint:                       // constant integer
610 			IMMED_WORD(w);                      // pick up word after opcode
611 			*--stack = w;                       // push integer on stack
612 
613 			if (op == op_strlit)
614 				D_OP1(op_strlit);
615 			else
616 				D_OP1(op_constint);
617 			break;
618 
619 		case op_getflag:                        // get a flag
620 			addr = bitAddress(this, &pc, &w);    // get address of bit
621 			*--stack = ((*addr) & w) ? 1 : 0;     // true or false if bit set
622 			D_OP2(op_getflag);
623 			break;
624 
625 		case op_getint:                         // read from integer field (mode)
626 			addr = byteAddress(this, &pc);   // get address of integer
627 			*--stack = *(uint16 *)addr;         // get integer from address
628 			D_OP2(op_getint);
629 			break;
630 
631 		case op_getbyte:                        // read from integer field (mode)
632 			addr = byteAddress(this, &pc);       // get address of integer
633 			*--stack = *addr;                   // get byte from address
634 			D_OP2(op_getbyte);
635 			break;
636 
637 		//  Note that in the current implementation, "put" ops leave
638 		//  the value that was stored on the stack. We mat also do a
639 		//  'vput' which consumes the variable.
640 
641 		case op_putflag:                    // put to flag bit (mode)
642 			addr = bitAddress(this, &pc, &w);  // get address of bit
643 			if (*stack) *addr |= w;         // set bit if stack non-zero
644 			else *addr &= ~w;               // else clear it
645 			D_OP3(op_putflag);
646 			break;
647 
648 		case op_putflag_v:                  // put to flag bit (mode)
649 			addr = bitAddress(this, &pc, &w);  // get address of bit
650 			if (*stack++) *addr |= w;       // set bit if stack non-zero
651 			else *addr &= ~w;               // else clear it
652 			D_OP3(op_putflag_v);
653 			break;
654 
655 		case op_putint:                     // put to integer field (mode)
656 			addr = byteAddress(this, &pc);   // get address of integer
657 			*(uint16 *)addr = *stack;       // put integer to address
658 			D_OP3(op_putint);
659 			break;
660 
661 		case op_putint_v:                   // put to integer field (mode)
662 			addr = byteAddress(this, &pc);   // get address of integer
663 			*(uint16 *)addr = *stack++;     // put integer to address
664 			D_OP3(op_putint_v);
665 			break;
666 
667 		case op_putbyte:                    // put to byte field (mode)
668 			addr = byteAddress(this, &pc);   // get address of integer
669 			*addr = *stack;                 // put integer to address
670 			D_OP3(op_putbyte);
671 			break;
672 
673 		case op_putbyte_v:                  // put to byte field (mode)
674 			addr = byteAddress(this, &pc);   // get address of integer
675 			*addr = *stack++;               // put integer to address
676 			D_OP3(op_putbyte_v);
677 			break;
678 
679 		case op_enter:
680 			D_OP(op_enter);
681 			print_script_name(pc - 1);
682 			*--stack = framePtr;            // save old frame ptr on stack
683 			framePtr = (uint8 *)stack - stackBase;  // new frame pointer
684 			IMMED_WORD(w);                  // pick up word after address
685 			stack -= w / 2;                 // make room for the locals!
686 			break;
687 
688 		//  function calls
689 
690 		case op_return:                     // return with value
691 			D_OP(op_return);
692 			returnVal = *stack++;
693 			// fall through
694 
695 		case op_return_v:                   // return with void
696 			D_OP(op_return_v);
697 			stack = (int16 *)(stackBase + framePtr);    // pop autos
698 			framePtr = *stack++;        // restore frame pointer
699 
700 			if (stack >= (int16 *)(stackBase + stackSize - initialStackFrameSize)) {
701 				//  Halt the thread here, wait for death
702 				programCounter.offset = (pc - (codeSeg));
703 				stackPtr = (uint8 *)stack;
704 				flags |= finished;
705 				return true;
706 			} else {
707 				programCounter.segment = *stack++;
708 				programCounter.offset = *stack++;
709 
710 				//RUnlockHandle((RHANDLE)codeSeg);
711 				codeSeg = scriptRes->loadIndexResource(programCounter.segment, "saga code segment");
712 				pc = (codeSeg) + programCounter.offset;
713 
714 				n = *stack++;               // get argument count from call
715 				stack += n;                 // pop that many args
716 
717 				if (op == op_return)        // if not void
718 					*--stack = returnVal;// push return value
719 			}
720 			break;
721 
722 		case op_call_near:                  // call function in same seg
723 			D_OP(op_call_near);
724 
725 			n = *pc++;                      // get argument count
726 
727 			programCounter.offset = (pc + 2 - codeSeg);
728 
729 			*--stack = n;                   // push number of args (16 bits)
730 			// push the program counter
731 			*--stack = programCounter.offset;
732 			*--stack = programCounter.segment;
733 
734 			IMMED_WORD(w);               // pick up segment offset
735 			programCounter.offset = w;      // store into pc
736 
737 			pc = codeSeg + w;              // calculate PC address
738 
739 			print_script_name(pc);
740 			break;
741 
742 		case op_call_far:                   // call function in other seg
743 			D_OP(op_call_far);
744 
745 			n = *pc++;                      // get argument count
746 
747 			programCounter.offset = (pc + 4 - codeSeg);
748 
749 			*--stack = n;                   // push number of args (16 bits)
750 			// push the program counter
751 			*--stack = programCounter.offset;
752 			*--stack = programCounter.segment;
753 
754 			IMMED_WORD(w);               // pick up segment number
755 			programCounter.segment = w;     // set current segment
756 			//RUnlockHandle((RHANDLE)codeSeg);
757 			codeSeg = scriptRes->loadIndexResource(w, "saga code segment");
758 			IMMED_WORD(w);               // pick up segment offset
759 			programCounter.offset = w;      // store into pc
760 
761 			pc = codeSeg + w;              // calculate PC address
762 			print_script_name(pc);
763 			break;
764 
765 		case op_ccall:                      // call C function
766 		case op_ccall_v:                    // call C function
767 			if (op == op_ccall)
768 				D_OP(op_ccall);
769 			else
770 				D_OP(op_call_v);
771 
772 			n = *pc++;                      // get argument count
773 			IMMED_WORD(w);                  // get function number
774 			if (w < 0 || w >= globalCFuncs.numEntries)
775 				error("Invalid function number");
776 
777 			cfunc = globalCFuncs.table[w];
778 			argCount = n;
779 			returnVal = cfunc(stack);        // call the function
780 
781 			stack += n;                     // pop args of of the stack
782 
783 			if (op == op_ccall) {           // push the return value
784 				*--stack = returnVal;       // onto the stack
785 				flags |= expectResult;      // script expecting result
786 			} else flags &= ~expectResult;  // script not expecting result
787 
788 			//  if the thread is asleep, then no more instructions
789 			if (flags & asleep)
790 				instruction_count = maxTimeSlice;   // break out of loop!
791 
792 			break;
793 
794 		case op_call_member:                // call member function
795 		case op_call_member_v:              // call member function (void)
796 			if (op == op_call_member)
797 				D_OP(op_call_member);
798 			else
799 				D_OP(op_call_member_v);
800 
801 			n = *pc++;                      // get argument count
802 			w = *pc++;                      // index of member function
803 
804 			{
805 				uint16  *vtable,
806 				        *vtableEntry,
807 				        seg,
808 				        offset;
809 
810 				//  REM: We need a more deterministic way to
811 				//  set up the c function tables.
812 
813 				CallTable   *callTab = &globalCFuncs;
814 
815 				//  Get the address of the object
816 				addr = objectAddress(this, &pc, seg, offset);
817 
818 				//  Handle the case of a builtin object which computes the
819 				//  vtable address in a different way.
820 
821 				if ((int16)seg < 0) {
822 					vtable = builtinVTableAddress((int16)seg, addr, &callTab);
823 				} else {
824 					vtable = (uint16 *)segmentAddress(((int16 *)addr)[0],
825 					                                  ((int16 *)addr)[1]);
826 				}
827 
828 				vtableEntry = vtable + (w * 2);
829 
830 				if (vtable == NULL) {
831 					//  Do nothing...
832 				} else if (vtableEntry[0] != 0xffff) { // It's a SAGA func
833 					programCounter.offset = (pc - codeSeg);
834 
835 					//  Push the address of the object
836 					*--stack = offset;
837 					*--stack = seg;
838 					//  Push number of args. including 'this'
839 					*--stack = n + 2;
840 
841 					// push the program counter
842 					*--stack = programCounter.offset;
843 					*--stack = programCounter.segment;
844 
845 					//  Get the segment of the member function, and
846 					//  determine it's real address (save segment number
847 					//  into thread).
848 					w = vtableEntry[0];
849 					programCounter.segment = w;
850 					//RUnlockHandle((RHANDLE)codeSeg);
851 					codeSeg = scriptRes->loadIndexResource(w, "saga code segment");
852 
853 					// store pc-offset into pc
854 					programCounter.offset = vtableEntry[1];
855 
856 					// calculate PC address
857 					pc = (codeSeg) + programCounter.offset;
858 					print_script_name(pc, objectName(seg, offset));
859 
860 					break;
861 				} else if (vtableEntry[1] != 0xffff) { // It's a C func
862 					//  Save the ID of the invoked object
863 					ObjectID    saveID = threadArgs.invokedObject;
864 
865 					//  Get the function number
866 					w = vtableEntry[1];
867 					if (w < 0 || w >= callTab->numEntries)
868 						error("Invalid member function number");
869 
870 					//  Set up thread-specific vars
871 					thisObject = addr;
872 					argCount = n;
873 					threadArgs.invokedObject = offset;
874 
875 					//  Get address of function and call it.
876 					cfunc = callTab->table[w];
877 					returnVal = cfunc(stack);        // call the function
878 
879 					//  Restore object ID from thread args
880 					threadArgs.invokedObject = saveID;
881 
882 					//  Pop args off of the stack
883 					stack += n;
884 
885 					//  Push the return value onto the stack if it's
886 					//  not a 'void' call.
887 					if (op == op_call_member) {
888 						*--stack = returnVal;   // onto the stack
889 						flags |= expectResult;  // script expecting result
890 					} else flags &= ~expectResult; // script not expecting result
891 
892 					//  if the thread is asleep, then break interpret loop
893 					if (flags & asleep) instruction_count = maxTimeSlice;
894 					break;
895 				}
896 				// else it's a NULL function (i.e. pure virtual)
897 			}
898 
899 			//  REM: Call the member function
900 
901 			if (op == op_call_member)       // push the return value
902 				*--stack = 0;               // onto the stack
903 
904 			break;
905 
906 		case op_jmp_true_v:
907 			D_OP(op_jmp_true_v);
908 			IMMED_WORD(w);               // pick up word after address
909 			if (*stack++ != 0) {
910 				BRANCH(w);    // if stack is non-zero, jump
911 			}
912 			break;
913 
914 		case op_jmp_false_v:
915 			D_OP(op_jmp_false_v);
916 			IMMED_WORD(w);               // pick up word after address
917 			if (*stack++ == 0) {
918 				BRANCH(w);    // if stack is zero, jump
919 			}
920 			break;
921 
922 		case op_jmp_true:
923 			D_OP(op_true);
924 			IMMED_WORD(w);               // pick up word after address
925 			if (*stack != 0) {
926 				BRANCH(w);      // if stack is non-zero. jump
927 			}
928 			break;
929 
930 		case op_jmp_false:
931 			D_OP(op_false);
932 			IMMED_WORD(w);               // pick up word after address
933 			if (*stack == 0) {
934 				BRANCH(w);      // if stack is zero, jump
935 			}
936 			break;
937 
938 		case op_jmp:
939 			D_OP(op_jmp);
940 			IMMED_WORD(w);               // pick up word after address
941 			BRANCH(w);                   // jump relative to module
942 			break;
943 
944 		case op_jmp_switch:
945 			D_OP(op_jmp_switch);
946 			IMMED_WORD(n);                  // n = number of cases
947 			w = *stack++;                   // w = value on stack
948 			{
949 				uint16      val,
950 				            jmp;
951 
952 				while (n--) {
953 					IMMED_WORD(val);         // val = case value
954 					IMMED_WORD(jmp);         // jmp = address to jump to
955 					debugC(3, kDebugScripts, "Case %d: jmp %d", val, jmp);
956 
957 					if (w == val) {         // if case values match
958 						BRANCH(jmp);         // jump to case
959 						break;
960 					}
961 				}
962 				if (n < 0) {
963 					IMMED_WORD(jmp);         // def = jump offset for default
964 					BRANCH(jmp);             // take default jump
965 				}
966 			}
967 			break;
968 
969 		case op_jmp_seedrandom:             // seeded random jump
970 		case op_jmp_random:                 // random jump
971 			if (op == op_jmp_seedrandom)
972 				D_OP(op_jmp_seedrandom);
973 			else
974 				D_OP(op_random);
975 
976 			if (op == op_jmp_random) {
977 				IMMED_WORD(n);              // n = number of cases
978 				IMMED_WORD(n);              // total probability
979 				n = (uint16)(g_vm->_rnd->getRandomNumber(n - 1));     // random number between 0 and n-1
980 			} else {
981 				int16   seed,
982 				        r;
983 
984 				seed = *stack++;            // the seed value
985 				IMMED_WORD(r);              // n = restriction
986 				IMMED_WORD(n);              // n = number of cases
987 				IMMED_WORD(n);              // total probability
988 
989 				n = RRandom(n, r, seed);
990 			}
991 
992 			for (;;) {
993 				uint16  val,
994 				        jmp;
995 
996 				IMMED_WORD(val);             // val = probability of this case
997 				IMMED_WORD(jmp);             // jmp = address to jump to
998 
999 				n -= val;                   // subtract prob from overall prob
1000 				if (n < 0) {                // if number within range
1001 					BRANCH(jmp);             // jump to prob
1002 					break;
1003 				}
1004 			}
1005 			break;
1006 
1007 		case op_negate:
1008 			D_OP(op_negate);
1009 			*stack = - *stack;
1010 			break;   // negate TOS
1011 		case op_not:
1012 			D_OP(op_not);
1013 			*stack = ! *stack;
1014 			break;   // not TOS
1015 		case op_compl:
1016 			D_OP(op_compl);
1017 			*stack = ~ *stack;
1018 			break;   // complement TOS
1019 
1020 		case op_inc_v:
1021 			D_OP(op_inc_v);
1022 			addr = byteAddress(this, &pc);   // get address of integer
1023 			*(uint16 *)addr += 1;           // bump value by one
1024 			break;
1025 
1026 		case op_dec_v:
1027 			D_OP(op_dec_v);
1028 			addr = byteAddress(this, &pc);   // get address of integer
1029 			*(uint16 *)addr -= 1;           // bump value by one
1030 			break;
1031 
1032 		case op_postinc:
1033 			D_OP(op_postinc);
1034 			addr = byteAddress(this, &pc);   // get address of integer
1035 			*--stack = *(uint16 *)addr;     // get integer from address
1036 			*(uint16 *)addr += 1;           // bump value by one
1037 			break;
1038 
1039 		case op_postdec:
1040 			D_OP(op_postdec);
1041 			addr = byteAddress(this, &pc);   // get address of integer
1042 			*--stack = *(uint16 *)addr;     // get integer from address
1043 			*(uint16 *)addr -= 1;           // bump value by one
1044 			break;
1045 
1046 		//  Binary ops. Since I don't know the order of evaluation of
1047 		//  These C operations, I use a temp variable. Note that
1048 		//  stack is incremented before storing to skip over the
1049 		//  dropped variable.
1050 
1051 		case op_add:
1052 			D_OP(op_add);
1053 			w = (stack[1] +  stack[0]);
1054 			*++stack = w;
1055 			break;
1056 		case op_sub:
1057 			D_OP(op_sub);
1058 			w = (stack[1] -  stack[0]);
1059 			*++stack = w;
1060 			break;
1061 		case op_mul:
1062 			D_OP(op_mul);
1063 			w = (stack[1] *  stack[0]);
1064 			*++stack = w;
1065 			break;
1066 		case op_div:
1067 			D_OP(op_div);
1068 			w = (stack[1] /  stack[0]);
1069 			*++stack = w;
1070 			break;
1071 		case op_mod:
1072 			D_OP(op_mod);
1073 			w = (stack[1] %  stack[0]);
1074 			*++stack = w;
1075 			break;
1076 		case op_eq:
1077 			D_OP(op_eq);
1078 			w = (stack[1] == stack[0]);
1079 			*++stack = w;
1080 			break;
1081 		case op_ne:
1082 			D_OP(op_ne);
1083 			w = (stack[1] != stack[0]);
1084 			*++stack = w;
1085 			break;
1086 		case op_gt:
1087 			D_OP(op_gt);
1088 			w = (stack[1] >  stack[0]);
1089 			*++stack = w;
1090 			break;
1091 		case op_lt:
1092 			D_OP(op_lt);
1093 			w = (stack[1] <  stack[0]);
1094 			*++stack = w;
1095 			break;
1096 		case op_ge:
1097 			D_OP(op_ge);
1098 			w = (stack[1] >= stack[0]);
1099 			*++stack = w;
1100 			break;
1101 		case op_le:
1102 			D_OP(op_le);
1103 			w = (stack[1] <= stack[0]);
1104 			*++stack = w;
1105 			break;
1106 		case op_rsh:
1107 			D_OP(op_rsh);
1108 			w = (stack[1] >> stack[0]);
1109 			*++stack = w;
1110 			break;
1111 		case op_lsh:
1112 			D_OP(op_lsh);
1113 			w = (stack[1] << stack[0]);
1114 			*++stack = w;
1115 			break;
1116 		case op_and:
1117 			D_OP(op_and);
1118 			w = (stack[1] &  stack[0]);
1119 			*++stack = w;
1120 			break;
1121 		case op_or:
1122 			D_OP(op_or);
1123 			w = (stack[1] |  stack[0]);
1124 			*++stack = w;
1125 			break;
1126 		case op_xor:
1127 			D_OP(op_xor);
1128 			w = (stack[1] ^  stack[0]);
1129 			*++stack = w;
1130 			break;
1131 		case op_land:
1132 			D_OP(op_land);
1133 			w = (stack[1] && stack[0]);
1134 			*++stack = w;
1135 			break;
1136 		case op_lor:
1137 			D_OP(op_lor);
1138 			w = (stack[1] || stack[0]);
1139 			*++stack = w;
1140 			break;
1141 		case op_lxor:
1142 			D_OP(op_lxor);
1143 			w = (stack[1] && !stack[0]) || (!stack[1] && stack[0]);
1144 			*++stack = w;
1145 			break;
1146 
1147 		case op_speak:
1148 		case op_dialog_begin:
1149 		case op_dialog_end:
1150 		case op_reply:
1151 		case op_animate:
1152 			script_error("Feature not implemented.\n");
1153 			break;
1154 
1155 		default:
1156 			script_error("fatal error: undefined opcode");
1157 			break;
1158 		}
1159 	}
1160 
1161 	programCounter.offset = (pc - (codeSeg));
1162 	stackPtr = (uint8 *)stack;
1163 
1164 	return false;
1165 }
1166 
1167 /* ============================================================================ *
1168                             ThreadList class
1169  * ============================================================================ */
1170 
1171 class ThreadList {
1172 	enum {
1173 		kNumThreads = 25
1174 	};
1175 
1176 	Thread *_list[kNumThreads];
1177 
1178 public:
1179 	//  Constructor
ThreadList(void)1180 	ThreadList(void) {
1181 		for (uint i = 0; i < kNumThreads; i++)
1182 			_list[i] = nullptr;
1183 	}
1184 
1185 	void read(Common::InSaveFile *in);
1186 
1187 	//  Return the number of bytes needed to archive this thread list
1188 	//  in an archive buffer
1189 	int32 archiveSize(void);
1190 
1191 	void write(Common::MemoryWriteStreamDynamic *out);
1192 
1193 	//  Cleanup the active threads
1194 	void cleanup(void);
1195 
1196 	//  Place a thread back into the inactive list
1197 	void deleteThread(Thread *p);
1198 
1199 	void newThread(Thread *p, ThreadID id);
1200 
1201 	void newThread(Thread *p);
1202 
1203 	//  Return the specified thread's ID
getThreadID(Thread * thread)1204 	ThreadID getThreadID(Thread *thread) {
1205 		for (uint i = 0; i < kNumThreads; i++) {
1206 			if (_list[i] == thread)
1207 				return i;
1208 		}
1209 
1210 		error("Unknown thread address: %p", (void *)thread);
1211 	}
1212 
1213 	//  Return a pointer to a thread, given an ID
getThreadAddress(ThreadID id)1214 	Thread *getThreadAddress(ThreadID id) {
1215 		return _list[id];
1216 	}
1217 
1218 	//  Return a pointer to the first active thread
1219 	Thread *first(void);
1220 
1221 	Thread *next(Thread *thread);
1222 };
1223 
read(Common::InSaveFile * in)1224 void ThreadList::read(Common::InSaveFile *in) {
1225 	int16 threadCount;
1226 
1227 	//  Get the count of threads and increment the buffer pointer
1228 	threadCount = in->readSint16LE();
1229 	debugC(3, kDebugSaveload, "... threadCount = %d", threadCount);
1230 
1231 	//  Iterate through the archive data, reconstructing the Threads
1232 	for (int i = 0; i < threadCount; i++) {
1233 		debugC(3, kDebugSaveload, "Saving Thread %d", i);
1234 		ThreadID id;
1235 
1236 		//  Retreive the Thread's id number
1237 		id = in->readSint16LE();
1238 		debugC(4, kDebugSaveload, "...... id = %d", id);
1239 
1240 		new Thread(in, id);
1241 	}
1242 }
1243 
archiveSize(void)1244 int32 ThreadList::archiveSize(void) {
1245 	int32 size = sizeof(int16);
1246 
1247 	for (uint i = 0; i < kNumThreads; i++) {
1248 		if (_list[i])
1249 			size += sizeof(ThreadID) + _list[i]->archiveSize();
1250 	}
1251 
1252 	return size;
1253 }
1254 
write(Common::MemoryWriteStreamDynamic * out)1255 void ThreadList::write(Common::MemoryWriteStreamDynamic *out) {
1256 	int16 threadCount = 0;
1257 	Thread *th;
1258 
1259 	//  Count the active threads
1260 	for (th = first(); th; th = next(th))
1261 		threadCount++;
1262 
1263 	//  Store the thread count in the archive buffer
1264 	out->writeSint16LE(threadCount);
1265 	debugC(3, kDebugSaveload, "... threadCount = %d", threadCount);
1266 
1267 	//  Iterate through the threads, archiving each
1268 	for (th = first(); th; th = next(th)) {
1269 		debugC(3, kDebugSaveload, "Loading ThreadID %d", getThreadID(th));
1270 		//  Store the Thread's id number
1271 		out->writeSint16LE(getThreadID(th));
1272 
1273 		th->write(out);
1274 	}
1275 }
1276 
1277 //-------------------------------------------------------------------
1278 //	Cleanup the active threads
1279 
cleanup(void)1280 void ThreadList::cleanup(void) {
1281 	for (uint i = 0; i < kNumThreads; i++) {
1282 		delete _list[i];
1283 		_list[i] = nullptr;
1284 	}
1285 }
1286 
1287 //-------------------------------------------------------------------
1288 //	Place a thread back into the inactive list
1289 
deleteThread(Thread * p)1290 void ThreadList::deleteThread(Thread *p) {
1291 	for (uint i = 0; i < kNumThreads; i++) {
1292 		if (_list[i] == p) {
1293 			_list[i] = nullptr;
1294 		}
1295 	}
1296 }
1297 
newThread(Thread * p,ThreadID id)1298 void ThreadList::newThread(Thread *p, ThreadID id) {
1299 	if (_list[id])
1300 		error("Thread %d already exists", id);
1301 
1302 	_list[id] = p;
1303 }
1304 
newThread(Thread * p)1305 void ThreadList::newThread(Thread *p) {
1306 	for (uint i = 0; i < kNumThreads; i++) {
1307 		if (!_list[i]) {
1308 			_list[i] = p;
1309 			return;
1310 		}
1311 	}
1312 
1313 	error("ThreadList::newThread(): Too many threads");
1314 }
1315 
1316 //-------------------------------------------------------------------
1317 //	Return a pointer to the first active thread
1318 
first(void)1319 Thread *ThreadList::first(void) {
1320 	for (uint i = 0; i < kNumThreads; i++)
1321 		if (_list[i])
1322 			return _list[i];
1323 
1324 	return nullptr;
1325 }
1326 
next(Thread * thread)1327 Thread *ThreadList::next(Thread *thread) {
1328 	uint i;
1329 	for (i = 0; i < kNumThreads; i++)
1330 		if (_list[i] == thread)
1331 			break;
1332 
1333 	i++;
1334 	if (i >= kNumThreads)
1335 		return nullptr;
1336 
1337 	for (; i < kNumThreads; i++)
1338 		if (_list[i])
1339 			return _list[i];
1340 
1341 	return nullptr;
1342 }
1343 
1344 
1345 /* ===================================================================== *
1346    Global thread list instantiation
1347  * ===================================================================== */
1348 
1349 //	The thread list is instantiated like this in order to keep the
1350 //	constructor from being called until it is explicitly called with
1351 //	the overloaded new operator.
1352 
1353 static uint8 threadListBuffer[sizeof(ThreadList)];
1354 static ThreadList &threadList = *((ThreadList *)threadListBuffer);
1355 
1356 /* ============================================================================ *
1357                      ThreadList management functions
1358  * ============================================================================ */
1359 
1360 //-------------------------------------------------------------------
1361 //	Initialize the SAGA thread list
1362 
initSAGAThreads(void)1363 void initSAGAThreads(void) {
1364 	//  Simply call the Thread List default constructor
1365 }
1366 
saveSAGAThreads(Common::OutSaveFile * outS)1367 void saveSAGAThreads(Common::OutSaveFile *outS) {
1368 	debugC(2, kDebugSaveload, "Saving SAGA Threads");
1369 
1370 	outS->write("SAGA", 4);
1371 	CHUNK_BEGIN;
1372 	threadList.write(out);
1373 	CHUNK_END;
1374 }
1375 
loadSAGAThreads(Common::InSaveFile * in,int32 chunkSize)1376 void loadSAGAThreads(Common::InSaveFile *in, int32 chunkSize) {
1377 	debugC(2, kDebugSaveload, "Loading SAGA Threads");
1378 
1379 	if (chunkSize == 0) {
1380 		return;
1381 	}
1382 
1383 	//  Reconstruct stackList from archived data
1384 	threadList.read(in);
1385 }
1386 
1387 //-------------------------------------------------------------------
1388 //	Dispose of the active SAGA threads
1389 
cleanupSAGAThreads(void)1390 void cleanupSAGAThreads(void) {
1391 	//  Simply call the ThreadList cleanup() function
1392 	threadList.cleanup();
1393 }
1394 
1395 //-------------------------------------------------------------------
1396 //	Dispose of an active SAGA thread
1397 
deleteThread(Thread * thread)1398 void deleteThread(Thread *thread) {
1399 	threadList.deleteThread(thread);
1400 }
1401 
newThread(Thread * p,ThreadID id)1402 void newThread(Thread *p, ThreadID id) {
1403 	threadList.newThread(p, id);
1404 }
1405 
newThread(Thread * thread)1406 void newThread(Thread *thread) {
1407 	threadList.newThread(thread);
1408 }
1409 
1410 //-------------------------------------------------------------------
1411 //	Return the ID of the specified SAGA thread
1412 
getThreadID(Thread * thread)1413 ThreadID getThreadID(Thread *thread) {
1414 	return threadList.getThreadID(thread);
1415 }
1416 
1417 //-------------------------------------------------------------------
1418 //	Return a pointer to a SAGA thread, given a thread ID
1419 
getThreadAddress(ThreadID id)1420 Thread *getThreadAddress(ThreadID id) {
1421 	return threadList.getThreadAddress(id);
1422 }
1423 
1424 /* ============================================================================ *
1425                            Thread member functions
1426  * ============================================================================ */
1427 
1428 //-----------------------------------------------------------------------
1429 //	Thread constructor
1430 
Thread(uint16 segNum,uint16 segOff,scriptCallFrame & args)1431 Thread::Thread(uint16 segNum, uint16 segOff, scriptCallFrame &args) {
1432 	codeSeg = scriptRes->loadIndexResource(segNum, "saga code segment");
1433 
1434 	//  initialize the thread
1435 	stackSize = kStackSize;
1436 	flags = 0;
1437 	returnVal = 0;
1438 	programCounter.segment = segNum;
1439 	programCounter.offset = segOff;
1440 	threadArgs = args;
1441 	stackBase = (byte *)malloc(stackSize);
1442 	stackPtr = stackBase + stackSize - initialStackFrameSize;
1443 	((uint16 *)stackPtr)[0] = 0;          // 0 args
1444 	((uint16 *)stackPtr)[1] = 0;          // dummy return address
1445 	((uint16 *)stackPtr)[2] = 0;          // dummy return address
1446 	framePtr = stackSize;
1447 	_valid = true;
1448 
1449 	if ((codeSeg)[programCounter.offset] != op_enter) {
1450 		//warning("SAGA failure: Invalid script entry point (export=%d) [segment=%d:%d]\n", lastExport, segNum, segOff);
1451 		_valid = false;
1452 	}
1453 
1454 	newThread(this);
1455 }
1456 
Thread(Common::SeekableReadStream * stream,ThreadID id)1457 Thread::Thread(Common::SeekableReadStream *stream, ThreadID id) {
1458 	int16   stackOffset;
1459 
1460 	programCounter.segment = stream->readUint16LE();
1461 	programCounter.offset = stream->readUint16LE();
1462 
1463 	stackSize = stream->readSint16LE();
1464 	flags = stream->readSint16LE();
1465 	framePtr = stream->readSint16LE();
1466 	returnVal = stream->readSint16LE();
1467 
1468 	waitAlarm.read(stream);
1469 
1470 	stackOffset = stream->readSint16LE();
1471 
1472 	debugC(4, kDebugSaveload, "...... stackSize = %d", stackSize);
1473 	debugC(4, kDebugSaveload, "...... flags = %d", flags);
1474 	debugC(4, kDebugSaveload, "...... framePtr = %d", framePtr);
1475 	debugC(4, kDebugSaveload, "...... returnVal = %d", returnVal);
1476 	debugC(4, kDebugSaveload, "...... stackOffset = %d", stackOffset);
1477 
1478 	codeSeg = scriptRes->loadIndexResource(programCounter.segment, "saga code segment");
1479 
1480 	stackBase = (byte *)malloc(stackSize);
1481 	stackPtr = stackBase + stackSize - stackOffset;
1482 
1483 	stream->read(stackPtr, stackOffset);
1484 
1485 	newThread(this, id);
1486 }
1487 
1488 //-----------------------------------------------------------------------
1489 //	Thread destructor
1490 
~Thread()1491 Thread::~Thread() {
1492 	//  Clear extended bit if it was set
1493 	clearExtended();
1494 
1495 	//  Free the thread's code segment
1496 	//RUnlockHandle((RHANDLE)codeSeg);
1497 
1498 	//  Deallocate the thread stack
1499 	free(stackBase);
1500 
1501 	deleteThread(this);
1502 }
1503 
1504 //-----------------------------------------------------------------------
1505 //	Return the number of bytes need to archive this thread in an arhive
1506 //	buffer
1507 
archiveSize(void)1508 int32 Thread::archiveSize(void) {
1509 	return      sizeof(programCounter)
1510 	            +   sizeof(stackSize)
1511 	            +   sizeof(flags)
1512 	            +   sizeof(framePtr)
1513 	            +   sizeof(returnVal)
1514 	            +   sizeof(waitAlarm)
1515 	            +   sizeof(int16)                //  stack offset
1516 	            + (stackBase + stackSize) - stackPtr;
1517 }
1518 
write(Common::MemoryWriteStreamDynamic * out)1519 void Thread::write(Common::MemoryWriteStreamDynamic *out) {
1520 	int16   stackOffset;
1521 
1522 	out->writeUint16LE(programCounter.segment);
1523 	out->writeUint16LE(programCounter.offset);
1524 
1525 	out->writeSint16LE(stackSize);
1526 	out->writeSint16LE(flags);
1527 	out->writeSint16LE(framePtr);
1528 	out->writeSint16LE(returnVal);
1529 
1530 	waitAlarm.write(out);
1531 
1532 	warning("STUB: Thread::write: Pointer arithmetic");
1533 	stackOffset = (stackBase + stackSize) - stackPtr;
1534 	out->writeSint16LE(stackOffset);
1535 
1536 	out->write(stackPtr, stackOffset);
1537 
1538 	debugC(4, kDebugSaveload, "...... stackSize = %d", stackSize);
1539 	debugC(4, kDebugSaveload, "...... flags = %d", flags);
1540 	debugC(4, kDebugSaveload, "...... framePtr = %d", framePtr);
1541 	debugC(4, kDebugSaveload, "...... returnVal = %d", returnVal);
1542 	debugC(4, kDebugSaveload, "...... stackOffset = %d", stackOffset);
1543 }
1544 
1545 //-----------------------------------------------------------------------
1546 //	Thread dispatcher
1547 
dispatch(void)1548 void Thread::dispatch(void) {
1549 	Thread              *th,
1550 	                    *nextThread;
1551 
1552 	int                 numThreads = 0,
1553 	                    numExecute = 0,
1554 	                    numWaitDelay = 0,
1555 	                    numWaitFrames = 0,
1556 	                    numWaitSemi = 0,
1557 	                    numWaitOther = 0;
1558 
1559 	for (th = threadList.first(); th; th = threadList.next(th)) {
1560 		if (th->flags & waiting) {
1561 			switch (th->waitType) {
1562 
1563 			case waitDelay:
1564 				numWaitDelay++;
1565 				break;
1566 			case waitFrameDelay:
1567 				numWaitFrames++;
1568 				break;
1569 			case waitTagSemaphore:
1570 				numWaitSemi++;
1571 				break;
1572 			default:
1573 				numWaitOther++;
1574 				break;
1575 			}
1576 		} else numExecute++;
1577 		numThreads++;
1578 	}
1579 
1580 	debugC(9, kDebugScripts, "Threads:%d X:%d D:%d F:%d T:%d O:%d", numThreads, numExecute, numWaitDelay, numWaitFrames, numWaitSemi, numWaitOther);
1581 
1582 	for (th = threadList.first(); th; th = nextThread) {
1583 		nextThread = threadList.next(th);
1584 
1585 		if (th->flags & (finished | aborted)) {
1586 			delete th;
1587 			continue;
1588 		}
1589 
1590 		if (th->flags & waiting) {
1591 			switch (th->waitType) {
1592 
1593 			case waitDelay:
1594 
1595 				//  Wake up the thread!
1596 
1597 				if (th->waitAlarm.check())
1598 					th->flags &= ~waiting;
1599 				break;
1600 
1601 			case waitFrameDelay:
1602 
1603 				if (th->waitFrameAlarm.check())
1604 					th->flags &= ~waiting;
1605 				break;
1606 
1607 			case waitTagSemaphore:
1608 				if (th->waitParam->isExclusive() == false) {
1609 					th->flags &= ~waiting;
1610 					th->waitParam->setExclusive(true);
1611 				}
1612 				break;
1613 			default:
1614 				break;
1615 			}
1616 		}
1617 
1618 		do {
1619 			if (th->flags & (waiting | finished | aborted))
1620 				break;
1621 
1622 			if (th->interpret())
1623 				goto break_thread_loop;
1624 		} while (th->flags & synchronous);
1625 	}
1626 break_thread_loop:
1627 	;
1628 }
1629 
1630 //-----------------------------------------------------------------------
1631 //	Run scripts which are on the queue
1632 
dispatchScripts(void)1633 void dispatchScripts(void) {
1634 	Thread::dispatch();
1635 }
1636 
1637 //-----------------------------------------------------------------------
1638 //	Run a script until finished
1639 
run(void)1640 scriptResult Thread::run(void) {
1641 	int             i = 4000;
1642 
1643 	while (i--) {
1644 		//  If script stopped, then return
1645 		if (flags & (waiting | finished | aborted)) {
1646 			if (flags & finished)   return scriptResultFinished;
1647 			if (flags & waiting)    return scriptResultAsync;
1648 			return scriptResultAborted;
1649 			// can't ever fall thru here...
1650 		}
1651 
1652 		//  run the script some more...
1653 		interpret();
1654 	}
1655 	error("Thread timed out!\n");
1656 }
1657 
1658 //-----------------------------------------------------------------------
1659 //	Convert to extended thread
1660 
setExtended(void)1661 void Thread::setExtended(void) {
1662 	if (!(flags & extended)) {
1663 		flags |= extended;
1664 		extendedThreadLevel++;
1665 	}
1666 }
1667 
1668 //-----------------------------------------------------------------------
1669 //	Convert back to regular thread
1670 
clearExtended(void)1671 void Thread::clearExtended(void) {
1672 	if (flags & extended) {
1673 		flags &= ~extended;
1674 		extendedThreadLevel--;
1675 	}
1676 }
1677 
1678 /* ============================================================================ *
1679                         Script Management functions
1680  * ============================================================================ */
initScripts(void)1681 void initScripts(void) {
1682 	//  Open the script resource group
1683 	scriptRes = scriptResFile->newContext(sagaID,  "script resources");
1684 	if (scriptRes == NULL)
1685 		error("Unable to open script resource file!\n");
1686 
1687 	//  Load the data segment
1688 	dataSegment = scriptRes->loadResource(dataSegID, "saga data segment");
1689 
1690 	if (dataSegment == NULL)
1691 		error("Unable to load the SAGA data segment");
1692 
1693 	dataSegSize = scriptRes->getSize(dataSegID, "saga data segment");
1694 	debugC(2, kDebugScripts, "dataSegment loaded at %p: size: %d", (void*)dataSegment, dataSegSize);
1695 
1696 //	Common::hexdump(dataSegment, dataSegSize);
1697 
1698 	exportSegment = scriptRes->loadResource(exportSegID, "saga export segment");
1699 	assert(exportSegment != NULL);
1700 
1701 //	Common::hexdump(exportSegment, scriptRes->getSize(exportSegID, "saga export segment"));
1702 
1703 	exportCount = (scriptRes->getSize(exportSegID, "saga export segment") / sizeof(uint32)) + 1;
1704 	debugC(2, kDebugScripts, "exportSegment loaded at %p: size: %d, exportCount: %ld",
1705 	       (void*)exportSegment, scriptRes->getSize(exportSegID, "saga export segment"), exportCount);
1706 }
1707 
cleanupScripts(void)1708 void cleanupScripts(void) {
1709 	if (exportSegment)
1710 		free(exportSegment);
1711 
1712 	if (dataSegment)
1713 		free(dataSegment);
1714 
1715 	if (scriptRes)
1716 		scriptResFile->disposeContext(scriptRes);
1717 	scriptRes = NULL;
1718 }
1719 
1720 //-----------------------------------------------------------------------
1721 //	Load the SAGA data segment from the resource file
1722 
initSAGADataSeg(void)1723 void initSAGADataSeg(void) {
1724 	//  Load the data segment
1725 	scriptRes->seek(dataSegID);
1726 	scriptRes->read(dataSegment, dataSegSize);
1727 }
1728 
saveSAGADataSeg(Common::OutSaveFile * outS)1729 void saveSAGADataSeg(Common::OutSaveFile *outS) {
1730 	debugC(2, kDebugSaveload, "Saving Data Segment");
1731 
1732 	outS->write("SDTA", 4);
1733 	CHUNK_BEGIN;
1734 	out->write(dataSegment, dataSegSize);
1735 	CHUNK_END;
1736 }
1737 
loadSAGADataSeg(Common::InSaveFile * in)1738 void loadSAGADataSeg(Common::InSaveFile *in) {
1739 	in->read(dataSegment, dataSegSize);
1740 }
1741 
1742 //-----------------------------------------------------------------------
1743 //	Look up an entry in the SAGA export table
1744 
lookupExport(uint16 entry,uint16 & segNum,uint16 & segOff)1745 static bool lookupExport(
1746     uint16          entry,
1747     uint16          &segNum,
1748     uint16          &segOff) {
1749 	uint32          segRef;
1750 
1751 	assert(entry > 0);
1752 	assert(entry <= exportCount);
1753 
1754 	segRef = READ_LE_INT32(exportSegment + 4 * entry - 2);
1755 	segOff = segRef >> 16,
1756 	segNum = segRef & 0x0000ffff;
1757 
1758 	lastExport = entry;
1759 	if (segNum > 1000)
1760 		error("SAGA failure: Bad data in export table entry #%d (see scripts.r)", entry);
1761 
1762 	return true;
1763 }
1764 
1765 //-----------------------------------------------------------------------
1766 //	Run a script to completion (or until it forks)
1767 
runScript(uint16 exportEntryNum,scriptCallFrame & args)1768 scriptResult runScript(uint16 exportEntryNum, scriptCallFrame &args) {
1769 	uint16          segNum,
1770 	                segOff;
1771 	Thread          *th;
1772 	scriptResult    result;
1773 	Thread          *saveThread = thisThread;
1774 
1775 	assert(exportEntryNum > 0);
1776 	lookupExport(exportEntryNum, segNum, segOff);
1777 
1778 	//  Create a new thread
1779 	th = new Thread(segNum, segOff, args);
1780 	thisThread = th;
1781 	// FIXME: We should probably just use an error(), but this will work for mass debugging
1782 	if (th == nullptr) {
1783 		debugC(4, kDebugScripts, "Couldn't allocate memory for Thread(%d, %d)", segNum, segOff);
1784 		return scriptResultNoScript;
1785 	} else if (!th->_valid) {
1786 		debugC(4, kDebugScripts, "Scripts: %d is not valid", lastExport);
1787 		return scriptResultNoScript;
1788 	}
1789 	print_script_name((th->codeSeg) + th->programCounter.offset, objectName(segNum, segOff));
1790 
1791 	//  Run the thread to completion
1792 	result = th->run();
1793 	args.returnVal = th->returnVal;
1794 
1795 	//  If the thread is not still running, then delete it
1796 	if (result != scriptResultAsync) delete th;
1797 
1798 	// restore "thisThread" ptr.
1799 	thisThread = saveThread;
1800 	return result;
1801 }
1802 
1803 //-----------------------------------------------------------------------
1804 //	Run a class member function to completion (or until it forks)
1805 
runMethod(uint16 scriptClassID,int16 bType,uint16 index,uint16 methodNum,scriptCallFrame & args)1806 scriptResult runMethod(
1807     uint16          scriptClassID,          // which script class
1808     int16           bType,                  // builtin type
1809     uint16          index,                  // object index
1810     uint16          methodNum,
1811     scriptCallFrame &args) {
1812 	uint16          segNum,
1813 	                segOff;
1814 	uint16          *vTable;
1815 	Thread          *th;
1816 	scriptResult    result = scriptResultNoScript;
1817 	Thread          *saveThread = thisThread;
1818 
1819 	//  For abstract classes, the object index is also the class
1820 	//  index.
1821 	if (bType == builtinAbstract)
1822 		index = scriptClassID;
1823 
1824 	lookupExport(scriptClassID, segNum, segOff);
1825 
1826 	//  Get address of class function table
1827 	vTable = (uint16 *)
1828 	         segmentAddress(segNum, segOff + methodNum * sizeof(uint32));
1829 
1830 	segNum = vTable[0];
1831 	segOff = vTable[1];
1832 
1833 	if (segNum == 0xffff) {                 // it's a CFUNC or NULL func
1834 		if (segOff == 0xffff) {             // it's a NULL function
1835 			return scriptResultNoScript;
1836 		} else {                            //  It's a C function
1837 			int16   funcNum = segOff;       // function number
1838 			int16   stack[1];             // dummy stack argument
1839 			C_Call  *cfunc;
1840 
1841 			//  Make sure the C function number is OK
1842 			assert(funcNum >= 0);
1843 			assert(funcNum < globalCFuncs.numEntries);
1844 			cfunc = globalCFuncs.table[funcNum];
1845 
1846 			//  Build a temporary dummy thread
1847 			th = new Thread(0, 0, args);
1848 			thisThread = th;
1849 			if (th == nullptr)
1850 				return scriptResultNoScript;
1851 			else if (!th->_valid)
1852 				return scriptResultNoScript;
1853 
1854 			result = (scriptResult)cfunc(stack);   // call the function
1855 			delete th;
1856 		}
1857 	} else {
1858 		//  Create a new thread
1859 		th = new Thread(segNum, segOff, args);
1860 		thisThread = th;
1861 		if (th == nullptr) {
1862 			debugC(3, kDebugScripts, "Couldn't allocate memory for Thread(%d, %d)", segNum, segOff);
1863 			return scriptResultNoScript;
1864 		} else if (!th->_valid) {
1865 			debugC(3, kDebugScripts, "Scripts: %d is not valid", lastExport);
1866 			return scriptResultNoScript;
1867 		}
1868 		print_script_name((th->codeSeg) + th->programCounter.offset, objectName(bType, index));
1869 
1870 		//  Put the object segment and ID onto the dummy stack frame
1871 		((uint16 *)th->stackPtr)[3] = bType;
1872 		((uint16 *)th->stackPtr)[4] = index;
1873 
1874 		//  Run the thread to completion
1875 		result = th->run();
1876 		args.returnVal = th->returnVal;
1877 		debugC(3, kDebugScripts, "return: %d", th->returnVal);
1878 
1879 		if (result != scriptResultAsync) delete th;
1880 	}
1881 
1882 	thisThread = saveThread;        // restore "thisThread" ptr.
1883 	return result;
1884 }
1885 
1886 //-----------------------------------------------------------------------
1887 //	Run a class member function to completion (or until it forks)
1888 
runObjectMethod(ObjectID id,uint16 methodNum,scriptCallFrame & args)1889 scriptResult runObjectMethod(
1890     ObjectID        id,
1891     uint16          methodNum,
1892     scriptCallFrame &args) {
1893 	GameObject      *obj;
1894 
1895 	obj = GameObject::objectAddress(id);
1896 
1897 	return runMethod(obj->scriptClass(),
1898 	                 builtinTypeObject,
1899 	                 id,
1900 	                 methodNum,
1901 	                 args);
1902 }
1903 
1904 //-----------------------------------------------------------------------
1905 //	Run a class member function to completion (or until it forks)
1906 
runTagMethod(uint16 index,uint16 methodNum,scriptCallFrame & args)1907 scriptResult runTagMethod(
1908     uint16          index,                      // tag number
1909     uint16          methodNum,
1910     scriptCallFrame &args) {
1911 	ActiveItemPtr   aItem;
1912 
1913 	aItem = ActiveItem::activeItemAddress(index);
1914 	if (!aItem->_data.scriptClassID)
1915 		return scriptResultNoScript;
1916 
1917 	return runMethod(aItem->_data.scriptClassID,
1918 	                 builtinTypeTAG,
1919 	                 index,
1920 	                 methodNum,
1921 	                 args);
1922 }
1923 
1924 //-----------------------------------------------------------------------
1925 //	Wake up a thread unconditionally
1926 
wakeUpThread(ThreadID id)1927 void wakeUpThread(ThreadID id) {
1928 	if (id != NoThread) {
1929 		Thread  *thread = getThreadAddress(id);
1930 
1931 		thread->flags &= ~Thread::waiting;
1932 	}
1933 }
1934 
wakeUpThread(ThreadID id,int16 returnVal)1935 void wakeUpThread(ThreadID id, int16 returnVal) {
1936 	if (id != NoThread) {
1937 		Thread  *thread = getThreadAddress(id);
1938 
1939 		if (thread->flags & Thread::expectResult) {
1940 			WriteStatusF(8, "Result %d", returnVal);
1941 			thread->returnVal = returnVal;
1942 			*(int16 *)thread->stackPtr = returnVal;
1943 		} else WriteStatusF(8, "Thread not expecting result!");
1944 
1945 		thread->flags &= ~(Thread::waiting | Thread::expectResult);
1946 	}
1947 }
1948 
1949 } // end of namespace Saga2
1950