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 /*
24  * This code is based on original Soltys source code
25  * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
26  */
27 
28 #include "cge/general.h"
29 #include "cge/sound.h"
30 #include "cge/snail.h"
31 #include "cge/vga13h.h"
32 #include "cge/text.h"
33 #include "cge/cge_main.h"
34 #include "cge/events.h"
35 #include "cge/walk.h"
36 
37 namespace CGE {
38 
39 const char *CommandHandler::_commandText[] = {
40 	"LABEL",  "PAUSE",  "WAIT",    "LEVEL",   "HIDE",
41 	"SAY",    "INF",    "TIME",    "CAVE",    "KILL",
42 	"RSEQ",   "SEQ",    "SEND",    "SWAP",    "KEEP",
43 	"GIVE",   "IF",     "GAME",    "SETX0",   "SETY0",
44 	"SLAVE",  "SETXY",  "RELX",    "RELY",    "RELZ",
45 	"SETX",   "SETY",   "SETZ",    "TRANS",   "PORT",
46 	"NEXT",   "NNEXT",  "TNEXT",   "RNNEXT",  "RTNEXT",
47 	"RMNEAR", "RMTAKE", "FLAG",    "SETREF",  "BACKPT",
48 	"FLASH",  "LIGHT",  "SETHB",   "SETVB",   "WALK",
49 	"REACH",  "COVER",  "UNCOVER", "CLEAR",   "TALK",
50 	"MOUSE",  "SOUND",  "COUNT",   NULL
51 };
52 
CommandHandler(CGEEngine * vm,bool turbo)53 CommandHandler::CommandHandler(CGEEngine *vm, bool turbo)
54 	: _turbo(turbo), _busy(false), _textDelay(false),
55 	  _timerExpiry(0), _talkEnable(true),
56 	  _head(0), _tail(0), _commandList((Command *)malloc(sizeof(Command) * 256)), _vm(vm) {
57 }
58 
~CommandHandler()59 CommandHandler::~CommandHandler() {
60 	free(_commandList);
61 }
62 
63 /**
64  * Add a Command on the head of _commandList
65  * @param com			Command
66  * @param ref			Reference
67  * @param val			Value
68  * @param ptr			Sprite pointer
69  */
addCommand(CommandType com,int ref,int val,void * ptr)70 void CommandHandler::addCommand(CommandType com, int ref, int val, void *ptr) {
71 	Command *headCmd = &_commandList[_head++];
72 	headCmd->_commandType = com;
73 	headCmd->_ref = ref;
74 	headCmd->_val = val;
75 	headCmd->_spritePtr = ptr;
76 	headCmd->_cbType = kNullCB;
77 	if (headCmd->_commandType == kCmdClear) {
78 		_tail = _head;
79 		_vm->killText();
80 		_timerExpiry = 0;
81 	}
82 }
83 
84 /**
85  * Add a Callback on the head of _commandList
86  * @param com			Command
87  * @param ref			Reference
88  * @param val			Value
89  * @param CallbackType	Callback type
90  */
addCallback(CommandType com,int ref,int val,CallbackType cbType)91 void CommandHandler::addCallback(CommandType com, int ref, int val, CallbackType cbType) {
92 	Command *headCmd = &_commandList[_head++];
93 	headCmd->_commandType = com;
94 	headCmd->_ref = ref;
95 	headCmd->_val = val;
96 	headCmd->_spritePtr = NULL;
97 	headCmd->_cbType = cbType;
98 	if (headCmd->_commandType == kCmdClear) {
99 		_tail = _head;
100 		_vm->killText();
101 		_timerExpiry = 0;
102 	}
103 }
104 
105 /**
106  * Add a Command on the tail of _commandList
107  * @param com			Command
108  * @param ref			Reference
109  * @param val			Value
110  * @param ptr			Sprite pointer
111  */
insertCommand(CommandType com,int ref,int val,void * ptr)112 void CommandHandler::insertCommand(CommandType com, int ref, int val, void *ptr) {
113 	Command *tailCmd;
114 
115 	if (_busy) {
116 		_commandList[(_tail - 1) & 0xFF] = _commandList[_tail];
117 		tailCmd = &_commandList[_tail];
118 	} else
119 		tailCmd = &_commandList[(_tail - 1) & 0xFF];
120 	_tail--;
121 	tailCmd->_commandType = com;
122 	tailCmd->_ref = ref;
123 	tailCmd->_val = val;
124 	tailCmd->_spritePtr = ptr;
125 	tailCmd->_cbType = kNullCB;
126 	if (tailCmd->_commandType == kCmdClear) {
127 		_tail = _head;
128 		_vm->killText();
129 		_timerExpiry = 0;
130 	}
131 }
132 
runCommand()133 void CommandHandler::runCommand() {
134 	if (_busy)
135 		return;
136 
137 	_busy = true;
138 	uint8 tmpHead = _head;
139 	while (_tail != tmpHead) {
140 		Command *tailCmd = &_commandList[_tail];
141 
142 		if (!_turbo) { // only for the slower one
143 			if (_timerExpiry) {
144 				// Delay in progress
145 				if (_timerExpiry > g_system->getMillis())
146 					// Delay not yet ended
147 					break;
148 
149 				// Delay is finished
150 				_timerExpiry = 0;
151 			} else {
152 				if (_textDelay) {
153 					_vm->killText();
154 					_textDelay = false;
155 				}
156 			}
157 			if (_vm->_talk && tailCmd->_commandType != kCmdPause)
158 				break;
159 		}
160 
161 		Sprite *spr = ((tailCmd->_ref >= 0) ? _vm->locate(tailCmd->_ref) : ((Sprite *) tailCmd->_spritePtr));
162 		switch (tailCmd->_commandType) {
163 		case kCmdLabel:
164 			break;
165 		case kCmdPause:
166 			_timerExpiry = g_system->getMillis() + tailCmd->_val * kCommandFrameDelay;
167 			if (_vm->_talk)
168 				_textDelay = true;
169 			break;
170 		case kCmdWait:
171 			if (spr) {
172 				if (spr->seqTest(tailCmd->_val) &&
173 					(tailCmd->_val >= 0 || spr != _vm->_hero || _vm->_hero->_tracePtr < 0)) {
174 					_timerExpiry = g_system->getMillis() + spr->_time * kCommandFrameDelay;
175 				} else {
176 					_busy = false;
177 					return;
178 				}
179 			}
180 			break;
181 		case kCmdLevel:
182 			_vm->snLevel(spr, tailCmd->_val);
183 			break;
184 		case kCmdHide:
185 			_vm->snHide(spr, tailCmd->_val);
186 			break;
187 		case kCmdSay:
188 			if (spr && _talkEnable) {
189 				if (spr == _vm->_hero && spr->seqTest(-1))
190 					spr->step(kSeqHTalk);
191 				_vm->_text->say(_vm->_text->getText(tailCmd->_val), spr);
192 				_vm->_sys->_funDel = kHeroFun0;
193 			}
194 			break;
195 		case kCmdInf:
196 			if (_talkEnable) {
197 				_vm->inf(_vm->_text->getText(tailCmd->_val), true);
198 				_vm->_sys->_funDel = kHeroFun0;
199 			}
200 			break;
201 		case kCmdTime:
202 			if (spr && _talkEnable) {
203 				if (spr == _vm->_hero && spr->seqTest(-1))
204 					spr->step(kSeqHTalk);
205 				_vm->_text->sayTime(spr);
206 			}
207 			break;
208 		case kCmdCave:
209 			_vm->switchScene(tailCmd->_val);
210 			break;
211 		case kCmdKill:
212 			_vm->snKill(spr);
213 			break;
214 		case kCmdSeq:
215 			_vm->snSeq(spr, tailCmd->_val);
216 			break;
217 		case kCmdRSeq:
218 			_vm->snRSeq(spr, tailCmd->_val);
219 			break;
220 		case kCmdSend:
221 			_vm->snSend(spr, tailCmd->_val);
222 			break;
223 		case kCmdSwap:
224 			_vm->snSwap(spr, tailCmd->_val);
225 			break;
226 		case kCmdCover:
227 			_vm->snCover(spr, tailCmd->_val);
228 			break;
229 		case kCmdUncover:
230 			_vm->snUncover(spr, (tailCmd->_val >= 0) ? _vm->locate(tailCmd->_val) : ((Sprite *) tailCmd->_spritePtr));
231 			break;
232 		case kCmdKeep:
233 			_vm->snKeep(spr, tailCmd->_val);
234 			break;
235 		case kCmdGive:
236 			_vm->snGive(spr, tailCmd->_val);
237 			break;
238 		case kCmdGame:
239 			_vm->snGame(spr, tailCmd->_val);
240 			break;
241 		case kCmdSetX0:
242 			_vm->snSetX0(tailCmd->_ref, tailCmd->_val);
243 			break;
244 		case kCmdSetY0:
245 			_vm->snSetY0(tailCmd->_ref, tailCmd->_val);
246 			break;
247 		case kCmdSetXY:
248 			_vm->snSetXY(spr, tailCmd->_val);
249 			break;
250 		case kCmdRelX:
251 			_vm->snRelX(spr, tailCmd->_val);
252 			break;
253 		case kCmdRelY:
254 			_vm->snRelY(spr, tailCmd->_val);
255 			break;
256 		case kCmdRelZ:
257 			_vm->snRelZ(spr, tailCmd->_val);
258 			break;
259 		case kCmdSetX:
260 			_vm->snSetX(spr, tailCmd->_val);
261 			break;
262 		case kCmdSetY:
263 			_vm->snSetY(spr, tailCmd->_val);
264 			break;
265 		case kCmdSetZ:
266 			_vm->snSetZ(spr, tailCmd->_val);
267 			break;
268 		case kCmdSlave:
269 			_vm->snSlave(spr, tailCmd->_val);
270 			break;
271 		case kCmdTrans:
272 			_vm->snTrans(spr, tailCmd->_val);
273 			break;
274 		case kCmdPort:
275 			_vm->snPort(spr, tailCmd->_val);
276 			break;
277 		case kCmdNext:
278 		case kCmdIf:
279 		case kCmdTalk:
280 			break;
281 		case kCmdMouse:
282 			_vm->snMouse(tailCmd->_val != 0);
283 			break;
284 		case kCmdNNext:
285 			_vm->snNNext(spr, tailCmd->_val);
286 			break;
287 		case kCmdTNext:
288 			_vm->snTNext(spr, tailCmd->_val);
289 			break;
290 		case kCmdRNNext:
291 			_vm->snRNNext(spr, tailCmd->_val);
292 			break;
293 		case kCmdRTNext:
294 			_vm->snRTNext(spr, tailCmd->_val);
295 			break;
296 		case kCmdRMNear:
297 			_vm->snRmNear(spr);
298 			break;
299 		case kCmdRmTake:
300 			_vm->snRmTake(spr);
301 			break;
302 		case kCmdFlag:
303 			_vm->snFlag(tailCmd->_ref & 3, tailCmd->_val != 0);
304 			break;
305 		case kCmdSetRef:
306 			_vm->snSetRef(spr, tailCmd->_val);
307 			break;
308 		case kCmdBackPt:
309 			_vm->snBackPt(spr, tailCmd->_val);
310 			break;
311 		case kCmdFlash:
312 			_vm->snFlash(tailCmd->_val != 0);
313 			break;
314 		case kCmdLight:
315 			_vm->snLight(tailCmd->_val != 0);
316 			break;
317 		case kCmdSetHBarrier:
318 			_vm->snHBarrier(tailCmd->_ref, tailCmd->_val);
319 			break;
320 		case kCmdSetVBarrier:
321 			_vm->snVBarrier(tailCmd->_ref, tailCmd->_val);
322 			break;
323 		case kCmdWalk:
324 			_vm->snWalk(spr, tailCmd->_ref, tailCmd->_val);
325 			break;
326 		case kCmdReach:
327 			_vm->snReach(spr, tailCmd->_val);
328 			break;
329 		case kCmdSound:
330 			_vm->snSound(spr, tailCmd->_val);
331 			break;
332 		case kCmdCount:
333 			_vm->_sound->setRepeat(tailCmd->_val);
334 			break;
335 		case kCmdExec:
336 			switch (tailCmd->_cbType) {
337 			case kQGame:
338 				_vm->qGame();
339 				break;
340 			case kMiniStep:
341 				_vm->miniStep(tailCmd->_val);
342 				break;
343 			case kXScene:
344 				_vm->xScene();
345 				break;
346 			case kSoundSetVolume:
347 				_vm->sndSetVolume();
348 				break;
349 			default:
350 				error("Unknown Callback Type in SNEXEC");
351 			}
352 			break;
353 		case kCmdStep:
354 			spr->step();
355 			break;
356 		case kCmdZTrim:
357 			_vm->snZTrim(spr);
358 			break;
359 		case kCmdGhost:
360 			_vm->snGhost((Bitmap *) tailCmd->_spritePtr);
361 			break;
362 		default:
363 			warning("Unhandled snc->_com in SNMouse(bool)");
364 			break;
365 		}
366 		_tail++;
367 		if (!_turbo)
368 			break;
369 	}
370 
371 	_busy = false;
372 }
373 
idle()374 bool CommandHandler::idle() {
375 	return (_head == _tail);
376 }
377 
reset()378 void CommandHandler::reset() {
379 	_tail = _head;
380 }
381 
382 /**
383  * Handles mini-Games logic
384  * @param com			Command
385  * @param num			mini game number
386  */
snGame(Sprite * spr,int num)387 void CGEEngine::snGame(Sprite *spr, int num) {
388 	debugC(1, kCGEDebugEngine, "CGEEngine::snGame(spr, %d)", num);
389 
390 	switch (num) {
391 	case 1: {
392 		static Sprite *dup[3] = { NULL, NULL, NULL };
393 		int buref = 0;
394 		int Stage = 0;
395 
396 		for (dup[0] = _vga->_showQ->first(); dup[0]; dup[0] = dup[0]->_next) {
397 			buref = dup[0]->_ref;
398 			if (buref / 1000 == 16 && buref % 100 == 6) {
399 				Stage = (buref / 100) % 10;
400 				break;
401 			}
402 		}
403 		if (dup[1] == NULL) {
404 			dup[1] = _vga->_showQ->locate(16003);    // pan
405 			dup[2] = _vga->_showQ->locate(16004);    // pani
406 		}
407 
408 		if (_game) { // continue game
409 			int i = newRandom(3), hand = (dup[0]->_shpCnt == 6);
410 			Stage++;
411 			if (hand && Stage > kDressed)
412 				++hand;
413 			if (i >= 0 && (dup[i] == spr && newRandom(3) == 0)) {
414 				_commandHandler->addCommand(kCmdSeq, -1, 3, dup[0]);               // Yes
415 				_commandHandler->addCommand(kCmdSeq, -1, 3, dup[1]);               // Yes
416 				_commandHandler->addCommand(kCmdSeq, -1, 3, dup[2]);               // Yes
417 				_commandHandler->addCommand(kCmdTNext, -1, 0, dup[0]);             // Reset Take
418 				_commandHandler->addCommand(kCmdTNext, -1, 0, dup[1]);             // Reset Take
419 				_commandHandler->addCommand(kCmdTNext, -1, 0, dup[2]);             // Reset Take
420 				_commandHandler->addCommand(kCmdNNext, -1, 0, dup[0]);             // Reset Near
421 				_commandHandler->addCommand(kCmdPause, -1, 72, NULL);              // Pause the game for 72/80 second
422 				_commandHandler->addCommand(kCmdSay, 1, 16009, NULL);              // Say "I win.."
423 				_commandHandler->addCommand(kCmdSay, buref, 16010, NULL);          // Say "Go Sit..."
424 				_commandHandler->addCommand(kCmdSay, 1, 16011, NULL);              // Say "I prefer not"
425 
426 				if (hand) {
427 					_commandHandler->addCommand(kCmdSend, 16060 + hand, 16, NULL);   // Give hand
428 					_commandHandler->addCommand(kCmdSeq, buref, 4, NULL);            // Take off
429 					_commandHandler->addCommand(kCmdSeq, 16060 + hand, 1, NULL);     // start one of the Bartender animations
430 					_commandHandler->addCommand(kCmdSound, 16060 + hand, 16002, NULL); // Play tear sound
431 					_commandHandler->addCommand(kCmdWait, 16060 + hand, 3, NULL);    // Take up
432 					_commandHandler->addCommand(kCmdSwap, buref, buref + 100, NULL); // Open hand
433 					_commandHandler->addCommand(kCmdSeq, 16016, Stage, NULL);        // Start Belongings animation
434 					_commandHandler->addCommand(kCmdSend, 16060 + hand, -1, NULL);   // Hide hand
435 					_commandHandler->addCommand(kCmdWait, 16060 + hand, -1, NULL);   // Stop moving hand
436 				} else {
437 					_commandHandler->addCommand(kCmdSeq, buref, 4, NULL);            // Take off
438 					_commandHandler->addCommand(kCmdSound, 16060 + hand, 16002, NULL); // Play tear sound
439 					_commandHandler->addCommand(kCmdWait, buref, -1, NULL);          // Will take off
440 					_commandHandler->addCommand(kCmdSwap, buref, buref + 100, NULL); // Open hand
441 					_commandHandler->addCommand(kCmdSeq, 16016, Stage, NULL);        // Start Belongings animation
442 				}
443 				_commandHandler->addCommand(kCmdPause, -1, 72, NULL);              // Pause the game for 72/80 second
444 				_commandHandler->addCommand(kCmdSeq, -1, 0, dup[1]);               // Get away (Him)
445 				_commandHandler->addCommand(kCmdSetXY, -1, 203 + kScrWidth * 49, dup[1]);
446 				_commandHandler->addCommand(kCmdSetZ, -1, 7, dup[1]);
447 				_commandHandler->addCommand(kCmdSeq, -1, 0, dup[2]);               // Get Away (Her)
448 				_commandHandler->addCommand(kCmdSetXY, -1, 182 + kScrWidth * 62, dup[2]);
449 				_commandHandler->addCommand(kCmdSetZ, -1, 9, dup[2]);
450 				_game = false;
451 				return;
452 			} else {
453 				_commandHandler->addCommand(kCmdSeq, -1, 2, dup[0]);               // reset animation sequence
454 				_commandHandler->addCommand(kCmdSeq, -1, 2, dup[1]);               // reset animation sequence
455 				_commandHandler->addCommand(kCmdSeq, -1, 2, dup[2]);               // reset animation sequence
456 				_commandHandler->addCommand(kCmdPause, -1, 72, NULL);              // Pause the game for 72/80 second
457 			}
458 		}
459 		_commandHandler->addCommand(kCmdWalk, 198, 134, NULL);                 // Go to place
460 		_commandHandler->addCommand(kCmdWait, 1, -1, NULL);                    // Stop moving
461 		_commandHandler->addCommand(kCmdCover, 1, 16101, NULL);                // Man to beat
462 		_commandHandler->addCommand(kCmdSeq, 16101, 1, NULL);                  // Start Chief animation (16dupnia)
463 		_commandHandler->addCommand(kCmdWait, 16101, 5, NULL);                 // wait
464 		_commandHandler->addCommand(kCmdPause, 16101, 24, NULL);               // Pause the game for 24/80 second
465 		_commandHandler->addCommand(kCmdSeq, 16040, 1, NULL);                  // Start Slap animation (16plask)
466 		_commandHandler->addCommand(kCmdSound, 16101, 16001, NULL);            // Play "Slap" sound
467 		_commandHandler->addCommand(kCmdPause, 16101, 24, NULL);               // Pause the game for 24/80 second
468 		_commandHandler->addCommand(kCmdSeq, 16040, 0, NULL);                  // Reset animation sequence
469 		_commandHandler->addCommand(kCmdWait, 16101, -1, NULL);                // stay
470 		_commandHandler->addCommand(kCmdUncover, 1, 16101, NULL);              // SDS
471 		if (!_game) {
472 			_commandHandler->addCommand(kCmdSay, buref, 16008, NULL);            // say "Guess!"
473 			_game = true;
474 		}
475 		}
476 		break;
477 	case 2:
478 		if (_sprTv == NULL) {
479 			_sprTv = _vga->_showQ->locate(20700);
480 			_sprK1 = _vga->_showQ->locate(20701);
481 			_sprK2 = _vga->_showQ->locate(20702);
482 			_sprK3 = _vga->_showQ->locate(20703);
483 		}
484 
485 		if (!_game) { // init
486 			_commandHandler->addCommand(kCmdGame, 20002, 2, NULL);
487 			_game = true;
488 			break;
489 		}
490 
491 		// cont
492 		_sprK1->step(newRandom(6));
493 		_sprK2->step(newRandom(6));
494 		_sprK3->step(newRandom(6));
495 
496 		// check the ALT key as it's the solution of the puzzle
497 		// the test has been restricted to some specific OSes
498 		// in order to avoid some obvious issues (like Android, iOS, NDS, N64...)
499 		// Not perfect, but at least better than nothing.
500 #if defined(WIN32) || defined(UNIX) || defined(MACOSX) || defined(MOTOEZX) || defined(LINUXMOTO_SDL)
501 		if (spr->_ref == 1 && _keyboard->_keyAlt) {
502 #else
503 		if (spr->_ref == 1 && _gameCase2Cpt > 1) {
504 #endif
505 			_sprK1->step(5);
506 			_sprK2->step(5);
507 			_sprK3->step(5);
508 		}
509 
510 		_commandHandler->addCommand(kCmdSetZ, 20700, 0, NULL);
511 		bool hit = (_sprK1->_seqPtr + _sprK2->_seqPtr + _sprK3->_seqPtr == 15);
512 		if (hit) {
513 			if (spr->_ref == 1) {
514 				_commandHandler->addCommand(kCmdSay,       1, 20003, NULL);       // hurray!
515 				_commandHandler->addCommand(kCmdSeq,   20011,     2, NULL);       // Camera away
516 				_commandHandler->addCommand(kCmdSend,  20701,    -1, NULL);       // move dice1 to scene -1
517 				_commandHandler->addCommand(kCmdSend,  20702,    -1, NULL);       // move dice2 to scene -1
518 				_commandHandler->addCommand(kCmdSend,  20703,    -1, NULL);       // move dice3 to scene -1
519 				_commandHandler->addCommand(kCmdSend,  20700,    -1, NULL);       // move TV to scene -1
520 				_commandHandler->addCommand(kCmdKeep,  20007,     0, NULL);       // to pocket
521 				_commandHandler->addCommand(kCmdSend,  20006,    20, NULL);       // Move Coin to scene 20
522 				_commandHandler->addCommand(kCmdSound, 20006, 20002, NULL);       // Play Coin sound
523 				_commandHandler->addCommand(kCmdSay,   20002, 20004, NULL);	      // Say "Luck guy..."
524 				_commandHandler->addCommand(kCmdSend,  20010,    20, NULL);       // Move Paper to scene 20
525 				_commandHandler->addCommand(kCmdSound, 20010, 20003, NULL);       // Play "ksh" sound! (fx20003.wav)
526 				_commandHandler->addCommand(kCmdSay,   20001, 20005, NULL);       // Say "Congratulations"
527 				_game = false;
528 				return;
529 			} else
530 				_sprK3->step(newRandom(5));
531 		}
532 
533 		if (_gameCase2Cpt < 100) {
534 			switch (_gameCase2Cpt) {
535 			case 15:
536 				// Give hint about ALTered dice
537 				_commandHandler->addCommand(kCmdSay, 20003, 20021, NULL);
538 				break;
539 			case 30:
540 			case 45:
541 			case 60:
542 			case 75:
543 				// Tell to use ALT key
544 				_commandHandler->addCommand(kCmdSay, 20003, 20022, NULL);
545 				break;
546 			}
547 			_gameCase2Cpt++;
548 		}
549 
550 		switch (spr->_ref) {
551 		case 1:
552 			_commandHandler->addCommand(kCmdSay,   20001, 20011, NULL);        // Say "It'a my turn"
553 			_commandHandler->addCommand(kCmdSeq,   20001,     1, NULL);        // Throw dice
554 			_commandHandler->addCommand(kCmdWait,  20001,     1, NULL);        // wait
555 			_commandHandler->addCommand(kCmdSetZ,  20700,     2, NULL);        // hide dice
556 			_commandHandler->addCommand(kCmdHide,  20007,     1, NULL);        // hide dice
557 			_commandHandler->addCommand(kCmdWait,  20001,    16, NULL);        // wait
558 			_commandHandler->addCommand(kCmdSeq,   20007,     1, NULL);        // Start dice animation (20kosci)
559 			_commandHandler->addCommand(kCmdHide,  20007,     0, NULL);        // unhide
560 			_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL);        // Play Dice sound
561 			_commandHandler->addCommand(kCmdWait,  20007,    -1, NULL);        // the end
562 			_commandHandler->addCommand(kCmdGame,  20001,     2, NULL);        // again!
563 			break;
564 
565 		case 20001:
566 			_commandHandler->addCommand(kCmdSay,   20002, 20012, NULL);        // Say "Now it's mine"
567 			_commandHandler->addCommand(kCmdSeq,   20002,     1, NULL);        // Throw dice
568 			_commandHandler->addCommand(kCmdWait,  20002,     3, NULL);        // wait
569 			_commandHandler->addCommand(kCmdSetZ,  20700,     2, NULL);        // hide dice
570 			_commandHandler->addCommand(kCmdHide,  20007,     1, NULL);        // hide dice
571 			_commandHandler->addCommand(kCmdWait,  20002,    10, NULL);        // wait
572 			_commandHandler->addCommand(kCmdSeq,   20007,     2, NULL);        // Start dice animation (20kosci)
573 			_commandHandler->addCommand(kCmdHide,  20007,     0, NULL);        // unhide
574 			_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL);        // Play Dice sound
575 			_commandHandler->addCommand(kCmdWait,  20007,    -1, NULL);        // the end
576 			_commandHandler->addCommand(kCmdGame,  20002,     2, NULL);        // again!
577 			break;
578 
579 		case 20002:
580 			_commandHandler->addCommand(kCmdSay,   20002, 20010, NULL);        // "Roll the bones!"
581 			_commandHandler->addCommand(kCmdWalk,  20005,    -1, NULL);        // Walk to table
582 			_commandHandler->addCommand(kCmdWait,      1,    -1, NULL);        // Wait
583 			_commandHandler->addCommand(kCmdCover,     1, 20101, NULL);        // grasol ??
584 			_commandHandler->addCommand(kCmdSeq,   20101,     1, NULL);        // Start Chief animation (20solgra)
585 			_commandHandler->addCommand(kCmdWait,  20101,     5, NULL);        // Wait
586 			_commandHandler->addCommand(kCmdSetZ,  20700,     2, NULL);        // Hide dice
587 			_commandHandler->addCommand(kCmdHide,  20007,     1, NULL);        // Hide dice
588 			_commandHandler->addCommand(kCmdWait,  20101,    15, NULL);        // wait
589 			_commandHandler->addCommand(kCmdSeq,   20007,     1, NULL);        // Start dice animation (20kosci)
590 			_commandHandler->addCommand(kCmdHide,  20007,     0, NULL);        // Unhide
591 			_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL);        // Play Dice sound
592 			_commandHandler->addCommand(kCmdWait,  20101,    -1, NULL);        // the end
593 			_commandHandler->addCommand(kCmdUncover,   1, 20101, NULL);        // SDS ??
594 			_commandHandler->addCommand(kCmdGame,      1,     2, NULL);        // again!
595 			break;
596 		}
597 	}
598 }
599 
600 void CGEEngine::expandSprite(Sprite *spr) {
601 	debugC(5, kCGEDebugEngine, "CGEEngine::expandSprite(spr)");
602 
603 	if (spr)
604 		_vga->_showQ->insert(_vga->_spareQ->remove(spr));
605 }
606 
607 void CGEEngine::contractSprite(Sprite *spr) {
608 	debugC(1, kCGEDebugEngine, "CGEEngine::contractSprite(spr)");
609 
610 	if (spr)
611 		_vga->_spareQ->append(_vga->_showQ->remove(spr));
612 }
613 
614 /**
615  * Check if an item is in the inventory, and returns its position
616  * @param spr			Sprite pointer
617  * @return -1			if not found, else index.
618  */
619 int CGEEngine::findPocket(Sprite *spr) {
620 	debugC(1, kCGEDebugEngine, "CGEEngine::findPocket(spr)");
621 
622 	for (int i = 0; i < kPocketNX; i++)
623 		if (_pocket[i] == spr)
624 			return i;
625 	return -1;
626 }
627 
628 /**
629  * Check if an item is in the inventory, and returns its position
630  * @param Inventory slot number		Sprite pointer
631  */
632 void CGEEngine::selectPocket(int n) {
633 	debugC(1, kCGEDebugEngine, "CGEEngine::selectPocket(%d)", n);
634 
635 	if (n < 0 || (_pocLight->_seqPtr && _pocPtr == n)) {
636 		// If no slot specified, or another slot already selected
637 		// stop the blinking animation
638 		_pocLight->step(0);
639 		n = findPocket(NULL);
640 		if (n >= 0)
641 			_pocPtr = n;
642 	} else {
643 		// If slot specified, check if the slot if used.
644 		// Is so, start the blinking animation
645 		if (_pocket[n] != NULL) {
646 			_pocPtr = n;
647 			_pocLight->step(1);
648 		}
649 	}
650 	_pocLight->gotoxy(kPocketX + _pocPtr * kPocketDX + kPocketSX, kPocketY + kPocketSY);
651 }
652 
653 /**
654  * Logic used when all the inventory slots are full and the user tries to pick
655  * another object.
656  * @param Inventory slot number		Sprite pointer
657  */
658 void CGEEngine::pocFul() {
659 	debugC(1, kCGEDebugEngine, "CGEEngine::pocFul()");
660 
661 	if (!_hero)
662 		error("pocFul - Unexpected null _hero");
663 
664 	_hero->park();
665 	_commandHandler->addCommand(kCmdWait, -1, -1, _hero);
666 	_commandHandler->addCommand(kCmdSeq, -1, kSeqPocketFull, _hero);
667 	_commandHandler->addCommand(kCmdSound, -1, 2, _hero); // Play the 'hum-hum" sound (fx00002)
668 	_commandHandler->addCommand(kCmdWait, -1, -1, _hero);
669 	_commandHandler->addCommand(kCmdSay,  1, kPocketFull, _hero);
670 }
671 
672 void CGEEngine::hide1(Sprite *spr) {
673 	debugC(1, kCGEDebugEngine, "CGEEngine::hide1(spr)");
674 
675 	_commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost());
676 }
677 
678 void CGEEngine::snGhost(Bitmap *bmp) {
679 	debugC(1, kCGEDebugEngine, "CGEEngine::snGhost(bmp)");
680 
681 	bmp->hide(bmp->_map & 0xFFFF, bmp->_map >> 16);
682 	bmp->_m = NULL;
683 	bmp->_map = 0;
684 	delete bmp;
685 }
686 
687 void CGEEngine::feedSnail(Sprite *spr, SnList snq) {
688 	debugC(1, kCGEDebugEngine, "CGEEngine::feedSnail(spr, snq)");
689 
690 	if (!spr || !spr->active())
691 		return;
692 
693 	uint8 ptr = (snq == kTake) ? spr->_takePtr : spr->_nearPtr;
694 
695 	if (ptr == kNoPtr)
696 		return;
697 
698 	CommandHandler::Command *comtab = spr->snList(snq);
699 	CommandHandler::Command *c = comtab + ptr;
700 
701 	if (findPocket(NULL) < 0) {                 // no empty pockets?
702 		CommandHandler::Command *p;
703 		for (p = c; p->_commandType != kCmdNext; p++) {     // find KEEP command
704 			if (p->_commandType == kCmdKeep) {
705 				pocFul();
706 				return;
707 			}
708 			if (p->_spritePtr)
709 				break;
710 		}
711 	}
712 	while (true) {
713 		if (c->_commandType == kCmdTalk) {
714 			if ((_commandHandler->_talkEnable = (c->_val != 0)) == false)
715 				killText();
716 		}
717 		if (c->_commandType == kCmdNext) {
718 			Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref);
719 			if (s) {
720 				uint8 *idx = (snq == kTake) ? &s->_takePtr : &s->_nearPtr;
721 				if (*idx != kNoPtr) {
722 					int v;
723 					switch (c->_val) {
724 					case -1 :
725 						v = c - comtab + 1;
726 						break;
727 					case -2 :
728 						v = c - comtab;
729 						break;
730 					case -3 :
731 						v = -1;
732 						break;
733 					default :
734 						v = c->_val;
735 						break;
736 					}
737 					if (v >= 0)
738 						*idx = v;
739 				}
740 			}
741 			if (s == spr)
742 				break;
743 		}
744 		if (c->_commandType == kCmdIf) {
745 			Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref);
746 			if (s) { // sprite extsts
747 				if (! s->seqTest(-1))
748 					c = comtab + c->_val;                // not parked
749 				else
750 					++c;
751 			} else
752 				++c;
753 		} else {
754 			_commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr);
755 			if (c->_spritePtr)
756 				break;
757 			else
758 				c++;
759 		}
760 	}
761 }
762 
763 void CGEEngine::snNNext(Sprite *spr, int p) {
764 	debugC(1, kCGEDebugEngine, "CGEEngine::snNNext(spr, %d)", p);
765 
766 	if (spr)
767 		if (spr->_nearPtr != kNoPtr)
768 			spr->_nearPtr = p;
769 }
770 
771 void CGEEngine::snTNext(Sprite *spr, int p) {
772 	debugC(1, kCGEDebugEngine, "CGEEngine::snTNext(spr, %d)", p);
773 
774 	if (spr)
775 		if (spr->_takePtr != kNoPtr)
776 			spr->_takePtr = p;
777 }
778 
779 void CGEEngine::snRNNext(Sprite *spr, int p) {
780 	debugC(1, kCGEDebugEngine, "CGEEngine::snRNNext(spr, %d)", p);
781 
782 	if (spr)
783 		if (spr->_nearPtr != kNoPtr)
784 			spr->_nearPtr += p;
785 }
786 
787 
788 void CGEEngine::snRTNext(Sprite *spr, int p) {
789 	debugC(1, kCGEDebugEngine, "CGEEngine::snRTNext(spr, %d)", p);
790 
791 	if (spr)
792 		if (spr->_takePtr != kNoPtr)
793 			spr->_takePtr += p;
794 }
795 
796 void CGEEngine::snZTrim(Sprite *spr) {
797 	debugC(4, kCGEDebugEngine, "CGEEngine::snZTrim(spr)");
798 
799 	if (!spr || !spr->active())
800 		return;
801 
802 	Sprite *s = (spr->_flags._shad) ? spr->_prev : NULL;
803 	_vga->_showQ->insert(_vga->_showQ->remove(spr));
804 	if (s) {
805 		s->_z = spr->_z;
806 		_vga->_showQ->insert(_vga->_showQ->remove(s), spr);
807 	}
808 }
809 
810 void CGEEngine::snHide(Sprite *spr, int val) {
811 	debugC(1, kCGEDebugEngine, "CGEEngine::snHide(spr, %d)", val);
812 
813 	if (spr) {
814 		spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide);
815 		if (spr->_flags._shad)
816 			spr->_prev->_flags._hide = spr->_flags._hide;
817 	}
818 }
819 
820 void CGEEngine::snRmNear(Sprite *spr) {
821 	debugC(1, kCGEDebugEngine, "CGEEngine::snRmNear(spr)");
822 
823 	if (spr)
824 		spr->_nearPtr = kNoPtr;
825 }
826 
827 void CGEEngine::snRmTake(Sprite *spr) {
828 	debugC(1, kCGEDebugEngine, "CGEEngine::snRmTake(spr)");
829 
830 	if (spr)
831 		spr->_takePtr = kNoPtr;
832 }
833 
834 void CGEEngine::snSeq(Sprite *spr, int val) {
835 	debugC(1, kCGEDebugEngine, "CGEEngine::snSeq(spr, %d)", val);
836 
837 	if (spr) {
838 		if (spr == _hero && val == 0)
839 			_hero->park();
840 		else
841 			spr->step(val);
842 	}
843 }
844 
845 void CGEEngine::snRSeq(Sprite *spr, int val) {
846 	debugC(1, kCGEDebugEngine, "CGEEngine::snRSeq(spr, %d)", val);
847 
848 	if (spr)
849 		snSeq(spr, spr->_seqPtr + val);
850 }
851 
852 void CGEEngine::snSend(Sprite *spr, int val) {
853 	debugC(1, kCGEDebugEngine, "CGEEngine::snSend(spr, %d)", val);
854 
855 	if (!spr)
856 		return;
857 
858 	int was = spr->_scene;
859 	bool was1 = (was == 0 || was == _now);
860 	bool val1 = (val == 0 || val == _now);
861 	spr->_scene = val;
862 	if (val1 != was1) {
863 		if (was1) {
864 			if (spr->_flags._kept) {
865 				int n = findPocket(spr);
866 				if (n >= 0)
867 					_pocket[n] = NULL;
868 			}
869 			hide1(spr);
870 			contractSprite(spr);
871 			spr->_flags._slav = false;
872 		} else {
873 			if (spr->_ref % 1000 == 0)
874 				_bitmapPalette = _vga->_sysPal;
875 			if (spr->_flags._back)
876 				spr->backShow(true);
877 			else
878 				expandSprite(spr);
879 			_bitmapPalette = NULL;
880 		}
881 	}
882 }
883 
884 void CGEEngine::snSwap(Sprite *spr, int xref) {
885 	debugC(1, kCGEDebugEngine, "CGEEngine::snSwap(spr, %d)", xref);
886 
887 	Sprite *xspr = locate(xref);
888 	if (!spr || !xspr)
889 		return;
890 
891 	int was = spr->_scene;
892 	int xwas = xspr->_scene;
893 	bool was1 = (was == 0 || was == _now);
894 	bool xwas1 = (xwas == 0 || xwas == _now);
895 
896 	SWAP(spr->_scene, xspr->_scene);
897 	SWAP(spr->_x, xspr->_x);
898 	SWAP(spr->_y, xspr->_y);
899 	SWAP(spr->_z, xspr->_z);
900 	if (spr->_flags._kept) {
901 		int n = findPocket(spr);
902 		if (n >= 0)
903 			_pocket[n] = xspr;
904 		xspr->_flags._kept = true;
905 		xspr->_flags._port = false;
906 	}
907 	if (xwas1 != was1) {
908 		if (was1) {
909 			hide1(spr);
910 			contractSprite(spr);
911 		} else
912 			expandSprite(spr);
913 		if (xwas1) {
914 			hide1(xspr);
915 			contractSprite(xspr);
916 		} else
917 			expandSprite(xspr);
918 	}
919 }
920 
921 void CGEEngine::snCover(Sprite *spr, int xref) {
922 	debugC(1, kCGEDebugEngine, "CGEEngine::snCover(spr, %d)", xref);
923 
924 	Sprite *xspr = locate(xref);
925 	if (!spr || !xspr)
926 		return;
927 
928 	spr->_flags._hide = true;
929 	xspr->_z = spr->_z;
930 	xspr->_scene = spr->_scene;
931 	xspr->gotoxy(spr->_x, spr->_y);
932 	expandSprite(xspr);
933 	if ((xspr->_flags._shad = spr->_flags._shad) == 1) {
934 		_vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr);
935 		spr->_flags._shad = false;
936 	}
937 	feedSnail(xspr, kNear);
938 }
939 
940 void CGEEngine::snUncover(Sprite *spr, Sprite *xspr) {
941 	debugC(1, kCGEDebugEngine, "CGEEngine::snUncover(spr, xspr)");
942 
943 	if (!spr || !xspr)
944 		return;
945 
946 	spr->_flags._hide = false;
947 	spr->_scene = xspr->_scene;
948 	spr->gotoxy(xspr->_x, xspr->_y);
949 	if ((spr->_flags._shad = xspr->_flags._shad) == 1) {
950 		_vga->_showQ->insert(_vga->_showQ->remove(xspr->_prev), spr);
951 		xspr->_flags._shad = false;
952 	}
953 	spr->_z = xspr->_z;
954 	snSend(xspr, -1);
955 	if (spr->_time == 0)
956 		spr->_time++;
957 }
958 
959 void CGEEngine::snSetX0(int scene, int x0) {
960 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetX0(%d, %d)", scene, x0);
961 
962 	_heroXY[scene - 1].x = x0;
963 }
964 
965 void CGEEngine::snSetY0(int scene, int y0) {
966 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetY0(%d, %d)", scene, y0);
967 
968 	_heroXY[scene - 1].y = y0;
969 }
970 
971 void CGEEngine::snSetXY(Sprite *spr, uint16 xy) {
972 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetXY(spr, %d)", xy);
973 
974 	if (spr)
975 		spr->gotoxy(xy % kScrWidth, xy / kScrWidth);
976 }
977 
978 void CGEEngine::snRelX(Sprite *spr, int x) {
979 	debugC(1, kCGEDebugEngine, "CGEEngine::snRelX(spr, %d)", x);
980 
981 	if (spr && _hero)
982 		spr->gotoxy(_hero->_x + x, spr->_y);
983 }
984 
985 void CGEEngine::snRelY(Sprite *spr, int y) {
986 	debugC(1, kCGEDebugEngine, "CGEEngine::snRelY(spr, %d)", y);
987 
988 	if (spr && _hero)
989 		spr->gotoxy(spr->_x, _hero->_y + y);
990 }
991 
992 void CGEEngine::snRelZ(Sprite *spr, int z) {
993 	debugC(1, kCGEDebugEngine, "CGEEngine::snRelZ(spr, %d)", z);
994 
995 	if (spr && _hero) {
996 		spr->_z = _hero->_z + z;
997 		snZTrim(spr);
998 	}
999 }
1000 
1001 void CGEEngine::snSetX(Sprite *spr, int x) {
1002 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetX(spr, %d)", x);
1003 
1004 	if (spr)
1005 		spr->gotoxy(x, spr->_y);
1006 }
1007 
1008 void CGEEngine::snSetY(Sprite *spr, int y) {
1009 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetY(spr, %d)", y);
1010 
1011 	if (spr)
1012 		spr->gotoxy(spr->_x, y);
1013 }
1014 
1015 void CGEEngine::snSetZ(Sprite *spr, int z) {
1016 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetZ(spr, %d)", z);
1017 
1018 	if (spr) {
1019 		spr->_z = z;
1020 		snZTrim(spr);
1021 	}
1022 }
1023 
1024 void CGEEngine::snSlave(Sprite *spr, int ref) {
1025 	debugC(1, kCGEDebugEngine, "CGEEngine::snSlave(spr, %d)", ref);
1026 
1027 	Sprite *slv = locate(ref);
1028 	if (spr && slv) {
1029 		if (spr->active()) {
1030 			snSend(slv, spr->_scene);
1031 			slv->_flags._slav = true;
1032 			slv->_z = spr->_z;
1033 			_vga->_showQ->insert(_vga->_showQ->remove(slv), spr->_next);
1034 		}
1035 	}
1036 }
1037 
1038 void CGEEngine::snTrans(Sprite *spr, int trans) {
1039 	debugC(1, kCGEDebugEngine, "CGEEngine::snTrans(spr, %d)", trans);
1040 
1041 	if (spr)
1042 		spr->_flags._tran = (trans < 0) ? !spr->_flags._tran : (trans != 0);
1043 }
1044 
1045 void CGEEngine::snPort(Sprite *spr, int port) {
1046 	debugC(1, kCGEDebugEngine, "CGEEngine::snPort(spr, %d)", port);
1047 
1048 	if (spr)
1049 		spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0);
1050 }
1051 
1052 void CGEEngine::snKill(Sprite *spr) {
1053 	debugC(1, kCGEDebugEngine, "CGEEngine::snKill(spr)");
1054 
1055 	if (!spr)
1056 		return;
1057 
1058 	if (spr->_flags._kept) {
1059 		int n = findPocket(spr);
1060 		if (n >= 0)
1061 			_pocket[n] = NULL;
1062 	}
1063 	Sprite *nx = spr->_next;
1064 	hide1(spr);
1065 	_vga->_showQ->remove(spr);
1066 	_eventManager->clearEvent(spr);
1067 	if (spr->_flags._kill) {
1068 		delete spr;
1069 	} else {
1070 		spr->_scene = -1;
1071 		_vga->_spareQ->append(spr);
1072 	}
1073 	if (nx) {
1074 		if (nx->_flags._slav)
1075 			snKill(nx);
1076 	}
1077 }
1078 
1079 /**
1080  * Play a FX sound
1081  * @param spr			Sprite pointer
1082  * @param wav			FX index
1083  */
1084 void CGEEngine::snSound(Sprite *spr, int wav) {
1085 	debugC(1, kCGEDebugEngine, "CGEEngine::snSound(spr, %d)", wav);
1086 
1087 	if (wav == -1)
1088 		_sound->stop();
1089 	else
1090 		_sound->play((*_fx)[wav], (spr) ? ((spr->_x + spr->_w / 2) / (kScrWidth / 16)) : 8);
1091 
1092 	_sound->setRepeat(1);
1093 }
1094 
1095 void CGEEngine::snKeep(Sprite *spr, int stp) {
1096 	debugC(1, kCGEDebugEngine, "CGEEngine::snKeep(spr, %d)", stp);
1097 
1098 	selectPocket(-1);
1099 	if (spr && ! spr->_flags._kept && _pocket[_pocPtr] == NULL) {
1100 		int16 oldRepeat = _sound->getRepeat();
1101 		_sound->setRepeat(1);
1102 		snSound(spr, 3);
1103 		_sound->setRepeat(oldRepeat);
1104 		_pocket[_pocPtr] = spr;
1105 		spr->_scene = 0;
1106 		spr->_flags._kept = true;
1107 		spr->gotoxy(kPocketX + kPocketDX * _pocPtr + kPocketDX / 2 - spr->_w / 2,
1108 		          kPocketY + kPocketDY / 2 - spr->_h / 2);
1109 		if (stp >= 0)
1110 			spr->step(stp);
1111 	}
1112 	selectPocket(-1);
1113 }
1114 
1115 /**
1116  * Remove an object from the inventory and (if specified) trigger an animation
1117  * @param spr			Inventory item
1118  * @param stp			Animation
1119  */
1120 void CGEEngine::snGive(Sprite *spr, int stp) {
1121 	debugC(1, kCGEDebugEngine, "CGEEngine::snGive(spr, %d)", stp);
1122 
1123 	if (spr) {
1124 		int p = findPocket(spr);
1125 		if (p >= 0) {
1126 			_pocket[p] = NULL;
1127 			spr->_scene = _now;
1128 			spr->_flags._kept = false;
1129 			if (stp >= 0)
1130 				spr->step(stp);
1131 		}
1132 	}
1133 	selectPocket(-1);
1134 }
1135 
1136 void CGEEngine::snBackPt(Sprite *spr, int stp) {
1137 	debugC(1, kCGEDebugEngine, "CGEEngine::snBackPt(spr, %d)", stp);
1138 
1139 	if (spr) {
1140 		if (stp >= 0)
1141 			spr->step(stp);
1142 		spr->backShow(true);
1143 	}
1144 }
1145 
1146 void CGEEngine::snLevel(Sprite *spr, int lev) {
1147 	debugC(1, kCGEDebugEngine, "CGEEngine::snLevel(spr, %d)", lev);
1148 
1149 	assert((lev >= 0) && (lev < 5));
1150 
1151 	for (int i = 0; i < 5; i++) {
1152 		spr = _vga->_spareQ->locate(100 + i);
1153 		if (spr) {
1154 			if (i <= lev) {
1155 				spr->backShow(true);
1156 				spr->_scene = 0;
1157 				spr->_flags._hide = false;
1158 			} else {
1159 				spr->_flags._hide = true;
1160 				spr->_scene = -1;
1161 			}
1162 		} else {
1163 			warning("SPR not found! ref: %d", 100 + i);
1164 		}
1165 	}
1166 
1167 	_lev = lev;
1168 	_maxScene = _maxSceneArr[_lev];
1169 }
1170 
1171 /**
1172  * Set a flag to a value
1173  * @param indx			Flag index
1174  * @param val			Flag value
1175  */
1176 void CGEEngine::snFlag(int indx, bool val) {
1177 	_flag[indx] = val;
1178 }
1179 
1180 void CGEEngine::snSetRef(Sprite *spr, int nr) {
1181 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetRef(spr, %d)", nr);
1182 
1183 	if (spr)
1184 		spr->_ref = nr;
1185 }
1186 
1187 void CGEEngine::snFlash(bool on) {
1188 	debugC(1, kCGEDebugEngine, "CGEEngine::snFlash(%s)", on ? "true" : "false");
1189 
1190 	if (on) {
1191 		Dac *pal = (Dac *)malloc(sizeof(Dac) * kPalCount);
1192 		if (pal) {
1193 			memcpy(pal, _vga->_sysPal, kPalSize);
1194 			for (int i = 0; i < kPalCount; i++) {
1195 				int c;
1196 				c = pal[i]._r << 1;
1197 				pal[i]._r = (c < 64) ? c : 63;
1198 				c = pal[i]._g << 1;
1199 				pal[i]._g = (c < 64) ? c : 63;
1200 				c = pal[i]._b << 1;
1201 				pal[i]._b = (c < 64) ? c : 63;
1202 			}
1203 			_vga->setColors(pal, 64);
1204 		}
1205 
1206 		free(pal);
1207 	} else
1208 		_vga->setColors(_vga->_sysPal, 64);
1209 	_dark = false;
1210 }
1211 
1212 void CGEEngine::snLight(bool in) {
1213 	debugC(1, kCGEDebugEngine, "CGEEngine::snLight(%s)", in ? "true" : "false");
1214 
1215 	if (in)
1216 		_vga->sunrise(_vga->_sysPal);
1217 	else
1218 		_vga->sunset();
1219 	_dark = !in;
1220 }
1221 
1222 /**
1223  * Set an horizontal boundary
1224  * @param scene			Scene number
1225  * @param barX			Horizontal boundary value
1226  */
1227 void CGEEngine::snHBarrier(const int scene, const int barX) {
1228 	debugC(1, kCGEDebugEngine, "CGEEngine::snHBarrier(%d, %d)", scene, barX);
1229 
1230 	_barriers[(scene > 0) ? scene : _now]._horz = barX;
1231 }
1232 
1233 /**
1234  * Set a vertical boundary
1235  * @param scene			Scene number
1236  * @param barY			Vertical boundary value
1237  */
1238 void CGEEngine::snVBarrier(const int scene, const int barY) {
1239 	debugC(1, kCGEDebugEngine, "CGEEngine::snVBarrier(%d, %d)", scene, barY);
1240 
1241 	_barriers[(scene > 0) ? scene : _now]._vert = barY;
1242 }
1243 
1244 void CGEEngine::snWalk(Sprite *spr, int x, int y) {
1245 	debugC(1, kCGEDebugEngine, "CGEEngine::snWalk(spr, %d, %d)", x, y);
1246 
1247 	if (_hero) {
1248 		if (spr && y < 0)
1249 			_hero->findWay(spr);
1250 		else
1251 			_hero->findWay(XZ(x, y));
1252 	}
1253 }
1254 
1255 void CGEEngine::snReach(Sprite *spr, int mode) {
1256 	debugC(1, kCGEDebugEngine, "CGEEngine::snReach(spr, %d)", mode);
1257 
1258 	if (_hero)
1259 		_hero->reach(spr, mode);
1260 }
1261 
1262 void CGEEngine::snMouse(bool on) {
1263 	debugC(1, kCGEDebugEngine, "CGEEngine::snMouse(%s)", on ? "true" : "false");
1264 
1265 	if (on)
1266 		_mouse->on();
1267 	else
1268 		_mouse->off();
1269 }
1270 
1271 } // End of namespace CGE
1272