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  * aint32 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 #define FORBIDDEN_SYMBOL_ALLOW_ALL // FIXME: Remove
28 
29 #include "common/debug.h"
30 
31 #include "saga2/saga2.h"
32 #include "saga2/fta.h"
33 #include "saga2/script.h"
34 #include "saga2/actor.h"
35 #include "saga2/speech.h"
36 #include "saga2/assign.h"
37 #include "saga2/intrface.h"
38 #include "saga2/document.h"
39 #include "saga2/motion.h"
40 #include "saga2/sensor.h"
41 #include "saga2/magic.h"
42 #include "saga2/uidialog.h"
43 #include "saga2/mission.h"
44 #include "saga2/band.h"
45 #include "saga2/tromode.h"
46 #include "saga2/automap.h"
47 #include "saga2/videobox.h"
48 #include "saga2/display.h"
49 #include "saga2/transit.h"
50 #include "saga2/contain.h"
51 #include "saga2/tile.h"
52 #include "saga2/tilemode.h"
53 
54 void drawMainDisplay(void);
55 
56 #define MONOLOG(s) {debugC(2, kDebugScripts, "cfunc: " #s );}
57 #define OBJLOG(s) {debugC(2, kDebugScripts, "cfunc: [%s]." #s , (((ObjectData *)thisThread->thisObject)->obj)->objName() );}
58 
59 namespace Saga2 {
60 
61 extern WorldMapData         *mapList;           //  master map data array
62 
63 /* ============================================================================ *
64    CFunc helper functions
65  * ============================================================================ */
66 
67 //-----------------------------------------------------------------------
68 //	Convert string ID to string text
69 
STRING(int strNum)70 inline char *STRING(int strNum) {
71 	return (char *)thisThread->strAddress(strNum);
72 }
73 
74 //-----------------------------------------------------------------------
75 //	SPrintf-like formatting of strings, except that it works on
76 //	SAGA arglists.
77 
stringf(char * buffer,long maxlen,int formatStr,int16 * args)78 int stringf(char *buffer, long maxlen, int formatStr, int16 *args) {
79 	char        *fmt = STRING(formatStr);
80 	char        *bufEnd = buffer + maxlen - 1;
81 	char        dbuf[16],             // temp buffer for digits
82 	            *dptr;
83 
84 	//  While there is room in the buffer
85 	while (buffer < bufEnd && *fmt != '\0') {
86 		//  Format string character
87 		if (*fmt == '%') {
88 			if (fmt[1] == 'd') {      //  If it's %d
89 				//  Convert numeric argument to string
90 				snprintf(dbuf, 15, "%d", *args++);
91 
92 				//  Copy string to buffer (if it fits)
93 				for (dptr = dbuf; *dptr && buffer < bufEnd;) {
94 					*buffer++ = *dptr++;
95 				}
96 			} else if (fmt[1] == 'x') { //  If it's %x
97 				//  Convert numeric argument to string
98 				snprintf(dbuf, 15, "%x", *args++);
99 
100 				//  Copy string to buffer (if it fits)
101 				for (dptr = dbuf; *dptr && buffer < bufEnd;) {
102 					*buffer++ = *dptr++;
103 				}
104 			} else if (fmt[1] == 's') { //  If it's %s
105 				//  Obtain SAGA string, copy to buffer (if it fits)
106 				for (dptr = STRING(*args++); *dptr && buffer < bufEnd;) {
107 					*buffer++ = *dptr++;
108 				}
109 			} else if (fmt[1] == 'n') { //  If it's %n (object name)
110 				GameObject  *obj = GameObject::objectAddress(*args++);
111 
112 				//  Obtain SAGA string, copy to buffer (if it fits)
113 				for (const char *dptr1 = obj->objName(); *dptr1 && buffer < bufEnd;) {
114 					*buffer++ = *dptr1++;
115 				}
116 			} else {
117 				//  Write the character after the '%' to the buffer
118 				*buffer++ = fmt[1];
119 			}
120 			fmt += 2;
121 		} else *buffer++ = *fmt++;
122 	}
123 
124 	*buffer++ = '\0';
125 
126 	//  Return the number of characters written to the buffer
127 	return buffer - (bufEnd - (maxlen - 1));
128 }
129 
130 /* ============================================================================ *
131    Script C-Function call tables
132  * ============================================================================ */
133 
134 //-----------------------------------------------------------------------
135 //	Returns the id of this object
136 //		GameObject id "c" thisID( void );
137 
scriptGameObjectThisID(int16 * args)138 int16 scriptGameObjectThisID(int16 *args) {
139 	OBJLOG(ThisID);
140 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
141 
142 	return obj->thisID();
143 }
144 
145 //-----------------------------------------------------------------------
146 //	Recharges this object
147 //		void "c" recharge( void );
148 
scriptGameObjectRecharge(int16 * args)149 int16 scriptGameObjectRecharge(int16 *args) {
150 	OBJLOG(Recharge);
151 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
152 
153 	obj->recharge();
154 	return 0;
155 }
156 
157 //-----------------------------------------------------------------------
158 //	this returns the type of charge this item should have
159 //  none, red, violet, etc...
160 //		int "c" getChargeType( void );
161 
scriptGameObjectGetChargeType(int16 * args)162 int16 scriptGameObjectGetChargeType(int16 *args) {
163 	OBJLOG(GetChargeType);
164 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
165 
166 	return obj->getChargeType();
167 }
168 
169 //-----------------------------------------------------------------------
170 //	Move an object to a new location. (optional 4th parameter
171 //	is for actor facing, only used by actors)
172 //		void "c" move( int u, int v, int z, ... );
173 
scriptActorMove(int16 * args)174 int16 scriptActorMove(int16 *args) {
175 	OBJLOG(Move);
176 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
177 
178 	//  Move the object to a new location
179 	obj->move(TilePoint(args[0], args[1], args[2]));
180 
181 	//  If optional 4th parameter is present, then set actor facing
182 	if (thisThread->argCount > 3 && isActor(obj)) {
183 		Actor       *a = (Actor *)obj;
184 
185 		a->_currentFacing = args[3];
186 	}
187 
188 	return 0;
189 }
190 
191 //-----------------------------------------------------------------------
192 //	Move object relative to another object (optional 4th
193 //	parameter is for actor facing, only used by actors)
194 //		void "c" moveRel( GameObject id baseObj, int angle, int distance, ... );
195 
196 extern const StaticTilePoint dirTable[8];
197 
scriptActorMoveRel(int16 * args)198 int16 scriptActorMoveRel(int16 *args) {
199 	OBJLOG(MoveRel);
200 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj,
201 	                 *baseObj = GameObject::objectAddress(args[0]);
202 	Location        l;
203 	TilePoint       tp;
204 
205 	l.context   = baseObj->IDParent();
206 	tp          = baseObj->getLocation();
207 
208 	//  Add offset for angle and distance
209 	tp += (dirTable[args[1] & 7] * args[2]) / 3;
210 
211 	//  Move the object to a new location
212 	*(TilePoint *)&l = tp;
213 	obj->move(l);
214 
215 	//  If optional 4th parameter is present, then set actor facing
216 	if (thisThread->argCount > 3 && isActor(obj)) {
217 		Actor       *a = (Actor *)obj;
218 
219 		a->_currentFacing = args[3];
220 	}
221 
222 	return 0;
223 }
224 
225 //-----------------------------------------------------------------------
226 //	Transfer object to a new context. (optional 4th parameter
227 //	is for actor facing, only used by actors)
228 //		void "c" transfer( GameObject id context, int u, int v, int z, ... );
229 
scriptActorTransfer(int16 * args)230 int16 scriptActorTransfer(int16 *args) {
231 	OBJLOG(Transfer);
232 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
233 
234 	//  Move the object to a new location
235 	if ((isObject(args[0])
236 	        && (GameObject::protoAddress(args[0])->containmentSet()
237 	            &   ProtoObj::isContainer))
238 	        ||  isActor(args[0])) {
239 		ObjectID        targetID = args[0];
240 		GameObject      *target = GameObject::objectAddress(targetID);
241 		TilePoint       targetSlot;
242 
243 		//  If it's an actor we're moving to, then "place" the object rather than
244 		//  using the explicit coordinates specified
245 		if (target->getAvailableSlot(obj, &targetSlot)) {
246 			uint16      cSet = target->proto()->containmentSet();
247 
248 			obj->move(Location(targetSlot, targetID));
249 			if ((cSet & (ProtoObj::isIntangible | ProtoObj::isContainer))
250 			        == (ProtoObj::isIntangible | ProtoObj::isContainer))
251 				g_vm->_cnm->setUpdate(targetID);
252 		}
253 	} else {
254 		obj->move(Location(args[1], args[2], args[3], args[0]));
255 	}
256 
257 	//  If optional 5th parameter is present, then set actor facing
258 	if (thisThread->argCount > 4 && isActor(obj)) {
259 		Actor       *a = (Actor *)obj;
260 
261 		a->_currentFacing = args[4];
262 	}
263 
264 	return 0;
265 }
266 
267 //-----------------------------------------------------------------------
268 //	Pick a random location for an object within an area
269 //		void "c" moveRandom( int u, int v, int z, int distance );
270 
scriptMoveRandom(int16 * args)271 int16 scriptMoveRandom(int16 *args) {
272 	OBJLOG(MoveRandom);
273 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
274 	TilePoint       tpMin, tpMax;
275 	int16           distance = args[3];
276 
277 	tpMin.u = args[0] - distance;
278 	tpMin.v = args[1] - distance;
279 	tpMin.z = 0;
280 
281 	tpMax.u = args[0] + distance;
282 	tpMax.v = args[1] + distance;
283 	tpMax.z = 100;
284 
285 	obj->moveRandom(tpMin, tpMax);
286 	return 0;
287 }
288 
289 //-----------------------------------------------------------------------
290 //	Return Name ID of actor
291 //		int "c" name( void );
292 
scriptActorGetName(int16 *)293 int16 scriptActorGetName(int16 *) {
294 	OBJLOG(GetName);
295 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
296 	int16           oldName = obj->getNameIndex();
297 
298 	return oldName;
299 }
300 
301 //-----------------------------------------------------------------------
302 //	Set Name ID of actor
303 //		int "c" setName( int nameID );
304 
scriptActorSetName(int16 * args)305 int16 scriptActorSetName(int16 *args) {
306 	OBJLOG(SetName);
307 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
308 	int16           oldName = obj->getNameIndex();
309 
310 	obj->setNameIndex(args[0]);
311 
312 	return oldName;
313 }
314 
315 //-----------------------------------------------------------------------
316 //	return current object prototype
317 //		int "c" proto( void );
318 
scriptActorGetProto(int16 *)319 int16 scriptActorGetProto(int16 *) {
320 	OBJLOG(GetProto);
321 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
322 	return obj->getProtoNum();
323 }
324 
325 //-----------------------------------------------------------------------
326 // Set object prototype and return old proto
327 //		int "c" setProto( int protoID );
328 
scriptActorSetProto(int16 * args)329 int16 scriptActorSetProto(int16 *args) {
330 	OBJLOG(SetProto);
331 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
332 	int16           oldProto = obj->getProtoNum();
333 
334 	if (isActor(obj) && (((Actor *)obj)->_flags & Actor::temporary)) {
335 		decTempActorCount(oldProto);
336 		incTempActorCount(args[0]);
337 	}
338 
339 	obj->setProtoNum(args[0]);
340 
341 	return oldProto;
342 }
343 
344 //-----------------------------------------------------------------------
345 //	return current object prototype class
346 //		int "c" protoClass( void );
347 
scriptActorGetProtoClass(int16 *)348 int16 scriptActorGetProtoClass(int16 *) {
349 	OBJLOG(GetProtoClass);
350 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
351 	ProtoObj        *objProto = obj->proto();
352 
353 	return objProto->classType;
354 }
355 
356 //-----------------------------------------------------------------------
357 //	return current object prototype
358 //		int "c" getScript( void );
359 
scriptActorGetScript(int16 *)360 int16 scriptActorGetScript(int16 *) {
361 	OBJLOG(GetScript);
362 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
363 	return obj->getScript();
364 }
365 
366 //-----------------------------------------------------------------------
367 // Set object script index and return old script
368 //		int "c" setScript( int protoID );
369 
scriptActorSetScript(int16 * args)370 int16 scriptActorSetScript(int16 *args) {
371 	OBJLOG(SetScript);
372 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
373 	int16           oldScript = obj->getScript();
374 
375 	obj->setScript(args[0]);
376 
377 	return oldScript;
378 }
379 
380 //-----------------------------------------------------------------------
381 //	Use this object
382 //		int "c" use( GameObject id enactor );
383 
scriptGameObjectUse(int16 * args)384 int16 scriptGameObjectUse(int16 *args) {
385 	OBJLOG(Use);
386 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
387 
388 	return obj->use(args[0]);
389 }
390 
391 //-----------------------------------------------------------------------
392 //	Use this object on another object
393 //		int "c" useOn( GameObject id enactor, GameObject id target );
394 
scriptGameObjectUseOn(int16 * args)395 int16 scriptGameObjectUseOn(int16 *args) {
396 	OBJLOG(UseOn);
397 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
398 
399 	return obj->useOn(args[0], args[1]);
400 }
401 
402 //-----------------------------------------------------------------------
403 //	Use this object on a TAI
404 //		int "c" useOnTAI( GameObject id enactor, TileActivityInstance id target );
405 
scriptGameObjectUseOnTAI(int16 * args)406 int16 scriptGameObjectUseOnTAI(int16 *args) {
407 	OBJLOG(UseOnTAI);
408 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
409 
410 	return obj->useOn(args[0], ActiveItem::activeItemAddress(args[1]));
411 }
412 
413 //-----------------------------------------------------------------------
414 //	Drop this object
415 //		int "c" drop(
416 //			GameObject id  enactor,
417 //			GameObject id  context,
418 //			int                u,
419 //			int                v,
420 //			int                z );
421 
scriptGameObjectDrop(int16 * args)422 int16 scriptGameObjectDrop(int16 *args) {
423 	OBJLOG(Drop);
424 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
425 
426 	return  obj->drop(
427 	            args[0],
428 	            Location(args[2], args[3], args[4], args[1 ]));
429 }
430 
431 //-----------------------------------------------------------------------
432 //	Drop this object on another object
433 //		int "c" dropOn( GameObject id enactor, GameObject id target );
434 
scriptGameObjectDropOn(int16 * args)435 int16 scriptGameObjectDropOn(int16 *args) {
436 	OBJLOG(DropOn);
437 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
438 
439 	return obj->dropOn(args[0], args[1]);
440 }
441 
442 //-----------------------------------------------------------------------
443 //	Drop this object on another object.  For mergeable objects only
444 //		int "c" dropMergeableOn(
445 //			GameObject id  enactor,
446 //			GameObject id  target,
447 //			int                count );
448 
scriptGameObjectDropMergeableOn(int16 * args)449 int16 scriptGameObjectDropMergeableOn(int16 *args) {
450 	OBJLOG(DropMergeableOn);
451 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
452 
453 	return obj->dropOn(args[0], args[1], args[2]);
454 }
455 
456 //-----------------------------------------------------------------------
457 //	Drop this object on a TAI
458 //		int "c" dropOnTAI(
459 //			GameObject id          enactor,
460 //			TileActivityInstance id target,
461 //			GameObject id          context,
462 //			int                        u,
463 //			int                        v,
464 //			int                        z );
465 
scriptGameObjectDropOnTAI(int16 * args)466 int16 scriptGameObjectDropOnTAI(int16 *args) {
467 	OBJLOG(DropOnTAI);
468 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
469 
470 	return  obj->dropOn(
471 	            args[0],
472 	            ActiveItem::activeItemAddress(args[1]),
473 	            Location(args[3], args[4], args[5], args[2 ]));
474 }
475 
476 //-----------------------------------------------------------------------
477 //	Causes actor (or object) to speak...
478 //		void "c" say( int flags, int sampleID, string, ... );
479 
scriptActorSay(int16 * args)480 int16 scriptActorSay(int16 *args) {
481 	OBJLOG(Say);
482 	//  Actor speech enums -- move these to include file
483 	// MOVED TO SPEECH.H - EO
484 //	enum {
485 //		speakContinued  = (1<<0),           // Append next speech
486 //		speakNoAnimate  = (1<<1),           // Don't animate speaking
487 //		speakWait       = (1<<2),           // wait until speech finished
488 //		speakLock       = (1<<3),           // LockUI while speaking
489 //	};
490 
491 	//  'obj' is the actor doing the speaking.
492 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
493 	uint16          flags = args[0];
494 	Speech          *sp;
495 
496 	if (isActor(obj)) {
497 		Actor       *a = (Actor *)obj;
498 
499 		if (a->isDead()) return 0;
500 	}
501 
502 	//  Determine if a speech record is being built for this actor.
503 	//  If so, then retrieve it. If not, then build a new one and
504 	//  retrieve it.
505 	sp = speechList.findSpeech(obj->thisID());
506 	if (sp == NULL) {
507 		uint16  spFlags = 0;
508 
509 		if (flags & speakNoAnimate) spFlags |= Speech::spNoAnimate;
510 		if (flags & speakLock)      spFlags |= Speech::spLock;
511 
512 		sp = speechList.newTask(obj->thisID(), spFlags);
513 
514 		if (sp == NULL) return 0;
515 	}
516 
517 	//  Loop through each of the arguments.
518 	//  REM: Might want to do some range checking on the arguments.
519 	for (int i = 1; i < thisThread->argCount; i += 2) {
520 		uint16      sampleNum = args[i];
521 		char        *speechText = STRING(args[i + 1]);
522 
523 		debugC(2, kDebugScripts, "Speech Text: - %s", speechText);
524 		sp->append(speechText, sampleNum);
525 	}
526 
527 	//  If we're ready to activate the speech
528 	if (!(flags & speakContinued)) {
529 		//  If we're going to wait for it synchronously
530 		if (flags & speakWait) {
531 			thisThread->waitForEvent(Thread::waitOther, 0);
532 			sp->setWakeUp(getThreadID(thisThread));
533 		}
534 
535 		//  Move speech to active queue
536 		sp->activate();
537 	}
538 
539 	return 0;
540 }
541 
542 //-----------------------------------------------------------------------
543 //	Appends a string of text (no samples) to speech buffer, but does not
544 //	begin the speech
545 //		void "c" sayText( string txt, ... );
546 
scriptActorSayText(int16 * args)547 int16 scriptActorSayText(int16 *args) {
548 	OBJLOG(SayText);
549 	//  'obj' is the actor doing the speaking.
550 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
551 	Speech          *sp;
552 	char            buffer[256];
553 
554 	//  Determine if a speech record is being built for this actor.
555 	//  If so, then retrieve it. If not, then fail.
556 	sp = speechList.findSpeech(obj->thisID());
557 	if (sp == NULL) return 0;
558 
559 	stringf(buffer, sizeof buffer, args[0], &args[1]);
560 	sp->append(buffer, 0);
561 	return 1;
562 }
563 
564 //-----------------------------------------------------------------------
565 //	Returns overall type of object
566 //		int "c" objectType( void );
567 
scriptActorObjectType(int16 *)568 int16 scriptActorObjectType(int16 *) {
569 	OBJLOG(ObjectType);
570 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
571 
572 	return (int16)(obj->containmentSet());
573 }
574 
575 //-----------------------------------------------------------------------
576 //	Returns overall type of object
577 //		GameObject id "c" copyObject( void );
578 
scriptActorCopyObject(int16 *)579 int16 scriptActorCopyObject(int16 *) {
580 	OBJLOG(CopyObject);
581 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
582 	Location        l(0, 0, 0, Nothing);
583 
584 	return (int16)(obj->copy(l));
585 }
586 
587 //-----------------------------------------------------------------------
588 //	Determine if this object is activated
589 //		int "c" isActivated( void );
590 
scriptGameObjectIsActivated(int16 * args)591 int16 scriptGameObjectIsActivated(int16 *args) {
592 	OBJLOG(IsActivated);
593 	return (((ObjectData *)thisThread->thisObject)->obj)->isActivated();
594 }
595 
596 //-----------------------------------------------------------------------
597 //	Object flags access functions
598 
scriptActorGetOpen(int16 *)599 int16 scriptActorGetOpen(int16 *) {
600 	OBJLOG(GetOpen);
601 	return (((ObjectData *)thisThread->thisObject)->obj)->isOpen();
602 }
603 
scriptActorGetLocked(int16 *)604 int16 scriptActorGetLocked(int16 *) {
605 	OBJLOG(GetLocked);
606 	return (((ObjectData *)thisThread->thisObject)->obj)->isLocked();
607 }
608 
scriptActorGetImportant(int16 *)609 int16 scriptActorGetImportant(int16 *) {
610 	OBJLOG(GetImportant);
611 	return (((ObjectData *)thisThread->thisObject)->obj)->isImportant();
612 }
613 
scriptActorGetScavengable(int16 *)614 int16 scriptActorGetScavengable(int16 *) {
615 	OBJLOG(GetScavengable);
616 	return (((ObjectData *)thisThread->thisObject)->obj)->isScavengable();
617 }
618 
619 /*
620 int16 scriptActorSetOpen( int16 *args )
621 {
622     (((ObjectData *)thisThread->thisObject)->obj)->setFlags(
623         args[0] ? 0xffff : 0,
624         objectOpen );
625     return 0;
626 }
627 
628 int16 scriptActorSetLocked( int16 *args )
629 {
630     (((ObjectData *)thisThread->thisObject)->obj)->setFlags(
631         args[0] ? 0xffff : 0,
632         objectLocked );
633     return 0;
634 }
635 */
636 
scriptActorSetImportant(int16 * args)637 int16 scriptActorSetImportant(int16 *args) {
638 	OBJLOG(SetImportant);
639 	(((ObjectData *)thisThread->thisObject)->obj)->setFlags(
640 	    args[0] ? (int16) 0xffff : (int16) 0,
641 	    objectImportant);
642 	return 0;
643 }
644 
scriptActorSetScavengable(int16 * args)645 int16 scriptActorSetScavengable(int16 *args) {
646 	OBJLOG(SetScavengable);
647 	(((ObjectData *)thisThread->thisObject)->obj)->setFlags(
648 	    args[0] ? (int16) 0xffff : (int16) 0,
649 	    objectScavengable);
650 	return 0;
651 }
652 
653 //-----------------------------------------------------------------------
654 //	Create a new timer for this object
655 //		int "c" addTimer( int timerID, int frameInterval );
656 
scriptGameObjectAddTimer(int16 * args)657 int16 scriptGameObjectAddTimer(int16 *args) {
658 	OBJLOG(AddTimer);
659 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
660 
661 	return obj->addTimer(args[0], args[1]);
662 }
663 
664 //-----------------------------------------------------------------------
665 //	Create a new timer for this object using the standard frame
666 //	interval (5 frames)
667 //		int "c" addStdTimer( int timerID, int frameInterval );
668 
scriptGameObjectAddStdTimer(int16 * args)669 int16 scriptGameObjectAddStdTimer(int16 *args) {
670 	OBJLOG(AddStdTimer);
671 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
672 
673 	return obj->addTimer(args[0]);
674 }
675 
676 //-----------------------------------------------------------------------
677 //	Delete a specific timer
678 //		void "c" removeTimer( int timerID );
679 
scriptGameObjectRemoveTimer(int16 * args)680 int16 scriptGameObjectRemoveTimer(int16 *args) {
681 	OBJLOG(RemoveTimer);
682 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
683 
684 	obj->removeTimer(args[0]);
685 
686 	return 0;
687 }
688 
689 //-----------------------------------------------------------------------
690 //	Delete all timers for this object
691 //		void "c" removeAllTimers( void );
692 
scriptGameObjectRemoveAllTimers(int16 * args)693 int16 scriptGameObjectRemoveAllTimers(int16 *args) {
694 	OBJLOG(RemoveAllTimers);
695 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
696 
697 	obj->removeAllTimers();
698 
699 	return 0;
700 }
701 
702 //-----------------------------------------------------------------------
703 //	Create a sensor for this object to detect the proximity of a
704 //	protaganist
705 //		int "c" addProtaganistSensor( int sensorID, int range );
706 
scriptGameObjectAddProtaganistSensor(int16 * args)707 int16 scriptGameObjectAddProtaganistSensor(int16 *args) {
708 	OBJLOG(AddProtaganistSensor);
709 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
710 
711 	return obj->addProtaganistSensor(args[0], args[1]);
712 }
713 
714 //-----------------------------------------------------------------------
715 //	Create a sensor for this object to detect the proximity of a
716 //	specified actor
717 //		int "c" addSpecificActorSensor(
718 //			int            sensorID,
719 //			int            range,
720 //			Actor id   actor );
721 
scriptGameObjectAddSpecificActorSensor(int16 * args)722 int16 scriptGameObjectAddSpecificActorSensor(int16 *args) {
723 	OBJLOG(AddSpecificActorSensor);
724 	assert(isActor(args[2]));
725 
726 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
727 
728 	return  obj->addSpecificActorSensor(
729 	            args[0],
730 	            args[1],
731 	            (Actor *)GameObject::objectAddress(args[2]));
732 }
733 
734 //-----------------------------------------------------------------------
735 //	Create a sensor for this object to detect the proximity of a
736 //	specified object
737 //		int "c" addSpecificObjectSensor(
738 //			int                sensorID,
739 //			int                range,
740 //			GameObject id  obj );
741 
scriptGameObjectAddSpecificObjectSensor(int16 * args)742 int16 scriptGameObjectAddSpecificObjectSensor(int16 *args) {
743 	OBJLOG(AddSpecificObjectSensor);
744 	assert(isObject(args[2]) || isActor(args[2]));
745 
746 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
747 
748 	return obj->addSpecificObjectSensor(args[0], args[1], args[2]);
749 }
750 
751 //-----------------------------------------------------------------------
752 //	Create a sensor for this object to detect the proximity of an
753 //	actor with a specified property
754 //		int "c" addActorPropertySensor(
755 //			int sensorID,
756 //			int range,
757 //			int actorProperty );
758 
scriptGameObjectAddActorPropertySensor(int16 * args)759 int16 scriptGameObjectAddActorPropertySensor(int16 *args) {
760 	OBJLOG(AddActorPropertySensor);
761 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
762 
763 	return obj->addActorPropertySensor(args[0], args[1], args[2]);
764 }
765 
766 //-----------------------------------------------------------------------
767 //	Create a sensor for this object to detect the proximity of an
768 //	object with a specified property
769 //		int "c" addObjectPropertySensor(
770 //			int sensorID,
771 //			int range,
772 //			int objectProperty );
773 
scriptGameObjectAddObjectPropertySensor(int16 * args)774 int16 scriptGameObjectAddObjectPropertySensor(int16 *args) {
775 	OBJLOG(AddObjectPropertySensor);
776 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
777 
778 	return obj->addObjectPropertySensor(args[0], args[1], args[2]);
779 }
780 
781 //-----------------------------------------------------------------------
782 //	Create a sensor for this object to detect a specified event
783 //	within this actor's proximity
784 //		int "c" addEventSensor( int sensorID, int range, int eventType );
785 
scriptGameObjectAddEventSensor(int16 * args)786 int16 scriptGameObjectAddEventSensor(int16 *args) {
787 	OBJLOG(AddEventSensor);
788 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
789 
790 	return  obj->addEventSensor(
791 	            args[0],
792 	            args[1],
793 	            args[2]);
794 }
795 
796 //-----------------------------------------------------------------------
797 //	Delete a specified sensor
798 //		void "c" removeSensor( int sensorID );
799 
scriptGameObjectRemoveSensor(int16 * args)800 int16 scriptGameObjectRemoveSensor(int16 *args) {
801 	OBJLOG(RemoveSensor);
802 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
803 
804 	obj->removeSensor(args[0]);
805 
806 	return 0;
807 }
808 
809 //-----------------------------------------------------------------------
810 //	Delete every sensor for this object
811 //		void "c" removeAllSensors( void );
812 
scriptGameObjectRemoveAllSensors(int16 * args)813 int16 scriptGameObjectRemoveAllSensors(int16 *args) {
814 	OBJLOG(RemoveAllSensors);
815 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
816 
817 	obj->removeAllSensors();
818 
819 	return 0;
820 }
821 
822 //-----------------------------------------------------------------------
823 //	Determine if this object can sense the proximity of a protaganist
824 //		int "c" canSenseProtaganist( int range );
825 
scriptGameObjectCanSenseProtaganist(int16 * args)826 int16 scriptGameObjectCanSenseProtaganist(int16 *args) {
827 	OBJLOG(CanSenseProtaganist);
828 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
829 	SenseInfo       info;
830 
831 	if (obj->canSenseProtaganist(info, args[0])) {
832 		scriptCallFrame     &scf = thisThread->threadArgs;
833 
834 		scf.enactor = obj->thisID();
835 		scf.directObject = info.sensedObject->thisID();
836 
837 		return true;
838 	}
839 
840 	return false;
841 }
842 
843 //-----------------------------------------------------------------------
844 //	Determine if this object can sense the proximity of a specific
845 //	actor
846 //		int "c" canSenseSpecificActor( int range, Actor id actor );
847 
scriptGameObjectCanSenseSpecificActor(int16 * args)848 int16 scriptGameObjectCanSenseSpecificActor(int16 *args) {
849 	OBJLOG(CanSenseSpecificActor);
850 	assert(isActor(args[1]));
851 
852 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
853 	SenseInfo       info;
854 
855 	if (obj->canSenseSpecificActor(
856 	            info,
857 	            args[0],
858 	            (Actor *)GameObject::objectAddress(args[1]))) {
859 		scriptCallFrame     &scf = thisThread->threadArgs;
860 
861 		scf.enactor = obj->thisID();
862 		scf.directObject = info.sensedObject->thisID();
863 
864 		return true;
865 	}
866 
867 	return false;
868 }
869 
870 //-----------------------------------------------------------------------
871 //	Determine if this object can sense the proximity of a specific
872 //	object
873 //		int "c" canSenseSpecificObject( int range, GameObject id obj );
874 
scriptGameObjectCanSenseSpecificObject(int16 * args)875 int16 scriptGameObjectCanSenseSpecificObject(int16 *args) {
876 	OBJLOG(CanSenseSpecificObject);
877 	assert(isObject(args[1]) || isActor(args[1]));
878 
879 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
880 	SenseInfo       info;
881 
882 	if (obj->canSenseSpecificObject(info, args[0], args[1])) {
883 		scriptCallFrame     &scf = thisThread->threadArgs;
884 
885 		scf.enactor = obj->thisID();
886 		scf.directObject = info.sensedObject->thisID();
887 
888 		return true;
889 	}
890 
891 	return false;
892 }
893 
894 //-----------------------------------------------------------------------
895 //	Determine if this object can sense the proximity of an actor
896 //	with a specified property
897 //		int "c" canSenseActorProperty( int range, int actorProperty );
898 
scriptGameObjectCanSenseActorProperty(int16 * args)899 int16 scriptGameObjectCanSenseActorProperty(int16 *args) {
900 	OBJLOG(CanSenseActorProperty);
901 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
902 	SenseInfo       info;
903 
904 	if (obj->canSenseActorProperty(info, args[0], args[1])) {
905 		scriptCallFrame     &scf = thisThread->threadArgs;
906 
907 		scf.enactor = obj->thisID();
908 		scf.directObject = info.sensedObject->thisID();
909 
910 		return true;
911 	}
912 
913 	return false;
914 }
915 
916 //-----------------------------------------------------------------------
917 //	Determine if this object can sense the proximity of an object
918 //	with a specified property
919 //		int "c" canSenseObjectProperty( int range, int objectProperty );
920 
scriptGameObjectCanSenseObjectProperty(int16 * args)921 int16 scriptGameObjectCanSenseObjectProperty(int16 *args) {
922 	OBJLOG(CanSenseObjectProperty);
923 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
924 	SenseInfo       info;
925 
926 	if (obj->canSenseObjectProperty(info, args[0], args[1])) {
927 		scriptCallFrame     &scf = thisThread->threadArgs;
928 
929 		scf.enactor = obj->thisID();
930 		scf.directObject = info.sensedObject->thisID();
931 
932 		return true;
933 	}
934 
935 	return false;
936 }
937 
938 //-----------------------------------------------------------------------
939 //	returns object script, or proto's script if has none
940 //		int "c" getActualScript( void );
941 
scriptGameObjectGetActualScript(int16 *)942 int16 scriptGameObjectGetActualScript(int16 *) {
943 	OBJLOG(GetActualScript);
944 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
945 	int16           script;
946 
947 	script = obj->getScript();
948 	if (script == 0)
949 		script = obj->proto()->script;
950 	return script;
951 }
952 
953 //-----------------------------------------------------------------------
954 //	returns the script of the prototype
955 //		int "c" getProtoScript( void );
956 
scriptGameObjectGetProtoScript(int16 *)957 int16 scriptGameObjectGetProtoScript(int16 *) {
958 	OBJLOG(GetProtoScript);
959 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
960 
961 	return obj->proto()->script;
962 }
963 
964 //-----------------------------------------------------------------------
965 //	Get and set mass count -- mergeable objects only
966 //		int "c" getMass( void );
967 
scriptGameObjectGetMass(int16 *)968 int16 scriptGameObjectGetMass(int16 *) {
969 	OBJLOG(GetMass);
970 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
971 
972 	return (obj->proto()->flags & ResourceObjectPrototype::objPropMergeable)
973 	       ? obj->getExtra() : 1;
974 }
975 
976 //-----------------------------------------------------------------------
977 //	Get and set mass count -- mergeable objects only
978 //		int "c" setMass( int newMass );
979 
scriptGameObjectSetMass(int16 * args)980 int16 scriptGameObjectSetMass(int16 *args) {
981 	OBJLOG(SetMass);
982 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
983 
984 	if (obj->proto()->flags & ResourceObjectPrototype::objPropMergeable) {
985 		obj->setExtra(args[0]);
986 		if (obj->proto()->flags & ResourceObjectPrototype::objPropMergeable) {
987 			g_vm->_cnm->setUpdate(obj->IDParent());
988 		}
989 		return true;
990 	} else return false;
991 }
992 
993 //-----------------------------------------------------------------------
994 //	Get the extra scratch var
995 //		int "c" getExtra( void );
996 
scriptGameObjectGetExtra(int16 *)997 int16 scriptGameObjectGetExtra(int16 *) {
998 	OBJLOG(GetExtra);
999 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
1000 
1001 	return obj->getExtra();
1002 }
1003 
1004 //-----------------------------------------------------------------------
1005 //	Set the extra scratch var
1006 //		void "c" setExtra( int newVal );
1007 
scriptGameObjectSetExtra(int16 * args)1008 int16 scriptGameObjectSetExtra(int16 *args) {
1009 	OBJLOG(SetExtra);
1010 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
1011 
1012 	obj->setExtra(args[0]);
1013 
1014 	return 0;
1015 }
1016 
1017 //-----------------------------------------------------------------------
1018 //	Make a copy of this object and all sub-objects
1019 //		GameObject id "c" deepCopy( void );
1020 
deepCopy(GameObject * src,ObjectID parentID,TilePoint tp)1021 int16 deepCopy(GameObject *src, ObjectID parentID, TilePoint tp) {
1022 	OBJLOG(DeepCopy);
1023 	Location    l;
1024 	int16       newID, childID;
1025 	GameObject  *childObj = nullptr;
1026 
1027 	l.u = tp.u;
1028 	l.v = tp.v;
1029 	l.z = tp.z;
1030 	l.context = parentID;
1031 
1032 	//  Make a copy of this object, and place it in the parent container we spec'd
1033 	newID = src->copy(l);
1034 	if (newID == Nothing) return 0; //  REM: How to send error message to script?
1035 
1036 	//  Now, recursively copy all the children of this object.
1037 	ContainerIterator   iter(src);
1038 	while ((childID = iter.next(&childObj)))
1039 		deepCopy(childObj, newID, childObj->getLocation());
1040 
1041 	//  Return the ID of the object just copied.
1042 	return newID;
1043 }
1044 
scriptGameObjectDeepCopy(int16 * args)1045 int16 scriptGameObjectDeepCopy(int16 *args) {
1046 	OBJLOG(DeepCopy);
1047 	ObjectID        newParentID = args[0];
1048 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj,
1049 	                 *newParent = GameObject::objectAddress(newParentID),
1050 	                  *newObj;
1051 	ObjectID        id;
1052 
1053 	id = deepCopy(obj, Nothing, TilePoint(0, 0, 0));
1054 
1055 	newObj = GameObject::objectAddress(id);
1056 	if (newParentID != Nothing) {
1057 		TilePoint       slot;
1058 
1059 		if (newParent->getAvailableSlot(newObj, &slot))
1060 			newObj->move(Location(slot, newParentID));
1061 	}
1062 
1063 	return id;
1064 }
1065 
1066 //-----------------------------------------------------------------------
1067 //	Add an enchantment to the object or actor
1068 //		GameObject id "c" addEnchantment(   int majorType,
1069 //											int minorType,
1070 //											int amount,
1071 //											int duration );
1072 
scriptGameObjectAddEnchantment(int16 * args)1073 int16 scriptGameObjectAddEnchantment(int16 *args) {
1074 	OBJLOG(Enchant);
1075 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
1076 
1077 	return EnchantObject(obj->thisID(),
1078 	                     makeEnchantmentID(args[0], args[1], args[2]),
1079 	                     args[3]);
1080 }
1081 
1082 //-----------------------------------------------------------------------
1083 //	Add an enchantment to the object or actor
1084 //		GameObject id "c" dispelEnchantment( int majorType, int minorType );
1085 
scriptGameObjectRemoveEnchantment(int16 * args)1086 int16 scriptGameObjectRemoveEnchantment(int16 *args) {
1087 	OBJLOG(Disenchant);
1088 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
1089 
1090 	return DispelObjectEnchantment(obj->thisID(),
1091 	                               makeEnchantmentID(args[0], args[1], 0));
1092 }
1093 
1094 //-----------------------------------------------------------------------
1095 //	Locates an enchantment object within the actor
1096 //		GameObject id "c" findEnchantment( int majorType, int minorType );
1097 
scriptGameObjectFindEnchantment(int16 * args)1098 int16 scriptGameObjectFindEnchantment(int16 *args) {
1099 	OBJLOG(FindEnchantment);
1100 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
1101 
1102 	return FindObjectEnchantment(obj->thisID(),
1103 	                             makeEnchantmentID(args[0], args[1], 0));
1104 }
1105 
1106 //-----------------------------------------------------------------------
1107 //  Determines if this object is currently in use.
1108 //    int "c" inUse( void );
1109 
scriptGameObjectInUse(int16 *)1110 int16 scriptGameObjectInUse(int16 *) {
1111 	OBJLOG(InUse);
1112 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
1113 
1114 	return obj->proto()->isObjectBeingUsed(obj);
1115 }
1116 
1117 //-----------------------------------------------------------------------
1118 //	Get the specified scratch variable value
1119 //		int "c" getScratchVar( int index );
1120 
scriptActorGetScratchVar(int16 * args)1121 int16 scriptActorGetScratchVar(int16 *args) {
1122 	OBJLOG(GetScratchVar);
1123 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1124 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1125 
1126 		return a->_scriptVar[args[0]];
1127 	}
1128 
1129 	return 0;
1130 }
1131 
1132 //-----------------------------------------------------------------------
1133 //	Set the specified scratch variable to a new value
1134 //		int "c" setScratchVar( int index, int newVal );
1135 
scriptActorSetScratchVar(int16 * args)1136 int16 scriptActorSetScratchVar(int16 *args) {
1137 	OBJLOG(SetScratchVar);
1138 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1139 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1140 		int16       oldVal = a->_scriptVar[args[0]];
1141 
1142 		a->_scriptVar[args[0]] = args[1];
1143 
1144 		return oldVal;
1145 	}
1146 
1147 	return 0;
1148 }
1149 
1150 //-----------------------------------------------------------------------
1151 //	Return this actor's disposition
1152 //		int "c" getDisposition( void );
1153 
scriptActorGetDisposition(int16 * args)1154 int16 scriptActorGetDisposition(int16 *args) {
1155 	OBJLOG(GetDisposition);
1156 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1157 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1158 
1159 		return a->getDisposition();
1160 	}
1161 
1162 	return 0;
1163 }
1164 
1165 //-----------------------------------------------------------------------
1166 //	Set this actor's disposition
1167 //		int "c" setDisposition( int newDisp );
1168 
scriptActorSetDisposition(int16 * args)1169 int16 scriptActorSetDisposition(int16 *args) {
1170 	OBJLOG(SetDisposition);
1171 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1172 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1173 
1174 		return a->setDisposition(args[0]);
1175 	}
1176 
1177 	return 0;
1178 }
1179 
1180 //-----------------------------------------------------------------------
1181 //	Get the value of a specified skill
1182 //		int "c" getSkill( int skillID );
1183 
scriptActorGetSkill(int16 * args)1184 int16 scriptActorGetSkill(int16 *args) {
1185 	OBJLOG(GetSkill);
1186 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1187 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1188 
1189 		return a->getStats()->skill(args[0]);
1190 	}
1191 
1192 	return 0;
1193 }
1194 
1195 //-----------------------------------------------------------------------
1196 //	Set a specified skill to a specified value
1197 //		int "c" setSkill( int skillID, int newVal );
1198 
scriptActorSetSkill(int16 * args)1199 int16 scriptActorSetSkill(int16 *args) {
1200 	OBJLOG(SetSkill);
1201 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1202 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1203 		uint8       &skillRef = a->getStats()->skill(args[0]);
1204 		uint8       oldVal = skillRef;
1205 
1206 		skillRef = args[1];
1207 
1208 		return oldVal;
1209 	}
1210 
1211 	return 0;
1212 }
1213 
1214 //-----------------------------------------------------------------------
1215 //	Get the value of a specified base skill
1216 //		int "c" getBaseSkill( int skillID );
1217 
scriptActorGetBaseSkill(int16 * args)1218 int16 scriptActorGetBaseSkill(int16 *args) {
1219 	OBJLOG(GetBaseSkill);
1220 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1221 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1222 
1223 		return a->getBaseStats()->skill(args[0]);
1224 	}
1225 
1226 	return 0;
1227 }
1228 
1229 //-----------------------------------------------------------------------
1230 //	Set a specified base skill to a specified value
1231 //		int "c" setBaseSkill( int skillID, int newVal );
1232 
scriptActorSetBaseSkill(int16 * args)1233 int16 scriptActorSetBaseSkill(int16 *args) {
1234 	OBJLOG(SetBaseSkill);
1235 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1236 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1237 		uint8       &skillRef = a->getBaseStats()->skill(args[0]);
1238 		uint8       oldVal = skillRef;
1239 
1240 
1241 		//  If not a player actor, do nothing
1242 		if (isPlayerActor(a)) skillRef = args[1];
1243 
1244 		return oldVal;
1245 	}
1246 
1247 	return 0;
1248 }
1249 
1250 //-----------------------------------------------------------------------
1251 //	Get the value of the actor's vitality
1252 //		int "c" getVitality( void );
1253 
scriptActorGetVitality(int16 *)1254 int16 scriptActorGetVitality(int16 *) {
1255 	OBJLOG(GetVitality);
1256 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1257 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1258 
1259 		debugC(2, kDebugScripts, " - value = %d", a->getStats()->vitality);
1260 		return a->getStats()->vitality;
1261 	}
1262 
1263 	return 0;
1264 }
1265 
1266 //-----------------------------------------------------------------------
1267 //	Set the actor's vitality to a specified value
1268 //		int "c" setVitality( int newVal );
1269 
scriptActorSetVitality(int16 * args)1270 int16 scriptActorSetVitality(int16 *args) {
1271 	OBJLOG(SetVitality);
1272 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1273 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1274 
1275 		if (a->_godmode)
1276 			return 0;
1277 
1278 		int16       &vitalityRef = a->getStats()->vitality;
1279 		int16       oldVal = vitalityRef;
1280 		PlayerActorID   pID;
1281 		debugC(2, kDebugScripts, " - value = %d", args[0]);
1282 
1283 		vitalityRef = args[0];
1284 		if (actorToPlayerID(a, pID)) updateBrotherControls(pID);
1285 
1286 		return oldVal;
1287 	}
1288 
1289 	return 0;
1290 }
1291 
1292 //-----------------------------------------------------------------------
1293 //	Get the value of the actor's base vitality
1294 //		int "c" getBaseVitality( void );
1295 
scriptActorGetBaseVitality(int16 *)1296 int16 scriptActorGetBaseVitality(int16 *) {
1297 	OBJLOG(GetBaseVitality);
1298 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1299 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1300 
1301 		return a->getBaseStats()->vitality;
1302 	}
1303 
1304 	return 0;
1305 }
1306 
1307 //-----------------------------------------------------------------------
1308 //	Set the actor's base vitality to a specified value
1309 //		int "c" setBaseVitality( int newVal );
1310 
scriptActorSetBaseVitality(int16 * args)1311 int16 scriptActorSetBaseVitality(int16 *args) {
1312 	OBJLOG(SetBaseVitality);
1313 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1314 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1315 		int16       &vitalityRef = a->getBaseStats()->vitality;
1316 		int16       oldVal = vitalityRef;
1317 		PlayerActorID   pID;
1318 
1319 		//  If not a player actor, do nothing
1320 		if (actorToPlayerID(a, pID)) {
1321 			vitalityRef = args[0];
1322 			updateBrotherControls(pID);
1323 		}
1324 
1325 		return oldVal;
1326 	}
1327 
1328 	return 0;
1329 }
1330 
1331 //-----------------------------------------------------------------------
1332 //	Get the value of the specified color of mana
1333 //		int "c" getMana( int manaID );
1334 
scriptActorGetMana(int16 * args)1335 int16 scriptActorGetMana(int16 *args) {
1336 	OBJLOG(GetMana);
1337 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1338 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1339 
1340 		return a->getStats()->mana(args[0]);
1341 	}
1342 
1343 	return 0;
1344 }
1345 
1346 //-----------------------------------------------------------------------
1347 //	Set the specified mana to the specified value
1348 //		int "c" setMana( int manaID, int newVal );
1349 
scriptActorSetMana(int16 * args)1350 int16 scriptActorSetMana(int16 *args) {
1351 	OBJLOG(SetMana);
1352 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1353 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1354 		int16       &manaRef = a->getStats()->mana(args[0]);
1355 		int16       oldVal = manaRef;
1356 		PlayerActorID   pID;
1357 
1358 		manaRef = args[1];
1359 		if (actorToPlayerID(a, pID)) updateBrotherControls(pID);
1360 
1361 		return oldVal;
1362 	}
1363 
1364 	return 0;
1365 }
1366 
1367 //-----------------------------------------------------------------------
1368 //	Get the value of the specified color of base mana
1369 //		int "c" getBaseMana( int manaID );
1370 
scriptActorGetBaseMana(int16 * args)1371 int16 scriptActorGetBaseMana(int16 *args) {
1372 	OBJLOG(GetBaseMana);
1373 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1374 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1375 
1376 		return a->getBaseStats()->mana(args[0]);
1377 	}
1378 
1379 	return 0;
1380 }
1381 
1382 //-----------------------------------------------------------------------
1383 //	Set the specified base mana to the specified value
1384 //		int "c" setBaseMana( int manaID, int newVal );
1385 
scriptActorSetBaseMana(int16 * args)1386 int16 scriptActorSetBaseMana(int16 *args) {
1387 	OBJLOG(SetBaseMana);
1388 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1389 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1390 		int16       &manaRef = a->getBaseStats()->mana(args[0]);
1391 		int16       oldVal = manaRef;
1392 		PlayerActorID   pID;
1393 
1394 		//  If not a player actor, do nothing
1395 		if (isPlayerActor(a)) manaRef = args[1];
1396 		if (actorToPlayerID(a, pID)) updateBrotherControls(pID);
1397 
1398 		return oldVal;
1399 	}
1400 
1401 	return 0;
1402 }
1403 
1404 //-----------------------------------------------------------------------
1405 //  Get actor's schedule
1406 //		int "c" getSchedule( void );
1407 
scriptActorGetSchedule(int16 * args)1408 int16 scriptActorGetSchedule(int16 *args) {
1409 	OBJLOG(GetSchedule);
1410 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1411 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1412 
1413 		return a->_schedule;
1414 	}
1415 
1416 	return 0;
1417 }
1418 
1419 //-----------------------------------------------------------------------
1420 //  Set actor's schedule -- also returns old schedule
1421 //		int "c" setSchedule( int schedule );
1422 
scriptActorSetSchedule(int16 * args)1423 int16 scriptActorSetSchedule(int16 *args) {
1424 	OBJLOG(SetSchedule);
1425 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1426 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1427 		uint16      oldSchedule = a->_schedule;
1428 
1429 		a->_schedule = (uint16)args[0];
1430 
1431 		if (a->getAssignment() != NULL)
1432 			delete a->getAssignment();
1433 
1434 		return (int16)oldSchedule;
1435 	}
1436 
1437 	return 0;
1438 }
1439 
1440 //-----------------------------------------------------------------------
1441 //	Lobotomize the actor
1442 //		void "c" lobotomize( void );
1443 
scriptActorLobotomize(int16 * args)1444 int16 scriptActorLobotomize(int16 *args) {
1445 	OBJLOG(Lobotomize);
1446 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1447 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1448 
1449 		a->lobotomize();
1450 	}
1451 
1452 	return 0;
1453 }
1454 
1455 //-----------------------------------------------------------------------
1456 //	De-lobotomize the actor
1457 //		void "c" delobotomize( void );
1458 
scriptActorDelobotomize(int16 * args)1459 int16 scriptActorDelobotomize(int16 *args) {
1460 	OBJLOG(Delobotomize);
1461 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1462 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1463 
1464 		a->delobotomize();
1465 	}
1466 
1467 	return 0;
1468 }
1469 
1470 //-----------------------------------------------------------------------
1471 //	Determine if an action is available
1472 //		int "c" isActionAvailable( int action, int anyDir );
1473 
scriptActorIsActionAvailable(int16 * args)1474 int16 scriptActorIsActionAvailable(int16 *args) {
1475 	OBJLOG(IsActionAvailable);
1476 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1477 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1478 
1479 		return a->isActionAvailable(args[0], args[1]);
1480 	}
1481 
1482 	return 0;
1483 }
1484 
1485 //-----------------------------------------------------------------------
1486 //	Set the current animation for this actor.  Returns the number
1487 //	of poses in the sequence, or 0 if there are no poses in the
1488 //	sequence.
1489 //		int "c" setAction( int action, int flags );
1490 
scriptActorSetAction(int16 * args)1491 int16 scriptActorSetAction(int16 *args) {
1492 	OBJLOG(SetAction);
1493 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1494 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1495 
1496 		return a->setAction(args[0], args[1]);
1497 	}
1498 
1499 	return 0;
1500 }
1501 
1502 //-----------------------------------------------------------------------
1503 //  Return the number of animation frames in the specified action
1504 //  for the specified direction.
1505 //		int "c" animationFrames( int action, int dir );
1506 
scriptActorAnimationFrames(int16 * args)1507 int16 scriptActorAnimationFrames(int16 *args) {
1508 	OBJLOG(AnimationFrames);
1509 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1510 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1511 
1512 		return a->animationFrames(args[0], args[1]);
1513 	}
1514 
1515 	return 0;
1516 }
1517 
1518 //-----------------------------------------------------------------------
1519 //	Update the current animation sequence to the next frame.
1520 //	Returns true if there are more animation frames in the current
1521 //	sequence.
1522 //		int "c" nextAnimationFrame( void );
1523 
scriptActorNextAnimationFrame(int16 * args)1524 int16 scriptActorNextAnimationFrame(int16 *args) {
1525 	OBJLOG(NextAnimationFrame);
1526 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1527 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1528 
1529 		return a->nextAnimationFrame();
1530 	}
1531 
1532 	return 0;
1533 }
1534 
1535 //-----------------------------------------------------------------------
1536 //	Causes actor to face in a new direction, and returns old actor facing
1537 //		int "c" face( int direction );
1538 
scriptActorFace(int16 * args)1539 int16 scriptActorFace(int16 *args) {
1540 	OBJLOG(Face);
1541 	int16           oldFacing = 0;
1542 
1543 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1544 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1545 
1546 		oldFacing = a->_currentFacing;
1547 
1548 		a->_currentFacing = args[0] & 7;
1549 	}
1550 
1551 	return oldFacing;
1552 }
1553 
1554 //-----------------------------------------------------------------------
1555 //	Causes actor to face towards another object or actor,
1556 //	returns old facing
1557 //		int "c" faceTowards( GameObject id );
1558 
scriptActorFaceTowards(int16 * args)1559 int16 scriptActorFaceTowards(int16 *args) {
1560 	OBJLOG(FaceTowards);
1561 	int16           oldFacing = 0;
1562 
1563 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1564 		assert(isObject(args[0]) || isActor(args[0]));
1565 
1566 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1567 
1568 		oldFacing = a->_currentFacing;
1569 
1570 		a->_currentFacing =
1571 		    (GameObject::objectAddress(args[0])->getLocation()
1572 		     -   a->getLocation()).quickDir();
1573 	}
1574 
1575 	return oldFacing;
1576 }
1577 
1578 //-----------------------------------------------------------------------
1579 //	Causes actor to turn to a new direction.
1580 //		int "c" turn( int direction, int flags );
1581 
scriptActorTurn(int16 * args)1582 int16 scriptActorTurn(int16 *args) {
1583 	OBJLOG(Turn);
1584 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1585 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1586 
1587 		if (a->isDead()) return 0;
1588 
1589 		uint16      flags = args[1];
1590 
1591 		if (flags & moveWait) {
1592 			thisThread->waitForEvent(Thread::waitOther, 0);
1593 			MotionTask::turn(getThreadID(thisThread), *a, args[0] & 7);
1594 		} else {
1595 			MotionTask::turn(*a, args[0] & 7);
1596 			return motionStarted;
1597 		}
1598 	}
1599 
1600 	return 0;
1601 }
1602 
1603 //-----------------------------------------------------------------------
1604 //	Causes actor to turn towards another object or actor.
1605 //		int "c" turnTowards( GameObject id, int flags );
1606 
scriptActorTurnTowards(int16 * args)1607 int16 scriptActorTurnTowards(int16 *args) {
1608 	OBJLOG(TurnTowards);
1609 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1610 		assert(isObject(args[0]) || isActor(args[0]));
1611 
1612 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1613 
1614 		if (a->isDead()) return 0;
1615 
1616 		uint16      flags = args[1];
1617 		Direction   dir;
1618 
1619 		dir = (GameObject::objectAddress(args[0])->getLocation()
1620 		       -   a->getLocation()).quickDir();
1621 
1622 		if (flags & moveWait) {
1623 			thisThread->waitForEvent(Thread::waitOther, 0);
1624 			MotionTask::turn(getThreadID(thisThread), *a, dir);
1625 		} else {
1626 			MotionTask::turn(*a, dir);
1627 			return motionStarted;
1628 		}
1629 	}
1630 
1631 	return 0;
1632 }
1633 //-----------------------------------------------------------------------
1634 //	Walk the actor to a point
1635 //		int "c" walk( int u, int v, int z, int flags );
1636 
scriptActorWalk(int16 * args)1637 int16 scriptActorWalk(int16 *args) {
1638 	OBJLOG(Walk);
1639 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1640 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1641 
1642 		if (a->isDead()) return 0;
1643 
1644 		TilePoint   dest(args[0], args[1], args[2]);
1645 		uint16      flags = args[3];
1646 
1647 		if (flags & moveWait) {
1648 			thisThread->waitForEvent(Thread::waitOther, 0);
1649 			MotionTask::walkToDirect(
1650 			    getThreadID(thisThread), *a, dest, flags & moveRun);
1651 		} else {
1652 			MotionTask::walkToDirect(*a, dest, flags & moveRun);
1653 			return motionStarted;
1654 		}
1655 	}
1656 
1657 	return 0;
1658 }
1659 
1660 //-----------------------------------------------------------------------
1661 //	Constructs a patrol route assignment for this actor.  Optional fourth
1662 //	parameter specifies the starting waypoint.
1663 //		int "c" assignPatrolRoute(
1664 //			int until,
1665 //			int routeNo,
1666 //			int flags,
1667 //			... );
1668 
scriptActorAssignPatrolRoute(int16 * args)1669 int16 scriptActorAssignPatrolRoute(int16 *args) {
1670 	OBJLOG(AssignPatrolRoute);
1671 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1672 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1673 
1674 		//  Delete the actor's current assignment
1675 		if (a->getAssignment() != NULL) delete a->getAssignment();
1676 
1677 		if (new PatrolRouteAssignment(a,
1678 		            (uint16)args[0]
1679 		            *   CalenderTime::kFramesPerHour,
1680 		            args[1],
1681 		            (uint8)args[2],
1682 		            thisThread->argCount >= 4
1683 		            ?   args[3]
1684 		            :   -1)
1685 		        !=  NULL)
1686 			return true;
1687 	}
1688 
1689 	return false;
1690 }
1691 
1692 //-----------------------------------------------------------------------
1693 //	Assign a patrol route and specify the begining and ending waypoints
1694 //		int "c" assignPartialPatrolRoute(
1695 //			int untilHour,
1696 //			int routeNo,
1697 //			int flags,
1698 //			int startingWayPoint,
1699 //			int endingWayPoint );
1700 
scriptActorAssignPartialPatrolRoute(int16 * args)1701 int16 scriptActorAssignPartialPatrolRoute(int16 *args) {
1702 	OBJLOG(AssignPartialPatrolRoute);
1703 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1704 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1705 
1706 		//  Delete the actor's current assignment
1707 		if (a->getAssignment() != NULL) delete a->getAssignment();
1708 
1709 		if (new PatrolRouteAssignment(a,
1710 		            (uint16)args[0]
1711 		            *   CalenderTime::kFramesPerHour,
1712 		            args[1],
1713 		            (uint8)args[2],
1714 		            args[3],
1715 		            args[4])
1716 		        !=  NULL)
1717 			return true;
1718 	}
1719 
1720 	return false;
1721 }
1722 
1723 //-----------------------------------------------------------------------
1724 //	Assign this actor to hunt to be near a location.  The range
1725 //	parameter specifies how close to be near the target.
1726 //		int "c" assignBeNearLocation(
1727 //			int    untilHour,
1728 //			int    targetU,
1729 //			int    targetV,
1730 //			int    targetZ,
1731 //			int    range );
1732 
scriptActorAssignBeNearLocation(int16 * args)1733 int16 scriptActorAssignBeNearLocation(int16 *args) {
1734 	OBJLOG(AssignBeNearLocation);
1735 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1736 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1737 		TilePoint   targetLoc = TilePoint(args[1], args[2], args[3]);
1738 
1739 		//  Delete the actor's current assignment
1740 		if (a->getAssignment() != NULL) delete a->getAssignment();
1741 
1742 		if (new HuntToBeNearLocationAssignment(a,
1743 		            args[0],
1744 		            targetLoc,
1745 		            args[4])
1746 		        !=  NULL)
1747 			return true;
1748 	}
1749 
1750 	return false;
1751 }
1752 
1753 //-----------------------------------------------------------------------
1754 //	Assign this actor to hunt to be near another actor.
1755 //	where the target actor is.
1756 //		int "c" assignBeNearActor(
1757 //			int            until,
1758 //			Actor id   target,
1759 //			int            range,
1760 //			int            track );
1761 
scriptActorAssignBeNearActor(int16 * args)1762 int16 scriptActorAssignBeNearActor(int16 *args) {
1763 	OBJLOG(AssignBeNearActor);
1764 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1765 		assert(isActor(args[1]));
1766 
1767 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj,
1768 		             *targetActor;
1769 
1770 		targetActor = (Actor *)GameObject::objectAddress(args[1]);
1771 
1772 		//  Delete the actor's current assignment
1773 		if (a->getAssignment() != NULL) delete a->getAssignment();
1774 
1775 		if (new HuntToBeNearActorAssignment(a,
1776 		            args[0],
1777 		            targetActor,
1778 		            args[2],
1779 		            args[3])
1780 		        !=  NULL)
1781 			return true;
1782 	}
1783 
1784 	return false;
1785 }
1786 
1787 //-----------------------------------------------------------------------
1788 //	Assign this actor to kill another actor.
1789 //		int "c" assignKillActor( int until, Actor id target, int track );
1790 
scriptActorAssignKillActor(int16 * args)1791 int16 scriptActorAssignKillActor(int16 *args) {
1792 	OBJLOG(AssignKillActor);
1793 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1794 		assert(isActor(args[1]));
1795 
1796 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj,
1797 		             *targetActor;
1798 
1799 		targetActor = (Actor *)GameObject::objectAddress(args[1]);
1800 
1801 		//  Delete the actor's current assignment
1802 		if (a->getAssignment() != NULL) delete a->getAssignment();
1803 
1804 		if (new HuntToKillAssignment(a,
1805 		            args[0],
1806 		            targetActor,
1807 		            args[2])
1808 		        !=  NULL)
1809 			return true;
1810 	}
1811 
1812 	return false;
1813 }
1814 
1815 //-----------------------------------------------------------------------
1816 //	Constructs a tethered wander assignment for this actor
1817 //		int "c" assignTetheredWander(
1818 //			int until,
1819 //			int minU,
1820 //			int minV,
1821 //			int maxU,
1822 //			int maxV );
1823 
scriptActorAssignTetheredWander(int16 * args)1824 int16 scriptActorAssignTetheredWander(int16 *args) {
1825 	OBJLOG(AssignTetheredWander);
1826 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1827 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1828 
1829 		//  Delete the actor's current assignment
1830 		if (a->getAssignment() != NULL) delete a->getAssignment();
1831 
1832 		TileRegion  tetherReg;
1833 		int16       &minU = args[1],
1834 		             &minV = args[2],
1835 		              &maxU = args[3],
1836 		               &maxV = args[4];
1837 
1838 		//  Normalize the coordinates
1839 		if (maxU < minU) {
1840 			int16   temp = maxU;
1841 			maxU = minU;
1842 			minU = temp;
1843 		}
1844 		if (maxV < minV) {
1845 			int16   temp = maxV;
1846 			maxV = minV;
1847 			minV = temp;
1848 		}
1849 
1850 		tetherReg.min = TilePoint(minU, minV, 0);
1851 		tetherReg.max = TilePoint(maxU, maxV, 0);
1852 
1853 		if (new TetheredWanderAssignment(a,
1854 		            (uint16)args[0]
1855 		            *   CalenderTime::kFramesPerHour,
1856 		            tetherReg)
1857 		        !=  NULL)
1858 			return true;
1859 	}
1860 
1861 	return false;
1862 }
1863 
1864 //-----------------------------------------------------------------------
1865 //	Constructs a patrol route assignment for this actor
1866 //		int "c" assignAttend( int frames, GameObject id obj );
1867 
scriptActorAssignAttend(int16 * args)1868 int16 scriptActorAssignAttend(int16 *args) {
1869 	OBJLOG(AssignAttend);
1870 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1871 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1872 
1873 		//  Delete the actor's current assignment
1874 		if (a->getAssignment() != NULL) delete a->getAssignment();
1875 
1876 		if (new AttendAssignment(a,
1877 		            (g_vm->_calender->frameInDay()
1878 		             + (uint16)args[0])
1879 		            %   CalenderTime::kFramesPerDay,
1880 		            GameObject::objectAddress(args[1]))
1881 		        !=  NULL)
1882 			return true;
1883 	}
1884 
1885 	return false;
1886 }
1887 
1888 //-----------------------------------------------------------------------
1889 //	Remove this actor's current assignment
1890 //		void "c" removeAssignment( void );
1891 
scriptActorRemoveAssignment(int16 * args)1892 int16 scriptActorRemoveAssignment(int16 *args) {
1893 	OBJLOG(removeAssignment);
1894 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1895 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1896 
1897 		if (a->getAssignment() != NULL) delete a->getAssignment();
1898 	}
1899 
1900 	return 0;
1901 }
1902 
1903 //-----------------------------------------------------------------------
1904 //	Bands this actor as a follower to the specified leader.
1905 //		void "c" bandWith( Actor id leader );
1906 
scriptActorBandWith(int16 * args)1907 int16 scriptActorBandWith(int16 *args) {
1908 	OBJLOG(BandWith);
1909 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1910 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1911 
1912 		assert(isActor(args[0]));
1913 
1914 		a->bandWith((Actor *)GameObject::objectAddress(args[0]));
1915 	}
1916 
1917 	return 0;
1918 }
1919 
1920 //-----------------------------------------------------------------------
1921 //	Remove the actor from his current band.
1922 //		void "c" disband( void );
1923 
scriptActorDisband(int16 *)1924 int16 scriptActorDisband(int16 *) {
1925 	OBJLOG(Disband);
1926 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1927 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1928 
1929 		a->disband();
1930 	}
1931 
1932 	return 0;
1933 }
1934 
1935 //-----------------------------------------------------------------------
1936 //	Returns this actor's leader's ID.
1937 //		Actor id "c" getLeader( void );
1938 
scriptActorGetLeader(int16 *)1939 int16 scriptActorGetLeader(int16 *) {
1940 	OBJLOG(GetLeader);
1941 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1942 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1943 
1944 		return a->_leader != NULL ? a->_leader->thisID() : Nothing;
1945 	}
1946 
1947 	return 0;
1948 }
1949 
1950 //-----------------------------------------------------------------------
1951 //	Returns the number of followers this actor has.
1952 //		int "c" numFollowers( void );
1953 
scriptActorNumFollowers(int16 *)1954 int16 scriptActorNumFollowers(int16 *) {
1955 	OBJLOG(ActorNumFollowers);
1956 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1957 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1958 
1959 		return a->_followers != NULL ? a->_followers->size() : 0;
1960 	}
1961 
1962 	return 0;
1963 }
1964 
1965 //-----------------------------------------------------------------------
1966 //	Returns the ID of the specified follower.
1967 //		Actor id "c" getFollower( int followerNum );
1968 
scriptActorGetFollower(int16 * args)1969 int16 scriptActorGetFollower(int16 *args) {
1970 	OBJLOG(GetFollower);
1971 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1972 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1973 
1974 		assert(a->_followers != NULL);
1975 		assert(args[0] < a->_followers->size());
1976 
1977 		return (*a->_followers)[args[0]]->thisID();
1978 	}
1979 
1980 	return 0;
1981 }
1982 
1983 //-----------------------------------------------------------------------
1984 //	Routine that is called by actor class to use that actor's
1985 //	knowledge list
1986 //		int "c" useKnowledge( GameObject id );
1987 
scriptActorUseKnowledge(int16 *)1988 int16 scriptActorUseKnowledge(int16 *) {
1989 	OBJLOG(UseKnowledge);
1990 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
1991 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
1992 
1993 		a->useKnowledge(thisThread->threadArgs);
1994 	}
1995 
1996 	return thisThread->threadArgs.returnVal;
1997 }
1998 
1999 //-----------------------------------------------------------------------
2000 //	add knowledge package to actor
2001 //		void "c" addKnowledge( int kpIndex );
2002 
scriptActorAddKnowledge(int16 * args)2003 int16 scriptActorAddKnowledge(int16 *args) {
2004 	OBJLOG(AddKnowledge);
2005 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
2006 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
2007 
2008 		a->addKnowledge(args[0]);
2009 	}
2010 
2011 	return 0;
2012 }
2013 
2014 //-----------------------------------------------------------------------
2015 //	delete knowledge package delete actor
2016 //		void "c" deleteKnowledge( int kpIndex );
2017 
scriptActorDeleteKnowledge(int16 * args)2018 int16 scriptActorDeleteKnowledge(int16 *args) {
2019 	OBJLOG(DeleteKnowledge);
2020 	if (isActor(((ObjectData *)thisThread->thisObject)->obj)) {
2021 		Actor       *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
2022 
2023 		if (args[0] == 0) a->clearKnowledge();
2024 		else a->removeKnowledge(args[0]);
2025 	}
2026 
2027 	return 0;
2028 }
2029 
2030 //-----------------------------------------------------------------------
2031 //	add knowledge package to actor (lasts for duration of mission)
2032 //		void "c" addMissionKnowledge( int missionID, int kpIndex );
2033 
scriptActorAddMissionKnowledge(int16 * args)2034 int16 scriptActorAddMissionKnowledge(int16 *args) {
2035 	OBJLOG(AddMissionKnowledge);
2036 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
2037 	ActiveMission   *am = ActiveMission::missionAddress(args[0]);
2038 
2039 	if (isActor(obj)) {
2040 		return am->addKnowledgeID(obj->thisID(), args[1]);
2041 	}
2042 	return 0;
2043 }
2044 
2045 //-----------------------------------------------------------------------
2046 //	delete mission knowledge package from actor
2047 //		void "c" removeMissionKnowledge( int missionID, int kpIndex );
2048 
scriptActorDeleteMissionKnowledge(int16 * args)2049 int16 scriptActorDeleteMissionKnowledge(int16 *args) {
2050 	OBJLOG(DeleteMissionKnowledge);
2051 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
2052 	ActiveMission   *am = ActiveMission::missionAddress(args[0]);
2053 
2054 	if (isActor(obj)) {
2055 		return am->removeKnowledgeID(obj->thisID(), args[1]);
2056 	}
2057 	return 0;
2058 }
2059 
2060 //-----------------------------------------------------------------------
2061 //	Deduct gold or other payment type from actor
2062 //		void "c" deductPayment( int paymentTypeProto, int paymentAmount );
2063 
scriptActorDeductPayment(int16 * args)2064 int16 scriptActorDeductPayment(int16 *args) {
2065 	OBJLOG(DeductPayment);
2066 	Actor           *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
2067 
2068 	ProtoObj    *currencyProto = g_vm->_objectProtos[args[0]];
2069 	int32       paymentAmount = args[1];
2070 	int32       paymentFound = 0;
2071 	GameObject  *obj, *delObj = NULL;
2072 	ObjectID    id;
2073 	bool        mergeable =
2074 	    currencyProto->flags & ResourceObjectPrototype::objPropMergeable;
2075 
2076 	RecursiveContainerIterator  iter(a);
2077 
2078 	//  See if he has enough currency
2079 	for (id = iter.first(&obj); id != Nothing; id = iter.next(&obj)) {
2080 		//  For each object of appropriate currency type
2081 		if (isObject(id) && obj->proto() == currencyProto) {
2082 			if (mergeable) paymentFound += obj->getExtra();
2083 			else paymentFound++;
2084 
2085 			if (paymentFound >= paymentAmount) break;
2086 		}
2087 	}
2088 
2089 	//  If he doesn't have enough, return false.
2090 	if (paymentFound < paymentAmount) return false;
2091 
2092 	//  Now, deduct the actual currency
2093 	for (id = iter.first(&obj); id != Nothing; id = iter.next(&obj)) {
2094 		//  If the object is valid currency
2095 		if (isObject(id) && obj->proto() == currencyProto) {
2096 			//  Mergeable object use the mass count
2097 			if (mergeable) {
2098 				int     massCount = obj->getExtra();
2099 
2100 				if (massCount > paymentAmount) {
2101 					obj->setExtra(massCount - paymentAmount);
2102 					g_vm->_cnm->setUpdate(obj->IDParent());
2103 					break;
2104 				} else {
2105 					if (delObj) {
2106 						ObjectID    dParent = delObj->IDParent();
2107 						delObj->deleteObject();
2108 						g_vm->_cnm->setUpdate(dParent);
2109 					}
2110 					paymentAmount -= massCount;
2111 					delObj = obj;
2112 					if (paymentAmount == 0)
2113 						break;
2114 				}
2115 			} else {
2116 				//  Non-mergeable objects count as 1
2117 				paymentAmount--;
2118 				if (delObj) {
2119 					ObjectID    dParent = delObj->IDParent();
2120 					delObj->deleteObject();
2121 					g_vm->_cnm->setUpdate(dParent);
2122 				}
2123 				delObj = obj;
2124 			}
2125 		}
2126 	}
2127 
2128 	if (delObj) {
2129 		ObjectID    dParent = delObj->IDParent();
2130 		delObj->deleteObject();
2131 		g_vm->_cnm->setUpdate(dParent);
2132 	}
2133 
2134 	//  Payment succeeded!
2135 	return true;
2136 }
2137 
2138 //-----------------------------------------------------------------------
2139 //	Count the amount of gold or other payment type actor has
2140 //		void "c" countPayment( int paymentTypeProto );
2141 
scriptActorCountPayment(int16 * args)2142 int16 scriptActorCountPayment(int16 *args) {
2143 	OBJLOG(CountPayment);
2144 	Actor           *a = (Actor *)((ObjectData *)thisThread->thisObject)->obj;
2145 
2146 	ProtoObj    *currencyProto = g_vm->_objectProtos[args[0]];
2147 	int32       paymentFound = 0;
2148 	GameObject  *obj = nullptr;
2149 	ObjectID    id;
2150 	bool        mergeable =
2151 	    currencyProto->flags & ResourceObjectPrototype::objPropMergeable;
2152 
2153 	RecursiveContainerIterator  iter(a);
2154 
2155 	for (id = iter.first(&obj); id != Nothing; id = iter.next(&obj)) {
2156 		if (isObject(id) && obj->proto() == currencyProto) {
2157 			if (mergeable) paymentFound += obj->getExtra();
2158 			else paymentFound++;
2159 		}
2160 	}
2161 
2162 	return paymentFound;
2163 }
2164 
2165 //-----------------------------------------------------------------------
2166 //	Physician, heal thyself...
2167 //		void "c" acceptHealing( int amt );
2168 
scriptActorAcceptHealing(int16 * args)2169 int16 scriptActorAcceptHealing(int16 *args) {
2170 	OBJLOG(acceptHealing);
2171 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
2172 
2173 	obj->acceptHealing(obj->thisID(), args[0]);
2174 	return 0;
2175 }
2176 
2177 //-----------------------------------------------------------------------
2178 //	Hurt me!
2179 //		void "c" acceptDamage( GameObject id enactor, absDamage, type );
2180 
scriptActorAcceptDamage(int16 * args)2181 int16 scriptActorAcceptDamage(int16 *args) {
2182 	OBJLOG(acceptHealing);
2183 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
2184 
2185 	obj->acceptDamage(args[0], args[1], (enum effectDamageTypes)args[2]);
2186 	return 0;
2187 }
2188 
2189 //-----------------------------------------------------------------------
2190 //	Ressurect
2191 //		void "c" imNotQuiteDead( void );
2192 
scriptActorImNotQuiteDead(int16 * args)2193 int16 scriptActorImNotQuiteDead(int16 *args) {
2194 	OBJLOG(imNotQuiteDead);
2195 	GameObject      *obj = ((ObjectData *)thisThread->thisObject)->obj;
2196 
2197 	if (isActor(obj)) {
2198 		((Actor *)obj)->imNotQuiteDead();
2199 	}
2200 
2201 	return 0;
2202 }
2203 
2204 //-----------------------------------------------------------------------
2205 //	Actor script call table
2206 
2207 C_Call *actorCFuncList[] = {
2208 	scriptGameObjectThisID,
2209 	scriptGameObjectRecharge,
2210 	scriptGameObjectGetChargeType,
2211 	scriptActorMove,
2212 	scriptActorMoveRel,
2213 	scriptActorTransfer,
2214 	scriptMoveRandom,
2215 	scriptActorGetName,
2216 	scriptActorSetName,
2217 	scriptActorGetProto,
2218 	scriptActorSetProto,
2219 	scriptActorGetProtoClass,
2220 	scriptActorGetScript,
2221 	scriptActorSetScript,
2222 
2223 	scriptGameObjectUse,
2224 	scriptGameObjectUseOn,
2225 	scriptGameObjectUseOnTAI,
2226 	scriptGameObjectDrop,
2227 	scriptGameObjectDropOn,
2228 	scriptGameObjectDropMergeableOn,
2229 	scriptGameObjectDropOnTAI,
2230 
2231 	scriptActorSay,
2232 	scriptActorSayText,
2233 	scriptActorObjectType,
2234 	scriptActorCopyObject,
2235 
2236 	scriptGameObjectIsActivated,
2237 
2238 	scriptActorGetOpen,
2239 	scriptActorGetLocked,
2240 	scriptActorGetImportant,
2241 	scriptActorSetImportant,
2242 	scriptActorGetScavengable,
2243 	scriptActorSetScavengable,
2244 
2245 	scriptGameObjectAddTimer,
2246 	scriptGameObjectAddStdTimer,
2247 	scriptGameObjectRemoveTimer,
2248 	scriptGameObjectRemoveAllTimers,
2249 
2250 	scriptGameObjectAddProtaganistSensor,
2251 	scriptGameObjectAddSpecificActorSensor,
2252 	scriptGameObjectAddSpecificObjectSensor,
2253 	scriptGameObjectAddActorPropertySensor,
2254 	scriptGameObjectAddObjectPropertySensor,
2255 	scriptGameObjectAddEventSensor,
2256 	scriptGameObjectRemoveSensor,
2257 	scriptGameObjectRemoveAllSensors,
2258 
2259 	scriptGameObjectCanSenseProtaganist,
2260 	scriptGameObjectCanSenseSpecificActor,
2261 	scriptGameObjectCanSenseSpecificObject,
2262 	scriptGameObjectCanSenseActorProperty,
2263 	scriptGameObjectCanSenseObjectProperty,
2264 
2265 	scriptGameObjectGetActualScript,
2266 	scriptGameObjectGetProtoScript,
2267 
2268 	scriptGameObjectGetMass,
2269 	scriptGameObjectSetMass,
2270 
2271 	scriptGameObjectGetExtra,
2272 	scriptGameObjectSetExtra,
2273 
2274 	scriptGameObjectDeepCopy,
2275 	scriptGameObjectAddEnchantment,
2276 	scriptGameObjectRemoveEnchantment,
2277 	scriptGameObjectFindEnchantment,
2278 
2279 	scriptGameObjectInUse,
2280 
2281 	scriptActorGetScratchVar,
2282 	scriptActorSetScratchVar,
2283 
2284 	scriptActorGetDisposition,
2285 	scriptActorSetDisposition,
2286 
2287 	scriptActorGetSkill,
2288 	scriptActorSetSkill,
2289 	scriptActorGetBaseSkill,
2290 	scriptActorSetBaseSkill,
2291 
2292 	scriptActorGetVitality,
2293 	scriptActorSetVitality,
2294 	scriptActorGetBaseVitality,
2295 	scriptActorSetBaseVitality,
2296 
2297 	scriptActorGetMana,
2298 	scriptActorSetMana,
2299 	scriptActorGetBaseMana,
2300 	scriptActorSetBaseMana,
2301 
2302 	scriptActorGetSchedule,
2303 	scriptActorSetSchedule,
2304 
2305 	scriptActorLobotomize,
2306 	scriptActorDelobotomize,
2307 	scriptActorIsActionAvailable,
2308 	scriptActorSetAction,
2309 	scriptActorAnimationFrames,
2310 	scriptActorNextAnimationFrame,
2311 	scriptActorFace,
2312 	scriptActorFaceTowards,
2313 	scriptActorTurn,
2314 	scriptActorTurnTowards,
2315 	scriptActorWalk,
2316 
2317 	scriptActorAssignPatrolRoute,
2318 	scriptActorAssignPartialPatrolRoute,
2319 	scriptActorAssignBeNearLocation,
2320 	scriptActorAssignBeNearActor,
2321 	scriptActorAssignKillActor,
2322 	scriptActorAssignTetheredWander,
2323 	scriptActorAssignAttend,
2324 	scriptActorRemoveAssignment,
2325 
2326 	scriptActorBandWith,
2327 	scriptActorDisband,
2328 	scriptActorGetLeader,
2329 	scriptActorNumFollowers,
2330 	scriptActorGetFollower,
2331 
2332 	scriptActorUseKnowledge,
2333 	scriptActorAddKnowledge,
2334 	scriptActorDeleteKnowledge,
2335 	scriptActorAddMissionKnowledge,
2336 	scriptActorDeleteMissionKnowledge,
2337 
2338 	scriptActorDeductPayment,
2339 	scriptActorCountPayment,
2340 
2341 	scriptActorAcceptHealing,
2342 	scriptActorAcceptDamage,
2343 	scriptActorImNotQuiteDead,
2344 };
2345 
2346 CallTable   actorCFuncs = { actorCFuncList, ARRAYSIZE(actorCFuncList), 0 };
2347 
2348 //-----------------------------------------------------------------------
2349 //	Return the id of this TAI
2350 //		TileActivityInstance id "c" thisID( void );
2351 
scriptTagThisID(int16 *)2352 int16 scriptTagThisID(int16 *) {
2353 	MONOLOG(TAG::ThisID);
2354 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2355 
2356 	return ai->thisID();
2357 }
2358 
2359 //-----------------------------------------------------------------------
2360 //	Return the current state of this tag
2361 //		int "c" getState( void );
2362 
scriptTagGetState(int16 * args)2363 int16 scriptTagGetState(int16 *args) {
2364 	MONOLOG(TAG::GetState);
2365 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2366 
2367 	return ai->getInstanceState(ai->getMapNum());
2368 }
2369 
2370 //-----------------------------------------------------------------------
2371 //	Set the tag instance to a given state
2372 //		void "c" setState( int state );
2373 
scriptTagSetState(int16 * args)2374 int16 scriptTagSetState(int16 *args) {
2375 	MONOLOG(TAG::SetState);
2376 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2377 
2378 	ai->setInstanceState(ai->getMapNum(), args[0]);
2379 
2380 	return 0;
2381 }
2382 
2383 //-----------------------------------------------------------------------
2384 //	Return the number of associations for this tag
2385 //		int "c" numAssociations( void );
2386 
scriptTagNumAssoc(int16 * args)2387 int16 scriptTagNumAssoc(int16 *args) {
2388 	MONOLOG(TAG::NumAssoc);
2389 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2390 
2391 	return ai->_data.numAssociations;
2392 }
2393 
2394 //-----------------------------------------------------------------------
2395 //	Get the Nth association for this tag
2396 //		TileActivityInstance id "c" assoc( int assocNum );
2397 
scriptTagAssoc(int16 * args)2398 int16 scriptTagAssoc(int16 *args) {
2399 	MONOLOG(TAG::Assoc);
2400 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2401 	int mapNum       = ai->getMapNum();
2402 
2403 	assert(args[0] >= 0);
2404 	assert(args[0] <  ai->_data.numAssociations);
2405 	assert(mapNum >= 0);
2406 	assert(mapNum < 8);
2407 
2408 	return (mapList[mapNum].assocList)[ai->_data.associationOffset + args[0]];
2409 }
2410 
2411 //-----------------------------------------------------------------------
2412 //	Return the target U coord of this tag
2413 //		int "c" getTargetU( void );
2414 
scriptTagGetTargetU(int16 * args)2415 int16 scriptTagGetTargetU(int16 *args) {
2416 	MONOLOG(TAG::GetTargetU);
2417 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2418 
2419 	return ai->_data.instance.targetU;
2420 }
2421 
2422 //-----------------------------------------------------------------------
2423 //	Return the target V coord of this tag
2424 //		int "c" getTargetV( void );
2425 
scriptTagGetTargetV(int16 *)2426 int16 scriptTagGetTargetV(int16 *) {
2427 	MONOLOG(TAG::GetTargetV);
2428 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2429 
2430 	return ai->_data.instance.targetV;
2431 }
2432 
2433 //-----------------------------------------------------------------------
2434 //	Return the target Z coord of this tag
2435 //		int "c" getTargetU( void );
2436 
scriptTagGetTargetZ(int16 *)2437 int16 scriptTagGetTargetZ(int16 *) {
2438 	MONOLOG(TAG::GetTargetZ);
2439 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2440 
2441 	return ai->_data.instance.targetZ;
2442 }
2443 
2444 //-----------------------------------------------------------------------
2445 //	Return the target world coord of this tag
2446 //		int "c" getTargetW( void );
2447 
scriptTagGetTargetW(int16 *)2448 int16 scriptTagGetTargetW(int16 *) {
2449 	MONOLOG(TAG::GetTargetW);
2450 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2451 
2452 	return ai->_data.instance.worldNum;
2453 }
2454 
2455 //-----------------------------------------------------------------------
2456 //	Return the state of the "locked" bit
2457 //		int "c" isLocked( void );
2458 
scriptTagIsLocked(int16 *)2459 int16 scriptTagIsLocked(int16 *) {
2460 	MONOLOG(TAG::IsLocked);
2461 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2462 
2463 	return ai->isLocked() ? true : false;
2464 }
2465 
2466 //-----------------------------------------------------------------------
2467 //	Change the state of the "locked" bit.
2468 //		int "c" setLocked( void );
2469 
2470 
scriptTagSetLocked(int16 * args)2471 int16 scriptTagSetLocked(int16 *args) {
2472 	MONOLOG(TAG::SetLocked);
2473 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2474 
2475 	ai->setLocked(args[0]);
2476 
2477 	return 0;
2478 }
2479 
2480 //-----------------------------------------------------------------------
2481 //	Return the tag's key type
2482 //		int "c" getKeyType( void );
2483 
scriptTagGetKeyType(int16 *)2484 int16 scriptTagGetKeyType(int16 *) {
2485 	MONOLOG(TAG::GetKeyType);
2486 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2487 
2488 	return ai->lockType();
2489 }
2490 
2491 //-----------------------------------------------------------------------
2492 //	Use this TAI
2493 //		int "c" use( GameObject id enactor );
2494 
scriptTagUse(int16 * args)2495 int16 scriptTagUse(int16 *args) {
2496 	MONOLOG(TAG::Use);
2497 	ActiveItem      *tai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2498 
2499 	return tai->use(args[0]);
2500 }
2501 
2502 //-----------------------------------------------------------------------
2503 //	Animate the tag
2504 //		void "c" setAnimation( int flags, int targetState );
2505 
2506 enum {
2507 	tileAnimateWait = (1 << 0)              // wait until animation finished
2508 };
2509 
scriptTagSetAnimation(int16 * args)2510 int16 scriptTagSetAnimation(int16 *args) {
2511 	MONOLOG(TAG::SetAnimation);
2512 	extern uint32 parse_res_id(char IDstr[]);
2513 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2514 	//TilePoint tagLoc;
2515 	int32       soundID = parse_res_id(STRING(args[2]));
2516 	Location    ail = ai->getInstanceLocation();
2517 
2518 	//  Assert that the state is valid
2519 	assert(args[1] >= 0);
2520 	assert(args[1] < ai->getGroup()->_data.group.numStates);
2521 
2522 	//  If soundID is not NULL, then play the sound
2523 	if (soundID) playSoundAt(soundID, ail);
2524 
2525 	//  If we want to wait until finished
2526 	if (args[0] & tileAnimateWait) {
2527 		//  Wait for the animation
2528 		thisThread->waitForEvent(Thread::waitOther, 0);
2529 
2530 		//  And start the tile animation
2531 		TileActivityTask::doScript(*ai, args[1], getThreadID(thisThread));
2532 	} else {
2533 		//  Else just start the tile animation
2534 		TileActivityTask::doScript(*ai, args[1], NoThread);
2535 	}
2536 
2537 	return ai->lockType();
2538 }
2539 
2540 //-----------------------------------------------------------------------
2541 //	Wait for animation to finish.
2542 //		void "c" waitAnimate( void );
2543 
scriptTagSetWait(int16 * args)2544 int16 scriptTagSetWait(int16 *args) {
2545 	MONOLOG(TAG::SetAnimation);
2546 	extern uint32 parse_res_id(char IDstr[]);
2547 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2548 
2549 	if (TileActivityTask::setWait(ai, getThreadID(thisThread))) {
2550 		//  Wait for the animation
2551 		thisThread->waitForEvent(Thread::waitOther, 0);
2552 	}
2553 
2554 	return 0;
2555 }
2556 
2557 //-----------------------------------------------------------------------
2558 //	Lock the tag for exclusive use, or else go to sleep
2559 //		void "c" obtainLock( void );
2560 //		void "c" releaseLock( void );
2561 
2562 #if DEBUG*0
2563 static int16 lockCount;
2564 #endif
2565 
scriptTagObtainLock(int16 *)2566 int16 scriptTagObtainLock(int16 *) {
2567 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2568 
2569 	if (ai->isExclusive() == false) {
2570 		ai->setExclusive(true);
2571 #if DEBUG*0
2572 		lockCount += 1;
2573 		WriteStatusF(15, "Locked: %d\n", lockCount);
2574 #endif
2575 	} else {
2576 		thisThread->waitForEvent(Thread::waitTagSemaphore, ai);
2577 #if DEBUG*0
2578 		lockCount += 1;
2579 		WriteStatusF(15, "Locked: %d\n", lockCount);
2580 #endif
2581 	}
2582 	return 0;
2583 }
2584 
scriptTagReleaseLock(int16 *)2585 int16 scriptTagReleaseLock(int16 *) {
2586 	ActiveItem  *ai = ((ActiveItemData *)thisThread->thisObject)->aItem;
2587 
2588 	ai->setExclusive(false);
2589 #if DEBUG*0
2590 	lockCount -= 1;
2591 	WriteStatusF(15, "Locked: %d\n", lockCount);
2592 #endif
2593 	return 0;
2594 }
2595 
2596 //-----------------------------------------------------------------------
2597 //	TAG Instance script call table
2598 
2599 C_Call *tagCFuncList[] = {
2600 	scriptTagThisID,
2601 	scriptTagGetState,
2602 	scriptTagSetState,
2603 	scriptTagSetAnimation,
2604 	scriptTagNumAssoc,
2605 	scriptTagAssoc,
2606 	scriptTagGetTargetU,
2607 	scriptTagGetTargetV,
2608 	scriptTagGetTargetZ,
2609 	scriptTagGetTargetW,
2610 	scriptTagIsLocked,
2611 	scriptTagSetLocked,
2612 	scriptTagGetKeyType,
2613 	scriptTagUse,
2614 	scriptTagSetWait,
2615 	scriptTagObtainLock,
2616 	scriptTagReleaseLock,
2617 };
2618 
2619 CallTable   tagCFuncs = { tagCFuncList, ARRAYSIZE(tagCFuncList), 0 };
2620 
2621 //-----------------------------------------------------------------------
2622 //	Find a mission by generator id
2623 //		void "c" deleteMission( int missionID );
2624 
scriptMissionDelete(int16 * args)2625 int16 scriptMissionDelete(int16 *args) {
2626 	MONOLOG(ActiveMission::Delete);
2627 	ActiveMission       *am = ((ActiveMissionData *)thisThread->thisObject)->aMission;
2628 
2629 	am->cleanup();
2630 	return 0;
2631 }
2632 
2633 //-----------------------------------------------------------------------
2634 //	Create a new object
2635 //		GameObject id "C" makeObject(   int protoID,
2636 //										int nameIndex,
2637 //										int scriptIndex );
2638 
2639 int16 scriptMakeObject(int16 *args);
2640 
scriptMissionMakeObject(int16 * args)2641 int16 scriptMissionMakeObject(int16 *args) {
2642 	MONOLOG(TAG::MakeObject);
2643 	ActiveMission       *am = ((ActiveMissionData *)thisThread->thisObject)->aMission;
2644 	ObjectID            id;
2645 
2646 	//  If there's room in the mission to record the existence of the object
2647 	if (!am->spaceForObject()) return Nothing;
2648 
2649 	//  Call the regular make-object function
2650 	id = scriptMakeObject(args);
2651 
2652 	//  And record it in the mission object
2653 	if (id != Nothing) {
2654 		am->addObjectID(id);
2655 	}
2656 
2657 	return id;
2658 }
2659 
2660 //-----------------------------------------------------------------------
2661 //	Create a new object
2662 //		GameObject id "C" makeActor(    int protoID,
2663 //										int nameIndex,
2664 //										int scriptIndex,
2665 //										string appearance,
2666 //										int color );
2667 
2668 int16 scriptMakeActor(int16 *args);
2669 
scriptMissionMakeActor(int16 * args)2670 int16 scriptMissionMakeActor(int16 *args) {
2671 	MONOLOG(ActiveMission::MakeActor);
2672 	ActiveMission       *am = ((ActiveMissionData *)thisThread->thisObject)->aMission;
2673 	ObjectID            id;
2674 
2675 	//  If there's room in the mission to record the existence of the actor
2676 	if (!am->spaceForObject()) return Nothing;
2677 
2678 	//  Call the regular make-actor function. Add in the "permanent"
2679 	//  flag, since actor will be deleted at mission end.
2680 	args[6] |= actorPermanent;
2681 	id = scriptMakeActor(args);
2682 
2683 	//  And record it in the mission object
2684 	if (id != Nothing) {
2685 		am->addObjectID(id);
2686 	}
2687 
2688 	return id;
2689 }
2690 
2691 //-----------------------------------------------------------------------
2692 //	ActiveMission Instance script call table
2693 
2694 C_Call *missionCFuncList[] = {
2695 	scriptMissionDelete,
2696 	scriptMissionMakeObject,
2697 	scriptMissionMakeActor,
2698 };
2699 
2700 CallTable   missionCFuncs = { missionCFuncList, ARRAYSIZE(missionCFuncList), 0 };
2701 
2702 //-----------------------------------------------------------------------
2703 //	Global functions
2704 
scriptWriteMessage(int16 * args)2705 int16 scriptWriteMessage(int16 *args) {
2706 	MONOLOG(WriteMessage);
2707 	char        buffer[256];
2708 
2709 	stringf(buffer, sizeof buffer, args[1], &args[2]);
2710 
2711 	WriteStatusF(args[0], buffer);
2712 	return 0;
2713 }
2714 
2715 //-----------------------------------------------------------------------
2716 //	Write a message to the status line
2717 //		void "C" status( string caption, ... );
2718 
scriptStatus(int16 * args)2719 int16 scriptStatus(int16 *args) {
2720 	MONOLOG(Status);
2721 	char        buffer[256];
2722 
2723 	stringf(buffer, sizeof buffer, args[0], &args[1]);
2724 
2725 	StatusMsg(buffer);
2726 	return 0;
2727 }
2728 
2729 //-----------------------------------------------------------------------
2730 //	Write a message to a log file
2731 //		void "C" status( string caption, ... );
2732 /*
2733 void writeLog( char *str )
2734 {
2735     static FILE     *logFile = NULL;
2736 
2737     if (logFile == NULL)
2738     {
2739         logFile = fopen( "logfile.txt", "a+t" );
2740     }
2741 
2742     if (logFile) fputs( str, logFile );
2743     fclose(logFile);
2744 }
2745 */
writeLog(char * str)2746 void writeLog(char *str) {
2747 	FILE        *logFile = NULL;
2748 #ifdef __WATCOMC__
2749 	time_t time_of_day;
2750 	auto char buf[26];
2751 	char strbuf[256];
2752 
2753 
2754 	logFile = fopen("logfile.txt", "a+t");
2755 	if (logFile) {
2756 		time_of_day = time(NULL);
2757 		_ctime(&time_of_day, buf);
2758 		buf[strlen(buf) - 1] = 0;
2759 		sprintf(strbuf, "%s: %s", buf, str);
2760 		fputs(strbuf, logFile);
2761 		fclose(logFile);
2762 	}
2763 #else
2764 	logFile = fopen("logfile.txt", "a+t");
2765 	if (logFile) {
2766 		fputs(str, logFile);
2767 		fclose(logFile);
2768 	}
2769 #endif
2770 }
2771 
writeObject(char * str)2772 void writeObject(char *str) {
2773 	FILE        *logFile = NULL;
2774 	logFile = fopen("objfile.txt", "a+t");
2775 	if (logFile) {
2776 		fputs(str, logFile);
2777 		fclose(logFile);
2778 	}
2779 }
2780 
scriptWriteLog(int16 * args)2781 int16 scriptWriteLog(int16 *args) {
2782 	MONOLOG(WriteLog);
2783 	char buffer[256];
2784 
2785 	stringf(buffer, sizeof buffer, args[0], &args[1]);
2786 	debugC(2, kDebugScripts, "%s", buffer);
2787 
2788 	return 0;
2789 }
2790 
scriptWriteObject(int16 * args)2791 int16 scriptWriteObject(int16 *args) {
2792 	MONOLOG(WriteObject);
2793 	char      buffer[256];
2794 
2795 	stringf(buffer, sizeof buffer, args[0], &args[1]);
2796 	writeObject(buffer);
2797 	return 0;
2798 }
2799 //-----------------------------------------------------------------------
2800 //	Put up an error-message dialog
2801 //		void "C" errorDialog( string caption, ... );
2802 
scriptErrorDialog(int16 * args)2803 int16 scriptErrorDialog(int16 *args) {
2804 	MONOLOG(ErrorDialog);
2805 	char        buffer[512];
2806 
2807 	stringf(buffer, sizeof buffer, args[1], &args[2]);
2808 
2809 //	WriteStatusF( 1, buffer );
2810 	return 0;
2811 }
2812 
2813 //-----------------------------------------------------------------------
2814 //	Put up a user-notification dialog
2815 //		void "C" messageDialog( string caption, ... );
2816 
scriptMessageDialog(int16 * args)2817 int16 scriptMessageDialog(int16 *args) {
2818 	MONOLOG(MessageDialog);
2819 	//stringf( buffer, sizeof buffer, args[1], &args[2] );
2820 
2821 	userDialog(STRING(args[0]),
2822 	           STRING(args[1]),
2823 	           args[2] ? STRING(args[2]) : NULL,
2824 	           NULL,
2825 	           NULL);
2826 
2827 //	WriteStatusF( 1, buffer );
2828 	return 0;
2829 }
2830 
2831 //-----------------------------------------------------------------------
2832 //	Put up a multiple-choice button dialog
2833 //		int "C" choiceDialog( string caption, string buttons, ... );
2834 
scriptChoiceDialog(int16 * args)2835 int16 scriptChoiceDialog(int16 *args) {
2836 	MONOLOG(ChoiceDialog);
2837 	//stringf( buffer, sizeof buffer, args[1], &args[2] );
2838 
2839 	userDialog(STRING(args[0]),
2840 	           STRING(args[1]),
2841 	           args[2] ? STRING(args[2]) : NULL,
2842 	           args[3] ? STRING(args[3]) : NULL,
2843 	           args[4] ? STRING(args[4]) : NULL);
2844 
2845 //	WriteStatusF( 1, buffer );
2846 	return 0;
2847 }
2848 
2849 //-----------------------------------------------------------------------
2850 //	Put up a placard (stone, wood, or brass)
2851 //		void "C" placard( int placardType, string text, ... );
2852 
2853 // defined in uidialog.h
2854 //enum placardTypes {
2855 //	WOOD_TYPE,
2856 //	STONE_TYPE,
2857 //	BRASS_TYPE
2858 //};
2859 
scriptPlacard(int16 * args)2860 int16 scriptPlacard(int16 *args) {
2861 	MONOLOG(Placard);
2862 	char        buffer[256];
2863 
2864 	stringf(buffer, sizeof buffer, args[1], &args[2]);
2865 
2866 	placardWindow(args[0], buffer);    // plaq type, text
2867 
2868 	//GameDisplay( buffer, 0 );
2869 	return 0;
2870 }
2871 
2872 //-----------------------------------------------------------------------
2873 //	Lock the display so that no updates occur
2874 //		void "C" lockDIsplay( int lockState );
2875 
scriptLockDisplay(int16 * args)2876 int16 scriptLockDisplay(int16 *args) {
2877 	MONOLOG(LockDisplay);
2878 //	WriteStatusF( args[0], STRING( args[1] ) );
2879 	return 0;
2880 }
2881 
2882 //-----------------------------------------------------------------------
2883 //	Set the current game mode
2884 //		void "C" setGameMode( int modeNumber );
2885 
scriptSetGameMode(int16 * args)2886 int16 scriptSetGameMode(int16 *args) {
2887 	MONOLOG(SetGameMode);
2888 	//  Mode zero is "game not running".
2889 	if (args[0] == 0)
2890 		endGame();
2891 	//gameRunning = false;
2892 
2893 	//  REM: Add other modes
2894 
2895 	return 0;
2896 }
2897 
2898 //-----------------------------------------------------------------------
2899 //	Extended-sequence functions (all these functions automatically
2900 //	cause the script to go into extended sequnce mode).
2901 
scriptWait(int16 * args)2902 int16 scriptWait(int16 *args) {
2903 	MONOLOG(Wait);
2904 	thisThread->waitAlarm.set(args[0]);
2905 	thisThread->waitForEvent(Thread::waitDelay, 0);
2906 	thisThread->setExtended();
2907 	return 0;
2908 }
2909 
scriptWaitFrames(int16 * args)2910 int16 scriptWaitFrames(int16 *args) {
2911 	MONOLOG(WaitFrames);
2912 	thisThread->waitFrameAlarm.set(args[0]);
2913 	thisThread->waitForEvent(Thread::waitFrameDelay, 0);
2914 	thisThread->setExtended();
2915 	return 0;
2916 }
2917 
2918 //-----------------------------------------------------------------------
2919 //	Play a song (with optional fade-out of old song)
2920 //		void "C" playSong( int songID, int fade );
2921 
scriptPlaySong(int16 * args)2922 int16 scriptPlaySong(int16 *args) {
2923 	MONOLOG(PlaySong);
2924 //	WriteStatusF( args[0], STRING( args[1] ) );
2925 	return 0;
2926 }
2927 
2928 //-----------------------------------------------------------------------
2929 //	Play sound effect (with optional looping) { volume = 0-127 }
2930 //		void "C" playFX( int fxID, int volume, int looped );
2931 
scriptPlayFX(int16 * args)2932 int16 scriptPlayFX(int16 *args) {
2933 	MONOLOG(PlayFX);
2934 //	WriteStatusF( args[0], STRING( args[1] ) );
2935 	return 0;
2936 }
2937 
2938 //-----------------------------------------------------------------------
2939 //	Type-casting function
2940 //		Actor id "C" object2Actor( GameObject id objID );
2941 
scriptObject2Actor(int16 * args)2942 int16 scriptObject2Actor(int16 *args) {
2943 	MONOLOG(Object2Actor);
2944 	//return isActor(args[0]) ? args[0] : Nothing;
2945 	return args[0];
2946 }
2947 
2948 //-----------------------------------------------------------------------
2949 //	Generic script type casting function
2950 
scriptGenericCast(int16 * args)2951 int16 scriptGenericCast(int16 *args) {
2952 	MONOLOG(genericCast);
2953 	return args[0];
2954 }
2955 
2956 //-----------------------------------------------------------------------
2957 //	Create a new object
2958 //		GameObject id "C" makeObject(   int protoID,
2959 //										int nameIndex,
2960 //										int scriptIndex );
2961 
scriptMakeObject(int16 * args)2962 int16 scriptMakeObject(int16 *args) {
2963 	MONOLOG(MakeObject);
2964 	GameObject      *obj = GameObject::newObject();
2965 
2966 	//  REM: We need to throw some kind of SAGA exception...?
2967 	//  (We don't have SAGA exceptions, only the C kind...)
2968 	if (obj == NULL) {
2969 		return 0;
2970 	}
2971 
2972 	obj->setProtoNum(args[0]);
2973 	obj->setNameIndex(args[1]);
2974 	obj->setScript(args[2]);
2975 
2976 	//  If it's a mergeable object, have it's mass count default to 1.
2977 	if (obj->proto()->flags & ResourceObjectPrototype::objPropMergeable)
2978 		obj->setExtra(1);
2979 
2980 	return obj->thisID();
2981 }
2982 
2983 //-----------------------------------------------------------------------
2984 //	Delete an existing object
2985 //		void "C" deleteObject( GameObject id objID );
2986 
scriptDeleteObject(int16 * args)2987 int16 scriptDeleteObject(int16 *args) {
2988 	MONOLOG(DeleteObject);
2989 	GameObject      *obj = GameObject::objectAddress(args[0]);
2990 	ObjectID        oldParentID;
2991 
2992 	assert(obj);
2993 	oldParentID = obj->IDParent();
2994 	obj->deleteObjectRecursive();
2995 	g_vm->_cnm->setUpdate(oldParentID);
2996 
2997 	return 0;
2998 }
2999 
3000 //-----------------------------------------------------------------------
3001 //	Create a new object
3002 //		GameObject id "C" makeActor(    int protoID,
3003 //										int nameIndex,
3004 //										int scriptIndex,
3005 //										string appearance,
3006 //										int color );
3007 
scriptMakeActor(int16 * args)3008 int16 scriptMakeActor(int16 *args) {
3009 	MONOLOG(MakeActor);
3010 	char        *actorAppearanceName = STRING(args[3]);
3011 	int32       actorAppearanceNum;
3012 	Actor       *a;
3013 
3014 	assert(actorAppearanceName);
3015 	actorAppearanceNum = READ_BE_INT32(actorAppearanceName);
3016 
3017 	a = Actor::newActor(
3018 	        args[0],
3019 	        args[1],
3020 	        args[2],
3021 	        actorAppearanceNum,
3022 	        args[4],
3023 	        args[5],
3024 	        args[6]);
3025 
3026 	//  REM: We need to throw some kind of SAGA exception...?
3027 	//  (We don't have SAGA exceptions, only the C kind...)
3028 	if (a == NULL) {
3029 		return 0;
3030 	}
3031 
3032 	return a->thisID();
3033 }
3034 
3035 //-----------------------------------------------------------------------
3036 //	Get the ID of the center actor
3037 //		Actor id "C" getCenterActor( void );
3038 
scriptGetCenterActor(int16 *)3039 int16 scriptGetCenterActor(int16 *) {
3040 	MONOLOG(GetCenterActor);
3041 	return getCenterActorID();
3042 }
3043 
3044 //-----------------------------------------------------------------------
3045 // SAGA Import defs
3046 //
3047 //  void "C" scriptPlaySound( string );
3048 //
3049 //  void "C" scriptPlayVoice( string );
3050 //
3051 //  void "C" scriptPlayLoop( string );
3052 //
3053 //  void "C" scriptPlayMusic( string );
3054 //
3055 
scriptPlaySound(int16 * args)3056 int16 scriptPlaySound(int16 *args) {
3057 	MONOLOG(PlaySound);
3058 	char        *sID = STRING(args[0]);
3059 
3060 	PlaySound(sID);
3061 
3062 	return 0;
3063 }
3064 
3065 uint32 parse_res_id(char IDstr[]);
3066 
scriptPlaySoundAt(int16 * args)3067 int16 scriptPlaySoundAt(int16 *args) {
3068 	MONOLOG(PlaySoundAt);
3069 	char        *sID = STRING(args[0]);
3070 	args++;
3071 	int16       u    = *args++; // << kTileUVShift;
3072 	int16       v    = *args++; // << kTileUVShift;
3073 	int16       h    = *args++;
3074 	Location l = Location(TilePoint(u, v, h), Nothing);
3075 	int32       soundID;
3076 	soundID = parse_res_id(sID);
3077 
3078 	if (soundID) playSoundAt(soundID, l);
3079 
3080 	return 0;
3081 }
3082 
scriptPlaySoundFrom(int16 * args)3083 int16 scriptPlaySoundFrom(int16 *args) {
3084 	MONOLOG(PlaySoundAt);
3085 	char        *sID = STRING(args[0]);
3086 	int32       soundID;
3087 	soundID = parse_res_id(sID);
3088 	GameObject *go = GameObject::objectAddress(args[1]);
3089 	assert(go != NULL);
3090 	if (soundID) playSoundAt(soundID, go->notGetWorldLocation());
3091 
3092 	return 0;
3093 }
3094 
scriptPlayMusic(int16 * args)3095 int16 scriptPlayMusic(int16 *args) {
3096 	MONOLOG(PlayMusic);
3097 	char        *sID = STRING(args[0]);
3098 	PlayMusic(sID);
3099 	return 0;
3100 }
3101 
scriptPlayLoop(int16 * args)3102 int16 scriptPlayLoop(int16 *args) {
3103 	MONOLOG(PlayLoop);
3104 	return 0;
3105 }
3106 
3107 
3108 void PlayLoopAt(char IDstr[], Location l);
3109 
scriptPlayLoopAt(int16 * args)3110 int16 scriptPlayLoopAt(int16 *args) {
3111 	MONOLOG(PlayLoop);
3112 	char        *sID = STRING(args[0]);
3113 	int16       u    = *args++; // << kTileUVShift;
3114 	int16       v    = *args++; // << kTileUVShift;
3115 	int16       h    = *args++;
3116 	Location l = Location(TilePoint(u, v, h), Nothing);
3117 	PlayLoopAt(sID, l);
3118 	return 0;
3119 }
3120 
scriptPlayVoice(int16 * args)3121 int16 scriptPlayVoice(int16 *args) {
3122 	MONOLOG(PlayVoice);
3123 	char        *sID = STRING(args[0]);
3124 	PlayVoice(sID);
3125 	return 0;
3126 }
3127 
3128 //-----------------------------------------------------------------------
3129 //	int "c" getHour( void );
3130 
scriptGetHour(int16 *)3131 int16 scriptGetHour(int16 *) {
3132 	MONOLOG(GetHour);
3133 	return g_vm->_calender->_hour;
3134 }
3135 
3136 //-----------------------------------------------------------------------
3137 //	int "c" getFrameInHour( void );
3138 
scriptGetFrameInHour(int16 *)3139 int16 scriptGetFrameInHour(int16 *) {
3140 	MONOLOG(GetFrameInHour);
3141 	return g_vm->_calender->_frameInHour;
3142 }
3143 
3144 //-----------------------------------------------------------------------
3145 //	int "c" getRandomBetween( int,  int );
3146 
scriptGetRandomBetween(int16 * args)3147 int16 scriptGetRandomBetween(int16 *args) {
3148 	MONOLOG(GetRandomBetween);
3149 	return (GetRandomBetween(args[0], args[1]));
3150 }
3151 
3152 //-----------------------------------------------------------------------
3153 //	Check if Object contained in another object
3154 //		bool "C" isContaining( GameObject id owner, GameObject id object);
3155 
scriptIsContaining(int16 * args)3156 int16 scriptIsContaining(int16 *args) {
3157 	MONOLOG(IsContaining);
3158 	GameObject *containerObject = GameObject::objectAddress(args[0]);
3159 	GameObject *containedObject = GameObject::objectAddress(args[1]);
3160 
3161 	return (containerObject->isContaining(containedObject));
3162 }
3163 
3164 //-----------------------------------------------------------------------
3165 //  void "C" scriptPlayLongSound( string );
3166 
scriptPlayLongSound(int16 * args)3167 int16 scriptPlayLongSound(int16 *args) {
3168 	MONOLOG(PlayLongSound);
3169 	char        *sID = STRING(args[0]);
3170 
3171 	PlayLongSound(sID);
3172 
3173 	return 0;
3174 }
3175 
3176 //-----------------------------------------------------------------------
3177 //   int "C" scriptResID( string  );  GT - 03/04/1996
3178 //   converts a standard HRES resource ID into a 16-bit integer.  The
3179 //   first character is interpreted as thousands, providing a total
3180 //   possible range of between 1-25,999.
3181 //-----------------------------------------------------------------------
3182 
scriptResID(int16 * args)3183 int16 scriptResID(int16 *args) {
3184 	char *sID = STRING(args[0]);
3185 	return (sID[0] - 'A') * 1000 + atoi(&sID[1]);
3186 }
3187 
scriptWorldNum2Object(int16 * args)3188 int16 scriptWorldNum2Object(int16 *args) {
3189 	MONOLOG(WorldNum2Object);
3190 	assert(args[0] >= 0);
3191 	//  REM: I can't seem to find a symbolic constant for the
3192 	//  maximum number of worlds. I know that it's currently 8.
3193 	assert(args[0] < 8);
3194 
3195 	return args[0] + WorldBaseID;
3196 }
3197 
3198 //-----------------------------------------------------------------------
3199 //	Append a set of strings to the book text
3200 //		void "C" bookText( string text, ... );
3201 
scriptAppendBookText(int16 * args)3202 int16 scriptAppendBookText(int16 *args) {
3203 	MONOLOG(AppendBookText);
3204 	//  If optional 4th parameter is present, then set actor facing
3205 	for (int i = 0; i < thisThread->argCount; i++) {
3206 		char        *bookText = STRING(args[i]);
3207 
3208 		appendBookText(bookText);
3209 	}
3210 	return 0;
3211 }
3212 
3213 #if 0
3214 //-----------------------------------------------------------------------
3215 //	Append a single string to the scroll text, with printf formatting
3216 //		void "C" bookTextF( string text, ... );
3217 
3218 int16 scriptAppendScrollTextF(int16 *args) {
3219 	MONOLOG(AppendScrollTextF);
3220 	char        buffer[256];
3221 
3222 	stringf(buffer, sizeof buffer, args[0], &args[1]);
3223 
3224 	appendBookText(buffer);
3225 
3226 	return 0;
3227 }
3228 
3229 //-----------------------------------------------------------------------
3230 //	Append a set of strings to the scroll text
3231 //		void "C" bookText( string text, ... );
3232 
3233 int16 scriptAppendScrollText(int16 *args) {
3234 	MONOLOG(AppendScrollText);
3235 	//  If optional 4th parameter is present, then set actor facing
3236 	for (int i = 0; i < thisThread->argCount; i++) {
3237 		char        *ScrollText = STRING(args[i]);
3238 
3239 		appendBookText(ScrollText);
3240 	}
3241 	return 0;
3242 }
3243 #endif
3244 
3245 //-----------------------------------------------------------------------
3246 //	Append a single string to the book text, with printf formatting
3247 //		void "C" bookTextF( string text, ... );
3248 
scriptAppendBookTextF(int16 * args)3249 int16 scriptAppendBookTextF(int16 *args) {
3250 	MONOLOG(AppendBookTextF);
3251 	char        buffer[256];
3252 
3253 	stringf(buffer, sizeof buffer, args[0], &args[1]);
3254 
3255 	appendBookText(buffer);
3256 
3257 	return 0;
3258 }
3259 
3260 
3261 //-----------------------------------------------------------------------
3262 //	Assert an event for any sensors which might be looking for it
3263 //	void "c" assertEvent(
3264 //		int             type,
3265 //		GameObject id   directObject,
3266 //		GameObject id   indirectObject );
3267 
scriptAssertEvent(int16 * args)3268 int16 scriptAssertEvent(int16 *args) {
3269 	MONOLOG(AssertEvent);
3270 	GameEvent       ev;
3271 
3272 	assert(isObject(args[1]) || isActor(args[1]));
3273 	assert(args[2] == Nothing
3274 	       ||  isObject(args[2])
3275 	       ||  isActor(args[2]));
3276 
3277 	ev.type = args[0];
3278 	ev.directObject = GameObject::objectAddress(args[1]);
3279 	ev.indirectObject = args[2] != Nothing
3280 	                    ?   GameObject::objectAddress(args[2])
3281 	                    :   NULL;
3282 
3283 	assertEvent(ev);
3284 
3285 	return 0;
3286 }
3287 
3288 //-----------------------------------------------------------------------
3289 //	Spell casting
3290 //
3291 //bool "C"  scriptCanCast    (
3292 //				GameObject id casterID,
3293 //				GameObject id spellID);
3294 //
3295 //void "C"  scriptCastSpellAtObject   (
3296 //				GameObject id casterID,
3297 //				GameObject id spellID,
3298 //				GameObject id targetID);
3299 //
3300 //void "C"  scriptCastSpellAtActor    (
3301 //				GameObject id casterID,
3302 //				GameObject id spellID,
3303 //				GameObject id targetID);
3304 //
3305 //void "C"  scriptCastSpellAtWorld    (
3306 //				GameObject id casterID,
3307 //				GameObject id spellID);
3308 //
3309 //void "C"  scriptCastSpellAtTAG      (
3310 //				GameObject id casterID,
3311 //				GameObject id spellID,
3312 //				TileActivityInstance id target);
3313 //
3314 //void "C"  scriptCastSpellAtTile         (
3315 //				GameObject id casterID,
3316 //				GameObject id spellID,
3317 //				int u, int v, int h);
3318 //
3319 
scriptCanCast(int16 * args)3320 int16 scriptCanCast(int16 *args) {
3321 	MONOLOG(CanCast);
3322 	GameObject  *caster = GameObject::objectAddress(*args++);
3323 	SkillProto  *spell  = skillProtoFromID(*args++);
3324 	assert(caster);
3325 	assert(spell);
3326 	return canCast(caster, spell);
3327 }
3328 
scriptCastSpellAtObject(int16 * args)3329 int16 scriptCastSpellAtObject(int16 *args) {
3330 	MONOLOG(CastSpellAtObject);
3331 	GameObject  *caster = GameObject::objectAddress(*args++);
3332 	SkillProto  *spell  = skillProtoFromID(*args++);
3333 	GameObject  *target = GameObject::objectAddress(*args++);
3334 	assert(caster);
3335 	assert(spell);
3336 	assert(target);
3337 	castSpell(caster, target, spell);
3338 	return 0;
3339 }
3340 
scriptCastSpellAtActor(int16 * args)3341 int16 scriptCastSpellAtActor(int16 *args) {
3342 	MONOLOG(CastSpellAtActor);
3343 	GameObject  *caster = GameObject::objectAddress(*args++);
3344 	SkillProto  *spell  = skillProtoFromID(*args++);
3345 	GameObject  *target = GameObject::objectAddress(*args++);
3346 	assert(caster);
3347 	assert(spell);
3348 	assert(target);
3349 	castSpell(caster, target, spell);
3350 	return 0;
3351 }
3352 
scriptCastSpellAtWorld(int16 * args)3353 int16 scriptCastSpellAtWorld(int16 *args) {
3354 	MONOLOG(CastSpellAtWorld);
3355 	GameObject  *caster = GameObject::objectAddress(*args++);
3356 	SkillProto  *spell  = skillProtoFromID(*args++);
3357 	assert(caster);
3358 	assert(spell);
3359 	castUntargetedSpell(caster, spell);
3360 	return 0;
3361 }
3362 
scriptCastSpellAtTAG(int16 * args)3363 int16 scriptCastSpellAtTAG(int16 *args) {
3364 	MONOLOG(CastSpellAtTAG);
3365 	GameObject  *caster = GameObject::objectAddress(*args++);
3366 	SkillProto  *spell  = skillProtoFromID(*args++);
3367 	ActiveItem  *ai     = ActiveItem::activeItemAddress(*args++);
3368 	assert(caster);
3369 	assert(spell);
3370 	assert(ai);
3371 	castSpell(caster, ai, spell);
3372 	return 0;
3373 }
3374 
scriptCastSpellAtTile(int16 * args)3375 int16 scriptCastSpellAtTile(int16 *args) {
3376 	MONOLOG(CastSpellAtTile);
3377 	GameObject  *caster = GameObject::objectAddress(*args++);
3378 	SkillProto  *spell  = skillProtoFromID(*args++);
3379 	int16       u    = *args++; // << kTileUVShift;
3380 	int16       v    = *args++; // << kTileUVShift;
3381 	int16       h    = *args++;
3382 	Location l = Location(TilePoint(u, v, h), Nothing);
3383 	assert(caster);
3384 	assert(spell);
3385 	castSpell(caster, l, spell);
3386 	return 0;
3387 }
3388 
3389 //-----------------------------------------------------------------------
3390 //	Function to select a site for a monster actor or object.
3391 //	returns it's result by filling in the threadCoords therad var.
3392 //	If the return height is negative, then it failed.
3393 //		int "C" SelectNearbySite(   int centerU,
3394 //									int centerV,
3395 //									int centerZ,
3396 //									int centerWorld,
3397 //									int minDist,
3398 //									int maxDist,
3399 //									int offScreenOnly );
3400 
scriptSelectNearbySite(int16 * args)3401 int16 scriptSelectNearbySite(int16 *args) {
3402 	MONOLOG(SelectNearbySite);
3403 	TilePoint       tp;
3404 
3405 	tp = selectNearbySite(args[3],
3406 	                      TilePoint(args[0], args[1], args[2]),
3407 	                      args[4],
3408 	                      args[5],
3409 	                      args[6]);
3410 
3411 	if (tp == Nowhere) return 0;
3412 	scriptCallFrame     &scf = thisThread->threadArgs;
3413 
3414 	scf.coords = tp;
3415 	return true;
3416 }
3417 
3418 //-----------------------------------------------------------------------
3419 //	Pick a random actor who is not dead
3420 //		GameObject id pickRandomLivingActor( ... );
3421 
scriptPickRandomLivingActor(int16 * args)3422 int16 scriptPickRandomLivingActor(int16 *args) {
3423 	MONOLOG(PickRandomLivingActor);
3424 	int             livingCount = 0,
3425 	                i;
3426 
3427 	for (i = 0; i < thisThread->argCount; i++) {
3428 		if (isActor(args[i])) {
3429 			Actor       *a = (Actor *)GameObject::objectAddress(args[i]);
3430 
3431 			if (!a->isDead()) livingCount++;
3432 		}
3433 	}
3434 
3435 	if (livingCount <= 0) return Nothing;
3436 
3437 	livingCount = g_vm->_rnd->getRandomNumber(livingCount - 1);
3438 
3439 	for (i = 0; i < thisThread->argCount; i++) {
3440 		if (isActor(args[i])) {
3441 			Actor       *a = (Actor *)GameObject::objectAddress(args[i]);
3442 
3443 			if (!a->isDead()) {
3444 				if (livingCount == 0) return args[i];
3445 				livingCount--;
3446 			}
3447 		}
3448 	}
3449 
3450 	return Nothing;
3451 }
3452 
3453 //-----------------------------------------------------------------------
3454 //	Create a new mission object
3455 //		int "c" newMission( GameObject id generatorID );
3456 
scriptNewMission(int16 * args)3457 int16 scriptNewMission(int16 *args) {
3458 	MONOLOG(NewMission);
3459 	ActiveMission   *am = ActiveMission::newMission(args[0], args[1]);
3460 
3461 	return am ? am->getMissionID() : -1;
3462 }
3463 
3464 //-----------------------------------------------------------------------
3465 //	Find a mission by generator id
3466 //		int "c" findMission( GameObject id generatorID );
3467 
scriptFindMission(int16 * args)3468 int16 scriptFindMission(int16 *args) {
3469 	MONOLOG(FindMission);
3470 	return ActiveMission::findMission(args[0]);
3471 }
3472 
3473 //-----------------------------------------------------------------------
3474 //	Set the speed of a tile cycling range
3475 //		void "c" setTileCycleSpeed( int range, int speed );
3476 
scriptSetTileCycleSpeed(int16 * args)3477 int16 scriptSetTileCycleSpeed(int16 *args) {
3478 	MONOLOG(SetTileCycleSpeed);
3479 	extern CyclePtr  cycleList;          // list of tile cycling info
3480 
3481 	TileCycleData   &tcd = cycleList[args[0]];
3482 
3483 	tcd.cycleSpeed = args[1];
3484 
3485 	return 0;
3486 }
3487 
3488 //-----------------------------------------------------------------------
3489 //	Set the state of a tile cycling range
3490 //		void "c" setTileCycleState( int range, int state );
3491 
scriptSetTileCycleState(int16 * args)3492 int16 scriptSetTileCycleState(int16 *args) {
3493 	MONOLOG(SetTileCycleState);
3494 	extern CyclePtr  cycleList;          // list of tile cycling info
3495 
3496 	TileCycleData   &tcd = cycleList[args[0]];
3497 
3498 	tcd.currentState = args[1];
3499 	tcd.counter = 0;
3500 
3501 	return 0;
3502 }
3503 
3504 //-----------------------------------------------------------------------
3505 //	Search a region of the tile map to see if any of the indicated
3506 //	objects are within that region.
3507 //		int "c" searchRegion(   GameObject id world,
3508 //								int uMin. int vMin,
3509 //								int uMax, int vMax, ... );
3510 
scriptSearchRegion(int16 * args)3511 int16 scriptSearchRegion(int16 *args) {
3512 	MONOLOG(SearchRegion);
3513 	GameWorld       *worldPtr;
3514 	ObjectID        searchObj;
3515 	int             count = 0;
3516 	TilePoint       minP,
3517 	                maxP;
3518 
3519 	//  Get a pointer to the world
3520 	assert(isWorld(args[0]));
3521 	worldPtr = (GameWorld *)GameObject::objectAddress(args[0]);
3522 	assert(worldPtr != NULL);
3523 
3524 	minP.u = MIN(args[1], args[3]);
3525 	minP.v = MIN(args[2], args[4]);
3526 	minP.z = -128;
3527 	maxP.u = MAX(args[1], args[3]);
3528 	maxP.v = MAX(args[2], args[4]);
3529 	maxP.z = 127;
3530 
3531 	//  Set up an iterator
3532 	RegionalObjectIterator  iter(worldPtr, minP, maxP);
3533 
3534 	//  Iterate through the search region
3535 	for (searchObj = iter.first(NULL);
3536 	        searchObj != Nothing;
3537 	        searchObj = iter.next(NULL)) {
3538 		//  Starting from the 5th argument, until we reach argCount,
3539 		//  see if the iterated object matches one in the arg list
3540 		for (int i = 5; i < thisThread->argCount; i++) {
3541 			if (args[i] == searchObj) {
3542 				count++;
3543 				break;
3544 			}
3545 		}
3546 	}
3547 
3548 	//  Return number of items found
3549 	return count;
3550 }
3551 
3552 //-----------------------------------------------------------------------
3553 //	Helper function: Returns the number of objects in a TileRegion
3554 
countObjectsInRegion(GameWorld * worldPtr,TileRegion & tr)3555 int countObjectsInRegion(GameWorld *worldPtr, TileRegion &tr) {
3556 	ObjectID        searchObj;
3557 	int             count;
3558 
3559 	//  Count how many objects are in the first region
3560 	RegionalObjectIterator  iter(worldPtr,
3561 	                             tr.min,
3562 	                             tr.max);
3563 
3564 	for (searchObj = iter.first(NULL), count = 0;
3565 	        searchObj != Nothing;
3566 	        searchObj = iter.next(NULL)) {
3567 		count++;
3568 	}
3569 
3570 	return count;
3571 }
3572 
3573 //-----------------------------------------------------------------------
3574 //	Helper Function: Returns a list of objects in a tile region
3575 
listObjectsInRegion(GameWorld * worldPtr,TileRegion & tr,ObjectID * list)3576 void listObjectsInRegion(
3577     GameWorld       *worldPtr,
3578     TileRegion      &tr,
3579     ObjectID        *list) {
3580 	ObjectID        searchObj;
3581 
3582 	//  Count how many objects are in the first region
3583 	RegionalObjectIterator  iter(worldPtr,
3584 	                             tr.min,
3585 	                             tr.max);
3586 
3587 	for (searchObj = iter.first(NULL);
3588 	        searchObj != Nothing;
3589 	        searchObj = iter.next(NULL)) {
3590 		*list++ = searchObj;
3591 	}
3592 }
3593 
3594 //-----------------------------------------------------------------------
3595 //	Swap all of the objects within two regions
3596 //		void "c" swapRegions(   GameObject id world1, int u1, int v1,
3597 //								GameObject id world2, int u2, int v2,
3598 //								int uSize, int vSize );
3599 
scriptSwapRegions(int16 * args)3600 int16 scriptSwapRegions(int16 *args) {
3601 	MONOLOG(SwapRegions);
3602 
3603 	ObjectID        worldID1 = args[0],
3604 	                worldID2 = args[3];
3605 	GameWorld       *worldPtr1,
3606 	                *worldPtr2;
3607 	ObjectID        *objArray1,
3608 	                *objArray2;
3609 	int             objCount1,
3610 	                objCount2;
3611 	TileRegion      region1,
3612 	                region2;
3613 
3614 	assert(isWorld(worldID1));
3615 	assert(isWorld(worldID2));
3616 
3617 	worldPtr1 = (GameWorld *)GameObject::objectAddress(worldID1);
3618 	worldPtr2 = (GameWorld *)GameObject::objectAddress(worldID2);
3619 
3620 	assert(worldPtr1 != NULL);
3621 	assert(worldPtr2 != NULL);
3622 
3623 	region1.min.u = args[1];
3624 	region1.min.v = args[2];
3625 	region1.min.z = -128;
3626 	region1.max.u = args[1] + ABS(args[6]);
3627 	region1.max.v = args[2] + ABS(args[7]);
3628 	region1.max.z = 127;
3629 
3630 	region2.min.u = args[4];
3631 	region2.min.v = args[5];
3632 	region2.min.z = -128;
3633 	region2.max.u = args[4] + ABS(args[6]);
3634 	region2.max.v = args[5] + ABS(args[7]);
3635 	region2.max.z = 127;
3636 
3637 	//  Count how many objects are in each region
3638 	objCount1 = countObjectsInRegion(worldPtr1, region1);
3639 	objCount2 = countObjectsInRegion(worldPtr2, region2);
3640 
3641 	//  Allocate an array to hold object ID's for each region
3642 	objArray1 = new ObjectID[objCount1];
3643 	assert(objArray1);
3644 	objArray2 = new ObjectID[objCount2];
3645 	assert(objArray2);
3646 
3647 	//  Get a list of the objects in each region
3648 	listObjectsInRegion(worldPtr1, region1, objArray1);
3649 	listObjectsInRegion(worldPtr2, region2, objArray2);
3650 
3651 	int i;
3652 
3653 	//  Move all the objects in the first list to region 2
3654 	for (i = 0; i < objCount1; i++) {
3655 		GameObject      *obj = GameObject::objectAddress(objArray1[i]);
3656 		Location    loc;
3657 		TilePoint   tp;
3658 
3659 		tp = obj->getLocation();
3660 
3661 		loc.context = worldID2;
3662 		loc.u = tp.u + region2.min.u - region1.min.u;
3663 		loc.v = tp.v + region2.min.v - region1.min.v;
3664 		loc.z = tp.z;
3665 
3666 		obj->move(loc);
3667 	}
3668 
3669 	//  Move all the objects in the second list to region 1
3670 	for (i = 0; i < objCount2; i++) {
3671 		GameObject      *obj = GameObject::objectAddress(objArray2[i]);
3672 		Location    loc;
3673 		TilePoint   tp;
3674 
3675 		tp = obj->getLocation();
3676 
3677 		loc.context = worldID1;
3678 		loc.u = tp.u + region1.min.u - region2.min.u;
3679 		loc.v = tp.v + region1.min.v - region2.min.v;
3680 		loc.z = tp.z;
3681 
3682 		obj->move(loc);
3683 	}
3684 
3685 	delete[] objArray1;
3686 	delete[] objArray2;
3687 
3688 	return 0;
3689 }
3690 
3691 //-----------------------------------------------------------------------
3692 //	Temporarily disable the updating of the tile display
3693 //		void "c" lockTiles( int lockState );
3694 
3695 extern bool tileLockFlag;
3696 
scriptLockTiles(int16 * args)3697 int16 scriptLockTiles(int16 *args) {
3698 	MONOLOG(LockTiles);
3699 	if (args[0] == false) tileLockFlag = false;
3700 	else tileLockFlag = true;
3701 
3702 	return 0;
3703 }
3704 
3705 //-----------------------------------------------------------------------
3706 //	Get the current attitude of a faction
3707 //		int "c" getFactionTally( actor.faction, int column );
3708 
scriptGetFactionTally(int16 * args)3709 int16 scriptGetFactionTally(int16 *args) {
3710 	MONOLOG(GetFactionTally);
3711 	return GetFactionTally(args[0], (enum factionTallyTypes)args[1]);
3712 }
3713 
3714 //-----------------------------------------------------------------------
3715 //	Adjust the attitude of a faction
3716 //		int "c" addFactionTally( actor.faction, int column, int amount );
3717 
scriptAddFactionTally(int16 * args)3718 int16 scriptAddFactionTally(int16 *args) {
3719 	MONOLOG(AddFactionTally);
3720 	return AddFactionTally(args[0], (enum factionTallyTypes)args[1], args[2]);
3721 }
3722 
3723 //-----------------------------------------------------------------------
3724 //	Return the count of how many temp actors of this type exist.
3725 //		int "c" numTempActors( int protoNum );
3726 
3727 extern int16 actorProtoCount;
3728 extern int16 objectProtoCount;
3729 
scriptNumTempActors(int16 * args)3730 int16 scriptNumTempActors(int16 *args) {
3731 	MONOLOG(NumTempActors);
3732 
3733 	assert(args[0] >= 0);
3734 	assert(args[0] < actorProtoCount);
3735 
3736 	return getTempActorCount(args[0]);
3737 }
3738 
3739 //-----------------------------------------------------------------------
3740 //	Return the base price of an object, given the prototype
3741 //		int16 "c" getObjectBasePrice( int protoNum );
3742 
scriptGetObjectBasePrice(int16 * args)3743 int16 scriptGetObjectBasePrice(int16 *args) {
3744 	MONOLOG(GetBaseObjectPrice);
3745 
3746 	assert(args[0] >= 0);
3747 	assert(args[0] < objectProtoCount);
3748 
3749 	return g_vm->_objectProtos[args[0]]->price;
3750 }
3751 
3752 //-----------------------------------------------------------------------
3753 //	Win the game
3754 //		int16 "c" gotoWinMode( void );
3755 
scriptGotoWinMode(int16 * args)3756 int16 scriptGotoWinMode(int16 *args) {
3757 	MONOLOG(gotoWinMode);
3758 	int16 winType = args[0];
3759 	setWintroMode(winType);
3760 	return 0;
3761 }
3762 
3763 
3764 //-----------------------------------------------------------------------
3765 //	open automap
3766 //		void "c" openAutoMap( void );
3767 
scriptOpenAutoMap(int16 * args)3768 int16 scriptOpenAutoMap(int16 *args) {
3769 	MONOLOG(openAutoMap);
3770 	openAutoMap();
3771 	return 0;
3772 }
3773 
3774 
3775 //-----------------------------------------------------------------------
3776 //  play a video
3777 //  void "C" scriptPlayVideo( string );
3778 
scriptPlayVideo(int16 * args)3779 int16 scriptPlayVideo(int16 *args) {
3780 	MONOLOG(PlaySound);
3781 	char        *sID = STRING(args[0]);
3782 
3783 	openVidBox(sID);
3784 
3785 	return 0;
3786 }
3787 
3788 //-----------------------------------------------------------------------
3789 //	Returns the horizontal distance between two objects
3790 //		int "c" distanceBetween( GameObject id obj1, GameObject id obj2 );
3791 
scriptDistanceBetween(int16 * args)3792 int16 scriptDistanceBetween(int16 *args) {
3793 	MONOLOG(distanceBetween);
3794 
3795 	assert((isObject(args[0]) || isActor(args[0]))
3796 	       && (isObject(args[1]) || isActor(args[1])));
3797 
3798 	GameObject      *obj1 = GameObject::objectAddress(args[0]),
3799 	                 *obj2 = GameObject::objectAddress(args[1]);
3800 
3801 	return (obj1->getLocation() - obj2->getLocation()).quickHDistance();
3802 }
3803 
3804 //-----------------------------------------------------------------------
3805 //	Transport the center actor and all banded brothers who have a path
3806 //	to the center actor
3807 //		void "c" transportCenterBand( GameObject id context, int u, int v, int z )
3808 
scriptTransportCenterBand(int16 * args)3809 int16 scriptTransportCenterBand(int16 *args) {
3810 	MONOLOG(transportCenterBand);
3811 
3812 	assert(isWorld(args[0]));
3813 
3814 	transportCenterBand(Location(args[1], args[2], args[3], args[0 ]));
3815 
3816 	return 0;
3817 }
3818 
3819 //-----------------------------------------------------------------------
3820 //	Lock the user interface
3821 //		void "c" lockUI( int locked )
3822 
scriptLockUI(int16 * args)3823 int16 scriptLockUI(int16 *args) {
3824 	MONOLOG(lockUI);
3825 
3826 	noStickyMap();
3827 	LockUI(args[0]);
3828 	return 0;
3829 }
3830 
3831 //-----------------------------------------------------------------------
3832 //	Return number of pending speeches in speech queue
3833 //		int "c" pendingSpeeches( void );
3834 
scriptPendingSpeeches(int16 * args)3835 int16 scriptPendingSpeeches(int16 *args) {
3836 	MONOLOG(PendingSpeeches);
3837 
3838 	return speechList.activeCount();
3839 }
3840 
3841 //-----------------------------------------------------------------------
3842 //	Redraw the main tile display
3843 //		void "c" drawFrame( void );
3844 
scriptDrawFrame(int16 *)3845 int16 scriptDrawFrame(int16 *) {
3846 	MONOLOG(DrawFrame);
3847 
3848 	drawMainDisplay();
3849 	return 0;
3850 }
3851 
3852 //-----------------------------------------------------------------------
3853 //	Fade down the palette - duh
3854 //		void "c" fadeDown( void );
3855 
scriptFadeDown(int16 *)3856 int16 scriptFadeDown(int16 *) {
3857 	MONOLOG(FadeDown);
3858 
3859 	fadeDown();
3860 	return 0;
3861 }
3862 
3863 //-----------------------------------------------------------------------
3864 //	Fade up the palette
3865 //		void "c" fadeUp( void );
3866 
scriptFadeUp(int16 *)3867 int16 scriptFadeUp(int16 *) {
3868 	MONOLOG(FadeUp);
3869 
3870 	fadeUp();
3871 	return 0;
3872 }
3873 
3874 //-----------------------------------------------------------------------
3875 //	Enable or disable script task switching.  Returns previous synchronous
3876 //	setting.
3877 //		int "c" setSynchronous( int val );
3878 
scriptSetSynchronous(int16 * args)3879 int16 scriptSetSynchronous(int16 *args) {
3880 	MONOLOG(SetSynchronous);
3881 
3882 	int16       oldVal = (thisThread->flags & Thread::synchronous) != 0;
3883 
3884 	if (args[0])
3885 		thisThread->flags |= Thread::synchronous;
3886 	else
3887 		thisThread->flags &= ~Thread::synchronous;
3888 
3889 	return oldVal;
3890 }
3891 
3892 //-----------------------------------------------------------------------
3893 //	Multiplication with overflow protection
3894 //		int "c" bigMul( int m1, int m2, int d );
3895 
scriptBigMul(int16 * args)3896 int16 scriptBigMul(int16 *args) {
3897 	MONOLOG(BigMul);
3898 
3899 	long        result = (long)args[0] * (long)args[1];
3900 
3901 	if (args[2] == 0) result = 0;
3902 	else result /= args[2];
3903 
3904 	result = clamp((short)minint16, (long)result, (short)maxint16);
3905 
3906 	return (int16)result;
3907 }
3908 
3909 //-----------------------------------------------------------------------
3910 //	Global script call table
3911 
3912 C_Call *globalCFuncList[] = {
3913 	scriptWriteMessage,
3914 	scriptStatus,
3915 	scriptErrorDialog,
3916 	scriptMessageDialog,
3917 	scriptChoiceDialog,
3918 	scriptPlacard,
3919 	scriptLockDisplay,
3920 	scriptSetGameMode,
3921 
3922 	scriptWait,
3923 	scriptWaitFrames,
3924 
3925 	scriptPlaySong,
3926 	scriptPlayFX,
3927 
3928 	scriptObject2Actor,
3929 
3930 	scriptGenericCast,
3931 	scriptGenericCast,
3932 	scriptGenericCast,
3933 	scriptGenericCast,
3934 	scriptGenericCast,
3935 	scriptGenericCast,
3936 
3937 	scriptWriteLog,
3938 	scriptWriteObject,
3939 	scriptMakeObject,
3940 	scriptDeleteObject,
3941 	scriptMakeActor,
3942 	scriptGetCenterActor,
3943 
3944 	scriptPlaySound,
3945 	scriptPlayVoice,
3946 	scriptPlayMusic,
3947 	scriptPlayLoop,
3948 	scriptResID,
3949 
3950 	scriptGetHour,
3951 	scriptGetFrameInHour,
3952 	scriptGetRandomBetween,
3953 	scriptIsContaining,
3954 	scriptPlayLongSound,
3955 	scriptWorldNum2Object,
3956 
3957 	scriptAppendBookText,
3958 	scriptAppendBookTextF,
3959 	scriptAppendBookText,   //  scriptAppendScrollText,
3960 	scriptAppendBookTextF,  //  scriptAppendScrollText,
3961 
3962 	scriptCastSpellAtObject,
3963 	scriptCastSpellAtActor,
3964 	scriptCastSpellAtWorld,
3965 	scriptCastSpellAtTAG,
3966 	scriptCastSpellAtTile,
3967 
3968 	scriptAssertEvent,
3969 
3970 	scriptSelectNearbySite,
3971 
3972 	scriptPickRandomLivingActor,
3973 	scriptNewMission,
3974 	scriptFindMission,
3975 
3976 	scriptSetTileCycleSpeed,
3977 	scriptSetTileCycleState,
3978 
3979 	scriptSearchRegion,
3980 	scriptSwapRegions,
3981 	scriptLockTiles,
3982 
3983 	scriptGetFactionTally,
3984 	scriptAddFactionTally,
3985 
3986 	scriptNumTempActors,
3987 	scriptGetObjectBasePrice,
3988 
3989 	scriptGotoWinMode,
3990 	scriptOpenAutoMap,
3991 
3992 	scriptCanCast,
3993 
3994 	scriptPlayVideo,
3995 
3996 	scriptDistanceBetween,
3997 
3998 	scriptTransportCenterBand,
3999 	scriptLockUI,
4000 
4001 	scriptPendingSpeeches,
4002 
4003 	scriptDrawFrame,
4004 	scriptFadeDown,
4005 	scriptFadeUp,
4006 
4007 	scriptSetSynchronous,
4008 
4009 	scriptPlaySoundAt,
4010 	scriptPlaySoundFrom,
4011 	scriptPlayLoopAt,
4012 
4013 	scriptBigMul,
4014 };
4015 
4016 CallTable   globalCFuncs = { globalCFuncList, ARRAYSIZE(globalCFuncList), 0 };
4017 
4018 } // end of namespace Saga2
4019