1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #ifdef ENABLE_HE
24
25 #include "common/config-manager.h"
26 #include "common/savefile.h"
27 #include "common/system.h"
28
29 #include "scumm/actor.h"
30 #include "scumm/charset.h"
31 #include "scumm/dialogs.h"
32 #include "scumm/file.h"
33 #include "scumm/he/intern_he.h"
34 #include "scumm/object.h"
35 #include "scumm/resource.h"
36 #include "scumm/scumm.h"
37 #include "scumm/he/sound_he.h"
38 #include "scumm/util.h"
39 #include "scumm/verbs.h"
40
41 namespace Scumm {
42
43 #define OPCODE(i, x) _opcodes[i]._OPCODE(ScummEngine_v72he, x)
44
setupOpcodes()45 void ScummEngine_v72he::setupOpcodes() {
46 ScummEngine_v71he::setupOpcodes();
47
48 OPCODE(0x02, o72_pushDWord);
49 OPCODE(0x04, o72_getScriptString);
50 _opcodes[0x0a].setProc(0, 0);
51 OPCODE(0x1b, o72_isAnyOf);
52 _opcodes[0x42].setProc(0, 0);
53 _opcodes[0x46].setProc(0, 0);
54 _opcodes[0x4a].setProc(0, 0);
55 _opcodes[0x4e].setProc(0, 0);
56 OPCODE(0x50, o72_resetCutscene);
57 OPCODE(0x52, o72_findObjectWithClassOf);
58 OPCODE(0x54, o72_getObjectImageX);
59 OPCODE(0x55, o72_getObjectImageY);
60 OPCODE(0x56, o72_captureWizImage);
61 OPCODE(0x58, o72_getTimer);
62 OPCODE(0x59, o72_setTimer);
63 OPCODE(0x5a, o72_getSoundPosition);
64 OPCODE(0x5e, o72_startScript);
65 OPCODE(0x60, o72_startObject);
66 OPCODE(0x61, o72_drawObject);
67 OPCODE(0x62, o72_printWizImage);
68 OPCODE(0x63, o72_getArrayDimSize);
69 OPCODE(0x64, o72_getNumFreeArrays);
70 _opcodes[0x97].setProc(0, 0); // was: o6_setObjectName
71 OPCODE(0x9c, o72_roomOps);
72 OPCODE(0x9d, o72_actorOps);
73 OPCODE(0x9e, o72_verbOps);
74 OPCODE(0xa0, o72_findObject);
75 OPCODE(0xa4, o72_arrayOps);
76 OPCODE(0xae, o72_systemOps);
77 OPCODE(0xba, o72_talkActor);
78 OPCODE(0xbb, o72_talkEgo);
79 OPCODE(0xbc, o72_dimArray);
80 OPCODE(0xc0, o72_dim2dimArray);
81 OPCODE(0xc1, o72_traceStatus);
82 OPCODE(0xc8, o72_kernelGetFunctions);
83 OPCODE(0xce, o72_drawWizImage);
84 OPCODE(0xcf, o72_debugInput);
85 OPCODE(0xd5, o72_jumpToScript);
86 OPCODE(0xda, o72_openFile);
87 OPCODE(0xdb, o72_readFile);
88 OPCODE(0xdc, o72_writeFile);
89 OPCODE(0xdd, o72_findAllObjects);
90 OPCODE(0xde, o72_deleteFile);
91 OPCODE(0xdf, o72_rename);
92 OPCODE(0xe1, o72_getPixel);
93 OPCODE(0xe3, o72_pickVarRandom);
94 OPCODE(0xea, o72_redimArray);
95 OPCODE(0xf3, o72_readINI);
96 OPCODE(0xf4, o72_writeINI);
97 OPCODE(0xf8, o72_getResourceSize);
98 OPCODE(0xf9, o72_createDirectory);
99 OPCODE(0xfa, o72_setSystemMessage);
100 }
101
102 static const int arrayDataSizes[] = { 0, 1, 4, 8, 8, 16, 32 };
103
defineArray(int array,int type,int dim2start,int dim2end,int dim1start,int dim1end)104 byte *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim2end,
105 int dim1start, int dim1end) {
106 int id;
107 int size;
108 ArrayHeader *ah;
109
110 assert(dim2start >= 0 && dim2start <= dim2end);
111 assert(dim1start >= 0 && dim1start <= dim1end);
112 assert(0 <= type && type <= 6);
113
114
115 if (type == kBitArray || type == kNibbleArray)
116 type = kByteArray;
117
118 nukeArray(array);
119
120 id = findFreeArrayId();
121
122 debug(9, "defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
123
124 if (array & 0x80000000) {
125 error("Can't define bit variable as array pointer");
126 }
127
128 size = arrayDataSizes[type];
129
130 if (_game.heversion >= 80)
131 id |= 0x33539000;
132
133 writeVar(array, id);
134
135 if (_game.heversion >= 80)
136 id &= ~0x33539000;
137
138 size *= dim2end - dim2start + 1;
139 size *= dim1end - dim1start + 1;
140 size >>= 3;
141
142 ah = (ArrayHeader *)_res->createResource(rtString, id, size + sizeof(ArrayHeader));
143
144 ah->type = TO_LE_32(type);
145 ah->dim1start = TO_LE_32(dim1start);
146 ah->dim1end = TO_LE_32(dim1end);
147 ah->dim2start = TO_LE_32(dim2start);
148 ah->dim2end = TO_LE_32(dim2end);
149
150 return ah->data;
151 }
152
readArray(int array,int idx2,int idx1)153 int ScummEngine_v72he::readArray(int array, int idx2, int idx1) {
154 debug(9, "readArray (array %d, idx2 %d, idx1 %d)", readVar(array), idx2, idx1);
155
156 if (readVar(array) == 0)
157 error("readArray: Reference to zeroed array pointer");
158
159 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
160
161 if (!ah)
162 error("readArray: invalid array %d (%d)", array, readVar(array));
163
164 if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) ||
165 idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) {
166 error("readArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]",
167 array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end),
168 FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end));
169 }
170
171 const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
172 (idx2 - FROM_LE_32(ah->dim2start)) + (idx1 - FROM_LE_32(ah->dim1start));
173
174 switch (FROM_LE_32(ah->type)) {
175 case kByteArray:
176 case kStringArray:
177 return ah->data[offset];
178
179 case kIntArray:
180 return (int16)READ_LE_UINT16(ah->data + offset * 2);
181
182 case kDwordArray:
183 return (int32)READ_LE_UINT32(ah->data + offset * 4);
184 }
185
186 return 0;
187 }
188
writeArray(int array,int idx2,int idx1,int value)189 void ScummEngine_v72he::writeArray(int array, int idx2, int idx1, int value) {
190 debug(9, "writeArray (array %d, idx2 %d, idx1 %d, value %d)", readVar(array), idx2, idx1, value);
191
192 if (readVar(array) == 0)
193 error("writeArray: Reference to zeroed array pointer");
194
195 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
196
197 if (!ah)
198 error("writeArray: Invalid array (%d) reference", readVar(array));
199
200 if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) ||
201 idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) {
202 error("writeArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]",
203 array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end),
204 FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end));
205 }
206
207 const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
208 (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1;
209
210 switch (FROM_LE_32(ah->type)) {
211 case kByteArray:
212 case kStringArray:
213 ah->data[offset] = value;
214 break;
215
216 case kIntArray:
217 WRITE_LE_UINT16(ah->data + offset * 2, value);
218 break;
219
220 case kDwordArray:
221 WRITE_LE_UINT32(ah->data + offset * 4, value);
222 break;
223 }
224 }
225
setupStringArray(int size)226 int ScummEngine_v72he::setupStringArray(int size) {
227 writeVar(0, 0);
228 defineArray(0, kStringArray, 0, 0, 0, size + 1);
229 writeArray(0, 0, 0, 0);
230 return readVar(0);
231 }
232
setupStringArrayFromString(const char * cStr)233 int ScummEngine_v72he::setupStringArrayFromString(const char *cStr) {
234 // this is PUI_ScummStringArrayFromCString() found in PUSERMAC.cpp
235 // I can see how its done up there in setupStringArray()
236 // yet I'd note that 'SCUMMVAR_user_reserved' var was used instead of 0
237 // and strlen(), not strlen() + 1 was used
238 // plus, this function actually copies the string, not just 'sets up' the array
239
240 writeVar(0, 0);
241
242 int len = strlen(cStr) + 1;
243 byte *ptr = defineArray(0, kStringArray, 0, 0, 0, len);
244 if (ptr != nullptr)
245 Common::strlcpy((char*)ptr, cStr, len);
246
247 return readVar(0);
248 }
249
readArrayFromIndexFile()250 void ScummEngine_v72he::readArrayFromIndexFile() {
251 int num;
252 int a, b, c;
253
254 while ((num = _fileHandle->readUint16LE()) != 0) {
255 a = _fileHandle->readUint16LE();
256 b = _fileHandle->readUint16LE();
257 c = _fileHandle->readUint16LE();
258
259 if (c == 1)
260 defineArray(num, kBitArray, 0, a, 0, b);
261 else
262 defineArray(num, kDwordArray, 0, a, 0, b);
263 }
264 }
265
copyScriptString(byte * dst,int dstSize)266 void ScummEngine_v72he::copyScriptString(byte *dst, int dstSize) {
267 byte string[1024];
268 byte chr;
269 int pos = 0;
270
271 int array = pop();
272 if (array == -1) {
273 if (_stringLength == 1)
274 error("String stack underflow");
275
276 _stringLength -= 2;
277 while ((chr = _stringBuffer[_stringLength]) != 0) {
278 string[pos] = chr;
279 pos++;
280
281 if (pos > dstSize)
282 error("String too long to pop");
283
284 _stringLength--;
285 }
286
287 string[pos] = 0;
288 _stringLength++;
289
290 // Reverse string
291 int len = resStrLen(string);
292 while (len--)
293 *dst++ = string[len];
294 } else {
295 writeVar(0, array);
296 while ((chr = readArray(0, 0, pos)) != 0) {
297 *dst++ = chr;
298 pos++;
299 }
300 }
301 *dst = 0;
302 }
303
decodeScriptString(byte * dst,bool scriptString)304 void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) {
305 const byte *src;
306 int args[31];
307 int num, len, val;
308 byte chr, string[1024];
309 memset(args, 0, sizeof(args));
310 memset(string, 0, sizeof(string));
311
312 // Get stack list, plus one
313 num = pop();
314 for (int i = num; i >= 0; i--)
315 args[i] = pop();
316
317 // Get string
318 if (scriptString) {
319 len = resStrLen(_scriptPointer) + 1;
320 memcpy(string, _scriptPointer, len);
321 _scriptPointer += len;
322 } else {
323 copyScriptString(string, sizeof(string));
324 len = resStrLen(string) + 1;
325 }
326
327 // Decode string
328 num = 0;
329 val = 0;
330 while (len--) {
331 chr = string[num++];
332 if (chr == '%') {
333 chr = string[num++];
334 switch (chr) {
335 case 'b':
336 //dst += sprintf((char *)dst, "%b", args[val++]);
337 break;
338 case 'c':
339 *dst++ = args[val++];
340 break;
341 case 'd':
342 dst += sprintf((char *)dst, "%d", args[val++]);
343 break;
344 case 's':
345 src = getStringAddress(args[val++]);
346 if (src) {
347 while (*src != 0)
348 *dst++ = *src++;
349 }
350 break;
351 case 'x':
352 dst += sprintf((char *)dst, "%x", args[val++]);
353 break;
354 default:
355 *dst++ = '%';
356 num--;
357 break;
358 }
359 } else {
360 *dst++ = chr;
361 }
362 }
363 *dst = 0;
364 }
365
findObject(int x,int y,int num,int * args)366 int ScummEngine_v72he::findObject(int x, int y, int num, int *args) {
367 int b, cls, i, result;
368
369 for (i = 1; i < _numLocalObjects; i++) {
370 result = 0;
371 if ((_objs[i].obj_nr < 1) || getClass(_objs[i].obj_nr, kObjectClassUntouchable))
372 continue;
373
374 // Check polygon bounds
375 if (_wiz->polygonDefined(_objs[i].obj_nr)) {
376 if (_wiz->polygonHit(_objs[i].obj_nr, x, y))
377 result = _objs[i].obj_nr;
378 else if (VAR_POLYGONS_ONLY != 0xFF && VAR(VAR_POLYGONS_ONLY))
379 continue;
380 }
381
382 if (!result) {
383 // Check object bounds
384 if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x &&
385 _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y)
386 result = _objs[i].obj_nr;
387 }
388
389 if (result) {
390 if (!num)
391 return result;
392
393 // Check object class
394 cls = args[0];
395 b = getClass(_objs[i].obj_nr, cls);
396 if ((cls & 0x80 && b) || (!(cls & 0x80) && !b))
397 return result;
398 }
399 }
400
401 return 0;
402 }
403
o72_pushDWord()404 void ScummEngine_v72he::o72_pushDWord() {
405 push(fetchScriptDWordSigned());
406 }
407
o72_getScriptString()408 void ScummEngine_v72he::o72_getScriptString() {
409 byte chr;
410
411 while ((chr = fetchScriptByte()) != 0) {
412 _stringBuffer[_stringLength] = chr;
413 _stringLength++;
414
415 if (_stringLength >= 4096)
416 error("String stack overflow");
417 }
418
419 _stringBuffer[_stringLength] = 0;
420 _stringLength++;
421 }
422
o72_isAnyOf()423 void ScummEngine_v72he::o72_isAnyOf() {
424 int args[128];
425 int num, value;
426
427 num = getStackList(args, ARRAYSIZE(args));
428 value = pop();
429
430 for (int i = 0; i < num; i++) {
431 if (args[i] == value) {
432 push(1);
433 return;
434 }
435 }
436
437 push(0);
438 }
439
o72_resetCutscene()440 void ScummEngine_v72he::o72_resetCutscene() {
441 int idx;
442
443 idx = vm.cutSceneStackPointer;
444 vm.cutSceneStackPointer = 0;
445 vm.cutScenePtr[idx] = 0;
446 vm.cutSceneScript[idx] = 0;
447
448 VAR(VAR_OVERRIDE) = 0;
449 }
450
o72_findObjectWithClassOf()451 void ScummEngine_v72he::o72_findObjectWithClassOf() {
452 int args[16], num;
453
454 num = getStackList(args, ARRAYSIZE(args));
455 int y = pop();
456 int x = pop();
457 int r = findObject(x, y, num, args);
458 push(r);
459 }
460
o72_getObjectImageX()461 void ScummEngine_v72he::o72_getObjectImageX() {
462 int object = pop();
463 int objnum = getObjectIndex(object);
464
465 if (objnum == -1) {
466 push(0);
467 return;
468 }
469
470 push(_objs[objnum].x_pos / 8);
471 }
472
o72_getObjectImageY()473 void ScummEngine_v72he::o72_getObjectImageY() {
474 int object = pop();
475 int objnum = getObjectIndex(object);
476
477 if (objnum == -1) {
478 push(0);
479 return;
480 }
481
482 push(_objs[objnum].y_pos / 8);
483 }
484
o72_captureWizImage()485 void ScummEngine_v72he::o72_captureWizImage() {
486 Common::Rect grab;
487 grab.bottom = pop() + 1;
488 grab.right = pop() + 1;
489 grab.top = pop();
490 grab.left = pop();
491 _wiz->captureWizImage(pop(), grab, false, true);
492 }
493
o72_getTimer()494 void ScummEngine_v72he::o72_getTimer() {
495 int timer = pop();
496 byte cmd = fetchScriptByte();
497
498 if (cmd == 10 || cmd == 50) {
499 push(getHETimer(timer));
500 } else {
501 push(0);
502 }
503 }
504
o72_setTimer()505 void ScummEngine_v72he::o72_setTimer() {
506 int timer = pop();
507 byte cmd = fetchScriptByte();
508
509 if (cmd == 158 || cmd == 61) {
510 setHETimer(timer);
511 } else {
512 error("TIMER command %d?", cmd);
513 }
514 }
515
o72_getSoundPosition()516 void ScummEngine_v72he::o72_getSoundPosition() {
517 int snd = pop();
518 push(((SoundHE *)_sound)->getSoundPos(snd));
519 }
520
o72_startScript()521 void ScummEngine_v72he::o72_startScript() {
522 int args[25];
523 int script;
524 byte flags;
525
526 getStackList(args, ARRAYSIZE(args));
527 script = pop();
528 flags = fetchScriptByte();
529
530 // HACK: The credits script in Russian HE99 version of Freddi Fish 3
531 // uses null strings, causing various errors, so skip it.
532 if (_game.id == GID_FREDDI3 && _game.heversion == 99 && _language == Common::RU_RUS &&
533 _currentRoom == 40 && script == 2057) {
534 return;
535 }
536
537 runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args);
538 }
539
o72_startObject()540 void ScummEngine_v72he::o72_startObject() {
541 int args[25];
542 int script, entryp;
543 byte flags;
544
545 getStackList(args, ARRAYSIZE(args));
546 entryp = pop();
547 script = pop();
548 flags = fetchScriptByte();
549 runObjectScript(script, entryp, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args);
550 }
551
o72_drawObject()552 void ScummEngine_v72he::o72_drawObject() {
553 byte subOp = fetchScriptByte();
554 int state, y, x;
555
556 switch (subOp) {
557 case 62:
558 state = pop();
559 y = pop();
560 x = pop();
561 break;
562 case 63:
563 state = pop();
564 if (state == 0)
565 state = 1;
566 y = x = -100;
567 break;
568 case 65:
569 state = 1;
570 y = pop();
571 x = pop();
572 break;
573 default:
574 error("o72_drawObject: default case %d", subOp);
575 }
576
577 int object = pop();
578 int objnum = getObjectIndex(object);
579 if (objnum == -1)
580 return;
581
582 if (y != -100 && x != -100) {
583 _objs[objnum].x_pos = x * 8;
584 _objs[objnum].y_pos = y * 8;
585 }
586
587 if (state != -1) {
588 addObjectToDrawQue(objnum);
589 putState(object, state);
590 }
591 }
592
o72_printWizImage()593 void ScummEngine_v72he::o72_printWizImage() {
594 WizImage wi;
595 wi.resNum = pop();
596 wi.x1 = wi.y1 = 0;
597 wi.state = 0;
598 wi.flags = kWIFPrint;
599 _wiz->displayWizImage(&wi);
600 }
601
o72_getArrayDimSize()602 void ScummEngine_v72he::o72_getArrayDimSize() {
603 byte subOp = fetchScriptByte();
604 int32 val1, val2;
605 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(fetchScriptWord()));
606 if (!ah) {
607 push(0);
608 return;
609 }
610
611 switch (subOp) {
612 case 1:
613 case 3:
614 val1 = FROM_LE_32(ah->dim1end);
615 val2 = FROM_LE_32(ah->dim1start);
616 push(val1 - val2 + 1);
617 break;
618 case 2:
619 val1 = FROM_LE_32(ah->dim2end);
620 val2 = FROM_LE_32(ah->dim2start);
621 push(val1 - val2 + 1);
622 break;
623 case 4:
624 push(FROM_LE_32(ah->dim1start));
625 break;
626 case 5:
627 push(FROM_LE_32(ah->dim1end));
628 break;
629 case 6:
630 push(FROM_LE_32(ah->dim2start));
631 break;
632 case 7:
633 push(FROM_LE_32(ah->dim2end));
634 break;
635 default:
636 error("o72_getArrayDimSize: default case %d", subOp);
637 }
638 }
639
o72_getNumFreeArrays()640 void ScummEngine_v72he::o72_getNumFreeArrays() {
641 const ResourceManager::ResTypeData &rtd = _res->_types[rtString];
642 int i, num = 0;
643
644 for (i = 1; i < _numArray; i++) {
645 if (!rtd[i]._address)
646 num++;
647 }
648
649 push(num);
650 }
651
o72_roomOps()652 void ScummEngine_v72he::o72_roomOps() {
653 int a, b, c, d, e;
654
655 byte subOp = fetchScriptByte();
656
657 switch (subOp) {
658 case 172: // SO_ROOM_SCROLL
659 b = pop();
660 a = pop();
661 if (a < (_screenWidth / 2))
662 a = (_screenWidth / 2);
663 if (b < (_screenWidth / 2))
664 b = (_screenWidth / 2);
665 if (a > _roomWidth - (_screenWidth / 2))
666 a = _roomWidth - (_screenWidth / 2);
667 if (b > _roomWidth - (_screenWidth / 2))
668 b = _roomWidth - (_screenWidth / 2);
669 VAR(VAR_CAMERA_MIN_X) = a;
670 VAR(VAR_CAMERA_MAX_X) = b;
671 break;
672
673 case 174: // SO_ROOM_SCREEN
674 b = pop();
675 a = pop();
676 initScreens(a, _screenHeight);
677 break;
678
679 case 175: // SO_ROOM_PALETTE
680 d = pop();
681 c = pop();
682 b = pop();
683 a = pop();
684 setPalColor(d, a, b, c);
685 break;
686
687 case 179: // SO_ROOM_INTENSITY
688 c = pop();
689 b = pop();
690 a = pop();
691 darkenPalette(a, a, a, b, c);
692 break;
693
694 case 180: // SO_ROOM_SAVEGAME
695 _saveTemporaryState = true;
696 _saveLoadSlot = pop();
697 _saveLoadFlag = pop();
698 break;
699
700 case 181: // SO_ROOM_FADE
701 // Defaults to 1 but doesn't use fade effects
702 a = pop();
703 break;
704
705 case 182: // SO_RGB_ROOM_INTENSITY
706 e = pop();
707 d = pop();
708 c = pop();
709 b = pop();
710 a = pop();
711 darkenPalette(a, b, c, d, e);
712 break;
713
714 case 213: // SO_ROOM_NEW_PALETTE
715 a = pop();
716 setCurrentPalette(a);
717 break;
718
719 case 220: // SO_ROOM_COPY_PALETTE
720 a = pop();
721 b = pop();
722 copyPalColor(a, b);
723 break;
724
725 case 221: // SO_ROOM_SAVEGAME_BY_NAME
726 byte buffer[256];
727
728 copyScriptString((byte *)buffer, sizeof(buffer));
729
730 _saveLoadFileName = (char *)buffer;
731 debug(1, "o72_roomOps: case 221: filename %s", _saveLoadFileName.c_str());
732
733 _saveLoadFlag = pop();
734 _saveLoadSlot = 255;
735 _saveTemporaryState = true;
736 break;
737
738 case 234: // SO_OBJECT_ORDER
739 b = pop();
740 a = pop();
741 swapObjects(a, b);
742 break;
743
744 case 236: // SO_ROOM_PALETTE_IN_ROOM
745 b = pop();
746 a = pop();
747 setRoomPalette(a, b);
748 break;
749
750 default:
751 error("o72_roomOps: default case %d", subOp);
752 }
753 }
754
o72_actorOps()755 void ScummEngine_v72he::o72_actorOps() {
756 ActorHE *a;
757 int i, j, k;
758 int args[32];
759 byte string[256];
760
761 byte subOp = fetchScriptByte();
762 if (subOp == 197) {
763 _curActor = pop();
764 return;
765 }
766
767 a = (ActorHE *)derefActorSafe(_curActor, "o72_actorOps");
768 if (!a)
769 return;
770
771 switch (subOp) {
772 case 21: // SO_CONDITION (HE 80+)
773 k = getStackList(args, ARRAYSIZE(args));
774 for (i = 0; i < k; ++i) {
775 a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
776 }
777 break;
778 case 24: // SO_TALK_CONDITION (HE 80+)
779 k = pop();
780 if (k == 0)
781 k = _rnd.getRandomNumberRng(1, 10);
782 a->_heNoTalkAnimation = 1;
783 a->setTalkCondition(k);
784 break;
785 case 43: // SO_PRIORITY (HE 90+)
786 a->_layer = pop();
787 a->_needRedraw = true;
788 break;
789 case 64: // SO_ACTOR_DEFAULT_CLIPPED
790 _actorClipOverride.bottom = pop();
791 _actorClipOverride.right = pop();
792 _actorClipOverride.top = pop();
793 _actorClipOverride.left = pop();
794 adjustRect(_actorClipOverride);
795 break;
796 case 65: // SO_AT (HE 98+)
797 j = pop();
798 i = pop();
799 a->putActor(i, j);
800 break;
801 case 67: // SO_CLIPPED (HE 99+)
802 a->_clipOverride.bottom = pop();
803 a->_clipOverride.right = pop();
804 a->_clipOverride.top = pop();
805 a->_clipOverride.left = pop();
806 adjustRect(a->_clipOverride);
807 break;
808 case 68: // // SO_ERASE (HE 90+)
809 k = pop();
810 a->setHEFlag(1, k);
811 break;
812 case 76: // SO_COSTUME
813 a->setActorCostume(pop());
814 break;
815 case 77: // SO_STEP_DIST
816 j = pop();
817 i = pop();
818 a->setActorWalkSpeed(i, j);
819 break;
820 case 78: // SO_SOUND
821 k = getStackList(args, ARRAYSIZE(args));
822 for (i = 0; i < k; i++)
823 a->_sound[i] = args[i];
824 break;
825 case 79: // SO_WALK_ANIMATION
826 a->_walkFrame = pop();
827 break;
828 case 80: // SO_TALK_ANIMATION
829 a->_talkStopFrame = pop();
830 a->_talkStartFrame = pop();
831 break;
832 case 81: // SO_STAND_ANIMATION
833 a->_standFrame = pop();
834 break;
835 case 82: // SO_ANIMATION
836 // dummy case in scumm6
837 pop();
838 pop();
839 pop();
840 break;
841 case 83: // SO_DEFAULT
842 a->initActor(0);
843 break;
844 case 84: // SO_ELEVATION
845 a->setElevation(pop());
846 break;
847 case 85: // SO_ANIMATION_DEFAULT
848 a->_initFrame = 1;
849 a->_walkFrame = 2;
850 a->_standFrame = 3;
851 a->_talkStartFrame = 4;
852 a->_talkStopFrame = 5;
853 break;
854 case 86: // SO_PALETTE
855 j = pop();
856 i = pop();
857 assertRange(0, i, 255, "palette slot");
858 a->remapActorPaletteColor(i, j);
859 a->_needRedraw = true;
860 break;
861 case 87: // SO_TALK_COLOR
862 a->_talkColor = pop();
863 break;
864 case 88: // SO_ACTOR_NAME
865 copyScriptString(string, sizeof(string));
866 loadPtrToResource(rtActorName, a->_number, string);
867 break;
868 case 89: // SO_INIT_ANIMATION
869 a->_initFrame = pop();
870 break;
871 case 91: // SO_ACTOR_WIDTH
872 a->_width = pop();
873 break;
874 case 92: // SO_SCALE
875 i = pop();
876 a->setScale(i, i);
877 break;
878 case 93: // SO_NEVER_ZCLIP
879 a->_forceClip = 0;
880 break;
881 case 94: // SO_ALWAYS_ZCLIP
882 a->_forceClip = pop();
883 break;
884 case 95: // SO_IGNORE_BOXES
885 a->_ignoreBoxes = 1;
886 a->_forceClip = 0;
887 if (a->isInCurrentRoom())
888 a->putActor();
889 break;
890 case 96: // SO_FOLLOW_BOXES
891 a->_ignoreBoxes = 0;
892 a->_forceClip = 0;
893 if (a->isInCurrentRoom())
894 a->putActor();
895 break;
896 case 97: // SO_ANIMATION_SPEED
897 a->setAnimSpeed(pop());
898 break;
899 case 98: // SO_SHADOW
900 a->_heXmapNum = pop();
901 a->_needRedraw = true;
902 break;
903 case 99: // SO_TEXT_OFFSET
904 a->_talkPosY = pop();
905 a->_talkPosX = pop();
906 break;
907 case 156: // SO_CHARSET (HE 72+)
908 a->_charset = pop();
909 break;
910 case 175: // SO_ROOM_PALETTE (HE 99+)
911 a->_hePaletteNum = pop();
912 a->_needRedraw = true;
913 break;
914 case 198: // SO_ACTOR_VARIABLE
915 i = pop();
916 a->setAnimVar(pop(), i);
917 break;
918 case 215: // SO_ACTOR_IGNORE_TURNS_ON
919 a->_ignoreTurns = true;
920 break;
921 case 216: // SO_ACTOR_IGNORE_TURNS_OFF
922 a->_ignoreTurns = false;
923 break;
924 case 217: // SO_ACTOR_NEW
925 a->initActor(2);
926 break;
927 case 218: // SO_BACKGROUND_ON
928 a->drawActorToBackBuf(a->getPos().x, a->getPos().y);
929 break;
930 case 219: // SO_BACKGROUND_OFF
931 a->_drawToBackBuf = false;
932 a->_needRedraw = true;
933 a->_needBgReset = true;
934 break;
935 case 225: // SO_TALKIE
936 {
937 copyScriptString(string, sizeof(string));
938 int slot = pop();
939
940 int len = resStrLen(string) + 1;
941 memcpy(a->_heTalkQueue[slot].sentence, string, len);
942
943 a->_heTalkQueue[slot].posX = a->_talkPosX;
944 a->_heTalkQueue[slot].posY = a->_talkPosY;
945 a->_heTalkQueue[slot].color = a->_talkColor;
946 break;
947 }
948 default:
949 error("o72_actorOps: default case %d", subOp);
950 }
951 }
952
o72_verbOps()953 void ScummEngine_v72he::o72_verbOps() {
954 int slot, a, b;
955 VerbSlot *vs;
956 byte name[200];
957
958 byte subOp = fetchScriptByte();
959 if (subOp == 196) {
960 _curVerb = pop();
961 _curVerbSlot = getVerbSlot(_curVerb, 0);
962 assertRange(0, _curVerbSlot, _numVerbs - 1, "new verb slot");
963 return;
964 }
965 vs = &_verbs[_curVerbSlot];
966 slot = _curVerbSlot;
967 switch (subOp) {
968 case 124: // SO_VERB_IMAGE
969 a = pop();
970 if (_curVerbSlot) {
971 setVerbObject(_roomResource, a, slot);
972 vs->type = kImageVerbType;
973 vs->imgindex = a;
974 }
975 break;
976 case 125: // SO_VERB_NAME
977 copyScriptString(name, sizeof(name));
978 loadPtrToResource(rtVerb, slot, name);
979 vs->type = kTextVerbType;
980 vs->imgindex = 0;
981 break;
982 case 126: // SO_VERB_COLOR
983 vs->color = pop();
984 break;
985 case 127: // SO_VERB_HICOLOR
986 vs->hicolor = pop();
987 break;
988 case 128: // SO_VERB_AT
989 vs->curRect.top = pop();
990 vs->curRect.left = pop();
991 break;
992 case 129: // SO_VERB_ON
993 vs->curmode = 1;
994 break;
995 case 130: // SO_VERB_OFF
996 vs->curmode = 0;
997 break;
998 case 131: // SO_VERB_DELETE
999 slot = getVerbSlot(pop(), 0);
1000 killVerb(slot);
1001 break;
1002 case 132: // SO_VERB_NEW
1003 slot = getVerbSlot(_curVerb, 0);
1004 if (slot == 0) {
1005 for (slot = 1; slot < _numVerbs; slot++) {
1006 if (_verbs[slot].verbid == 0)
1007 break;
1008 }
1009 if (slot == _numVerbs)
1010 error("Too many verbs");
1011 _curVerbSlot = slot;
1012 }
1013 vs = &_verbs[slot];
1014 vs->verbid = _curVerb;
1015 vs->color = 2;
1016 vs->hicolor = 0;
1017 vs->dimcolor = 8;
1018 vs->type = kTextVerbType;
1019 vs->charset_nr = _string[0]._default.charset;
1020 vs->curmode = 0;
1021 vs->saveid = 0;
1022 vs->key = 0;
1023 vs->center = 0;
1024 vs->imgindex = 0;
1025 break;
1026 case 133: // SO_VERB_DIMCOLOR
1027 vs->dimcolor = pop();
1028 break;
1029 case 134: // SO_VERB_DIM
1030 vs->curmode = 2;
1031 break;
1032 case 135: // SO_VERB_KEY
1033 vs->key = pop();
1034 break;
1035 case 136: // SO_VERB_CENTER
1036 vs->center = 1;
1037 break;
1038 case 137: // SO_VERB_NAME_STR
1039 a = pop();
1040 if (a == 0) {
1041 loadPtrToResource(rtVerb, slot, (const byte *)"");
1042 } else {
1043 loadPtrToResource(rtVerb, slot, getStringAddress(a));
1044 }
1045 vs->type = kTextVerbType;
1046 vs->imgindex = 0;
1047 break;
1048 case 139: // SO_VERB_IMAGE_IN_ROOM
1049 b = pop();
1050 a = pop();
1051
1052 if (slot && a != vs->imgindex) {
1053 setVerbObject(b, a, slot);
1054 vs->type = kImageVerbType;
1055 vs->imgindex = a;
1056 }
1057 break;
1058 case 140: // SO_VERB_BAKCOLOR
1059 vs->bkcolor = pop();
1060 break;
1061 case 255:
1062 drawVerb(slot, 0);
1063 verbMouseOver(0);
1064 break;
1065 default:
1066 error("o72_verbops: default case %d", subOp);
1067 }
1068 }
1069
o72_findObject()1070 void ScummEngine_v72he::o72_findObject() {
1071 int y = pop();
1072 int x = pop();
1073 int r = findObject(x, y, 0, 0);
1074 push(r);
1075 }
1076
o72_arrayOps()1077 void ScummEngine_v72he::o72_arrayOps() {
1078 byte *data;
1079 byte string[1024];
1080 int dim1end, dim1start, dim2end, dim2start;
1081 int id, len, b, c, list[128];
1082 int offs, tmp, tmp2;
1083 uint tmp3;
1084
1085 byte subOp = fetchScriptByte();
1086 int array = fetchScriptWord();
1087 debug(9,"o72_arrayOps: array %d case %d", array, subOp);
1088
1089 switch (subOp) {
1090 case 7: // SO_ASSIGN_STRING
1091 copyScriptString(string, sizeof(string));
1092 len = resStrLen(string);
1093 data = defineArray(array, kStringArray, 0, 0, 0, len);
1094 memcpy(data, string, len);
1095 break;
1096
1097 case 126: // SO_COMPLEX_ARRAY_ASSIGNMENT
1098 len = getStackList(list, ARRAYSIZE(list));
1099 dim1end = pop();
1100 dim1start = pop();
1101 dim2end = pop();
1102 dim2start = pop();
1103 id = readVar(array);
1104 if (id == 0) {
1105 defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end);
1106 }
1107 checkArrayLimits(array, dim2start, dim2end, dim1start, dim1end);
1108
1109 tmp2 = 0;
1110 while (dim2start <= dim2end) {
1111 tmp = dim1start;
1112 while (tmp <= dim1end) {
1113 writeArray(array, dim2start, tmp, list[tmp2++]);
1114 if (tmp2 == len)
1115 tmp2 = 0;
1116 tmp++;
1117 }
1118 dim2start++;
1119 }
1120 break;
1121 case 127: // SO_COMPLEX_ARRAY_COPY_OPERATION
1122 {
1123 int a2_dim1end = pop();
1124 int a2_dim1start = pop();
1125 int a2_dim2end = pop();
1126 int a2_dim2start = pop();
1127 int array2 = fetchScriptWord();
1128 int a1_dim1end = pop();
1129 int a1_dim1start = pop();
1130 int a1_dim2end = pop();
1131 int a1_dim2start = pop();
1132 if (a1_dim1end - a1_dim1start != a2_dim1end - a2_dim1start || a2_dim2end - a2_dim2start != a1_dim2end - a1_dim2start) {
1133 error("Source and dest ranges size are mismatched");
1134 }
1135 copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end);
1136 }
1137 break;
1138 case 128: // SO_RANGE_ARRAY_ASSIGNMENT
1139 b = pop();
1140 c = pop();
1141 dim1end = pop();
1142 dim1start = pop();
1143 dim2end = pop();
1144 dim2start = pop();
1145 id = readVar(array);
1146 if (id == 0) {
1147 defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end);
1148 }
1149 checkArrayLimits(array, dim2start, dim2end, dim1start, dim1end);
1150
1151 offs = (b >= c) ? 1 : -1;
1152 tmp2 = c;
1153 tmp3 = c - b + 1;
1154 while (dim2start <= dim2end) {
1155 tmp = dim1start;
1156 while (tmp <= dim1end) {
1157 writeArray(array, dim2start, tmp, tmp2);
1158 if (--tmp3 == 0) {
1159 tmp2 = c;
1160 tmp3 = c - b + 1;
1161 } else {
1162 tmp2 += offs;
1163 }
1164 tmp++;
1165 }
1166 dim2start++;
1167 }
1168 break;
1169 case 194: // SO_FORMATTED_STRING
1170 decodeScriptString(string);
1171 len = resStrLen(string);
1172 data = defineArray(array, kStringArray, 0, 0, 0, len);
1173 memcpy(data, string, len);
1174 break;
1175 case 208: // SO_ASSIGN_INT_LIST
1176 b = pop();
1177 c = pop();
1178 id = readVar(array);
1179 if (id == 0) {
1180 defineArray(array, kDwordArray, 0, 0, 0, b + c - 1);
1181 }
1182 while (c--) {
1183 writeArray(array, 0, b + c, pop());
1184 }
1185 break;
1186 case 212: // SO_ASSIGN_2DIM_LIST
1187 len = getStackList(list, ARRAYSIZE(list));
1188 id = readVar(array);
1189 if (id == 0)
1190 error("Must DIM a two dimensional array before assigning");
1191 c = pop();
1192 while (--len >= 0) {
1193 writeArray(array, c, len, list[len]);
1194 }
1195 break;
1196 default:
1197 error("o72_arrayOps: default case %d (array %d)", subOp, array);
1198 }
1199 }
1200
o72_systemOps()1201 void ScummEngine_v72he::o72_systemOps() {
1202 byte string[1024];
1203
1204 byte subOp = fetchScriptByte();
1205
1206 switch (subOp) {
1207 case 22: // HE80+
1208 clearDrawObjectQueue();
1209 break;
1210 case 26: // HE80+
1211 restoreBackgroundHE(Common::Rect(_screenWidth, _screenHeight));
1212 updatePalette();
1213 break;
1214 case 158:
1215 restart();
1216 break;
1217 case 160:
1218 // Confirm shutdown
1219 confirmExitDialog();
1220 break;
1221 case 244:
1222 quitGame();
1223 break;
1224 case 251:
1225 copyScriptString(string, sizeof(string));
1226 debug(0, "Start executable (%s)", string);
1227 break;
1228 case 252:
1229 copyScriptString(string, sizeof(string));
1230 debug(0, "Start game (%s)", string);
1231 break;
1232 default:
1233 error("o72_systemOps invalid case %d", subOp);
1234 }
1235 }
1236
o72_talkActor()1237 void ScummEngine_v72he::o72_talkActor() {
1238 Actor *a;
1239
1240 int act = pop();
1241
1242 _string[0].loadDefault();
1243
1244 // A value of 225 can occur when examining the gold in the mine of pajama, after mining the gold.
1245 // This is a script bug, the script should set the subtitle color, not actor number.
1246 // This script bug was fixed in the updated version of pajama.
1247 if (act == 225) {
1248 _string[0].color = act;
1249 } else {
1250 _actorToPrintStrFor = act;
1251 if (_actorToPrintStrFor != 0xFF) {
1252 a = derefActor(_actorToPrintStrFor, "o72_talkActor");
1253 _string[0].color = a->_talkColor;
1254 }
1255 }
1256
1257 actorTalk(_scriptPointer);
1258
1259 _scriptPointer += resStrLen(_scriptPointer) + 1;
1260 }
1261
o72_talkEgo()1262 void ScummEngine_v72he::o72_talkEgo() {
1263 push(VAR(VAR_EGO));
1264 o72_talkActor();
1265 }
1266
o72_dimArray()1267 void ScummEngine_v72he::o72_dimArray() {
1268 int data;
1269
1270 byte subOp = fetchScriptByte();
1271
1272 switch (subOp) {
1273 case 2: // SO_BIT_ARRAY
1274 data = kBitArray;
1275 break;
1276 case 3: // SO_NIBBLE_ARRAY
1277 data = kNibbleArray;
1278 break;
1279 case 4: // SO_BYTE_ARRAY
1280 data = kByteArray;
1281 break;
1282 case 5: // SO_INT_ARRAY
1283 data = kIntArray;
1284 break;
1285 case 6:
1286 data = kDwordArray;
1287 break;
1288 case 7: // SO_STRING_ARRAY
1289 data = kStringArray;
1290 break;
1291 case 204: // SO_UNDIM_ARRAY
1292 nukeArray(fetchScriptWord());
1293 return;
1294 default:
1295 error("o72_dimArray: default case %d", subOp);
1296 }
1297
1298 defineArray(fetchScriptWord(), data, 0, 0, 0, pop());
1299 }
1300
1301
o72_dim2dimArray()1302 void ScummEngine_v72he::o72_dim2dimArray() {
1303 int data, dim1end, dim2end;
1304
1305 byte subOp = fetchScriptByte();
1306
1307 switch (subOp) {
1308 case 2: // SO_BIT_ARRAY
1309 data = kBitArray;
1310 break;
1311 case 3: // SO_NIBBLE_ARRAY
1312 data = kNibbleArray;
1313 break;
1314 case 4: // SO_BYTE_ARRAY
1315 data = kByteArray;
1316 break;
1317 case 5: // SO_INT_ARRAY
1318 data = kIntArray;
1319 break;
1320 case 6:
1321 data = kDwordArray;
1322 break;
1323 case 7: // SO_STRING_ARRAY
1324 data = kStringArray;
1325 break;
1326 default:
1327 error("o72_dim2dimArray: default case %d", subOp);
1328 }
1329
1330 dim1end = pop();
1331 dim2end = pop();
1332 defineArray(fetchScriptWord(), data, 0, dim2end, 0, dim1end);
1333 }
1334
o72_traceStatus()1335 void ScummEngine_v72he::o72_traceStatus() {
1336 byte string[80];
1337
1338 copyScriptString(string, sizeof(string));
1339 pop();
1340 }
1341
o72_kernelGetFunctions()1342 void ScummEngine_v72he::o72_kernelGetFunctions() {
1343 int args[29];
1344 byte *data;
1345 getStackList(args, ARRAYSIZE(args));
1346
1347 switch (args[0]) {
1348 case 1:
1349 writeVar(0, 0);
1350 data = defineArray(0, kByteArray, 0, 0, 0, virtScreenSave(0, args[1], args[2], args[3], args[4]));
1351 virtScreenSave(data, args[1], args[2], args[3], args[4]);
1352 push(readVar(0));
1353 break;
1354 default:
1355 error("o72_kernelGetFunctions: default case %d", args[0]);
1356 }
1357 }
1358
o72_drawWizImage()1359 void ScummEngine_v72he::o72_drawWizImage() {
1360 WizImage wi;
1361 wi.flags = pop();
1362 wi.y1 = pop();
1363 wi.x1 = pop();
1364 wi.resNum = pop();
1365 wi.state = 0;
1366 _wiz->displayWizImage(&wi);
1367 }
1368
debugInput(byte * string)1369 void ScummEngine_v72he::debugInput(byte* string) {
1370 byte *debugInputString;
1371
1372 DebugInputDialog dialog(this, (char *)string);
1373 runDialog(dialog);
1374 while (!dialog.done) {
1375 parseEvents();
1376 dialog.handleKeyDown(_keyPressed);
1377 }
1378
1379 writeVar(0, 0);
1380 debugInputString = defineArray(0, kStringArray, 0, 0, 0, dialog.buffer.size());
1381 memcpy(debugInputString, dialog.buffer.c_str(), dialog.buffer.size());
1382 push(readVar(0));
1383 }
1384
o72_debugInput()1385 void ScummEngine_v72he::o72_debugInput() {
1386 byte string[255];
1387
1388 copyScriptString(string, sizeof(string));
1389 debugInput(string);
1390 }
1391
o72_jumpToScript()1392 void ScummEngine_v72he::o72_jumpToScript() {
1393 int args[25];
1394 int script;
1395 byte flags;
1396
1397 getStackList(args, ARRAYSIZE(args));
1398 script = pop();
1399 flags = fetchScriptByte();
1400 stopObjectCode();
1401 runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args);
1402 }
1403
o72_openFile()1404 void ScummEngine_v72he::o72_openFile() {
1405 int mode, slot, i;
1406 byte buffer[256];
1407
1408 mode = pop();
1409 copyScriptString(buffer, sizeof(buffer));
1410 debug(1, "Trying to open file '%s'", (char *)buffer);
1411
1412 slot = -1;
1413 for (i = 1; i < 17; i++) {
1414 if (_hInFileTable[i] == 0 && _hOutFileTable[i] == 0) {
1415 slot = i;
1416 break;
1417 }
1418 }
1419
1420 if (slot != -1) {
1421 switch (mode) {
1422 case 1: // Read mode
1423 _hInFileTable[slot] = openFileForReading(buffer);
1424 break;
1425 case 2: // Write mode
1426 if (!strchr((char *)buffer, '/')) {
1427 _hOutFileTable[slot] = openSaveFileForWriting(buffer);
1428 }
1429 break;
1430 case 6: // Append mode
1431 if (!strchr((char *)buffer, '/'))
1432 _hOutFileTable[slot] = openSaveFileForAppending(buffer);
1433 break;
1434 default:
1435 error("o72_openFile(): wrong open file mode %d", mode);
1436 }
1437
1438 if (_hInFileTable[slot] == 0 && _hOutFileTable[slot] == 0)
1439 slot = -1;
1440
1441 }
1442 debug(1, "o72_openFile: slot %d, mode %d", slot, mode);
1443 push(slot);
1444 }
1445
readFileToArray(int slot,int32 size)1446 int ScummEngine_v72he::readFileToArray(int slot, int32 size) {
1447 writeVar(0, 0);
1448 byte *data = defineArray(0, kByteArray, 0, 0, 0, size);
1449
1450 if (slot != -1) {
1451 _hInFileTable[slot]->read(data, size + 1);
1452 }
1453
1454 return readVar(0);
1455 }
1456
o72_readFile()1457 void ScummEngine_v72he::o72_readFile() {
1458 int slot, val;
1459 int32 size;
1460 byte subOp = fetchScriptByte();
1461
1462 switch (subOp) {
1463 case 4:
1464 slot = pop();
1465 assert(_hInFileTable[slot]);
1466 val = _hInFileTable[slot]->readByte();
1467 push(val);
1468 break;
1469 case 5:
1470 slot = pop();
1471 assert(_hInFileTable[slot]);
1472 val = _hInFileTable[slot]->readUint16LE();
1473 push(val);
1474 break;
1475 case 6:
1476 slot = pop();
1477 assert(_hInFileTable[slot]);
1478 val = _hInFileTable[slot]->readUint32LE();
1479 push(val);
1480 break;
1481 case 8:
1482 fetchScriptByte();
1483 size = pop();
1484 slot = pop();
1485 assert(_hInFileTable[slot]);
1486 val = readFileToArray(slot, size);
1487 push(val);
1488 break;
1489 default:
1490 error("o72_readFile: default case %d", subOp);
1491 }
1492 }
1493
writeFileFromArray(int slot,int32 resID)1494 void ScummEngine_v72he::writeFileFromArray(int slot, int32 resID) {
1495 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID);
1496 int32 size = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
1497 (FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1);
1498
1499 if (slot != -1) {
1500 _hOutFileTable[slot]->write(ah->data, size);
1501 }
1502 }
1503
getStringFromArray(int arrayNumber,char * buffer,int maxLength)1504 void ScummEngine_v72he::getStringFromArray(int arrayNumber, char *buffer, int maxLength) {
1505 // I'm not really sure it belongs here and not some other version
1506 // this is ARRAY_GetStringFromArray() from ARRAYS.cpp of SPUTM
1507
1508 // this function makes a C-string out of <arrayNumber> contents
1509
1510 VAR(0) = arrayNumber; // it was 0 in original code, but I've seen ScummVM Moonbase code which uses VAR_U32_ARRAY_UNK
1511
1512 int i, ch;
1513 for (i = 0; i < maxLength; ++i) {
1514 if (!(ch = readArray(0, 0, i))) {
1515 break;
1516 }
1517
1518 buffer[i] = ch;
1519 }
1520
1521 buffer[i] = 0;
1522 }
1523
o72_writeFile()1524 void ScummEngine_v72he::o72_writeFile() {
1525 int32 resID = pop();
1526 int slot = pop();
1527 byte subOp = fetchScriptByte();
1528
1529 assert(_hOutFileTable[slot]);
1530 switch (subOp) {
1531 case 4:
1532 _hOutFileTable[slot]->writeByte(resID);
1533 break;
1534 case 5:
1535 _hOutFileTable[slot]->writeUint16LE(resID);
1536 break;
1537 case 6:
1538 _hOutFileTable[slot]->writeUint32LE(resID);
1539 break;
1540 case 8:
1541 fetchScriptByte();
1542 writeFileFromArray(slot, resID);
1543 break;
1544 default:
1545 error("o72_writeFile: default case %d", subOp);
1546 }
1547 }
1548
o72_findAllObjects()1549 void ScummEngine_v72he::o72_findAllObjects() {
1550 int room = pop();
1551 int i;
1552
1553 if (room != _currentRoom)
1554 error("o72_findAllObjects: current room is not %d", room);
1555
1556 writeVar(0, 0);
1557 defineArray(0, kDwordArray, 0, 0, 0, _numLocalObjects);
1558 writeArray(0, 0, 0, _numLocalObjects);
1559
1560 for (i = 1; i < _numLocalObjects; i++) {
1561 writeArray(0, 0, i, _objs[i].obj_nr);
1562 }
1563
1564 push(readVar(0));
1565 }
1566
o72_deleteFile()1567 void ScummEngine_v72he::o72_deleteFile() {
1568 byte buffer[256];
1569
1570 copyScriptString(buffer, sizeof(buffer));
1571
1572 debug(1, "o72_deleteFile(%s)", (char *)buffer);
1573
1574 deleteSaveFile(buffer);
1575 }
1576
o72_rename()1577 void ScummEngine_v72he::o72_rename() {
1578 byte buffer1[100],buffer2[100];
1579
1580 copyScriptString(buffer1, sizeof(buffer1));
1581 copyScriptString(buffer2, sizeof(buffer2));
1582
1583 debug(1, "o72_rename(%s to %s)", (char *)buffer2, (char *)buffer1);
1584
1585 renameSaveFile(buffer2, buffer1);
1586 }
1587
o72_getPixel()1588 void ScummEngine_v72he::o72_getPixel() {
1589 uint16 area;
1590
1591 int y = pop();
1592 int x = pop();
1593 byte subOp = fetchScriptByte();
1594
1595 VirtScreen *vs = findVirtScreen(y);
1596 if (vs == NULL || x > _screenWidth - 1 || x < 0) {
1597 push(-1);
1598 return;
1599 }
1600
1601 switch (subOp) {
1602 case 9: // HE 100
1603 case 218:
1604 if (_game.features & GF_16BIT_COLOR)
1605 area = READ_UINT16(vs->getBackPixels(x, y - vs->topline));
1606 else
1607 area = *vs->getBackPixels(x, y - vs->topline);
1608 break;
1609 case 8: // HE 100
1610 case 219:
1611 if (_game.features & GF_16BIT_COLOR)
1612 area = READ_UINT16(vs->getPixels(x, y - vs->topline));
1613 else
1614 area = *vs->getPixels(x, y - vs->topline);
1615 break;
1616 default:
1617 error("o72_getPixel: default case %d", subOp);
1618 }
1619 push(area);
1620 }
1621
o72_pickVarRandom()1622 void ScummEngine_v72he::o72_pickVarRandom() {
1623 int num;
1624 int args[100];
1625 int32 dim1end;
1626
1627 num = getStackList(args, ARRAYSIZE(args));
1628 int value = fetchScriptWord();
1629
1630 if (readVar(value) == 0) {
1631 defineArray(value, kDwordArray, 0, 0, 0, num);
1632 if (num > 0) {
1633 int16 counter = 0;
1634 do {
1635 writeArray(value, 0, counter + 1, args[counter]);
1636 } while (++counter < num);
1637 }
1638
1639 shuffleArray(value, 1, num);
1640 writeArray(value, 0, 0, 2);
1641 push(readArray(value, 0, 1));
1642 return;
1643 }
1644
1645 num = readArray(value, 0, 0);
1646
1647 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(value));
1648 dim1end = FROM_LE_32(ah->dim1end);
1649
1650 if (dim1end < num) {
1651 int32 var_2 = readArray(value, 0, num - 1);
1652 shuffleArray(value, 1, dim1end);
1653 if (readArray(value, 0, 1) == var_2) {
1654 num = 2;
1655 } else {
1656 num = 1;
1657 }
1658 }
1659
1660 writeArray(value, 0, 0, num + 1);
1661 push(readArray(value, 0, num));
1662 }
1663
o72_redimArray()1664 void ScummEngine_v72he::o72_redimArray() {
1665 int newX, newY;
1666 newY = pop();
1667 newX = pop();
1668
1669 byte subOp = fetchScriptByte();
1670
1671 switch (subOp) {
1672 case 4:
1673 redimArray(fetchScriptWord(), 0, newX, 0, newY, kByteArray);
1674 break;
1675 case 5:
1676 redimArray(fetchScriptWord(), 0, newX, 0, newY, kIntArray);
1677 break;
1678 case 6:
1679 redimArray(fetchScriptWord(), 0, newX, 0, newY, kDwordArray);
1680 break;
1681 default:
1682 error("o72_redimArray: default type %d", subOp);
1683 }
1684 }
1685
redimArray(int arrayId,int newDim2start,int newDim2end,int newDim1start,int newDim1end,int type)1686 void ScummEngine_v72he::redimArray(int arrayId, int newDim2start, int newDim2end,
1687 int newDim1start, int newDim1end, int type) {
1688 int newSize, oldSize;
1689
1690 if (readVar(arrayId) == 0)
1691 error("redimArray: Reference to zeroed array pointer");
1692
1693 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId));
1694
1695 if (!ah)
1696 error("redimArray: Invalid array (%d) reference", readVar(arrayId));
1697
1698 newSize = arrayDataSizes[type];
1699 oldSize = arrayDataSizes[FROM_LE_32(ah->type)];
1700
1701 newSize *= (newDim1end - newDim1start + 1) * (newDim2end - newDim2start + 1);
1702 oldSize *= (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
1703 (FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1);
1704
1705 newSize >>= 3;
1706 oldSize >>= 3;
1707
1708 if (newSize != oldSize)
1709 error("redimArray: array %d redim mismatch", readVar(arrayId));
1710
1711 ah->type = TO_LE_32(type);
1712 ah->dim1start = TO_LE_32(newDim1start);
1713 ah->dim1end = TO_LE_32(newDim1end);
1714 ah->dim2start = TO_LE_32(newDim2start);
1715 ah->dim2end = TO_LE_32(newDim2end);
1716 }
1717
checkArrayLimits(int array,int dim2start,int dim2end,int dim1start,int dim1end)1718 void ScummEngine_v72he::checkArrayLimits(int array, int dim2start, int dim2end, int dim1start, int dim1end) {
1719 if (dim1end < dim1start) {
1720 error("Across max %d smaller than min %d", dim1end, dim1start);
1721 }
1722 if (dim2end < dim2start) {
1723 error("Down max %d smaller than min %d", dim2end, dim2start);
1724 }
1725 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
1726 assert(ah);
1727 if ((int)FROM_LE_32(ah->dim2start) > dim2start || (int)FROM_LE_32(ah->dim2end) < dim2end || (int)FROM_LE_32(ah->dim1start) > dim1start || (int)FROM_LE_32(ah->dim1end) < dim1end) {
1728 error("Invalid array access (%d,%d,%d,%d) limit (%d,%d,%d,%d)", dim2start, dim2end, dim1start, dim1end, FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end), FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end));
1729 }
1730 }
1731
copyArray(int array1,int a1_dim2start,int a1_dim2end,int a1_dim1start,int a1_dim1end,int array2,int a2_dim2start,int a2_dim2end,int a2_dim1start,int a2_dim1end)1732 void ScummEngine_v72he::copyArray(int array1, int a1_dim2start, int a1_dim2end, int a1_dim1start, int a1_dim1end,
1733 int array2, int a2_dim2start, int a2_dim2end, int a2_dim1start, int a2_dim1end)
1734 {
1735 byte *dst, *src;
1736 int dstPitch, srcPitch;
1737 int rowSize;
1738 checkArrayLimits(array1, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end);
1739 checkArrayLimits(array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end);
1740 int a12_num = a1_dim2end - a1_dim2start + 1;
1741 int a11_num = a1_dim1end - a1_dim1start + 1;
1742 int a22_num = a2_dim2end - a2_dim2start + 1;
1743 int a21_num = a2_dim1end - a2_dim1start + 1;
1744 if (a22_num != a12_num || a21_num != a11_num) {
1745 error("Operation size mismatch (%d vs %d)(%d vs %d)", a12_num, a22_num, a11_num, a21_num);
1746 }
1747
1748 if (array1 != array2) {
1749 ArrayHeader *ah1 = (ArrayHeader *)getResourceAddress(rtString, readVar(array1));
1750 assert(ah1);
1751 ArrayHeader *ah2 = (ArrayHeader *)getResourceAddress(rtString, readVar(array2));
1752 assert(ah2);
1753 if (FROM_LE_32(ah1->type) == FROM_LE_32(ah2->type)) {
1754 copyArrayHelper(ah1, a1_dim2start, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize);
1755 copyArrayHelper(ah2, a2_dim2start, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize);
1756 for (; a1_dim2start <= a1_dim2end; ++a1_dim2start) {
1757 memcpy(dst, src, rowSize);
1758 dst += dstPitch;
1759 src += srcPitch;
1760 }
1761 } else {
1762 for (; a1_dim2start <= a1_dim2end; ++a1_dim2start, ++a2_dim2start) {
1763 int a2dim1 = a2_dim1start;
1764 int a1dim1 = a1_dim1start;
1765 for (; a1dim1 <= a1_dim1end; ++a1dim1, ++a2dim1) {
1766 int val = readArray(array2, a2_dim2start, a2dim1);
1767 writeArray(array1, a1_dim2start, a1dim1, val);
1768 }
1769 }
1770 }
1771 } else {
1772 if (a2_dim2start != a1_dim2start || a2_dim1start != a1_dim1start) {
1773 ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array1));
1774 assert(ah);
1775 if (a2_dim2start > a1_dim2start) {
1776 copyArrayHelper(ah, a1_dim2start, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize);
1777 copyArrayHelper(ah, a2_dim2start, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize);
1778 } else {
1779 // start at the end, so we copy backwards (in case the indices overlap)
1780 copyArrayHelper(ah, a1_dim2end, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize);
1781 copyArrayHelper(ah, a2_dim2end, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize);
1782 dstPitch = -dstPitch;
1783 srcPitch = -srcPitch;
1784 }
1785 for (; a1_dim2start <= a1_dim2end; ++a1_dim2start) {
1786 memcpy(dst, src, rowSize);
1787 dst += dstPitch;
1788 src += srcPitch;
1789 }
1790 }
1791 }
1792 }
1793
copyArrayHelper(ArrayHeader * ah,int idx2,int idx1,int len1,byte ** data,int * size,int * num)1794 void ScummEngine_v72he::copyArrayHelper(ArrayHeader *ah, int idx2, int idx1, int len1, byte **data, int *size, int *num) {
1795 const int pitch = FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1;
1796 const int offset = pitch * (idx2 - FROM_LE_32(ah->dim2start)) + idx1 - FROM_LE_32(ah->dim1start);
1797
1798 switch (FROM_LE_32(ah->type)) {
1799 case kByteArray:
1800 case kStringArray:
1801 *num = len1 - idx1 + 1;
1802 *size = pitch;
1803 *data = ah->data + offset;
1804 break;
1805 case kIntArray:
1806 *num = (len1 - idx1) * 2 + 2;
1807 *size = pitch * 2;
1808 *data = ah->data + offset * 2;
1809 break;
1810 case kDwordArray:
1811 *num = (len1 - idx1) * 4 + 4;
1812 *size = pitch * 4;
1813 *data = ah->data + offset * 4;
1814 break;
1815 default:
1816 error("Invalid array type %d", FROM_LE_32(ah->type));
1817 }
1818 }
1819
o72_readINI()1820 void ScummEngine_v72he::o72_readINI() {
1821 byte option[128];
1822 byte *data;
1823
1824 copyScriptString(option, sizeof(option));
1825 byte subOp = fetchScriptByte();
1826
1827 switch (subOp) {
1828 case 43: // HE 100
1829 case 6: // number
1830 if (!strcmp((char *)option, "DisablePrinting") || !strcmp((char *)option, "NoPrinting")) {
1831 push(1);
1832 } else if (!strcmp((char *)option, "TextOn")) {
1833 push(ConfMan.getBool("subtitles"));
1834 } else if (!strcmp((char *)option, "Disk") && (_game.id == GID_BIRTHDAYRED || _game.id == GID_BIRTHDAYYELLOW)) {
1835 // WORKAROUND: Override the disk detection
1836 // This removes the reliance on having the binary file around (which is
1837 // very bad for the Mac version) just for the scripts to figure out if
1838 // we're running Yellow or Red
1839 if (_game.id == GID_BIRTHDAYRED)
1840 push(4);
1841 else
1842 push(2);
1843 } else {
1844 push(ConfMan.getInt((char *)option));
1845 }
1846 break;
1847 case 77: // HE 100
1848 case 7: // string
1849 writeVar(0, 0);
1850 if (!strcmp((char *)option, "HE3File")) {
1851 Common::String fileName = generateFilename(-3);
1852 int len = resStrLen((const byte *)fileName.c_str());
1853 data = defineArray(0, kStringArray, 0, 0, 0, len);
1854 memcpy(data, fileName.c_str(), len);
1855 } else if (!strcmp((char *)option, "GameResourcePath") || !strcmp((char *)option, "SaveGamePath")) {
1856 // We set SaveGamePath in order to detect where it used
1857 // in convertFilePath and to avoid warning about invalid
1858 // path in Macintosh verisons.
1859 data = defineArray(0, kStringArray, 0, 0, 0, 2);
1860 if (_game.platform == Common::kPlatformMacintosh)
1861 memcpy(data, (const char *)"*:", 2);
1862 else
1863 memcpy(data, (const char *)"*\\", 2);
1864 } else {
1865 const char *entry = (ConfMan.get((char *)option).c_str());
1866 int len = resStrLen((const byte *)entry);
1867 data = defineArray(0, kStringArray, 0, 0, 0, len);
1868 memcpy(data, entry, len);
1869 }
1870 push(readVar(0));
1871 break;
1872 default:
1873 error("o72_readINI: default type %d", subOp);
1874 }
1875
1876 debug(1, "o72_readINI: Option %s", option);
1877 }
1878
o72_writeINI()1879 void ScummEngine_v72he::o72_writeINI() {
1880 int value;
1881 byte option[256], string[1024];
1882
1883 byte subOp = fetchScriptByte();
1884
1885 switch (subOp) {
1886 case 43: // HE 100
1887 case 6: // number
1888 value = pop();
1889 copyScriptString(option, sizeof(option));
1890 debug(1, "o72_writeINI: Option %s Value %d", option, value);
1891
1892 ConfMan.setInt((char *)option, value);
1893 break;
1894 case 77: // HE 100
1895 case 7: // string
1896 copyScriptString(string, sizeof(string));
1897 copyScriptString(option, sizeof(option));
1898 debug(1, "o72_writeINI: Option %s String %s", option, string);
1899
1900 // Filter out useless setting
1901 if (!strcmp((char *)option, "HETest"))
1902 return;
1903
1904 // Filter out confusing subtitle setting
1905 if (!strcmp((char *)option, "TextOn"))
1906 return;
1907
1908 // Filter out confusing path settings
1909 if (!strcmp((char *)option, "DownLoadPath") || !strcmp((char *)option, "GameResourcePath") || !strcmp((char *)option, "SaveGamePath"))
1910 return;
1911
1912 ConfMan.set((char *)option, (char *)string);
1913 break;
1914 default:
1915 error("o72_writeINI: default type %d", subOp);
1916 }
1917
1918 ConfMan.flushToDisk();
1919 }
1920
o72_getResourceSize()1921 void ScummEngine_v72he::o72_getResourceSize() {
1922 const byte *ptr;
1923 int size;
1924 ResType type;
1925
1926 int resid = pop();
1927 if (_game.heversion == 72) {
1928 push(getSoundResourceSize(resid));
1929 return;
1930 }
1931
1932 byte subOp = fetchScriptByte();
1933
1934 switch (subOp) {
1935 case 13:
1936 push(getSoundResourceSize(resid));
1937 return;
1938 case 14:
1939 type = rtRoomImage;
1940 break;
1941 case 15:
1942 type = rtImage;
1943 break;
1944 case 16:
1945 type = rtCostume;
1946 break;
1947 case 17:
1948 type = rtScript;
1949 break;
1950 default:
1951 error("o72_getResourceSize: default type %d", subOp);
1952 }
1953
1954 ptr = getResourceAddress(type, resid);
1955 assert(ptr);
1956 size = READ_BE_UINT32(ptr + 4) - 8;
1957 push(size);
1958 }
1959
o72_createDirectory()1960 void ScummEngine_v72he::o72_createDirectory() {
1961 byte directoryName[255];
1962
1963 copyScriptString(directoryName, sizeof(directoryName));
1964 debug(1,"o72_createDirectory: %s", directoryName);
1965 }
1966
o72_setSystemMessage()1967 void ScummEngine_v72he::o72_setSystemMessage() {
1968 byte name[1024];
1969
1970 copyScriptString(name, sizeof(name));
1971 byte subOp = fetchScriptByte();
1972
1973 switch (subOp) {
1974 case 240:
1975 debug(1,"o72_setSystemMessage: (%d) %s", subOp, name);
1976 break;
1977 case 241: // Set Version
1978 debug(1,"o72_setSystemMessage: (%d) %s", subOp, name);
1979 break;
1980 case 242:
1981 debug(1,"o72_setSystemMessage: (%d) %s", subOp, name);
1982 break;
1983 case 243: // Set Window Caption
1984 // TODO: The 'name' string can contain non-ASCII data. This can lead to
1985 // problems, because (a) the encoding used for "name" is not clear,
1986 // (b) OSystem::setWindowCaption only supports ASCII. As a result, odd
1987 // behavior can occur, from strange wrong titles, up to crashes (happens
1988 // under Mac OS X).
1989 //
1990 // Possible fixes/workarounds:
1991 // - Simply stop using this. It's a rather unimportant "feature" anyway.
1992 // - Try to translate the text to ASCII.
1993 // - Refine OSystem to accept window captions that are non-ASCII, e.g.
1994 // by enhancing all backends to deal with UTF-8 data. Of course, then
1995 // one still would have to convert 'name' to the correct encoding.
1996 //_system->setWindowCaption((const char *)name);
1997 break;
1998 default:
1999 error("o72_setSystemMessage: default case %d", subOp);
2000 }
2001 }
2002
decodeParseString(int m,int n)2003 void ScummEngine_v72he::decodeParseString(int m, int n) {
2004 Actor *a;
2005 int i, colors, size;
2006 int args[31];
2007 byte name[1024];
2008
2009 byte b = fetchScriptByte();
2010
2011 switch (b) {
2012 case 65: // SO_AT
2013 _string[m].ypos = pop();
2014 _string[m].xpos = pop();
2015 _string[m].overhead = false;
2016 break;
2017 case 66: // SO_COLOR
2018 _string[m].color = pop();
2019 break;
2020 case 67: // SO_CLIPPED
2021 _string[m].right = pop();
2022 break;
2023 case 69: // SO_CENTER
2024 _string[m].center = true;
2025 _string[m].overhead = false;
2026 break;
2027 case 71: // SO_LEFT
2028 _string[m].center = false;
2029 _string[m].overhead = false;
2030 break;
2031 case 72: // SO_OVERHEAD
2032 _string[m].overhead = true;
2033 _string[m].no_talk_anim = false;
2034 break;
2035 case 74: // SO_MUMBLE
2036 _string[m].no_talk_anim = true;
2037 break;
2038 case 75: // SO_TEXTSTRING
2039 printString(m, _scriptPointer);
2040 _scriptPointer += resStrLen(_scriptPointer) + 1;
2041 break;
2042 case 194:
2043 decodeScriptString(name, true);
2044 printString(m, name);
2045 break;
2046 case 0xE1:
2047 {
2048 byte *dataPtr = getResourceAddress(rtTalkie, pop());
2049 byte *text = findWrappedBlock(MKTAG('T','E','X','T'), dataPtr, 0, 0);
2050 size = getResourceDataSize(text);
2051 memcpy(name, text, size);
2052 printString(m, name);
2053 }
2054 break;
2055 case 0xF9:
2056 colors = pop();
2057 if (colors == 1) {
2058 _string[m].color = pop();
2059 } else {
2060 push(colors);
2061 getStackList(args, ARRAYSIZE(args));
2062 for (i = 0; i < 16; i++)
2063 _charsetColorMap[i] = _charsetData[_string[m]._default.charset][i] = (unsigned char)args[i];
2064 _string[m].color = _charsetColorMap[0];
2065 }
2066 break;
2067 case 0xFE:
2068 _string[m].loadDefault();
2069 if (n) {
2070 _actorToPrintStrFor = pop();
2071 if (_actorToPrintStrFor != 0xFF) {
2072 a = derefActor(_actorToPrintStrFor, "decodeParseString");
2073 _string[m].color = a->_talkColor;
2074 }
2075 }
2076 break;
2077 case 0xFF:
2078 _string[m].saveDefault();
2079 break;
2080 default:
2081 error("decodeParseString: default case 0x%x", b);
2082 }
2083 }
2084
2085 } // End of namespace Scumm
2086
2087 #endif // ENABLE_HE
2088