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