1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "cruise/cruise.h"
24 #include "cruise/cruise_main.h"
25 #include "cruise/cell.h"
26 #include "cruise/sound.h"
27 #include "cruise/staticres.h"
28 
29 #include "common/textconsole.h"
30 #include "common/util.h"
31 
32 namespace Cruise {
33 
Period(uint32 hz)34 uint32 Period(uint32 hz) {
35 	return ((uint32)(100000000L / ((uint32)hz * 28L)));
36 }
37 
38 //#define FUNCTION_DEBUG
39 
Op_LoadOverlay()40 int16 Op_LoadOverlay() {
41 	char *pOverlayName;
42 	char overlayName[38] = "";
43 	int overlayLoadResult;
44 
45 	pOverlayName = (char *)popPtr();
46 
47 	if (strlen(pOverlayName) == 0)
48 		return 0;
49 
50 	strcpy(overlayName, pOverlayName);
51 	strToUpper(overlayName);
52 
53 	//gfxModuleData.field_84();
54 	//gfxModuleData.field_84();
55 
56 	overlayLoadResult = loadOverlay(overlayName);
57 
58 	updateAllScriptsImports();
59 
60 	Common::strlcpy(nextOverlay, overlayName, sizeof(nextOverlay));
61 
62 	return overlayLoadResult;
63 }
64 
Op_Strcpy()65 int16 Op_Strcpy() {
66 	char *ptr1 = (char *)popPtr();
67 	char *ptr2 = (char *)popPtr();
68 
69 	while (*ptr1) {
70 		*ptr2 = *ptr1;
71 
72 		ptr2++;
73 		ptr1++;
74 	}
75 
76 	*ptr2 = 0;
77 
78 	return (0);
79 }
80 
Op_Exec()81 int16 Op_Exec() {
82 	int scriptIdx;
83 	int ovlIdx;
84 	uint8 *ptr;
85 	uint8 *ptr2;
86 	int16 popTable[200];
87 
88 	int numOfArgToPop = popVar();
89 
90 	for (int i = 0; i < numOfArgToPop; i++) {
91 		popTable[numOfArgToPop - i - 1] = popVar();
92 	}
93 
94 	scriptIdx = popVar();
95 	ovlIdx = popVar();
96 
97 	if (!ovlIdx) {
98 		ovlIdx = currentScriptPtr->overlayNumber;
99 	}
100 
101 	ptr = attacheNewScriptToTail(&procHead, ovlIdx, scriptIdx, currentScriptPtr->type, currentScriptPtr->scriptNumber, currentScriptPtr->overlayNumber, scriptType_MinusPROC);
102 
103 	if (!ptr)
104 		return (0);
105 
106 	if (numOfArgToPop <= 0) {
107 		return (0);
108 	}
109 
110 	ptr2 = ptr;
111 
112 	for (int i = 0; i < numOfArgToPop; i++) {
113 		WRITE_BE_UINT16(ptr2, popTable[i]);
114 		ptr2 += 2;
115 	}
116 
117 	return (0);
118 }
119 
Op_AddProc()120 int16 Op_AddProc() {
121 	int pop1 = popVar();
122 	int pop2;
123 	int overlay;
124 	int param[160];
125 
126 	for (long int i = 0; i < pop1; i++) {
127 		param[i] = popVar();
128 	}
129 
130 	pop2 = popVar();
131 	overlay = popVar();
132 
133 	if (!overlay)
134 		overlay = currentScriptPtr->overlayNumber;
135 
136 	if (!overlay)
137 		return (0);
138 
139 	uint8* procBss = attacheNewScriptToTail(&procHead, overlay, pop2, currentScriptPtr->type, currentScriptPtr->scriptNumber, currentScriptPtr->overlayNumber, scriptType_PROC);
140 
141 	if (procBss) {
142 		for (long int i = 0; i < pop1; i++) {
143 			int16* ptr = (int16 *)(procBss + i * 2);
144 			*ptr = param[i];
145 			bigEndianShortToNative(ptr);
146 		}
147 	}
148 
149 	return (0);
150 }
151 
Op_Narrator()152 int16 Op_Narrator() {
153 	int pop1 = popVar();
154 	int pop2 = popVar();
155 
156 	if (!pop2)
157 		pop2 = currentScriptPtr->overlayNumber;
158 
159 	narratorOvl = pop2;
160 	narratorIdx = pop1;
161 
162 	return (0);
163 }
164 
Op_GetMouseX()165 int16 Op_GetMouseX() {
166 	int16 dummy;
167 	int16 mouseX;
168 	int16 mouseY;
169 	int16 mouseButton;
170 
171 	getMouseStatus(&dummy, &mouseX, &mouseButton, &mouseY);
172 
173 	return (mouseX);
174 }
175 
Op_GetMouseY()176 int16 Op_GetMouseY() {
177 	int16 dummy;
178 	int16 mouseX;
179 	int16 mouseY;
180 	int16 mouseButton;
181 
182 	getMouseStatus(&dummy, &mouseX, &mouseButton, &mouseY);
183 
184 	return (mouseY);
185 }
186 
Op_Random()187 int16 Op_Random() {
188 	int var = popVar();
189 
190 	if (var < 2) {
191 		return (0);
192 	}
193 
194 	return (_vm->_rnd.getRandomNumber(var - 1));
195 }
196 
Op_PlayFX()197 int16 Op_PlayFX() {
198 	int volume = popVar();
199 
200 #if 0
201 	int speed = popVar();
202 	int channelNum = popVar();
203 #else
204 	popVar();
205 	popVar();
206 #endif
207 
208 	int sampleNum = popVar();
209 
210 	if ((sampleNum >= 0) && (sampleNum < NUM_FILE_ENTRIES) && (filesDatabase[sampleNum].subData.ptr)) {
211 #if 0
212 		if (speed == -1)
213 			speed = filesDatabase[sampleNum].subData.transparency;
214 #endif
215 
216 		_vm->sound().playSound(filesDatabase[sampleNum].subData.ptr,
217 			filesDatabase[sampleNum].width, volume);
218 	}
219 
220 	return (0);
221 }
222 
Op_LoopFX()223 int16 Op_LoopFX() {
224 	int volume = popVar();
225 
226 #if 0
227 	int speed = popVar();
228 	int channelNum = popVar();
229 #else
230 	popVar();
231 	popVar();
232 #endif
233 
234 	int sampleNum = popVar();
235 
236 	if ((sampleNum >= 0) && (sampleNum < NUM_FILE_ENTRIES) && (filesDatabase[sampleNum].subData.ptr)) {
237 
238 #if 0
239 		if (speed == -1)
240 			speed = filesDatabase[sampleNum].subData.transparency;
241 #endif
242 
243 		_vm->sound().playSound(filesDatabase[sampleNum].subData.ptr,
244 			filesDatabase[sampleNum].width, volume);
245 	}
246 
247 	return (0);
248 }
249 
Op_StopFX()250 int16 Op_StopFX() {
251 	int channelNum = popVar();
252 
253 	if (channelNum == -1) {
254 		_vm->sound().stopChannel(0);
255 		_vm->sound().stopChannel(1);
256 		_vm->sound().stopChannel(2);
257 		_vm->sound().stopChannel(3);
258 	} else {
259 		_vm->sound().stopChannel(channelNum);
260 	}
261 
262 	return 0;
263 }
264 
Op_FreqFX()265 int16 Op_FreqFX() {
266 	int volume = popVar();
267 	int freq2 = popVar();
268 	int channelNum = popVar();
269 	int sampleNum = popVar();
270 
271 	if ((sampleNum >= 0) && (sampleNum < NUM_FILE_ENTRIES) && (filesDatabase[sampleNum].subData.ptr)) {
272 		int freq = Period(freq2 * 1000);
273 
274 		_vm->sound().startNote(channelNum, volume, freq);
275 	}
276 
277 	return (0);
278 }
279 
Op_FreeCT()280 int16 Op_FreeCT() {
281 	freeCTP();
282 	return (0);
283 }
284 
freeObjectList(cellStruct * pListHead)285 void freeObjectList(cellStruct *pListHead) {
286 	int var_2 = 0;
287 	cellStruct *pCurrent = pListHead->next;
288 
289 	while (pCurrent) {
290 		cellStruct *pNext = pCurrent->next;
291 
292 		if (pCurrent->freeze == 0) {
293 			if (pCurrent->gfxPtr)
294 				freeGfx(pCurrent->gfxPtr);
295 			MemFree(pCurrent);
296 		}
297 
298 		var_2 = 1;
299 
300 		pCurrent = pNext;
301 	}
302 
303 	if (var_2) {
304 		resetPtr(pListHead);
305 	}
306 }
307 
Op_FreeCell()308 int16 Op_FreeCell() {
309 	freeObjectList(&cellHead);
310 	return (0);
311 }
312 
Op_freeBackgroundInscrustList()313 int16 Op_freeBackgroundInscrustList() {
314 	freeBackgroundIncrustList(&backgroundIncrustHead);
315 	return (0);
316 }
317 
318 
Op_UnmergeBackgroundIncrust()319 int16 Op_UnmergeBackgroundIncrust() {
320 	int obj = popVar();
321 	int ovl = popVar();
322 
323 	if (!ovl) {
324 		ovl = currentScriptPtr->overlayNumber;
325 	}
326 
327 	unmergeBackgroundIncrust(&backgroundIncrustHead, ovl, obj);
328 
329 	return (0);
330 }
331 
Op_FreePreload()332 int16 Op_FreePreload() {
333 	// TODO: See if this is needed
334 	debug(1, "Op_FreePreload not implemented");
335 	return (0);
336 }
337 
Op_RemoveMessage()338 int16 Op_RemoveMessage() {
339 	int idx;
340 	int overlay;
341 
342 	idx = popVar();
343 	overlay = popVar();
344 
345 	if (!overlay) {
346 		overlay = currentScriptPtr->overlayNumber;
347 	}
348 
349 	removeCell(&cellHead, overlay, idx, 5, masterScreen);
350 
351 	return (0);
352 }
353 
Op_FindSet()354 int16 Op_FindSet() {
355 	char *ptr = (char *) popPtr();
356 	if (!ptr)
357 		return -1;
358 
359 	char name[36] = "";
360 	Common::strlcpy(name, ptr, sizeof(name));
361 	strToUpper(name);
362 
363 	for (int i = 0; i < NUM_FILE_ENTRIES; i++) {
364 		if (!strcmp(name, filesDatabase[i].subData.name)) {
365 			return (i);
366 		}
367 	}
368 
369 	return -1;
370 }
371 
Op_RemoveFrame()372 int16 Op_RemoveFrame() {
373 	int count = popVar();
374 	int start = popVar();
375 
376 	resetFileEntryRange(start, count);
377 
378 	return (0);
379 }
380 
Op_comment()381 int16 Op_comment() {
382 	char *var;
383 
384 	var = (char *)popPtr();
385 
386 	debug(1, "COMMENT: \"%s\"", var);
387 
388 	return (0);
389 }
390 
Op_RemoveProc()391 int16 Op_RemoveProc() {
392 	int idx;
393 	int overlay;
394 
395 	idx = popVar();
396 	overlay = popVar();
397 
398 	if (!overlay) {
399 		overlay = currentScriptPtr->overlayNumber;
400 	}
401 
402 	removeScript(overlay, idx, &procHead);
403 
404 	return (0);
405 }
406 
Op_FreeOverlay()407 int16 Op_FreeOverlay() {
408 	char localName[36] = "";
409 	char *namePtr;
410 
411 	namePtr = (char *) popPtr();
412 	Common::strlcpy(localName, namePtr, sizeof(localName));
413 
414 	if (localName[0]) {
415 		strToUpper(localName);
416 		releaseOverlay((char *)localName);
417 	}
418 
419 	return 0;
420 }
421 
Op_FindProc()422 int16 Op_FindProc() {
423 	char name[36] = "";
424 
425 	char *ptr = (char *)popPtr();
426 	Common::strlcpy(name, ptr, sizeof(name));
427 	int param = getProcParam(popVar(), 20, name);
428 
429 	return param;
430 }
431 
Op_GetRingWord()432 int16 Op_GetRingWord() {
433 	// Original method had a ringed queue allowing this method to return words one at a time.
434 	// But it never seemed to be used; no entries were ever added to the list
435 	return 0;
436 }
437 
Op_KillMenu()438 int16 Op_KillMenu() {
439 	// Free menus, if active
440 	if (menuTable[0]) {
441 		freeMenu(menuTable[0]);
442 		menuTable[0] = NULL;
443 		currentActiveMenu = -1;
444 	}
445 
446 	if (menuTable[1]) {
447 		freeMenu(menuTable[1]);
448 		menuTable[1] = NULL;
449 		currentActiveMenu = -1;
450 	}
451 
452 	// Free the message list
453 //	if (linkedMsgList) freeMsgList(linkedMsgList);
454 	linkedMsgList = NULL;
455 	linkedRelation = NULL;
456 
457 	return 0;
458 }
459 
Op_UserMenu()460 int16 Op_UserMenu() {
461 	int oldValue = playerMenuEnabled;
462 	playerMenuEnabled = popVar();
463 
464 	return oldValue;
465 }
466 
Op_UserOn()467 int16 Op_UserOn() {
468 	int oldValue = userEnabled;
469 	int newValue = popVar();
470 
471 	if (newValue != -1) {
472 		userEnabled = newValue;
473 	}
474 
475 	return oldValue;
476 }
477 
Op_Display()478 int16 Op_Display() {
479 	int oldValue = displayOn;
480 	int newValue = popVar();
481 
482 	if (newValue != -1) {
483 		displayOn = newValue;
484 	}
485 
486 	return oldValue;
487 }
488 
Op_FreezeParent()489 int16 Op_FreezeParent() {
490 	if (currentScriptPtr->var1A == 20) {
491 		changeScriptParamInList(currentScriptPtr->var18, currentScriptPtr->var16, &procHead, -1, 9997);
492 	} else if (currentScriptPtr->var1A == 30) {
493 		changeScriptParamInList(currentScriptPtr->var18, currentScriptPtr->var16, &relHead, -1, 9997);
494 	}
495 
496 	return 0;
497 }
498 
Op_LoadBackground()499 int16 Op_LoadBackground() {
500 	int result = 0;
501 	char bgName[36] = "";
502 	char *ptr;
503 	int bgIdx;
504 
505 	ptr = (char *) popPtr();
506 
507 	Common::strlcpy(bgName, ptr, sizeof(bgName));
508 
509 	bgIdx = popVar();
510 
511 	if (bgIdx >= 0 && bgIdx < NBSCREENS) {
512 		strToUpper(bgName);
513 
514 		gfxModuleData_gfxWaitVSync();
515 		gfxModuleData_gfxWaitVSync();
516 
517 		result = loadBackground(bgName, bgIdx);
518 
519 		gfxModuleData_addDirtyRect(Common::Rect(0, 0, 320, 200));
520 	}
521 
522 	changeCursor(CURSOR_NORMAL);
523 
524 	return result;
525 }
526 
Op_FrameExist()527 int16 Op_FrameExist() {
528 	int param;
529 
530 	param = popVar();
531 
532 	if (param < 0 || param > 255) {
533 		return 0;
534 	}
535 
536 	if (filesDatabase[param].subData.ptr) {
537 		return 1;
538 	}
539 
540 	return 0;
541 }
542 
Op_LoadFrame()543 int16 Op_LoadFrame() {
544 	int param1;
545 	int param2;
546 	int param3;
547 
548 	char name[36] = "";
549 	char *ptr = (char *) popPtr();
550 	Common::strlcpy(name, ptr, sizeof(name));
551 
552 	param1 = popVar();
553 	param2 = popVar();
554 	param3 = popVar();
555 
556 	if (param3 >= 0 && param3 < NUM_FILE_ENTRIES) {
557 		strToUpper(name);
558 
559 		gfxModuleData_gfxWaitVSync();
560 		gfxModuleData_gfxWaitVSync();
561 
562 		lastAni[0] = 0;
563 
564 		loadFileRange(name, param2, param3, param1);
565 
566 		lastAni[0] = 0;
567 	}
568 
569 	changeCursor(CURSOR_NORMAL);
570 	return 0;
571 }
572 
Op_LoadAbs()573 int16 Op_LoadAbs() {
574 	int result = 0;
575 
576 	char *ptr = (char *) popPtr();
577 	int slot = popVar();
578 
579 	if ((slot >= 0) && (slot < NUM_FILE_ENTRIES)) {
580 		char name[36] = "";
581 		Common::strlcpy(name, ptr, sizeof(name));
582 		strToUpper(name);
583 
584 		gfxModuleData_gfxWaitVSync();
585 		gfxModuleData_gfxWaitVSync();
586 
587 		result = loadFullBundle(name, slot);
588 	}
589 
590 	changeCursor(CURSOR_NORMAL);
591 	return result;
592 }
593 
Op_InitializeState()594 int16 Op_InitializeState() {
595 	int param1 = popVar();
596 	int objIdx = popVar();
597 	int ovlIdx = popVar();
598 
599 	if (!ovlIdx)
600 		ovlIdx = currentScriptPtr->overlayNumber;
601 
602 #ifdef FUNCTION_DEBUG
603 	debug(1, "Init %s state to %d", getObjectName(objIdx, overlayTable[ovlIdx].ovlData->arrayNameObj), param1);
604 #endif
605 
606 	objInit(ovlIdx, objIdx, param1);
607 
608 	return (0);
609 }
610 
Op_GetlowMemory()611 int16 Op_GetlowMemory() {
612 	return 0;
613 }
614 
Op_AniDir()615 int16 Op_AniDir() {
616 	int type = popVar();
617 	int objIdx = popVar();
618 	int ovlIdx = popVar();
619 
620 	if (!ovlIdx)
621 		ovlIdx = currentScriptPtr->overlayNumber;
622 
623 	actorStruct *pActor = findActor(&actorHead, ovlIdx, objIdx, type);
624 	if (pActor)
625 		return pActor->startDirection;
626 
627 	return -1;
628 }
629 
Op_FadeOut()630 int16 Op_FadeOut() {
631 	for (long int i = 0; i < 256; i += 32) {
632 		for (long int j = 0; j < 256; j++) {
633 			int offsetTable[3];
634 			offsetTable[0] = -32;
635 			offsetTable[1] = -32;
636 			offsetTable[2] = -32;
637 			calcRGB(&workpal[3*j], &workpal[3*j], offsetTable);
638 		}
639 		gfxModuleData_setPal256(workpal);
640 		gfxModuleData_flipScreen();
641 	}
642 
643 	memset(globalScreen, 0, 320 * 200);
644 	flip();
645 
646 	fadeFlag = 1;
647 	PCFadeFlag = true;
648 
649 	return 0;
650 }
651 
isOverlayLoaded(const char * name)652 int16 isOverlayLoaded(const char * name) {
653 	int16 i;
654 
655 	for (i = 1; i < numOfLoadedOverlay; i++) {
656 		if (!strcmp(overlayTable[i].overlayName, name) && overlayTable[i].alreadyLoaded) {
657 			return i;
658 		}
659 	}
660 
661 	return 0;
662 }
663 
Op_FindOverlay()664 int16 Op_FindOverlay() {
665 	char name[36] = "";
666 	char *ptr;
667 
668 	ptr = (char *) popPtr();
669 	Common::strlcpy(name, ptr, sizeof(name));
670 	strToUpper(name);
671 
672 	return (isOverlayLoaded(name));
673 }
674 
Op_WriteObject()675 int16 Op_WriteObject() {
676 	int16 returnParam;
677 
678 	int16 param1 = popVar();
679 	int16 param2 = popVar();
680 	int16 param3 = popVar();
681 	int16 param4 = popVar();
682 
683 	getSingleObjectParam(param4, param3, param2, &returnParam);
684 	setObjectPosition(param4, param3, param2, param1);
685 
686 	return returnParam;
687 }
688 
Op_ReadObject()689 int16 Op_ReadObject() {
690 	int16 returnParam;
691 
692 	int member = popVar();
693 	int obj = popVar();
694 	int ovl = popVar();
695 
696 	getSingleObjectParam(ovl, obj, member, &returnParam);
697 
698 	return returnParam;
699 }
700 
Op_FadeIn()701 int16 Op_FadeIn() {
702 	doFade = 1;
703 	return 0;
704 }
705 
Op_GetMouseButton()706 int16 Op_GetMouseButton() {
707 	int16 dummy;
708 	int16 mouseX;
709 	int16 mouseY;
710 	int16 mouseButton;
711 
712 	getMouseStatus(&dummy, &mouseX, &mouseButton, &mouseY);
713 
714 	return mouseButton;
715 }
716 
Op_AddCell()717 int16 Op_AddCell() {
718 	int16 objType = popVar();
719 	int16 objIdx = popVar();
720 	int16 overlayIdx = popVar();
721 
722 	if (!overlayIdx)
723 		overlayIdx = currentScriptPtr->overlayNumber;
724 
725 	addCell(&cellHead, overlayIdx, objIdx, objType, masterScreen, currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, currentScriptPtr->type);
726 
727 	return 0;
728 }
729 
Op_AddBackgroundIncrust()730 int16 Op_AddBackgroundIncrust() {
731 
732 	int16 objType = popVar();
733 	int16 objIdx = popVar();
734 	int16 overlayIdx = popVar();
735 
736 	if (!overlayIdx)
737 		overlayIdx = currentScriptPtr->overlayNumber;
738 
739 	addBackgroundIncrust(overlayIdx, objIdx, &backgroundIncrustHead, currentScriptPtr->scriptNumber, currentScriptPtr->overlayNumber, masterScreen, objType);
740 
741 	return 0;
742 }
743 
Op_RemoveCell()744 int16 Op_RemoveCell() {
745 	int objType = popVar();
746 	int objectIdx = popVar();
747 	int ovlNumber = popVar();
748 
749 	if (!ovlNumber) {
750 		ovlNumber = currentScriptPtr->overlayNumber;
751 	}
752 
753 	removeCell(&cellHead, ovlNumber, objectIdx, objType, masterScreen);
754 
755 	return 0;
756 }
757 
758 int16 fontFileIndex = -1;
759 
Op_SetFont()760 int16 Op_SetFont() {
761 	fontFileIndex = popVar();
762 
763 	return 0;
764 }
765 
Op_UnfreezeParent()766 int16 Op_UnfreezeParent() {
767 	if (currentScriptPtr->var1A == 0x14) {
768 		changeScriptParamInList(currentScriptPtr->var18, currentScriptPtr->var16, &procHead, -1, 0);
769 	} else if (currentScriptPtr->var1A == 0x1E) {
770 		changeScriptParamInList(currentScriptPtr->var18, currentScriptPtr->var16, &relHead, -1, 0);
771 	}
772 
773 	return 0;
774 }
775 
Op_ProtectionFlag()776 int16 Op_ProtectionFlag() {
777 	int16 temp = protectionCode;
778 	int16 newVar;
779 
780 	newVar = popVar();
781 	if (newVar != -1) {
782 		protectionCode = newVar;
783 	}
784 
785 	return temp;
786 }
787 
Op_ClearScreen()788 int16 Op_ClearScreen() {
789 	int bgIdx = popVar();
790 
791 	if ((bgIdx >= 0) && (bgIdx < NBSCREENS) && (backgroundScreens[bgIdx])) {
792 		memset(backgroundScreens[bgIdx], 0, 320 * 200);
793 		backgroundChanged[bgIdx] = true;
794 		strcpy(backgroundTable[0].name, "");
795 	}
796 
797 	return 0;
798 }
799 
Op_AddMessage()800 int16 Op_AddMessage() {
801 	int16 color = popVar();
802 	int16 var_2 = popVar();
803 	int16 var_4 = popVar();
804 	int16 var_6 = popVar();
805 	int16 var_8 = popVar();
806 	int16 overlayIdx = popVar();
807 
808 	if (!overlayIdx)
809 		overlayIdx = currentScriptPtr->overlayNumber;
810 
811 	if (color == -1) {
812 		color = findHighColor();
813 	} else {
814 		if (CVTLoaded) {
815 			color = cvtPalette[color];
816 		}
817 	}
818 
819 	createTextObject(&cellHead, overlayIdx, var_8, var_6, var_4, var_2, color, masterScreen, currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber);
820 
821 	return 0;
822 }
823 
Op_Preload()824 int16 Op_Preload() {
825 	popPtr();
826 	popVar();
827 
828 	return 0;
829 }
830 
Op_LoadCt()831 int16 Op_LoadCt() {
832 	return initCt((const char *)popPtr());
833 }
834 
Op_EndAnim()835 int16 Op_EndAnim() {
836 	int param1 = popVar();
837 	int param2 = popVar();
838 	int overlay = popVar();
839 
840 	if (!overlay)
841 		overlay = currentScriptPtr->overlayNumber;
842 
843 	return isAnimFinished(overlay, param2, &actorHead, param1);
844 }
845 
Op_Protect()846 int16 Op_Protect() {
847 	popPtr();
848 	popVar();
849 
850 	return 0;
851 }
852 
Op_AutoCell()853 int16 Op_AutoCell() {
854 	cellStruct *pObject;
855 
856 	int signal = popVar();
857 	int loop = popVar();
858 	int wait = popVar();
859 	int animStep = popVar();
860 	int end = popVar();
861 	int start = popVar();
862 	int type = popVar();
863 	int change = popVar();
864 	int obj = popVar();
865 	int overlay = popVar();
866 
867 	if (!overlay)
868 		overlay = currentScriptPtr->overlayNumber;
869 
870 	pObject = addCell(&cellHead, overlay, obj, 4, masterScreen, currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, currentScriptPtr->type);
871 
872 	if (!pObject)
873 		return 0;
874 
875 	pObject->animSignal = signal;
876 	pObject->animLoop = loop;
877 	pObject->animWait = wait;
878 	pObject->animStep = animStep;
879 	pObject->animEnd = end;
880 	pObject->animStart = start;
881 	pObject->animType = type;
882 	pObject->animChange = change;
883 
884 	if (type) {
885 		if (currentScriptPtr->type == scriptType_PROC) {
886 			changeScriptParamInList(currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, &procHead, -1, 9996);
887 		} else if (currentScriptPtr->type == scriptType_REL) {
888 			changeScriptParamInList(currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, &relHead, -1, 9996);
889 		}
890 	}
891 
892 	if (change == 5) {
893 		objInit(pObject->overlay, pObject->idx, start);
894 	} else {
895 		setObjectPosition(pObject->overlay, pObject->idx, pObject->animChange, start);
896 	}
897 
898 	if (wait < 0) {
899 		objectParamsQuery params;
900 
901 		getMultipleObjectParam(overlay, obj, &params);
902 		pObject->animCounter = params.state2 - 1;
903 	}
904 
905 	return 0;
906 }
907 
Op_Sizeof()908 int16 Op_Sizeof() {
909 	objectParamsQuery params;
910 	int index = popVar();
911 	int overlay = popVar();
912 
913 	if (!overlay)
914 		overlay = currentScriptPtr->overlayNumber;
915 
916 	getMultipleObjectParam(overlay, index, &params);
917 
918 	return params.nbState - 1;
919 }
920 
Op_SetActiveBackground()921 int16 Op_SetActiveBackground() {
922 	int currentPlane = masterScreen;
923 	int newPlane = popVar();
924 
925 	if (newPlane >= 0 && newPlane < NBSCREENS) {
926 		if (backgroundScreens[newPlane]) {
927 			masterScreen = newPlane;
928 			backgroundChanged[newPlane] = true;
929 			switchPal = 1;
930 		}
931 	}
932 
933 	return currentPlane;
934 }
935 
Op_RemoveBackground()936 int16 Op_RemoveBackground() {
937 	int backgroundIdx = popVar();
938 
939 	if (backgroundIdx > 0 && backgroundIdx < 8) {
940 		if (backgroundScreens[backgroundIdx])
941 			MemFree(backgroundScreens[backgroundIdx]);
942 
943 		if (masterScreen == backgroundIdx) {
944 			masterScreen = 0;
945 			backgroundChanged[0] = true;
946 		}
947 
948 		strcpy(backgroundTable[backgroundIdx].name, "");
949 	} else {
950 		strcpy(backgroundTable[0].name, "");
951 	}
952 
953 	return (0);
954 }
955 
956 int vblLimit;
957 
Op_VBL()958 int16 Op_VBL() {
959 	vblLimit = popVar();
960 	return 0;
961 }
962 
963 int op7BVar = 0;
964 
Op_Sec()965 int16 Op_Sec() {
966 	int di = popVar();
967 	int si = 1 - op7BVar;
968 	int sign;
969 
970 	if (di) {
971 		sign = di / (ABS(di));
972 	} else {
973 		sign = 0;
974 	}
975 
976 	op7BVar = -sign;
977 
978 	return si;
979 }
980 
Op_RemoveBackgroundIncrust()981 int16 Op_RemoveBackgroundIncrust() {
982 	int idx = popVar();
983 	int overlay = popVar();
984 
985 	if (!overlay) {
986 		overlay = currentScriptPtr->overlayNumber;
987 	}
988 
989 	removeBackgroundIncrust(overlay, idx, &backgroundIncrustHead);
990 
991 	return 0;
992 }
993 
Op_SetColor()994 int16 Op_SetColor()	{
995 	int colorB = popVar();
996 	int colorG = popVar();
997 	int colorR = popVar();
998 	int endIdx = popVar();
999 	int startIdx = popVar();
1000 
1001 #define convertRatio 36.571428571428571428571428571429
1002 
1003 	for (int i = startIdx; i <= endIdx; i++) {
1004 		int offsetTable[3];
1005 
1006 		offsetTable[0] = (int)(colorR * convertRatio);
1007 		offsetTable[1] = (int)(colorG * convertRatio);
1008 		offsetTable[2] = (int)(colorB * convertRatio);
1009 
1010 		if (CVTLoaded) {
1011 			int colorIdx = cvtPalette[i];
1012 			calcRGB(&palScreen[masterScreen][3*colorIdx], &workpal[3*colorIdx], offsetTable);
1013 		} else {
1014 			calcRGB(&palScreen[masterScreen][3*i], &workpal[3*i], offsetTable);
1015 		}
1016 	}
1017 
1018 	gfxModuleData_setPalEntries(workpal, 0, 32);
1019 
1020 	return 0;
1021 }
1022 
Op_Inventory()1023 int16 Op_Inventory() {
1024 	int si = var41;
1025 
1026 	var41 = popVar();
1027 
1028 	return si;
1029 }
1030 
Op_RemoveOverlay()1031 int16 Op_RemoveOverlay() {
1032 	int overlayIdx;
1033 
1034 	overlayIdx = popVar();
1035 
1036 	if (strlen(overlayTable[overlayIdx].overlayName)) {
1037 		releaseOverlay(overlayTable[overlayIdx].overlayName);
1038 	}
1039 
1040 	return 0;
1041 }
1042 
Op_ComputeLine()1043 int16 Op_ComputeLine() {
1044 	int y2 = popVar();
1045 	int x2 = popVar();
1046 	int y1 = popVar();
1047 	int x1 = popVar();
1048 
1049 	point* pDest = (point *)popPtr();
1050 
1051 	int maxValue = cor_droite(x1, y1, x2, y2, pDest);
1052 
1053 	flipGen(pDest, maxValue * 4);
1054 
1055 	return maxValue;
1056 }
1057 
Op_FindMsg()1058 int16 Op_FindMsg() {
1059 	int si = popVar();
1060 	popVar();
1061 
1062 	return si;
1063 }
1064 
Op_SetZoom()1065 int16 Op_SetZoom() {
1066 	var46 = popVar();
1067 	var45 = popVar();
1068 	var42 = popVar();
1069 	var39 = popVar();
1070 	return 0;
1071 }
1072 
computeZoom(int param)1073 int16 computeZoom(int param) {
1074 	return (((param - var46) * (var39 - var42)) / (var45 - var46)) + var42;
1075 }
1076 
subOp23(int param1,int param2)1077 int16 subOp23(int param1, int param2) {
1078 	return (param1 * param2) >> 8;
1079 }
1080 
Op_GetStep()1081 int16 Op_GetStep() {
1082 	int si = popVar();
1083 	int dx = popVar();
1084 
1085 	return subOp23(dx, si);
1086 }
1087 
Op_GetZoom()1088 int16 Op_GetZoom() {
1089 	return (computeZoom(popVar()));
1090 }
1091 
addAnimation(actorStruct * pHead,int overlay,int objIdx,int param,int param2)1092 actorStruct *addAnimation(actorStruct * pHead, int overlay, int objIdx, int param, int param2) {
1093 	actorStruct *pPrevious = pHead;
1094 	actorStruct *pCurrent = pHead->next;
1095 
1096 	// go to the end of the list
1097 	while (pCurrent) {
1098 		pPrevious = pCurrent;
1099 		pCurrent = pPrevious->next;
1100 	}
1101 
1102 	actorStruct *pNewElement = (actorStruct *) MemAlloc(sizeof(actorStruct));
1103 	if (!pNewElement)
1104 		return NULL;
1105 
1106 	memset(pNewElement, 0, sizeof(actorStruct));
1107 	pNewElement->next = pPrevious->next;
1108 	pPrevious->next = pNewElement;
1109 
1110 	if (!pCurrent) {
1111 		pCurrent = pHead;
1112 	}
1113 
1114 	pNewElement->prev = pCurrent->prev;
1115 	pCurrent->prev = pNewElement;
1116 
1117 	pNewElement->idx = objIdx;
1118 	pNewElement->type = param2;
1119 	pNewElement->pathId = -1;
1120 	pNewElement->overlayNumber = overlay;
1121 	pNewElement->startDirection = param;
1122 	pNewElement->nextDirection = -1;
1123 	pNewElement->stepX = 5;
1124 	pNewElement->stepY = 2;
1125 	pNewElement->phase = ANIM_PHASE_WAIT;
1126 	pNewElement->flag = 0;
1127 	pNewElement->freeze = 0;
1128 
1129 	return pNewElement;
1130 }
1131 
removeAnimation(actorStruct * pHead,int overlay,int objIdx,int objType)1132 int removeAnimation(actorStruct * pHead, int overlay, int objIdx, int objType) {
1133 	actorStruct* pl;
1134 	actorStruct* pl2;
1135 	actorStruct* pl3;
1136 	actorStruct* pl4;
1137 
1138 	int dir = 0;
1139 
1140 	pl = pHead;
1141 	pl2 = pl;
1142 	pl = pl2->next;
1143 
1144 	while (pl) {
1145 		pl2 = pl;
1146 
1147 		if (((pl->overlayNumber == overlay) || (overlay == -1)) &&
1148 		        ((pl->idx == objIdx) || (objIdx == -1)) &&
1149 		        ((pl->type == objType) || (objType == -1))) {
1150 			pl->type = -1;
1151 		}
1152 
1153 		pl = pl2->next;
1154 	}
1155 
1156 	pl = pHead;
1157 	pl2 = pl;
1158 	pl = pl2->next;
1159 
1160 	while (pl) {
1161 		if (pl->type == -1) {
1162 			pl4 = pl->next;
1163 			pl2->next = pl4;
1164 			pl3 = pl4;
1165 
1166 			if (pl3 == NULL)
1167 				pl3 = pHead;
1168 
1169 			pl3->prev = pl->prev;
1170 
1171 			dir = pl->startDirection;
1172 
1173 			if (pl->pathId >= 0)
1174 				freePerso(pl->pathId);
1175 
1176 			MemFree(pl);
1177 			pl = pl4;
1178 		} else {
1179 			pl2 = pl;
1180 			pl = pl2->next;
1181 		}
1182 	}
1183 
1184 	return dir;
1185 }
1186 
1187 int flag_obstacle;		// numPolyBis
1188 
1189 // add animation
Op_AddAnimation()1190 int16 Op_AddAnimation() {
1191 	int stepY = popVar();
1192 	int stepX = popVar();
1193 	int direction = popVar();
1194 	int start = popVar();
1195 	int type = popVar();
1196 	int obj = popVar();
1197 	int overlay = popVar();
1198 
1199 	if (!overlay) {
1200 		overlay = currentScriptPtr->overlayNumber;
1201 	}
1202 
1203 	if (direction >= 0 && direction <= 3) {
1204 		actorStruct *si;
1205 
1206 		si = addAnimation(&actorHead, overlay, obj, direction, type);
1207 
1208 		if (si) {
1209 			objectParamsQuery params;
1210 
1211 			getMultipleObjectParam(overlay, obj, &params);
1212 
1213 			si->x = params.X;
1214 			si->y = params.Y;
1215 			si->x_dest = -1;
1216 			si->y_dest = -1;
1217 			si->endDirection = -1;
1218 			si->start = start;
1219 			si->stepX = stepX;
1220 			si->stepY = stepY;
1221 
1222 			int newFrame = ABS(actor_end[direction][0]) - 1;
1223 
1224 			int zoom = computeZoom(params.Y);
1225 
1226 			if (actor_end[direction][0] < 0) {
1227 				zoom = -zoom;
1228 			}
1229 
1230 			getPixel(params.X, params.Y);
1231 
1232 			setObjectPosition(overlay, obj, 3, newFrame + start);
1233 			setObjectPosition(overlay, obj, 4, zoom);
1234 			setObjectPosition(overlay, obj, 5, numPoly);
1235 
1236 			animationStart = false;
1237 		}
1238 	}
1239 
1240 	return 0;
1241 }
1242 
Op_RemoveAnimation()1243 int16 Op_RemoveAnimation() {
1244 	int objType = popVar();
1245 	int objIdx = popVar();
1246 	int ovlIdx = popVar();
1247 
1248 	if (!ovlIdx) {
1249 		ovlIdx = currentScriptPtr->overlayNumber;
1250 	}
1251 
1252 	return removeAnimation(&actorHead, ovlIdx, objIdx, objType);
1253 }
1254 
Op_regenerateBackgroundIncrust()1255 int16 Op_regenerateBackgroundIncrust() {
1256 	regenerateBackgroundIncrust(&backgroundIncrustHead);
1257 	return 0;
1258 }
1259 
Op_SetStringColors()1260 int16 Op_SetStringColors() {
1261 	// TODO: here ignore if low color mode
1262 
1263 	subColor = (uint8) popVar();
1264 	itemColor = (uint8) popVar();
1265 	selectColor = (uint8) popVar();
1266 	titleColor = (uint8) popVar();
1267 
1268 	return 0;
1269 }
1270 
Op_XClick()1271 int16 Op_XClick() {
1272 	int x = popVar();
1273 
1274 	if (x != -1) {
1275 		aniX = x;
1276 		animationStart = true;
1277 	}
1278 
1279 	return aniX;
1280 }
1281 
Op_YClick()1282 int16 Op_YClick() {
1283 	int y = popVar();
1284 
1285 	if (y != -1) {
1286 		aniY = y;
1287 		animationStart = true;
1288 	}
1289 
1290 	return aniY;
1291 }
1292 
Op_GetPixel()1293 int16 Op_GetPixel() {
1294 	int x = popVar();
1295 	int y = popVar();
1296 
1297 	getPixel(x, y);
1298 	return numPoly;
1299 }
1300 
Op_TrackAnim()1301 int16 Op_TrackAnim() {		// setup actor position
1302 	actorStruct *pActor;
1303 
1304 	int var0 = popVar();
1305 	int actorY = popVar();
1306 	int actorX = popVar();
1307 	int var1 = popVar();
1308 	int var2 = popVar();
1309 	int overlay = popVar();
1310 
1311 	if (!overlay) {
1312 		overlay = currentScriptPtr->overlayNumber;
1313 	}
1314 
1315 	pActor = findActor(&actorHead, overlay, var2, var1);
1316 
1317 	if (!pActor) {
1318 		return 1;
1319 	}
1320 
1321 	animationStart = false;
1322 
1323 	pActor->x_dest = actorX;
1324 	pActor->y_dest = actorY;
1325 	pActor->flag = 1;
1326 	pActor->endDirection = var0;
1327 
1328 	return 0;
1329 }
1330 
Op_BgName()1331 int16 Op_BgName() {
1332 	char* bgName = (char *)popPtr();
1333 	int bgIdx = popVar();
1334 
1335 	if ((bgIdx >= 0) && (bgIdx < NBSCREENS) && bgName) {
1336 		strcpy(bgName, backgroundTable[bgIdx].name);
1337 
1338 		if (strlen(bgName))
1339 			return 1;
1340 
1341 		return 0;
1342 	}
1343 
1344 	return 0;
1345 }
1346 
Op_LoadSong()1347 int16 Op_LoadSong() {
1348 	const char *ptr = (const char *)popPtr();
1349 	char buffer[33];
1350 
1351 	Common::strlcpy(buffer, ptr, sizeof(buffer));
1352 	strToUpper(buffer);
1353 	_vm->sound().loadMusic(buffer);
1354 
1355 	changeCursor(CURSOR_NORMAL);
1356 	return 0;
1357 }
1358 
Op_PlaySong()1359 int16 Op_PlaySong() {
1360 	if (_vm->sound().songLoaded() && !_vm->sound().songPlayed())
1361 		_vm->sound().playMusic();
1362 
1363 	return 0;
1364 }
1365 
Op_StopSong()1366 int16 Op_StopSong() {
1367 	if (_vm->sound().isPlaying())
1368 		_vm->sound().stopMusic();
1369 
1370 	return 0;
1371 }
1372 
Op_RestoreSong()1373 int16 Op_RestoreSong() {
1374 	// Used in the original to restore the contents of a song. Doesn't seem to be used,
1375 	// since the backup buffer it uses is never set
1376 	return 0;
1377 }
1378 
Op_SongSize()1379 int16 Op_SongSize() {
1380 	int oldSize;
1381 	if (_vm->sound().songLoaded()) {
1382 		oldSize = _vm->sound().numOrders();
1383 
1384 		int size = popVar();
1385 		if ((size >= 1) && (size < 128))
1386 			_vm->sound().setNumOrders(size);
1387 	} else
1388 		oldSize = 0;
1389 
1390 	return oldSize;
1391 }
1392 
Op_SetPattern()1393 int16 Op_SetPattern() {
1394 	int value = popVar();
1395 	int offset = popVar();
1396 
1397 	if (_vm->sound().songLoaded()) {
1398 		_vm->sound().setPattern(offset, value);
1399 	}
1400 
1401 	return 0;
1402 }
1403 
Op_FadeSong()1404 int16 Op_FadeSong() {
1405 	_vm->sound().fadeSong();
1406 
1407 	return 0;
1408 }
1409 
Op_FreeSong()1410 int16 Op_FreeSong() {
1411 	_vm->sound().stopMusic();
1412 	_vm->sound().removeMusic();
1413 	return 0;
1414 }
1415 
Op_SongLoop()1416 int16 Op_SongLoop() {
1417 	bool oldLooping = _vm->sound().musicLooping();
1418 	_vm->sound().musicLoop(popVar() != 0);
1419 
1420 	return oldLooping;
1421 }
1422 
Op_SongPlayed()1423 int16 Op_SongPlayed() {
1424 	return _vm->sound().songPlayed();
1425 }
1426 
setVar49Value(int value)1427 void setVar49Value(int value) {
1428 	flagCt = value;
1429 }
1430 
Op_CTOn()1431 int16 Op_CTOn() {
1432 	setVar49Value(1);
1433 	return 0;
1434 }
1435 
Op_CTOff()1436 int16 Op_CTOff() {
1437 	setVar49Value(0);
1438 	return 0;
1439 }
1440 
Op_FreezeOverlay()1441 int16 Op_FreezeOverlay() {
1442 	//int var0;
1443 	//int var1;
1444 	int temp;
1445 
1446 	int var0 = popVar();
1447 	int var1 = popVar();
1448 
1449 	if (!var1) {
1450 		var1 = currentScriptPtr->overlayNumber;
1451 	}
1452 
1453 	temp = overlayTable[var1].executeScripts;
1454 	overlayTable[var1].executeScripts = var0;
1455 
1456 	return temp;
1457 }
1458 
Op_FreezeCell()1459 int16 Op_FreezeCell() {
1460 	int newFreezz = popVar();
1461 	int oldFreeze = popVar();
1462 	int backgroundPlante = popVar();
1463 	int objType = popVar();
1464 	int objIdx = popVar();
1465 	int overlayIdx = popVar();
1466 
1467 	if (!overlayIdx) {
1468 		overlayIdx = currentScriptPtr->overlayNumber;
1469 	}
1470 
1471 	freezeCell(&cellHead, overlayIdx, objIdx, objType, backgroundPlante, oldFreeze, newFreezz);
1472 
1473 	return 0;
1474 }
1475 
Op_60Sub(int overlayIdx,actorStruct * pActorHead,int _var0,int _var1,int _var2,int _var3)1476 void Op_60Sub(int overlayIdx, actorStruct * pActorHead, int _var0, int _var1, int _var2, int _var3) {
1477 	actorStruct *pActor = findActor(pActorHead, overlayIdx, _var0, _var3);
1478 
1479 	if (pActor) {
1480 		if ((pActor->freeze == _var2) || (_var2 == -1)) {
1481 			pActor->freeze = _var1;
1482 		}
1483 	}
1484 }
1485 
Op_FreezeAni()1486 int16 Op_FreezeAni() {
1487 	/*
1488 	 * int var0;
1489 	 * int var1;
1490 	 * int var2;
1491 	 * int var3;
1492 	 * int var4;
1493 	 */
1494 
1495 	int var0 = popVar();
1496 	int var1 = popVar();
1497 	int var2 = popVar();
1498 	int var3 = popVar();
1499 	int var4 = popVar();
1500 
1501 	if (!var4) {
1502 		var4 = currentScriptPtr->overlayNumber;
1503 	}
1504 
1505 	Op_60Sub(var4, &actorHead, var3, var0, var1, var2);
1506 
1507 	return 0;
1508 }
1509 
Op_Itoa()1510 int16 Op_Itoa() {
1511 	int nbp = popVar();
1512 	int param[160];
1513 	char txt[40];
1514 
1515 	for (int i = 0; i < 160; ++i)
1516 		param[i] = 0;
1517 
1518 	for (int i = nbp - 1; i >= 0; i--)
1519 		param[i] = popVar();
1520 
1521 	int val = popVar();
1522 	char* pDest = (char *)popPtr();
1523 
1524 	if (!nbp)
1525 		sprintf(txt, "%d", val);
1526 	else {
1527 		char format[30];
1528 		char nbf[20];
1529 		strcpy(format, "%");
1530 		sprintf(nbf, "%d", param[0]);
1531 		strcat(format, nbf);
1532 		strcat(format, "d");
1533 		sprintf(txt, format, val);
1534 	}
1535 
1536 	for (int i = 0; txt[i]; i++)
1537 		*(pDest++) = txt[i];
1538 	*(pDest++) = '\0';
1539 
1540 	return 0;
1541 }
1542 
Op_Strcat()1543 int16 Op_Strcat() {
1544 	char *pSource = (char *)popPtr();
1545 	char *pDest = (char *)popPtr();
1546 
1547 	while (*pDest)
1548 		pDest++;
1549 
1550 	while (*pSource)
1551 		*(pDest++) = *(pSource++);
1552 	*(pDest++) = '\0';
1553 
1554 	return 0;
1555 }
1556 
Op_FindSymbol()1557 int16 Op_FindSymbol() {
1558 	int var0 = popVar();
1559 	char *ptr = (char *)popPtr();
1560 	int var1 = popVar();
1561 
1562 	if (!var1)
1563 		var1 = currentScriptPtr->overlayNumber;
1564 
1565 	return getProcParam(var1, var0, ptr);
1566 }
1567 
Op_FindObject()1568 int16 Op_FindObject() {
1569 	char var_26[36];
1570 	char *ptr = (char *)popPtr();
1571 	int overlayIdx;
1572 
1573 	var_26[0] = 0;
1574 
1575 	if (ptr) {
1576 		Common::strlcpy(var_26, ptr, sizeof(var_26));
1577 	}
1578 
1579 	overlayIdx = popVar();
1580 
1581 	if (!overlayIdx)
1582 		overlayIdx = currentScriptPtr->overlayNumber;
1583 
1584 	return getProcParam(overlayIdx, 40, var_26);
1585 }
1586 
Op_SetObjectAtNode()1587 int16 Op_SetObjectAtNode() {
1588 	int16 node = popVar();
1589 	int16 obj = popVar();
1590 	int16 ovl = popVar();
1591 
1592 	if (!ovl)
1593 		ovl = currentScriptPtr->overlayNumber;
1594 
1595 	int nodeInfo[2];
1596 
1597 	if (!getNode(nodeInfo, node)) {
1598 		setObjectPosition(ovl, obj, 0, nodeInfo[0]);
1599 		setObjectPosition(ovl, obj, 1, nodeInfo[1]);
1600 		setObjectPosition(ovl, obj, 2, nodeInfo[1]);
1601 		setObjectPosition(ovl, obj, 4, computeZoom(nodeInfo[1]));
1602 	}
1603 
1604 	return 0;
1605 }
1606 
Op_GetNodeX()1607 int16 Op_GetNodeX() {
1608 	int16 node = popVar();
1609 
1610 	int nodeInfo[2];
1611 
1612 	int result = getNode(nodeInfo, node);
1613 
1614 	assert(result == 0);
1615 
1616 	return nodeInfo[0];
1617 }
1618 
Op_GetNodeY()1619 int16 Op_GetNodeY() {
1620 	int16 node = popVar();
1621 
1622 	int nodeInfo[2];
1623 
1624 	int result = getNode(nodeInfo, node);
1625 
1626 	assert(result == 0);
1627 
1628 	return nodeInfo[1];
1629 }
1630 
Op_SetVolume()1631 int16 Op_SetVolume() {
1632 	int oldVolume = _vm->sound().getVolume();
1633 	int newVolume = popVar();
1634 
1635 	if (newVolume > 63) newVolume = 63;
1636 	if (newVolume >= 0) {
1637 		int volume = 63 - newVolume;
1638 		_vm->sound().setVolume(volume);
1639 	}
1640 
1641 	return oldVolume >> 2;
1642 }
1643 
Op_SongExist()1644 int16 Op_SongExist() {
1645 	const char *songName = (char *)popPtr();
1646 
1647 	if (songName) {
1648 		char name[33];
1649 		Common::strlcpy(name, songName, sizeof(name));
1650 		strToUpper(name);
1651 
1652 		if (!strcmp(_vm->sound().musicName(), name))
1653 			return 1;
1654 	}
1655 
1656 	return 0;
1657 }
1658 
Op_TrackPos()1659 int16 Op_TrackPos() {
1660 	// This function returns a variable that never seems to change from 0
1661 	return 0;
1662 }
1663 
Op_SetNodeState()1664 int16 Op_SetNodeState() {
1665 	int16 state = popVar();
1666 	int16 node = popVar();
1667 
1668 	return setNodeState(node, state);
1669 }
1670 
Op_SetNodeColor()1671 int16 Op_SetNodeColor() {
1672 	int16 color = popVar();
1673 	int16 node = popVar();
1674 
1675 	return setNodeColor(node, color);
1676 }
1677 
Op_SetXDial()1678 int16 Op_SetXDial() {
1679 	int16 old = xdial;
1680 	xdial = popVar();
1681 
1682 	return old;
1683 }
1684 
Op_DialogOn()1685 int16 Op_DialogOn() {
1686 	dialogueObj = popVar();
1687 	dialogueOvl = popVar();
1688 
1689 	if (dialogueOvl == 0)
1690 		dialogueOvl = currentScriptPtr->overlayNumber;
1691 
1692 	dialogueEnabled = true;
1693 
1694 	return 0;
1695 }
1696 
Op_DialogOff()1697 int16 Op_DialogOff() {
1698 	dialogueEnabled = false;
1699 
1700 	objectReset();
1701 
1702 	if (menuTable[0]) {
1703 		freeMenu(menuTable[0]);
1704 		menuTable[0] = NULL;
1705 		changeCursor(CURSOR_NORMAL);
1706 		currentActiveMenu = -1;
1707 	}
1708 
1709 	return 0;
1710 }
1711 
Op_LinkObjects()1712 int16 Op_LinkObjects() {
1713 	int type = popVar();
1714 	int obj2 = popVar();
1715 	int ovl2 = popVar();
1716 	int obj = popVar();
1717 	int ovl = popVar();
1718 
1719 	if (!ovl)
1720 		ovl = currentScriptPtr->overlayNumber;
1721 	if (!ovl2)
1722 		ovl2 = currentScriptPtr->overlayNumber;
1723 
1724 	linkCell(&cellHead, ovl, obj, type, ovl2, obj2);
1725 
1726 	return 0;
1727 }
1728 
Op_UserClick()1729 int16 Op_UserClick() {
1730 	sysKey = popVar();
1731 	sysY = popVar();
1732 	sysX = popVar();
1733 
1734 	return 0;
1735 }
1736 
Op_XMenuItem()1737 int16 Op_XMenuItem() {
1738 	int index = popVar();
1739 	int count = 0;
1740 
1741 	if (!menuTable[0] || (menuTable[0]->numElements == 0))
1742 		return 0;
1743 
1744 	menuElementStruct *p = menuTable[0]->ptrNextElement;
1745 
1746 	while (p) {
1747 		if (count == index)
1748 			return p->x + 1;
1749 
1750 		++count;
1751 		p = p->next;
1752 	}
1753 
1754 	return 0;
1755 }
1756 
Op_YMenuItem()1757 int16 Op_YMenuItem() {
1758 	int index = popVar();
1759 	int count = 0;
1760 
1761 	if (!menuTable[0] || (menuTable[0]->numElements == 0))
1762 		return 0;
1763 
1764 	menuElementStruct *p = menuTable[0]->ptrNextElement;
1765 
1766 	while (p) {
1767 		if (count == index)
1768 			return p->y + 1;
1769 
1770 		++count;
1771 		p = p->next;
1772 	}
1773 
1774 	return 0;
1775 }
1776 
1777 
Op_Menu()1778 int16 Op_Menu() {
1779 	return (int16)(menuTable[0] != NULL);
1780 }
1781 
Op_AutoControl()1782 int16 Op_AutoControl() {
1783 	int oldValue = automaticMode;
1784 	int newValue = popVar();
1785 
1786 	if (newValue >= 0) {
1787 		automaticMode = newValue;
1788 		activeMouse = newValue;
1789 	}
1790 
1791 	return oldValue;
1792 }
1793 
Op_MouseMove()1794 int16 Op_MouseMove() {
1795 	int16 handle, button;
1796 	Common::Point pt;
1797 
1798 	getMouseStatus(&handle, &pt.x, &button, &pt.y);
1799 
1800 	// x/y parameters aren't used
1801 	popVar();
1802 	popVar();
1803 
1804 	return 0;
1805 }
1806 
Op_MouseEnd()1807 int16 Op_MouseEnd() {
1808 	if (automoveInc < automoveMax)
1809 		return (int16)false;
1810 
1811 	return (int16)true;
1812 }
1813 
Op_MsgExist()1814 int16 Op_MsgExist() {
1815 	return isMessage;
1816 }
1817 
Op_UserDelay()1818 int16 Op_UserDelay() {
1819 	int delay = popVar();
1820 
1821 	if (delay >= 0) {
1822 		userDelay = delay;
1823 	}
1824 
1825 	return userDelay;
1826 }
1827 
Op_ThemeReset()1828 int16 Op_ThemeReset() {
1829 	objectReset();
1830 
1831 	return 0;
1832 }
1833 
Op_UserWait()1834 int16 Op_UserWait() {
1835 	userWait = true;
1836 	if (currentScriptPtr->type == scriptType_PROC) {
1837 		changeScriptParamInList(currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, &procHead, -1, 9999);
1838 	} else if (currentScriptPtr->type == scriptType_REL) {
1839 		changeScriptParamInList(currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, &relHead, -1, 9999);
1840 	}
1841 
1842 	return 0;
1843 }
1844 
1845 opcodeFunction opcodeTablePtr[] = {
1846 	NULL, // 0x00
1847 	Op_FadeIn,
1848 	Op_FadeOut,
1849 	Op_LoadBackground,
1850 	Op_LoadAbs,
1851 	Op_AddCell,
1852 	Op_AddProc,
1853 	Op_InitializeState,
1854 	Op_RemoveCell,
1855 	Op_FreeCell,
1856 	Op_RemoveProc,
1857 	Op_RemoveFrame,
1858 	Op_LoadOverlay,
1859 	Op_SetColor,
1860 	Op_PlayFX,
1861 	NULL,	// used to be debug
1862 
1863 	Op_FreeOverlay, // 0x10
1864 	Op_FindOverlay,
1865 	NULL,	// used to be exec debug
1866 	Op_AddMessage,
1867 	Op_RemoveMessage,
1868 	Op_UserWait,
1869 	Op_FreezeCell,
1870 	Op_LoadCt,
1871 	Op_AddAnimation,
1872 	Op_RemoveAnimation,
1873 	Op_SetZoom,
1874 	Op_SetObjectAtNode,
1875 	Op_SetNodeState,
1876 	Op_SetNodeColor,
1877 	Op_TrackAnim,
1878 	Op_GetNodeX,
1879 
1880 	Op_GetNodeY, // 0x20
1881 	Op_EndAnim,
1882 	Op_GetZoom,
1883 	Op_GetStep,
1884 	Op_SetStringColors,
1885 	Op_XClick,
1886 	Op_YClick,
1887 	Op_GetPixel,
1888 	Op_UserOn,
1889 	Op_FreeCT,
1890 	Op_FindObject,
1891 	Op_FindProc,
1892 	Op_WriteObject,
1893 	Op_ReadObject,
1894 	Op_RemoveOverlay,
1895 	Op_AddBackgroundIncrust,
1896 
1897 	Op_RemoveBackgroundIncrust, // 0x30
1898 	Op_UnmergeBackgroundIncrust,
1899 	Op_freeBackgroundInscrustList,
1900 	Op_DialogOn,
1901 	Op_DialogOff,
1902 	Op_UserDelay,
1903 	Op_ThemeReset,
1904 	Op_Narrator,
1905 	Op_RemoveBackground,
1906 	Op_SetActiveBackground,
1907 	Op_CTOn,
1908 	Op_CTOff,
1909 	Op_Random,
1910 	Op_LoadSong,
1911 	Op_FadeSong,
1912 	Op_PlaySong,
1913 
1914 	Op_FreeSong, // 0x40
1915 	Op_FrameExist,
1916 	Op_SetVolume,
1917 	Op_SongExist,
1918 	Op_TrackPos,
1919 	Op_StopSong,
1920 	Op_RestoreSong,
1921 	Op_SongSize,
1922 	Op_SetPattern,
1923 	Op_SongLoop,
1924 	Op_SongPlayed,
1925 	Op_LinkObjects,
1926 	Op_UserClick,
1927 	Op_XMenuItem,
1928 	Op_YMenuItem,
1929 	Op_Menu,
1930 
1931 	Op_AutoControl, // 0x50
1932 	Op_MouseMove,
1933 	Op_MouseEnd,
1934 	Op_MsgExist,
1935 	Op_SetFont,
1936 	NULL, // MergeMsg
1937 	Op_Display,
1938 	Op_GetMouseX,
1939 	Op_GetMouseY,
1940 	Op_GetMouseButton,
1941 	Op_FindSet,
1942 	Op_regenerateBackgroundIncrust,
1943 	Op_BgName,
1944 	Op_LoopFX,
1945 	Op_StopFX,
1946 	Op_FreqFX,
1947 
1948 	Op_FreezeAni, // 0x60
1949 	Op_FindMsg,
1950 	Op_FreezeParent,
1951 	Op_UnfreezeParent,
1952 	Op_Exec,
1953 	Op_AutoCell,
1954 	Op_Sizeof,
1955 	Op_Preload,
1956 	Op_FreePreload,
1957 	NULL, // DeletePreload
1958 	Op_VBL,
1959 	Op_LoadFrame,
1960 	Op_FreezeOverlay,
1961 	Op_Strcpy,
1962 	Op_Strcat,
1963 	Op_Itoa,
1964 
1965 	Op_comment, // 0x70
1966 	Op_ComputeLine,
1967 	Op_FindSymbol,
1968 	Op_SetXDial,
1969 	Op_GetlowMemory,
1970 	Op_AniDir,
1971 	Op_Protect,
1972 	Op_ClearScreen,
1973 	Op_Inventory,
1974 	Op_UserMenu,
1975 	Op_GetRingWord,
1976 	Op_Sec,
1977 	Op_ProtectionFlag,
1978 	Op_KillMenu,
1979 };
1980 
opcodeType8()1981 int32 opcodeType8() {
1982 	int opcode = getByteFromScript();
1983 
1984 	if (!opcode)
1985 		return (-21);
1986 
1987 	if (opcode > 0x100)
1988 		return (-21);
1989 
1990 	if (opcode < ARRAYSIZE(opcodeTablePtr) && opcodeTablePtr[opcode]) {
1991 		pushVar(opcodeTablePtr[opcode]());
1992 		return (0);
1993 	} else {
1994 		warning("Unsupported opcode %d in opcode type 8", opcode);
1995 		pushVar(0);
1996 		// exit(1);
1997 	}
1998 
1999 	return 0;
2000 
2001 }
2002 
2003 } // End of namespace Cruise
2004